From 3721c598bd914215b7f483328e568a144b5ec70e Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 29 Jul 2011 13:12:28 +0200 Subject: [PATCH] Bugfix: Set the cursor via the Xlib connection if XCursor is supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a race where we created cursors on the Xlib connection, flushed, then used the cursor on the XCB connection. Even though we flushed, the X server did not process the requests yet and therefore returned a BadCursor error. This bugfix uses the Xlib connection for setting the root window cursor which will ensure that the requests are properly serialized. An easy test for this (on my machine) is the following ~/.xsession: xsetroot -cursor_name cross exec i3 If you see a cross cursor instead of the pointer, the race happens. You’ll see a error_code=6 error in your ~/.xsession-errors. --- include/xcursor.h | 13 +++++++++++++ src/main.c | 3 +-- src/xcursor.c | 16 ++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/include/xcursor.h b/include/xcursor.h index 1872fa0e..af70cf1e 100644 --- a/include/xcursor.h +++ b/include/xcursor.h @@ -17,4 +17,17 @@ extern void xcursor_load_cursors(); extern Cursor xcursor_get_cursor(enum xcursor_cursor_t c); extern int xcursor_get_xcb_cursor(enum xcursor_cursor_t c); +/** + * Sets the cursor of the root window to the 'pointer' cursor. + * + * This function is called when i3 is initialized, because with some login + * managers, the root window will not have a cursor otherwise. + * + * We have a separate xcursor function to use the same X11 connection as the + * xcursor_load_cursors() function. If we mix the Xlib and the XCB connection, + * races might occur (even though we flush the Xlib connection). + * + */ +void xcursor_set_root_cursor(); + #endif diff --git a/src/main.c b/src/main.c index 434942ce..54df5431 100644 --- a/src/main.c +++ b/src/main.c @@ -338,8 +338,7 @@ int main(int argc, char *argv[]) { /* Set a cursor for the root window (otherwise the root window will show no cursor until the first client is launched). */ if (xcursor_supported) { - uint32_t values[1] = { xcursor_get_cursor(XCURSOR_CURSOR_POINTER) }; - xcb_change_window_attributes(conn, root, XCB_CW_CURSOR, values); + xcursor_set_root_cursor(); } else { xcb_cursor_t cursor_id = xcb_generate_id(conn); i3Font cursor_font = load_font("cursor", false); diff --git a/src/xcursor.c b/src/xcursor.c index 54ef34d2..69518c30 100644 --- a/src/xcursor.c +++ b/src/xcursor.c @@ -28,7 +28,23 @@ void xcursor_load_cursors() { cursors[XCURSOR_CURSOR_POINTER] = load_cursor("left_ptr"); cursors[XCURSOR_CURSOR_RESIZE_HORIZONTAL] = load_cursor("sb_h_double_arrow"); cursors[XCURSOR_CURSOR_RESIZE_VERTICAL] = load_cursor("sb_v_double_arrow"); +} +/* + * Sets the cursor of the root window to the 'pointer' cursor. + * + * This function is called when i3 is initialized, because with some login + * managers, the root window will not have a cursor otherwise. + * + * We have a separate xcursor function to use the same X11 connection as the + * xcursor_load_cursors() function. If we mix the Xlib and the XCB connection, + * races might occur (even though we flush the Xlib connection). + * + */ +void xcursor_set_root_cursor() { + XSetWindowAttributes attributes; + attributes.cursor = xcursor_get_cursor(XCURSOR_CURSOR_POINTER); + XChangeWindowAttributes(xlibdpy, DefaultRootWindow(xlibdpy), CWCursor, &attributes); XFlush(xlibdpy); }