]> git.sur5r.net Git - i3/i3/blobdiff - i3bar/src/xcb.c
Remove compatibility definitions for xcb-util < 0.3.8 (#2473)
[i3/i3] / i3bar / src / xcb.c
index 92b0d1abddc470af476d5139c84940a3bfa1a0be..d44da4582f5f47539cee32ed7ee1883a7e9e8c54 100644 (file)
 #include <xcb/xkb.h>
 #include <xcb/xproto.h>
 #include <xcb/xcb_aux.h>
-
-#ifdef XCB_COMPAT
-#include "xcb_compat.h"
-#endif
+#include <xcb/xcb_cursor.h>
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <X11/XKBlib.h>
 #include <X11/extensions/XKB.h>
 
+#ifdef I3_ASAN_ENABLED
+#include <sanitizer/lsan_interface.h>
+#endif
+
 #include "common.h"
 #include "libi3.h"
 
+/** This is the equivalent of XC_left_ptr. I’m not sure why xcb doesn’t have a
+ * constant for that. */
+#define XCB_CURSOR_LEFT_PTR 68
+
 /* We save the atoms in an easy to access array, indexed by an enum */
 enum {
 #define ATOM_DO(name) name,
@@ -49,6 +54,7 @@ xcb_connection_t *xcb_connection;
 int screen;
 xcb_screen_t *root_screen;
 xcb_window_t xcb_root;
+static xcb_cursor_t cursor;
 
 /* selection window for tray support */
 static xcb_window_t selwin = XCB_NONE;
@@ -174,7 +180,7 @@ static void draw_separator(i3_output *output, uint32_t x, struct status_block *b
     uint32_t center_x = x - sep_offset;
     if (config.separator_symbol == NULL) {
         /* Draw a classic one pixel, vertical separator. */
-        draw_util_rectangle(&output->statusline_buffer, sep_fg,
+        draw_util_rectangle(xcb_connection, &output->statusline_buffer, sep_fg,
                             center_x,
                             logical_px(sep_voff_px),
                             logical_px(1),
@@ -243,7 +249,7 @@ void draw_statusline(i3_output *output, uint32_t clip_left, bool use_focus_color
     struct status_block *block;
 
     color_t bar_color = (use_focus_colors ? colors.focus_bar_bg : colors.bar_bg);
-    draw_util_clear_surface(&output->statusline_buffer, bar_color);
+    draw_util_clear_surface(xcb_connection, &output->statusline_buffer, bar_color);
 
     /* Use unsigned integer wraparound to clip off the left side.
      * For example, if clip_left is 75, then x will start at the very large
@@ -294,13 +300,13 @@ void draw_statusline(i3_output *output, uint32_t clip_left, bool use_focus_color
             }
 
             /* Draw the border. */
-            draw_util_rectangle(&output->statusline_buffer, border_color,
+            draw_util_rectangle(xcb_connection, &output->statusline_buffer, border_color,
                                 x, logical_px(1),
                                 full_render_width,
                                 bar_height - logical_px(2));
 
             /* Draw the background. */
-            draw_util_rectangle(&output->statusline_buffer, bg_color,
+            draw_util_rectangle(xcb_connection, &output->statusline_buffer, bg_color,
                                 x + border_width,
                                 logical_px(1) + border_width,
                                 full_render_width - 2 * border_width,
@@ -435,7 +441,7 @@ void init_colors(const struct xcb_color_strings_t *new_colors) {
 
 /*
  * Handle a button press event (i.e. a mouse click on one of our bars).
- * We determine, whether the click occured on a workspace button or if the scroll-
+ * We determine, whether the click occurred on a workspace button or if the scroll-
  * wheel was used and change the workspace appropriately
  *
  */
@@ -759,19 +765,9 @@ static void handle_client_message(xcb_client_message_event_t *event) {
                     break;
             }
 
-            /* Check whether any "tray_output primary" was defined for this bar. */
-            bool contains_primary = false;
-            TAILQ_FOREACH(tray_output, &(config.tray_outputs), tray_outputs) {
-                if (strcasecmp("primary", tray_output->output) == 0) {
-                    contains_primary = true;
-                    break;
-                }
-            }
-
-            /* In case of tray_output == primary and there is no primary output
-             * configured, we fall back to the first available output. We do the
-             * same if no tray_output was specified. */
-            if (output == NULL && (contains_primary || TAILQ_EMPTY(&(config.tray_outputs)))) {
+            /* If no tray_output has been specified, we fall back to the first
+             * available output. */
+            if (output == NULL && TAILQ_EMPTY(&(config.tray_outputs))) {
                 SLIST_FOREACH(walk, outputs, slist) {
                     if (!walk->active)
                         continue;
@@ -780,6 +776,7 @@ static void handle_client_message(xcb_client_message_event_t *event) {
                     break;
                 }
             }
+
             if (output == NULL) {
                 ELOG("No output found\n");
                 return;
@@ -814,7 +811,7 @@ static void handle_client_message(xcb_client_message_event_t *event) {
             ev->type = atoms[_XEMBED];
             ev->format = 32;
             ev->data.data32[0] = XCB_CURRENT_TIME;
-            ev->data.data32[1] = atoms[XEMBED_EMBEDDED_NOTIFY];
+            ev->data.data32[1] = XEMBED_EMBEDDED_NOTIFY;
             ev->data.data32[2] = output->bar.id;
             ev->data.data32[3] = xe_version;
             xcb_send_event(xcb_connection,
@@ -1064,6 +1061,9 @@ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) {
 
     if (xcb_connection_has_error(xcb_connection)) {
         ELOG("X11 connection was closed unexpectedly - maybe your X server terminated / crashed?\n");
+#ifdef I3_ASAN_ENABLED
+        __lsan_do_leak_check();
+#endif
         exit(1);
     }
 
@@ -1081,7 +1081,7 @@ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) {
             DLOG("received an xkb event\n");
 
             xcb_xkb_state_notify_event_t *state = (xcb_xkb_state_notify_event_t *)event;
-            if (state->xkbType == XCB_XKB_STATE_NOTIFY) {
+            if (state->xkbType == XCB_XKB_STATE_NOTIFY && config.modifier != XCB_NONE) {
                 int modstate = state->mods & config.modifier;
 
 #define DLOGMOD(modmask, status)                        \
@@ -1206,6 +1206,24 @@ char *init_xcb_early() {
     colormap = root_screen->default_colormap;
     visual_type = get_visualtype(root_screen);
 
+    xcb_cursor_context_t *cursor_ctx;
+    if (xcb_cursor_context_new(conn, root_screen, &cursor_ctx) == 0) {
+        cursor = xcb_cursor_load_cursor(cursor_ctx, "left_ptr");
+        xcb_cursor_context_free(cursor_ctx);
+    } else {
+        cursor = xcb_generate_id(xcb_connection);
+        i3Font cursor_font = load_font("cursor", false);
+        xcb_create_glyph_cursor(
+            xcb_connection,
+            cursor,
+            cursor_font.specific.xcb.id,
+            cursor_font.specific.xcb.id,
+            XCB_CURSOR_LEFT_PTR,
+            XCB_CURSOR_LEFT_PTR + 1,
+            0, 0, 0,
+            65535, 65535, 65535);
+    }
+
     /* The various watchers to communicate with xcb */
     xcb_io = smalloc(sizeof(ev_io));
     xcb_prep = smalloc(sizeof(ev_prepare));
@@ -1401,6 +1419,8 @@ void init_tray(void) {
         return;
     }
 
+    free(selreply);
+
     send_tray_clientmessage();
 }
 
@@ -1462,6 +1482,9 @@ void clean_xcb(void) {
     FREE_SLIST(outputs, i3_output);
     FREE(outputs);
 
+    free_font();
+
+    xcb_free_cursor(xcb_connection, cursor);
     xcb_flush(xcb_connection);
     xcb_aux_sync(xcb_connection);
     xcb_disconnect(xcb_connection);
@@ -1605,7 +1628,7 @@ xcb_void_cookie_t config_strut_partial(i3_output *output) {
  */
 void reconfig_windows(bool redraw_bars) {
     uint32_t mask;
-    uint32_t values[5];
+    uint32_t values[6];
     static bool tray_configured = false;
 
     i3_output *walk;
@@ -1623,7 +1646,7 @@ 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_pixmap_t statusline_buffer_id = xcb_generate_id(xcb_connection);
-            mask = XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP;
+            mask = XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP | XCB_CW_CURSOR;
 
             values[0] = colors.bar_bg.colorpixel;
             values[1] = root_screen->black_pixel;
@@ -1645,6 +1668,7 @@ void reconfig_windows(bool redraw_bars) {
                 walk->visible = true;
             }
             values[4] = colormap;
+            values[5] = cursor;
 
             xcb_void_cookie_t win_cookie = xcb_create_window_checked(xcb_connection,
                                                                      depth,
@@ -1709,9 +1733,9 @@ void reconfig_windows(bool redraw_bars) {
                                                                 1,
                                                                 (unsigned char *)&atoms[_NET_WM_WINDOW_TYPE_DOCK]);
 
-            draw_util_surface_init(&walk->bar, bar_id, walk->rect.w, bar_height);
-            draw_util_surface_init(&walk->buffer, buffer_id, walk->rect.w, bar_height);
-            draw_util_surface_init(&walk->statusline_buffer, statusline_buffer_id, walk->rect.w, bar_height);
+            draw_util_surface_init(xcb_connection, &walk->bar, bar_id, NULL, walk->rect.w, bar_height);
+            draw_util_surface_init(xcb_connection, &walk->buffer, buffer_id, NULL, walk->rect.w, bar_height);
+            draw_util_surface_init(xcb_connection, &walk->statusline_buffer, statusline_buffer_id, NULL, walk->rect.w, bar_height);
 
             xcb_void_cookie_t strut_cookie = config_strut_partial(walk);
 
@@ -1733,16 +1757,35 @@ void reconfig_windows(bool redraw_bars) {
             }
 
             /* Unless "tray_output none" was specified, we need to initialize the tray. */
-            const char *first = (TAILQ_EMPTY(&(config.tray_outputs))) ? SLIST_FIRST(outputs)->name : TAILQ_FIRST(&(config.tray_outputs))->output;
-            if (!tray_configured && strcasecmp(first, "none") != 0) {
-                /* We do a sanity check here to ensure that this i3bar instance actually handles
-                 * the output on which the tray should appear. For example,
-                 * consider tray_output == [VGA-1], but output == [HDMI-1]. */
+            bool no_tray = false;
+            if (!(TAILQ_EMPTY(&(config.tray_outputs)))) {
+                no_tray = strcasecmp(TAILQ_FIRST(&(config.tray_outputs))->output, "none") == 0;
+            }
 
+            /*
+             * There are three scenarios in which we need to initialize the tray:
+             *   1. A specific output was listed in tray_outputs which is also
+             *      in the list of outputs managed by this bar.
+             *   2. No tray_output directive was specified. In this case, we
+             *      use the first available output.
+             *   3. 'tray_output primary' was specified. In this case we use the
+             *      primary output.
+             *
+             * Three scenarios in which we specifically don't want to
+             * initialize the tray are:
+             *   1. 'tray_output none' was specified.
+             *   2. A specific output was listed as a tray_output, but is not
+             *      one of the outputs managed by this bar. For example, consider
+             *      tray_outputs == [VGA-1], but outputs == [HDMI-1].
+             *   3. 'tray_output primary' was specified and no output in the list
+             *      is primary.
+             */
+            if (!tray_configured && !no_tray) {
                 /* If no tray_output was specified, we go ahead and initialize the tray as
                  * we will be using the first available output. */
-                if (TAILQ_EMPTY(&(config.tray_outputs)))
+                if (TAILQ_EMPTY(&(config.tray_outputs))) {
                     init_tray();
+                }
 
                 /* If one or more tray_output assignments were specified, we ensure that at least one of
                  * them is actually an output managed by this instance. */
@@ -1820,12 +1863,12 @@ void reconfig_windows(bool redraw_bars) {
                                                                       walk->rect.w,
                                                                       bar_height);
 
-            draw_util_surface_free(&(walk->bar));
-            draw_util_surface_free(&(walk->buffer));
-            draw_util_surface_free(&(walk->statusline_buffer));
-            draw_util_surface_init(&(walk->bar), walk->bar.id, walk->rect.w, bar_height);
-            draw_util_surface_init(&(walk->buffer), walk->buffer.id, walk->rect.w, bar_height);
-            draw_util_surface_init(&(walk->statusline_buffer), walk->statusline_buffer.id, walk->rect.w, bar_height);
+            draw_util_surface_free(xcb_connection, &(walk->bar));
+            draw_util_surface_free(xcb_connection, &(walk->buffer));
+            draw_util_surface_free(xcb_connection, &(walk->statusline_buffer));
+            draw_util_surface_init(xcb_connection, &(walk->bar), walk->bar.id, NULL, walk->rect.w, bar_height);
+            draw_util_surface_init(xcb_connection, &(walk->buffer), walk->buffer.id, NULL, walk->rect.w, bar_height);
+            draw_util_surface_init(xcb_connection, &(walk->statusline_buffer), walk->statusline_buffer.id, NULL, walk->rect.w, bar_height);
 
             xcb_void_cookie_t map_cookie, umap_cookie;
             if (redraw_bars) {
@@ -1886,7 +1929,7 @@ void draw_bars(bool unhide) {
         bool use_focus_colors = output_has_focus(outputs_walk);
 
         /* First things first: clear the backbuffer */
-        draw_util_clear_surface(&(outputs_walk->buffer),
+        draw_util_clear_surface(xcb_connection, &(outputs_walk->buffer),
                                 (use_focus_colors ? colors.focus_bar_bg : colors.bar_bg));
 
         if (!config.disable_ws) {
@@ -1917,14 +1960,14 @@ void draw_bars(bool unhide) {
                 }
 
                 /* Draw the border of the button. */
-                draw_util_rectangle(&(outputs_walk->buffer), border_color,
+                draw_util_rectangle(xcb_connection, &(outputs_walk->buffer), border_color,
                                     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));
 
                 /* Draw the inside of the button. */
-                draw_util_rectangle(&(outputs_walk->buffer), bg_color,
+                draw_util_rectangle(xcb_connection, &(outputs_walk->buffer), bg_color,
                                     workspace_width + logical_px(1),
                                     2 * logical_px(1),
                                     ws_walk->name_width + 2 * logical_px(ws_hoff_px),
@@ -1947,13 +1990,13 @@ void draw_bars(bool unhide) {
             color_t fg_color = colors.binding_mode_fg;
             color_t bg_color = colors.binding_mode_bg;
 
-            draw_util_rectangle(&(outputs_walk->buffer), colors.binding_mode_border,
+            draw_util_rectangle(xcb_connection, &(outputs_walk->buffer), colors.binding_mode_border,
                                 workspace_width,
                                 logical_px(1),
                                 binding.width + 2 * logical_px(ws_hoff_px) + 2 * logical_px(1),
                                 font.height + 2 * logical_px(ws_voff_px) - 2 * logical_px(1));
 
-            draw_util_rectangle(&(outputs_walk->buffer), bg_color,
+            draw_util_rectangle(xcb_connection, &(outputs_walk->buffer), bg_color,
                                 workspace_width + logical_px(1),
                                 2 * logical_px(1),
                                 binding.width + 2 * logical_px(ws_hoff_px),
@@ -1989,7 +2032,7 @@ void draw_bars(bool unhide) {
             int x_dest = outputs_walk->rect.w - tray_width - logical_px(sb_hoff_px) - visible_statusline_width;
 
             draw_statusline(outputs_walk, clip_left, use_focus_colors, use_short_text);
-            draw_util_copy_surface(&outputs_walk->statusline_buffer, &outputs_walk->buffer, 0, 0,
+            draw_util_copy_surface(xcb_connection, &outputs_walk->statusline_buffer, &outputs_walk->buffer, 0, 0,
                                    x_dest, 0, visible_statusline_width, (int16_t)bar_height);
 
             outputs_walk->statusline_width = statusline_width;
@@ -2020,7 +2063,7 @@ void redraw_bars(void) {
             continue;
         }
 
-        draw_util_copy_surface(&(outputs_walk->buffer), &(outputs_walk->bar), 0, 0,
+        draw_util_copy_surface(xcb_connection, &(outputs_walk->buffer), &(outputs_walk->bar), 0, 0,
                                0, 0, outputs_walk->rect.w, outputs_walk->rect.h);
         xcb_flush(xcb_connection);
     }