]> git.sur5r.net Git - i3/i3/commitdiff
get_colorpixel support for non-true color displays 2135/head
authorAlex Auvolat <alex@adnab.me>
Mon, 28 Dec 2015 11:58:32 +0000 (12:58 +0100)
committerAlex Auvolat <alex@adnab.me>
Tue, 29 Dec 2015 13:26:21 +0000 (14:26 +0100)
Re-introduce fully-fledged get_colorpixel function, which enables arbitrary
color depths for the display.  The previous code is kept as an optimization for
the case of a true color display, where a X11 roundtrip is unnecessary.

libi3/get_colorpixel.c

index f81ea6c21b378a961c8f2872553e46b0918ab440..8820938f277352ba423f0c3a19a2f70703e46277 100644 (file)
@@ -9,21 +9,28 @@
 #include <stdint.h>
 #include <string.h>
 
+#include "queue.h"
 #include "libi3.h"
 
+struct Colorpixel {
+    char *hex;
+    uint32_t pixel;
+
+    SLIST_ENTRY(Colorpixel)
+    colorpixels;
+};
+
+SLIST_HEAD(colorpixel_head, Colorpixel)
+colorpixels;
+
 /*
- * Returns the colorpixel to use for the given hex color (think of HTML). Only
- * works for true-color (vast majority of cases) at the moment, avoiding a
- * roundtrip to X11.
+ * Returns the colorpixel to use for the given hex color (think of HTML).
  *
  * The hex_color has to start with #, for example #FF00FF.
  *
  * NOTE that get_colorpixel() does _NOT_ check the given color code for validity.
  * This has to be done by the caller.
  *
- * NOTE that this function may in the future rely on a global xcb_connection_t
- * variable called 'conn' to be present.
- *
  */
 uint32_t get_colorpixel(const char *hex) {
     char strgroups[3][3] = {
@@ -34,5 +41,43 @@ uint32_t get_colorpixel(const char *hex) {
     uint8_t g = strtol(strgroups[1], NULL, 16);
     uint8_t b = strtol(strgroups[2], NULL, 16);
 
-    return (0xFF << 24) | (r << 16 | g << 8 | b);
+    /* Shortcut: if our screen is true color, no need to do a roundtrip to X11 */
+    if (root_screen->root_depth == 24 || root_screen->root_depth == 32) {
+        return (0xFF << 24) | (r << 16 | g << 8 | b);
+    }
+
+    /* Lookup this colorpixel in the cache */
+    struct Colorpixel *colorpixel;
+    SLIST_FOREACH(colorpixel, &(colorpixels), colorpixels) {
+        if (strcmp(colorpixel->hex, hex) == 0)
+            return colorpixel->pixel;
+    }
+
+#define RGB_8_TO_16(i) (65535 * ((i)&0xFF) / 255)
+    int r16 = RGB_8_TO_16(r);
+    int g16 = RGB_8_TO_16(g);
+    int b16 = RGB_8_TO_16(b);
+
+    xcb_alloc_color_reply_t *reply;
+
+    reply = xcb_alloc_color_reply(conn, xcb_alloc_color(conn, root_screen->default_colormap,
+                                                        r16, g16, b16),
+                                  NULL);
+
+    if (!reply) {
+        LOG("Could not allocate color\n");
+        exit(1);
+    }
+
+    uint32_t pixel = reply->pixel;
+    free(reply);
+
+    /* Store the result in the cache */
+    struct Colorpixel *cache_pixel = scalloc(1, sizeof(struct Colorpixel));
+    cache_pixel->hex = sstrdup(hex);
+    cache_pixel->pixel = pixel;
+
+    SLIST_INSERT_HEAD(&(colorpixels), cache_pixel, colorpixels);
+
+    return pixel;
 }