From 58ecd1490088da428e89ce732c583cb8cefaf320 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sat, 28 Jan 2012 16:09:02 +0000 Subject: [PATCH] Implement support for chosing a 32 bit visual (necessary for pseudo-transparency) (Thanks darkraven) You need to specify the --enable-32bit-visual flag when starting i3. This is done because everything feels sluggish on my system when using a 32 bit visual instead of a 24 bit visual. Fast > fancy. --- include/i3.h | 7 +++++ libi3/get_colorpixel.c | 6 ++-- src/main.c | 64 ++++++++++++++++++++++++++++++++++++++++++ src/x.c | 19 +++++++++++-- src/xcb.c | 15 ++++++++-- 5 files changed, 103 insertions(+), 8 deletions(-) diff --git a/include/i3.h b/include/i3.h index dbe477be..bd40f16b 100644 --- a/include/i3.h +++ b/include/i3.h @@ -50,7 +50,14 @@ extern TAILQ_HEAD(ws_assignments_head, Workspace_Assignment) ws_assignments; extern TAILQ_HEAD(assignments_head, Assignment) assignments; extern SLIST_HEAD(stack_wins_head, Stack_Window) stack_wins; extern xcb_screen_t *root_screen; + +/* Color depth, visual id and colormap to use when creating windows and + * pixmaps. Will use 32 bit depth and an appropriate visual, if available, + * otherwise the root window’s default (usually 24 bit TrueColor). */ extern uint8_t root_depth; +extern xcb_visualid_t visual_id; +extern xcb_colormap_t colormap; + extern bool xcursor_supported, xkb_supported; extern xcb_window_t root; extern struct ev_loop *main_loop; diff --git a/libi3/get_colorpixel.c b/libi3/get_colorpixel.c index 73bbef3d..b093594e 100644 --- a/libi3/get_colorpixel.c +++ b/libi3/get_colorpixel.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) * */ #include @@ -32,5 +32,7 @@ uint32_t get_colorpixel(const char *hex) { uint8_t g = strtol(strgroups[1], NULL, 16); uint8_t b = strtol(strgroups[2], NULL, 16); - return (r << 16 | g << 8 | b); + /* We set the first 8 bits high to have 100% opacity in case of a 32 bit + * color depth visual. */ + return (0xFF << 24) | (r << 16 | g << 8 | b); } diff --git a/src/main.c b/src/main.c index 7738dacc..76ea838d 100644 --- a/src/main.c +++ b/src/main.c @@ -53,7 +53,13 @@ xcb_timestamp_t last_timestamp = XCB_CURRENT_TIME; xcb_screen_t *root_screen; xcb_window_t root; + +/* Color depth, visual id and colormap to use when creating windows and + * pixmaps. Will use 32 bit depth and an appropriate visual, if available, + * otherwise the root window’s default (usually 24 bit TrueColor). */ uint8_t root_depth; +xcb_visualid_t visual_id; +xcb_colormap_t colormap; struct ev_loop *main_loop; @@ -244,6 +250,7 @@ int main(int argc, char *argv[]) { bool delete_layout_path = false; bool force_xinerama = false; bool disable_signalhandler = false; + bool enable_32bit_visual = false; static struct option long_options[] = { {"no-autostart", no_argument, 0, 'a'}, {"config", required_argument, 0, 'c'}, @@ -258,9 +265,12 @@ int main(int argc, char *argv[]) { {"shmlog_size", required_argument, 0, 0}, {"get-socketpath", no_argument, 0, 0}, {"get_socketpath", no_argument, 0, 0}, + {"enable-32bit-visual", no_argument, 0, 0}, + {"enable_32bit_visual", no_argument, 0, 0}, {0, 0, 0, 0} }; int option_index = 0, opt; + xcb_void_cookie_t colormap_cookie; setlocale(LC_ALL, ""); @@ -358,6 +368,11 @@ int main(int argc, char *argv[]) { layout_path = sstrdup(optarg); delete_layout_path = true; break; + } else if (strcmp(long_options[option_index].name, "enable_32bit_visual") == 0 || + strcmp(long_options[option_index].name, "enable-32bit-visual") == 0) { + LOG("Enabling 32 bit visual (if available)\n"); + enable_32bit_visual = true; + break; } /* fall-through */ default: @@ -384,6 +399,10 @@ int main(int argc, char *argv[]) { "\tto 0 disables SHM logging entirely.\n" "\tThe default is %d bytes.\n", shmlog_size); fprintf(stderr, "\n"); + fprintf(stderr, "\t--enable-32bit-visual\n" + "\tMakes i3 use a 32 bit visual, if available. Necessary for\n" + "\tpseudo-transparency with xcompmgr.\n"); + fprintf(stderr, "\n"); fprintf(stderr, "If you pass plain text arguments, i3 will interpret them as a command\n" "to send to a currently running i3 (like i3-msg). This allows you to\n" "use nice and logical commands, such as:\n" @@ -494,7 +513,38 @@ int main(int argc, char *argv[]) { root_screen = xcb_aux_get_screen(conn, conn_screen); root = root_screen->root; + + /* By default, we use the same depth and visual as the root window, which + * usually is TrueColor (24 bit depth) and the corresponding visual. + * However, we also check if a 32 bit depth and visual are available (for + * transparency) and use it if so. */ root_depth = root_screen->root_depth; + visual_id = root_screen->root_visual; + colormap = root_screen->default_colormap; + + if (enable_32bit_visual) { + xcb_depth_iterator_t depth_iter; + xcb_visualtype_iterator_t visual_iter; + for (depth_iter = xcb_screen_allowed_depths_iterator(root_screen); + depth_iter.rem; + xcb_depth_next(&depth_iter)) { + if (depth_iter.data->depth != 32) + continue; + visual_iter = xcb_depth_visuals_iterator(depth_iter.data); + if (!visual_iter.rem) + continue; + + visual_id = visual_iter.data->visual_id; + root_depth = depth_iter.data->depth; + colormap = xcb_generate_id(conn); + colormap_cookie = xcb_create_colormap_checked(conn, XCB_COLORMAP_ALLOC_NONE, colormap, root, visual_id); + DLOG("Found a visual with 32 bit depth.\n"); + break; + } + } + + DLOG("root_depth = %d, visual_id = 0x%08x.\n", root_depth, visual_id); + xcb_get_geometry_cookie_t gcookie = xcb_get_geometry(conn, root); xcb_query_pointer_cookie_t pointercookie = xcb_query_pointer(conn, root); @@ -524,6 +574,20 @@ int main(int argc, char *argv[]) { cookie = xcb_change_window_attributes_checked(conn, root, mask, values); check_error(conn, cookie, "Another window manager seems to be running"); + /* By now we already checked for replies once, so let’s see if colormap + * creation worked (if requested). */ + if (colormap != root_screen->default_colormap) { + xcb_generic_error_t *error = xcb_request_check(conn, colormap_cookie); + if (error != NULL) { + ELOG("Could not create ColorMap for 32 bit visual, falling back to X11 default.\n"); + root_depth = root_screen->root_depth; + visual_id = root_screen->root_visual; + colormap = root_screen->default_colormap; + DLOG("root_depth = %d, visual_id = 0x%08x.\n", root_depth, visual_id); + free(error); + } + } + xcb_get_geometry_reply_t *greply = xcb_get_geometry_reply(conn, gcookie, NULL); if (greply == NULL) { ELOG("Could not get geometry of the root window, exiting\n"); diff --git a/src/x.c b/src/x.c index e4e768ea..fe64d3ec 100644 --- a/src/x.c +++ b/src/x.c @@ -90,15 +90,28 @@ void x_con_init(Con *con) { * get the initial geometry right */ uint32_t mask = 0; - uint32_t values[2]; + uint32_t values[5]; + + /* We explicitly set a background color and border color (even though we + * don’t even have a border) because the X11 server requires us to when + * using 32 bit color depths, see + * http://stackoverflow.com/questions/3645632 */ + mask |= XCB_CW_BACK_PIXEL; + values[0] = root_screen->black_pixel; + + mask |= XCB_CW_BORDER_PIXEL; + values[1] = root_screen->black_pixel; /* our own frames should not be managed */ mask |= XCB_CW_OVERRIDE_REDIRECT; - values[0] = 1; + values[2] = 1; /* see include/xcb.h for the FRAME_EVENT_MASK */ mask |= XCB_CW_EVENT_MASK; - values[1] = FRAME_EVENT_MASK & ~XCB_EVENT_MASK_ENTER_WINDOW; + values[3] = FRAME_EVENT_MASK & ~XCB_EVENT_MASK_ENTER_WINDOW; + + mask |= XCB_CW_COLORMAP; + values[4] = colormap; Rect dims = { -15, -15, 10, 10 }; con->frame = create_window(conn, dims, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCURSOR_CURSOR_POINTER, false, mask, values); diff --git a/src/xcb.c b/src/xcb.c index 48906a26..5aa74b32 100644 --- a/src/xcb.c +++ b/src/xcb.c @@ -20,8 +20,17 @@ xcb_window_t create_window(xcb_connection_t *conn, Rect dims, uint16_t window_cl enum xcursor_cursor_t cursor, bool map, uint32_t mask, uint32_t *values) { xcb_window_t result = xcb_generate_id(conn); - /* If the window class is XCB_WINDOW_CLASS_INPUT_ONLY, depth has to be 0 */ - uint16_t depth = (window_class == XCB_WINDOW_CLASS_INPUT_ONLY ? 0 : XCB_COPY_FROM_PARENT); + /* By default, the color depth determined in src/main.c is used (32 bit if + * available, otherwise the X11 root window’s default depth). */ + uint16_t depth = root_depth; + xcb_visualid_t visual = visual_id; + + /* If the window class is XCB_WINDOW_CLASS_INPUT_ONLY, we copy depth and + * visual id from the parent window. */ + if (window_class == XCB_WINDOW_CLASS_INPUT_ONLY) { + depth = XCB_COPY_FROM_PARENT; + visual = XCB_COPY_FROM_PARENT; + } xcb_create_window(conn, depth, @@ -30,7 +39,7 @@ xcb_window_t create_window(xcb_connection_t *conn, Rect dims, uint16_t window_cl dims.x, dims.y, dims.width, dims.height, /* dimensions */ 0, /* border = 0, we draw our own */ window_class, - XCB_WINDOW_CLASS_COPY_FROM_PARENT, /* copy visual from parent */ + visual, mask, values);