]> 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 c6c9846b5d3f194979a2f05b53341a26149be5bb..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;
@@ -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,
@@ -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. */