]> git.sur5r.net Git - i3/i3/commitdiff
Use 32-bit visuals for i3bar when possible and allow RGBA colors.
authorIngo Bürk <ingo.buerk@tngtech.com>
Mon, 5 Oct 2015 10:58:05 +0000 (12:58 +0200)
committerIngo Bürk <ingo.buerk@tngtech.com>
Tue, 6 Oct 2015 21:01:57 +0000 (23:01 +0200)
This patch creates all necessary windows for i3bar with 32-bit visuals if available.
It also introduces the possibility to define RGBA colors (next to RGB colors), which
allows the user to set the opacity of any color. This requires running a compositor.

With this patch we also start supporting _NET_SYSTEM_TRAY_VISUAL, which is necessary
for the tray icons so they create the tray window with the correct depth and visual.

i3-input/main.c
i3-nagbar/main.c
i3bar/include/cairo_util.h
i3bar/src/cairo_util.c
i3bar/src/xcb.c
include/libi3.h
libi3/font.c
src/restore_layout.c
src/sighandler.c
src/x.c

index cf3884e9b40e9874b697789bbd52d4568b99abd5..4e1be78b8a9a770affc8b6440058abcfb777ab07 100644 (file)
@@ -141,12 +141,12 @@ static int handle_expose(void *data, xcb_connection_t *conn, xcb_expose_event_t
 
     /* draw the prompt … */
     if (prompt != NULL) {
 
     /* draw the prompt … */
     if (prompt != NULL) {
-        draw_text(prompt, pixmap, pixmap_gc, logical_px(4), logical_px(4), logical_px(492));
+        draw_text(prompt, pixmap, pixmap_gc, NULL, logical_px(4), logical_px(4), logical_px(492));
     }
     /* … and the text */
     if (input_position > 0) {
         i3String *input = i3string_from_ucs2(glyphs_ucs, input_position);
     }
     /* … and the text */
     if (input_position > 0) {
         i3String *input = i3string_from_ucs2(glyphs_ucs, input_position);
-        draw_text(input, pixmap, pixmap_gc, prompt_offset + logical_px(4), logical_px(4), logical_px(492));
+        draw_text(input, pixmap, pixmap_gc, NULL, prompt_offset + logical_px(4), logical_px(4), logical_px(492));
         i3string_free(input);
     }
 
         i3string_free(input);
     }
 
index d86cd69a3f984f15f80012117b868d168f06ef3b..d6ace221821b207f8dadb5c4d8323c217243ae31 100644 (file)
@@ -196,7 +196,7 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) {
 
     /* restore font color */
     set_font_colors(pixmap_gc, color_text, color_background);
 
     /* restore font color */
     set_font_colors(pixmap_gc, color_text, color_background);
-    draw_text(prompt, pixmap, pixmap_gc,
+    draw_text(prompt, pixmap, pixmap_gc, NULL,
               logical_px(4) + logical_px(4),
               logical_px(4) + logical_px(4),
               rect.width - logical_px(4) - logical_px(4));
               logical_px(4) + logical_px(4),
               logical_px(4) + logical_px(4),
               rect.width - logical_px(4) - logical_px(4));
@@ -264,7 +264,7 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) {
         values[1] = color_button_background;
         set_font_colors(pixmap_gc, color_text, color_button_background);
         /* the x term seems to set left/right padding */
         values[1] = color_button_background;
         set_font_colors(pixmap_gc, color_text, color_button_background);
         /* the x term seems to set left/right padding */
-        draw_text(buttons[c].label, pixmap, pixmap_gc,
+        draw_text(buttons[c].label, pixmap, pixmap_gc, NULL,
                   y - w - line_width + logical_px(6),
                   logical_px(4) + logical_px(3),
                   rect.width - y + w + line_width - logical_px(6));
                   y - w - line_width + logical_px(6),
                   logical_px(4) + logical_px(3),
                   rect.width - y + w + line_width - logical_px(6));
index 749beec8b60e1fd1a718d57facbcce94182bfb59..390e6a1c8e2f76c80a06490ac13967373b255954 100644 (file)
@@ -15,6 +15,7 @@ typedef struct color_t {
     double red;
     double green;
     double blue;
     double red;
     double green;
     double blue;
+    double alpha;
 
     /* For compatibility, we also store the colorpixel for now. */
     uint32_t colorpixel;
 
     /* For compatibility, we also store the colorpixel for now. */
     uint32_t colorpixel;
index aff763c3fbc9e7a6004be9e951952ab95b992032..288969c965fd9d9957f86e1f6ea4cdc97244aaf8 100644 (file)
@@ -8,6 +8,7 @@
  */
 #include <stdlib.h>
 #include <err.h>
  */
 #include <stdlib.h>
 #include <err.h>
+#include <string.h>
 #include <xcb/xcb.h>
 #include <xcb/xcb_aux.h>
 #include <cairo/cairo-xcb.h>
 #include <xcb/xcb.h>
 #include <xcb/xcb_aux.h>
 #include <cairo/cairo-xcb.h>
@@ -16,7 +17,7 @@
 #include "libi3.h"
 
 xcb_connection_t *xcb_connection;
 #include "libi3.h"
 
 xcb_connection_t *xcb_connection;
-xcb_screen_t *root_screen;
+xcb_visualtype_t *visual_type;
 
 /*
  * Initialize the cairo surface to represent the given drawable.
 
 /*
  * Initialize the cairo surface to represent the given drawable.
@@ -30,7 +31,7 @@ void cairo_surface_init(surface_t *surface, xcb_drawable_t drawable, int width,
     if (xcb_request_failed(gc_cookie, "Could not create graphical context"))
         exit(EXIT_FAILURE);
 
     if (xcb_request_failed(gc_cookie, "Could not create graphical context"))
         exit(EXIT_FAILURE);
 
-    surface->surface = cairo_xcb_surface_create(xcb_connection, surface->id, get_visualtype(root_screen), width, height);
+    surface->surface = cairo_xcb_surface_create(xcb_connection, surface->id, visual_type, width, height);
     surface->cr = cairo_create(surface->surface);
 }
 
     surface->cr = cairo_create(surface->surface);
 }
 
@@ -50,15 +51,25 @@ void cairo_surface_free(surface_t *surface) {
  *
  */
 color_t cairo_hex_to_color(const char *color) {
  *
  */
 color_t cairo_hex_to_color(const char *color) {
-    char groups[3][3] = {
+    char alpha[2];
+    if (strlen(color) == strlen("#rrggbbaa")) {
+        alpha[0] = color[7];
+        alpha[1] = color[8];
+    } else {
+        alpha[0] = alpha[1] = 'F';
+    }
+
+    char groups[4][3] = {
         {color[1], color[2], '\0'},
         {color[3], color[4], '\0'},
         {color[1], color[2], '\0'},
         {color[3], color[4], '\0'},
-        {color[5], color[6], '\0'}};
+        {color[5], color[6], '\0'},
+        {alpha[0], alpha[1], '\0'}};
 
     return (color_t){
         .red = strtol(groups[0], NULL, 16) / 255.0,
         .green = strtol(groups[1], NULL, 16) / 255.0,
         .blue = strtol(groups[2], NULL, 16) / 255.0,
 
     return (color_t){
         .red = strtol(groups[0], NULL, 16) / 255.0,
         .green = strtol(groups[1], NULL, 16) / 255.0,
         .blue = strtol(groups[2], NULL, 16) / 255.0,
+        .alpha = strtol(groups[3], NULL, 16) / 255.0,
         .colorpixel = get_colorpixel(color)};
 }
 
         .colorpixel = get_colorpixel(color)};
 }
 
@@ -67,5 +78,5 @@ color_t cairo_hex_to_color(const char *color) {
  *
  */
 void cairo_set_source_color(surface_t *surface, color_t color) {
  *
  */
 void cairo_set_source_color(surface_t *surface, color_t color) {
-    cairo_set_source_rgb(surface->cr, color.red, color.green, color.blue);
+    cairo_set_source_rgba(surface->cr, color.red, color.green, color.blue, color.alpha);
 }
 }
index f5d065f0684c36256d1d63e168870a3e30b0616a..443e30eadda9b8f9b48b69d1960df50bffbfeb67 100644 (file)
@@ -64,6 +64,10 @@ static i3Font font;
 /* Icon size (based on font size) */
 int icon_size;
 
 /* Icon size (based on font size) */
 int icon_size;
 
+xcb_visualtype_t *visual_type;
+uint8_t depth;
+xcb_colormap_t colormap;
+
 /* Overall height of the bar (based on font size) */
 int bar_height;
 
 /* Overall height of the bar (based on font size) */
 int bar_height;
 
@@ -170,14 +174,17 @@ static void draw_separator(uint32_t x, struct status_block *block) {
     uint32_t center_x = x - sep_offset;
     if (config.separator_symbol == NULL) {
         /* Draw a classic one pixel, vertical separator. */
     uint32_t center_x = x - sep_offset;
     if (config.separator_symbol == NULL) {
         /* Draw a classic one pixel, vertical separator. */
+        cairo_save(statusline_surface.cr);
+        cairo_set_operator(statusline_surface.cr, CAIRO_OPERATOR_SOURCE);
         cairo_set_source_color(&statusline_surface, colors.sep_fg);
         cairo_rectangle(statusline_surface.cr, center_x, logical_px(sep_voff_px), logical_px(1), bar_height - 2 * logical_px(sep_voff_px));
         cairo_fill(statusline_surface.cr);
         cairo_set_source_color(&statusline_surface, colors.sep_fg);
         cairo_rectangle(statusline_surface.cr, center_x, logical_px(sep_voff_px), logical_px(1), bar_height - 2 * logical_px(sep_voff_px));
         cairo_fill(statusline_surface.cr);
+        cairo_restore(statusline_surface.cr);
     } else {
         /* Draw a custom separator. */
         uint32_t separator_x = MAX(x - block->sep_block_width, center_x - separator_symbol_width / 2);
         set_font_colors(statusline_surface.gc, colors.sep_fg.colorpixel, colors.bar_bg.colorpixel);
     } else {
         /* Draw a custom separator. */
         uint32_t separator_x = MAX(x - block->sep_block_width, center_x - separator_symbol_width / 2);
         set_font_colors(statusline_surface.gc, colors.sep_fg.colorpixel, colors.bar_bg.colorpixel);
-        draw_text(config.separator_symbol, statusline_surface.id, statusline_surface.gc,
+        draw_text(config.separator_symbol, statusline_surface.id, statusline_surface.gc, visual_type,
                   separator_x, logical_px(ws_voff_px), x - separator_x);
     }
 }
                   separator_x, logical_px(ws_voff_px), x - separator_x);
     }
 }
@@ -239,9 +246,11 @@ void refresh_statusline(bool use_short_text) {
         realloc_sl_buffer();
 
     /* Clear the statusline pixmap. */
         realloc_sl_buffer();
 
     /* Clear the statusline pixmap. */
+    cairo_save(statusline_surface.cr);
     cairo_set_source_color(&statusline_surface, colors.bar_bg);
     cairo_set_source_color(&statusline_surface, colors.bar_bg);
-    cairo_rectangle(statusline_surface.cr, 0, 0, MAX(root_screen->width_in_pixels, statusline_width), bar_height);
-    cairo_fill(statusline_surface.cr);
+    cairo_set_operator(statusline_surface.cr, CAIRO_OPERATOR_SOURCE);
+    cairo_paint(statusline_surface.cr);
+    cairo_restore(statusline_surface.cr);
 
     /* Draw the text of each block. */
     uint32_t x = 0;
 
     /* Draw the text of each block. */
     uint32_t x = 0;
@@ -263,7 +272,8 @@ void refresh_statusline(bool use_short_text) {
         }
 
         set_font_colors(statusline_surface.gc, fg_color.colorpixel, colors.bar_bg.colorpixel);
         }
 
         set_font_colors(statusline_surface.gc, fg_color.colorpixel, colors.bar_bg.colorpixel);
-        draw_text(block->full_text, statusline_surface.id, statusline_surface.gc, x + block->x_offset, logical_px(ws_voff_px), block->width);
+        draw_text(block->full_text, statusline_surface.id, statusline_surface.gc, visual_type,
+                  x + block->x_offset, logical_px(ws_voff_px), block->width);
         x += block->width + block->sep_block_width + block->x_offset + block->x_append;
 
         /* If this is not the last block, draw a separator. */
         x += block->width + block->sep_block_width + block->x_offset + block->x_append;
 
         /* If this is not the last block, draw a separator. */
@@ -699,11 +709,15 @@ static void handle_client_message(xcb_client_message_event_t *event) {
                 ELOG("No output found\n");
                 return;
             }
                 ELOG("No output found\n");
                 return;
             }
-            xcb_reparent_window(xcb_connection,
-                                client,
-                                output->bar.id,
-                                output->rect.w - icon_size - logical_px(config.tray_padding),
-                                logical_px(config.tray_padding));
+
+            xcb_void_cookie_t rcookie = xcb_reparent_window(xcb_connection,
+                                                            client,
+                                                            output->bar.id,
+                                                            output->rect.w - icon_size - logical_px(config.tray_padding),
+                                                            logical_px(config.tray_padding));
+            if (xcb_request_failed(rcookie, "Could not reparent window. Maybe it is using an incorrect depth/visual?"))
+                return;
+
             /* We reconfigure the window to use a reasonable size. The systray
              * specification explicitly says:
              *   Tray icons may be assigned any size by the system tray, and
             /* We reconfigure the window to use a reasonable size. The systray
              * specification explicitly says:
              *   Tray icons may be assigned any size by the system tray, and
@@ -1106,11 +1120,29 @@ char *init_xcb_early() {
     root_screen = xcb_aux_get_screen(xcb_connection, screen);
     xcb_root = root_screen->root;
 
     root_screen = xcb_aux_get_screen(xcb_connection, screen);
     xcb_root = root_screen->root;
 
+    depth = root_screen->root_depth;
+    colormap = root_screen->default_colormap;
+    visual_type = xcb_aux_find_visual_by_attrs(root_screen, -1, 32);
+    if (visual_type) {
+        depth = xcb_aux_get_depth_of_visual(root_screen, visual_type->visual_id);
+        colormap = xcb_generate_id(xcb_connection);
+        xcb_void_cookie_t cm_cookie = xcb_create_colormap_checked(xcb_connection,
+                                                                  XCB_COLORMAP_ALLOC_NONE,
+                                                                  colormap,
+                                                                  xcb_root,
+                                                                  visual_type->visual_id);
+        if (xcb_request_failed(cm_cookie, "Could not allocate colormap")) {
+            exit(EXIT_FAILURE);
+        }
+    } else {
+        visual_type = get_visualtype(root_screen);
+    }
+
     /* We draw the statusline to a seperate pixmap, because it looks the same on all bars and
      * this way, we can choose to crop it */
     xcb_pixmap_t statusline_id = xcb_generate_id(xcb_connection);
     xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection,
     /* We draw the statusline to a seperate pixmap, because it looks the same on all bars and
      * this way, we can choose to crop it */
     xcb_pixmap_t statusline_id = xcb_generate_id(xcb_connection);
     xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection,
-                                                               root_screen->root_depth,
+                                                               depth,
                                                                statusline_id,
                                                                xcb_root,
                                                                root_screen->width_in_pixels,
                                                                statusline_id,
                                                                xcb_root,
                                                                root_screen->width_in_pixels,
@@ -1248,17 +1280,17 @@ void init_tray(void) {
 
     /* tray support: we need a window to own the selection */
     selwin = xcb_generate_id(xcb_connection);
 
     /* tray support: we need a window to own the selection */
     selwin = xcb_generate_id(xcb_connection);
-    uint32_t selmask = XCB_CW_OVERRIDE_REDIRECT;
-    uint32_t selval[] = {1};
+    uint32_t selmask = XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_COLORMAP;
+    uint32_t selval[] = {root_screen->black_pixel, root_screen->black_pixel, 1, colormap};
     xcb_create_window(xcb_connection,
     xcb_create_window(xcb_connection,
-                      root_screen->root_depth,
+                      depth,
                       selwin,
                       xcb_root,
                       -1, -1,
                       1, 1,
                       0,
                       XCB_WINDOW_CLASS_INPUT_OUTPUT,
                       selwin,
                       xcb_root,
                       -1, -1,
                       1, 1,
                       0,
                       XCB_WINDOW_CLASS_INPUT_OUTPUT,
-                      root_screen->root_visual,
+                      visual_type->visual_id,
                       selmask,
                       selval);
 
                       selmask,
                       selval);
 
@@ -1272,6 +1304,14 @@ void init_tray(void) {
                         32,
                         1,
                         &orientation);
                         32,
                         1,
                         &orientation);
+    xcb_change_property(xcb_connection,
+                        XCB_PROP_MODE_REPLACE,
+                        selwin,
+                        atoms[_NET_SYSTEM_TRAY_VISUAL],
+                        XCB_ATOM_VISUALID,
+                        32,
+                        1,
+                        &visual_type->visual_id);
 
     init_tray_colors();
 
 
     init_tray_colors();
 
@@ -1473,7 +1513,7 @@ void realloc_sl_buffer(void) {
 
     xcb_pixmap_t statusline_id = xcb_generate_id(xcb_connection);
     xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection,
 
     xcb_pixmap_t statusline_id = xcb_generate_id(xcb_connection);
     xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection,
-                                                               root_screen->root_depth,
+                                                               depth,
                                                                statusline_id,
                                                                xcb_root,
                                                                MAX(root_screen->width_in_pixels, statusline_width),
                                                                statusline_id,
                                                                xcb_root,
                                                                MAX(root_screen->width_in_pixels, statusline_width),
@@ -1551,41 +1591,44 @@ void reconfig_windows(bool redraw_bars) {
 
             xcb_window_t bar_id = xcb_generate_id(xcb_connection);
             xcb_pixmap_t buffer_id = xcb_generate_id(xcb_connection);
 
             xcb_window_t bar_id = xcb_generate_id(xcb_connection);
             xcb_pixmap_t buffer_id = xcb_generate_id(xcb_connection);
-            mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK;
-            /* Black background */
+            mask = XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP;
+
             values[0] = colors.bar_bg.colorpixel;
             values[0] = colors.bar_bg.colorpixel;
+            values[1] = root_screen->black_pixel;
             /* If hide_on_modifier is set to hide or invisible mode, i3 is not supposed to manage our bar windows */
             /* If hide_on_modifier is set to hide or invisible mode, i3 is not supposed to manage our bar windows */
-            values[1] = (config.hide_on_modifier == M_DOCK ? 0 : 1);
+            values[2] = (config.hide_on_modifier == M_DOCK ? 0 : 1);
             /* We enable the following EventMask fields:
              * EXPOSURE, to get expose events (we have to re-draw then)
              * SUBSTRUCTURE_REDIRECT, to get ConfigureRequests when the tray
              *                        child windows use ConfigureWindow
              * BUTTON_PRESS, to handle clicks on the workspace buttons
              * */
             /* We enable the following EventMask fields:
              * EXPOSURE, to get expose events (we have to re-draw then)
              * SUBSTRUCTURE_REDIRECT, to get ConfigureRequests when the tray
              *                        child windows use ConfigureWindow
              * BUTTON_PRESS, to handle clicks on the workspace buttons
              * */
-            values[2] = XCB_EVENT_MASK_EXPOSURE |
+            values[3] = XCB_EVENT_MASK_EXPOSURE |
                         XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
                         XCB_EVENT_MASK_BUTTON_PRESS;
             if (config.hide_on_modifier == M_DOCK) {
                 /* If the bar is normally visible, catch visibility change events to suspend
                  * the status process when the bar is obscured by full-screened windows.  */
                         XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
                         XCB_EVENT_MASK_BUTTON_PRESS;
             if (config.hide_on_modifier == M_DOCK) {
                 /* If the bar is normally visible, catch visibility change events to suspend
                  * the status process when the bar is obscured by full-screened windows.  */
-                values[2] |= XCB_EVENT_MASK_VISIBILITY_CHANGE;
+                values[3] |= XCB_EVENT_MASK_VISIBILITY_CHANGE;
                 walk->visible = true;
             }
                 walk->visible = true;
             }
+            values[4] = colormap;
+
             xcb_void_cookie_t win_cookie = xcb_create_window_checked(xcb_connection,
             xcb_void_cookie_t win_cookie = xcb_create_window_checked(xcb_connection,
-                                                                     root_screen->root_depth,
+                                                                     depth,
                                                                      bar_id,
                                                                      xcb_root,
                                                                      walk->rect.x, walk->rect.y + walk->rect.h - bar_height,
                                                                      walk->rect.w, bar_height,
                                                                      0,
                                                                      XCB_WINDOW_CLASS_INPUT_OUTPUT,
                                                                      bar_id,
                                                                      xcb_root,
                                                                      walk->rect.x, walk->rect.y + walk->rect.h - bar_height,
                                                                      walk->rect.w, bar_height,
                                                                      0,
                                                                      XCB_WINDOW_CLASS_INPUT_OUTPUT,
-                                                                     root_screen->root_visual,
+                                                                     visual_type->visual_id,
                                                                      mask,
                                                                      values);
 
             /* The double-buffer we use to render stuff off-screen */
             xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection,
                                                                      mask,
                                                                      values);
 
             /* The double-buffer we use to render stuff off-screen */
             xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection,
-                                                                    root_screen->root_depth,
+                                                                    depth,
                                                                     buffer_id,
                                                                     bar_id,
                                                                     walk->rect.w,
                                                                     buffer_id,
                                                                     bar_id,
                                                                     walk->rect.w,
@@ -1701,7 +1744,7 @@ void reconfig_windows(bool redraw_bars) {
 
             DLOG("Recreating buffer for output %s\n", walk->name);
             xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection,
 
             DLOG("Recreating buffer for output %s\n", walk->name);
             xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection,
-                                                                    root_screen->root_depth,
+                                                                    depth,
                                                                     walk->buffer.id,
                                                                     walk->bar.id,
                                                                     walk->rect.w,
                                                                     walk->buffer.id,
                                                                     walk->bar.id,
                                                                     walk->rect.w,
@@ -1766,10 +1809,13 @@ void draw_bars(bool unhide) {
             /* Oh shit, an active output without an own bar. Create it now! */
             reconfig_windows(false);
         }
             /* Oh shit, an active output without an own bar. Create it now! */
             reconfig_windows(false);
         }
+
         /* First things first: clear the backbuffer */
         /* First things first: clear the backbuffer */
+        cairo_save(outputs_walk->buffer.cr);
         cairo_set_source_color(&(outputs_walk->buffer), colors.bar_bg);
         cairo_set_source_color(&(outputs_walk->buffer), colors.bar_bg);
-        cairo_rectangle(outputs_walk->buffer.cr, 0, 0, outputs_walk->rect.w, bar_height);
-        cairo_fill(outputs_walk->buffer.cr);
+        cairo_set_operator(outputs_walk->buffer.cr, CAIRO_OPERATOR_SOURCE);
+        cairo_paint(outputs_walk->buffer.cr);
+        cairo_restore(outputs_walk->buffer.cr);
 
         if (!config.disable_ws) {
             i3_ws *ws_walk;
 
         if (!config.disable_ws) {
             i3_ws *ws_walk;
@@ -1798,20 +1844,27 @@ void draw_bars(bool unhide) {
                     unhide = true;
                 }
 
                     unhide = true;
                 }
 
+                cairo_save(outputs_walk->buffer.cr);
+                cairo_set_operator(outputs_walk->buffer.cr, CAIRO_OPERATOR_SOURCE);
+
+                /* Draw the border of the button. */
                 cairo_set_source_color(&(outputs_walk->buffer), border_color);
                 cairo_rectangle(outputs_walk->buffer.cr, workspace_width, logical_px(1),
                                 ws_walk->name_width + 2 * logical_px(ws_hoff_px) + 2 * logical_px(1),
                                 font.height + 2 * logical_px(ws_voff_px) - 2 * logical_px(1));
                 cairo_fill(outputs_walk->buffer.cr);
 
                 cairo_set_source_color(&(outputs_walk->buffer), border_color);
                 cairo_rectangle(outputs_walk->buffer.cr, workspace_width, logical_px(1),
                                 ws_walk->name_width + 2 * logical_px(ws_hoff_px) + 2 * logical_px(1),
                                 font.height + 2 * logical_px(ws_voff_px) - 2 * logical_px(1));
                 cairo_fill(outputs_walk->buffer.cr);
 
+                /* Draw the inside of the button. */
                 cairo_set_source_color(&(outputs_walk->buffer), bg_color);
                 cairo_rectangle(outputs_walk->buffer.cr, workspace_width + logical_px(1), 2 * logical_px(1),
                                 ws_walk->name_width + 2 * logical_px(ws_hoff_px),
                                 font.height + 2 * logical_px(ws_voff_px) - 4 * logical_px(1));
                 cairo_fill(outputs_walk->buffer.cr);
 
                 cairo_set_source_color(&(outputs_walk->buffer), bg_color);
                 cairo_rectangle(outputs_walk->buffer.cr, workspace_width + logical_px(1), 2 * logical_px(1),
                                 ws_walk->name_width + 2 * logical_px(ws_hoff_px),
                                 font.height + 2 * logical_px(ws_voff_px) - 4 * logical_px(1));
                 cairo_fill(outputs_walk->buffer.cr);
 
+                cairo_restore(outputs_walk->buffer.cr);
+
                 set_font_colors(outputs_walk->buffer.gc, fg_color.colorpixel, bg_color.colorpixel);
                 set_font_colors(outputs_walk->buffer.gc, fg_color.colorpixel, bg_color.colorpixel);
-                draw_text(ws_walk->name, outputs_walk->buffer.id, outputs_walk->buffer.gc,
+                draw_text(ws_walk->name, outputs_walk->buffer.id, outputs_walk->buffer.gc, visual_type,
                           workspace_width + logical_px(ws_hoff_px) + logical_px(1),
                           logical_px(ws_voff_px),
                           ws_walk->name_width);
                           workspace_width + logical_px(ws_hoff_px) + logical_px(1),
                           logical_px(ws_voff_px),
                           ws_walk->name_width);
@@ -1828,6 +1881,9 @@ void draw_bars(bool unhide) {
             color_t fg_color = colors.binding_mode_fg;
             color_t bg_color = colors.binding_mode_bg;
 
             color_t fg_color = colors.binding_mode_fg;
             color_t bg_color = colors.binding_mode_bg;
 
+            cairo_save(outputs_walk->buffer.cr);
+            cairo_set_operator(outputs_walk->buffer.cr, CAIRO_OPERATOR_SOURCE);
+
             cairo_set_source_color(&(outputs_walk->buffer), colors.binding_mode_border);
             cairo_rectangle(outputs_walk->buffer.cr, workspace_width, logical_px(1),
                             binding.width + 2 * logical_px(ws_hoff_px) + 2 * logical_px(1),
             cairo_set_source_color(&(outputs_walk->buffer), colors.binding_mode_border);
             cairo_rectangle(outputs_walk->buffer.cr, workspace_width, logical_px(1),
                             binding.width + 2 * logical_px(ws_hoff_px) + 2 * logical_px(1),
@@ -1840,10 +1896,13 @@ void draw_bars(bool unhide) {
                             font.height + 2 * logical_px(ws_voff_px) - 4 * logical_px(1));
             cairo_fill(outputs_walk->buffer.cr);
 
                             font.height + 2 * logical_px(ws_voff_px) - 4 * logical_px(1));
             cairo_fill(outputs_walk->buffer.cr);
 
+            cairo_restore(outputs_walk->buffer.cr);
+
             set_font_colors(outputs_walk->buffer.gc, fg_color.colorpixel, bg_color.colorpixel);
             draw_text(binding.name,
                       outputs_walk->buffer.id,
                       outputs_walk->buffer.gc,
             set_font_colors(outputs_walk->buffer.gc, fg_color.colorpixel, bg_color.colorpixel);
             draw_text(binding.name,
                       outputs_walk->buffer.id,
                       outputs_walk->buffer.gc,
+                      visual_type,
                       workspace_width + logical_px(ws_hoff_px) + logical_px(1),
                       logical_px(ws_voff_px),
                       binding.width);
                       workspace_width + logical_px(ws_hoff_px) + logical_px(1),
                       logical_px(ws_voff_px),
                       binding.width);
@@ -1876,9 +1935,12 @@ void draw_bars(bool unhide) {
             int x_src = (int16_t)(statusline_width - visible_statusline_width);
             int x_dest = (int16_t)(outputs_walk->rect.w - tray_width - logical_px(sb_hoff_px) - visible_statusline_width);
 
             int x_src = (int16_t)(statusline_width - visible_statusline_width);
             int x_dest = (int16_t)(outputs_walk->rect.w - tray_width - logical_px(sb_hoff_px) - visible_statusline_width);
 
+            cairo_save(outputs_walk->buffer.cr);
+            cairo_set_operator(outputs_walk->buffer.cr, CAIRO_OPERATOR_SOURCE);
             cairo_set_source_surface(outputs_walk->buffer.cr, statusline_surface.surface, x_dest - x_src, 0);
             cairo_rectangle(outputs_walk->buffer.cr, x_dest, 0, (int16_t)visible_statusline_width, (int16_t)bar_height);
             cairo_fill(outputs_walk->buffer.cr);
             cairo_set_source_surface(outputs_walk->buffer.cr, statusline_surface.surface, x_dest - x_src, 0);
             cairo_rectangle(outputs_walk->buffer.cr, x_dest, 0, (int16_t)visible_statusline_width, (int16_t)bar_height);
             cairo_fill(outputs_walk->buffer.cr);
+            cairo_restore(outputs_walk->buffer.cr);
         }
 
         workspace_width = 0;
         }
 
         workspace_width = 0;
@@ -1906,9 +1968,14 @@ void redraw_bars(void) {
         if (!outputs_walk->active) {
             continue;
         }
         if (!outputs_walk->active) {
             continue;
         }
+
+        cairo_save(outputs_walk->bar.cr);
+        cairo_set_operator(outputs_walk->bar.cr, CAIRO_OPERATOR_SOURCE);
         cairo_set_source_surface(outputs_walk->bar.cr, outputs_walk->buffer.surface, 0, 0);
         cairo_rectangle(outputs_walk->bar.cr, 0, 0, outputs_walk->rect.w, outputs_walk->rect.h);
         cairo_fill(outputs_walk->bar.cr);
         cairo_set_source_surface(outputs_walk->bar.cr, outputs_walk->buffer.surface, 0, 0);
         cairo_rectangle(outputs_walk->bar.cr, 0, 0, outputs_walk->rect.w, outputs_walk->rect.h);
         cairo_fill(outputs_walk->bar.cr);
+        cairo_restore(outputs_walk->bar.cr);
+
         xcb_flush(xcb_connection);
     }
 }
         xcb_flush(xcb_connection);
     }
 }
index 9e7ef133fb4ca3ce49d253fa2956adcec57186b7..c1e109ef12b63243c59a451e361a3f02ecb13eeb 100644 (file)
@@ -402,8 +402,8 @@ bool font_is_pango(void);
  * Text must be specified as an i3String.
  *
  */
  * Text must be specified as an i3String.
  *
  */
-void draw_text(i3String *text, xcb_drawable_t drawable,
-               xcb_gcontext_t gc, int x, int y, int max_width);
+void draw_text(i3String *text, xcb_drawable_t drawable, xcb_gcontext_t gc,
+               xcb_visualtype_t *visual, int x, int y, int max_width);
 
 /**
  * ASCII version of draw_text to print static strings.
 
 /**
  * ASCII version of draw_text to print static strings.
index b8c31b73b7547de014881666a5f2b3bd26491cc4..8bdf3d600fd0ab95210012dd26d324413a05d553 100644 (file)
@@ -102,12 +102,12 @@ static bool load_pango_font(i3Font *font, const char *desc) {
  *
  */
 static void draw_text_pango(const char *text, size_t text_len,
  *
  */
 static void draw_text_pango(const char *text, size_t text_len,
-                            xcb_drawable_t drawable, int x, int y,
+                            xcb_drawable_t drawable, xcb_visualtype_t *visual, int x, int y,
                             int max_width, bool is_markup) {
     /* Create the Pango layout */
     /* root_visual_type is cached in load_pango_font */
     cairo_surface_t *surface = cairo_xcb_surface_create(conn, drawable,
                             int max_width, bool is_markup) {
     /* Create the Pango layout */
     /* root_visual_type is cached in load_pango_font */
     cairo_surface_t *surface = cairo_xcb_surface_create(conn, drawable,
-                                                        root_visual_type, x + max_width, y + savedFont->height);
+                                                        visual, x + max_width, y + savedFont->height);
     cairo_t *cr = cairo_create(surface);
     PangoLayout *layout = create_layout_with_dpi(cr);
     gint height;
     cairo_t *cr = cairo_create(surface);
     PangoLayout *layout = create_layout_with_dpi(cr);
     gint height;
@@ -391,9 +391,12 @@ static void draw_text_xcb(const xcb_char2b_t *text, size_t text_len, xcb_drawabl
  * Text must be specified as an i3String.
  *
  */
  * Text must be specified as an i3String.
  *
  */
-void draw_text(i3String *text, xcb_drawable_t drawable,
-               xcb_gcontext_t gc, int x, int y, int max_width) {
+void draw_text(i3String *text, xcb_drawable_t drawable, xcb_gcontext_t gc,
+               xcb_visualtype_t *visual, int x, int y, int max_width) {
     assert(savedFont != NULL);
     assert(savedFont != NULL);
+    if (visual == NULL) {
+        visual = root_visual_type;
+    }
 
     switch (savedFont->type) {
         case FONT_TYPE_NONE:
 
     switch (savedFont->type) {
         case FONT_TYPE_NONE:
@@ -407,7 +410,7 @@ void draw_text(i3String *text, xcb_drawable_t drawable,
         case FONT_TYPE_PANGO:
             /* Render the text using Pango */
             draw_text_pango(i3string_as_utf8(text), i3string_get_num_bytes(text),
         case FONT_TYPE_PANGO:
             /* Render the text using Pango */
             draw_text_pango(i3string_as_utf8(text), i3string_get_num_bytes(text),
-                            drawable, x, y, max_width, i3string_is_markup(text));
+                            drawable, visual, x, y, max_width, i3string_is_markup(text));
             return;
 #endif
         default:
             return;
 #endif
         default:
@@ -432,7 +435,7 @@ void draw_text_ascii(const char *text, xcb_drawable_t drawable,
             if (text_len > 255) {
                 /* The text is too long to draw it directly to X */
                 i3String *str = i3string_from_utf8(text);
             if (text_len > 255) {
                 /* The text is too long to draw it directly to X */
                 i3String *str = i3string_from_utf8(text);
-                draw_text(str, drawable, gc, x, y, max_width);
+                draw_text(str, drawable, gc, NULL, x, y, max_width);
                 i3string_free(str);
             } else {
                 /* X11 coordinates for fonts start at the baseline */
                 i3string_free(str);
             } else {
                 /* X11 coordinates for fonts start at the baseline */
@@ -446,7 +449,7 @@ void draw_text_ascii(const char *text, xcb_drawable_t drawable,
         case FONT_TYPE_PANGO:
             /* Render the text using Pango */
             draw_text_pango(text, strlen(text),
         case FONT_TYPE_PANGO:
             /* Render the text using Pango */
             draw_text_pango(text, strlen(text),
-                            drawable, x, y, max_width, false);
+                            drawable, root_visual_type, x, y, max_width, false);
             return;
 #endif
         default:
             return;
 #endif
         default:
index 439d23ccf43abbb33c47220724fc53a801c626eb..70eed523a6d5337689ccc79bc9f030d206af67ed 100644 (file)
@@ -161,7 +161,7 @@ static void update_placeholder_contents(placeholder_state *state) {
         DLOG("con %p (placeholder 0x%08x) line %d: %s\n", state->con, state->window, n, serialized);
 
         i3String *str = i3string_from_utf8(serialized);
         DLOG("con %p (placeholder 0x%08x) line %d: %s\n", state->con, state->window, n, serialized);
 
         i3String *str = i3string_from_utf8(serialized);
-        draw_text(str, state->pixmap, state->gc, 2, (n * (config.font.height + 2)) + 2, state->rect.width - 2);
+        draw_text(str, state->pixmap, state->gc, NULL, 2, (n * (config.font.height + 2)) + 2, state->rect.width - 2);
         i3string_free(str);
         n++;
         free(serialized);
         i3string_free(str);
         n++;
         free(serialized);
@@ -172,7 +172,7 @@ static void update_placeholder_contents(placeholder_state *state) {
     int text_width = predict_text_width(line);
     int x = (state->rect.width / 2) - (text_width / 2);
     int y = (state->rect.height / 2) - (config.font.height / 2);
     int text_width = predict_text_width(line);
     int x = (state->rect.width / 2) - (text_width / 2);
     int y = (state->rect.height / 2) - (config.font.height / 2);
-    draw_text(line, state->pixmap, state->gc, x, y, text_width);
+    draw_text(line, state->pixmap, state->gc, NULL, x, y, text_width);
     i3string_free(line);
     xcb_flush(conn);
     xcb_aux_sync(conn);
     i3string_free(line);
     xcb_flush(conn);
     xcb_aux_sync(conn);
index ceaa4842286ec14f27567fdf56c29188853719f9..555f5e55a2b996ab8e1f2cbba59119bbe5116a77 100644 (file)
@@ -154,7 +154,7 @@ static int sig_draw_window(xcb_window_t win, int width, int height, int font_hei
         if (i == backtrace_string_index)
             set_font_colors(pixmap_gc, get_colorpixel(bt_colour), get_colorpixel("#000000"));
 
         if (i == backtrace_string_index)
             set_font_colors(pixmap_gc, get_colorpixel(bt_colour), get_colorpixel("#000000"));
 
-        draw_text(crash_text_i3strings[i], pixmap, pixmap_gc,
+        draw_text(crash_text_i3strings[i], pixmap, pixmap_gc, NULL,
                   8, 5 + i * font_height, width - 16);
 
         /* and reset the colour again for other lines */
                   8, 5 + i * font_height, width - 16);
 
         /* and reset the colour again for other lines */
diff --git a/src/x.c b/src/x.c
index 9b9ba6aa75482a338a4f0dc2db73bb84c0e92de6..d312666bda116dd6b956885215af9607fb3a897e 100644 (file)
--- a/src/x.c
+++ b/src/x.c
@@ -552,7 +552,7 @@ void x_draw_decoration(Con *con) {
         FREE(formatted_mark);
         mark_width = predict_text_width(mark);
 
         FREE(formatted_mark);
         mark_width = predict_text_width(mark);
 
-        draw_text(mark, parent->pixmap, parent->pm_gc,
+        draw_text(mark, parent->pixmap, parent->pm_gc, NULL,
                   con->deco_rect.x + con->deco_rect.width - mark_width - logical_px(2),
                   con->deco_rect.y + text_offset_y, mark_width);
 
                   con->deco_rect.x + con->deco_rect.width - mark_width - logical_px(2),
                   con->deco_rect.y + text_offset_y, mark_width);
 
@@ -561,7 +561,7 @@ void x_draw_decoration(Con *con) {
 
     i3String *title = win->title_format == NULL ? win->name : window_parse_title_format(win);
     draw_text(title,
 
     i3String *title = win->title_format == NULL ? win->name : window_parse_title_format(win);
     draw_text(title,
-              parent->pixmap, parent->pm_gc,
+              parent->pixmap, parent->pm_gc, NULL,
               con->deco_rect.x + logical_px(2) + indent_px, con->deco_rect.y + text_offset_y,
               con->deco_rect.width - logical_px(2) - indent_px - mark_width - logical_px(2));
     if (win->title_format != NULL)
               con->deco_rect.x + logical_px(2) + indent_px, con->deco_rect.y + text_offset_y,
               con->deco_rect.width - logical_px(2) - indent_px - mark_width - logical_px(2));
     if (win->title_format != NULL)