From 780cb8d15d07febbb9be47cb1bc1201072b31838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Tue, 17 Nov 2015 12:50:06 +0100 Subject: [PATCH] Use 32-bit visual by default if available. With this patch, we use 32-bit visuals per default whenever it is available. Otherwise, we fall back to the actual root window's depth, which will typically be 24-bit. Before this patch, we already used 32-bit depth for containers with a window that uses 32-bit. However, this means that we didn't use 32-bit for split parent containers on which decoration is drawn. For 32-bit windows using transparency, this caused a graphical glitch because the decoration pixmap behind it would show through. This behavior is fixed with this change. relates to #1278 --- include/libi3.h | 3 +++ include/xcb.h | 5 ++++ libi3/draw_util.c | 18 ++++++++++--- src/con.c | 2 +- src/main.c | 28 ++++++++++++++------ src/x.c | 65 +++++++++++++++++++++-------------------------- src/xcb.c | 5 ++++ 7 files changed, 77 insertions(+), 49 deletions(-) diff --git a/include/libi3.h b/include/libi3.h index 02988837..08b01402 100644 --- a/include/libi3.h +++ b/include/libi3.h @@ -499,11 +499,14 @@ typedef struct color_t { double red; double green; double blue; + double alpha; /* The colorpixel we use for direct XCB calls. */ uint32_t colorpixel; } color_t; +#define COLOR_TRANSPARENT ((color_t){.red = 0.0, .green = 0.0, .blue = 0.0, .colorpixel = 0}) + /* A wrapper grouping an XCB drawable and both a graphics context * and the corresponding cairo objects representing it. */ typedef struct surface_t { diff --git a/include/xcb.h b/include/xcb.h index 7fae41f5..86019c5d 100644 --- a/include/xcb.h +++ b/include/xcb.h @@ -139,6 +139,11 @@ void xcb_set_root_cursor(int cursor); * */ uint16_t get_visual_depth(xcb_visualid_t visual_id); + +/** + * Get visual type specified by visualid + * + */ xcb_visualtype_t *get_visualtype_by_id(xcb_visualid_t visual_id); /** diff --git a/libi3/draw_util.c b/libi3/draw_util.c index 4015ba92..f6c53865 100644 --- a/libi3/draw_util.c +++ b/libi3/draw_util.c @@ -38,7 +38,7 @@ static void draw_util_set_source_color(xcb_connection_t *conn, surface_t *surfac void draw_util_surface_init(xcb_connection_t *conn, surface_t *surface, xcb_drawable_t drawable, xcb_visualtype_t *visual, int width, int height) { surface->id = drawable; - surface->visual_type = (visual == NULL) ? visual_type : visual; + surface->visual_type = ((visual == NULL) ? visual_type : visual); surface->width = width; surface->height = height; @@ -87,15 +87,25 @@ void draw_util_surface_set_size(surface_t *surface, int width, int height) { * */ color_t draw_util_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[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, + .alpha = strtol(groups[3], NULL, 16) / 255.0, .colorpixel = get_colorpixel(color)}; } @@ -107,7 +117,7 @@ static void draw_util_set_source_color(xcb_connection_t *conn, surface_t *surfac RETURN_UNLESS_SURFACE_INITIALIZED(surface); #ifdef CAIRO_SUPPORT - 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); #else uint32_t colorpixel = color.colorpixel; xcb_change_gc(conn, surface->gc, XCB_GC_FOREGROUND | XCB_GC_BACKGROUND, diff --git a/src/con.c b/src/con.c index 03fd0ee6..64dbec69 100644 --- a/src/con.c +++ b/src/con.c @@ -47,7 +47,7 @@ Con *con_new_skeleton(Con *parent, i3Window *window) { new->depth = window->depth; new->window->aspect_ratio = 0.0; } else { - new->depth = XCB_COPY_FROM_PARENT; + new->depth = root_depth; } DLOG("opening window\n"); diff --git a/src/main.c b/src/main.c index 1e0ec4a5..9c67b42a 100644 --- a/src/main.c +++ b/src/main.c @@ -59,7 +59,6 @@ xcb_window_t root; * 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_visualtype_t *visual_type; xcb_colormap_t colormap; @@ -482,16 +481,29 @@ int main(int argc, char *argv[]) { #include "atoms.xmacro" #undef xmacro - /* 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; - visual_type = get_visualtype(root_screen); colormap = root_screen->default_colormap; + visual_type = xcb_aux_find_visual_by_attrs(root_screen, -1, 32); + if (visual_type != NULL) { + root_depth = xcb_aux_get_depth_of_visual(root_screen, visual_type->visual_id); + colormap = xcb_generate_id(conn); - DLOG("root_depth = %d, visual_id = 0x%08x.\n", root_depth, visual_id); + xcb_void_cookie_t cm_cookie = xcb_create_colormap_checked(conn, + XCB_COLORMAP_ALLOC_NONE, + colormap, + root, + visual_type->visual_id); + + xcb_generic_error_t *error = xcb_request_check(conn, cm_cookie); + if (error != NULL) { + ELOG("Could not create colormap. Error code: %d\n", error->error_code); + exit(EXIT_FAILURE); + } + } else { + visual_type = get_visualtype(root_screen); + } + + DLOG("root_depth = %d, visual_id = 0x%08x.\n", root_depth, visual_type->visual_id); DLOG("root_screen->height_in_pixels = %d, root_screen->height_in_millimeters = %d, dpi = %d\n", root_screen->height_in_pixels, root_screen->height_in_millimeters, (int)((double)root_screen->height_in_pixels * 25.4 / (double)root_screen->height_in_millimeters)); diff --git a/src/x.c b/src/x.c index 17970fb8..f1f971e9 100644 --- a/src/x.c +++ b/src/x.c @@ -101,47 +101,32 @@ void x_con_init(Con *con, uint16_t depth) { uint32_t mask = 0; uint32_t values[5]; - xcb_visualid_t visual = XCB_COPY_FROM_PARENT; - xcb_colormap_t win_colormap = XCB_NONE; - if (depth != root_depth && depth != XCB_COPY_FROM_PARENT) { - /* For custom visuals, we need to create a colormap before creating - * this window. It will be freed directly after creating the window. */ - visual = get_visualid_by_depth(depth); - win_colormap = xcb_generate_id(conn); - xcb_create_colormap_checked(conn, XCB_COLORMAP_ALLOC_NONE, win_colormap, root, visual); + /* For custom visuals, we need to create a colormap before creating + * this window. It will be freed directly after creating the window. */ + xcb_visualid_t visual = get_visualid_by_depth(depth); + xcb_colormap_t win_colormap = xcb_generate_id(conn); + xcb_create_colormap_checked(conn, XCB_COLORMAP_ALLOC_NONE, win_colormap, root, visual); - /* 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; + /* 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; + mask |= XCB_CW_BORDER_PIXEL; + values[1] = root_screen->black_pixel; - /* our own frames should not be managed */ - mask |= XCB_CW_OVERRIDE_REDIRECT; - values[2] = 1; + /* our own frames should not be managed */ + mask |= XCB_CW_OVERRIDE_REDIRECT; + values[2] = 1; - /* see include/xcb.h for the FRAME_EVENT_MASK */ - mask |= XCB_CW_EVENT_MASK; - values[3] = FRAME_EVENT_MASK & ~XCB_EVENT_MASK_ENTER_WINDOW; + /* see include/xcb.h for the FRAME_EVENT_MASK */ + mask |= XCB_CW_EVENT_MASK; + values[3] = FRAME_EVENT_MASK & ~XCB_EVENT_MASK_ENTER_WINDOW; - mask |= XCB_CW_COLORMAP; - values[4] = win_colormap; - } else { - /* our own frames should not be managed */ - mask = XCB_CW_OVERRIDE_REDIRECT; - values[0] = 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; - - mask |= XCB_CW_COLORMAP; - values[2] = colormap; - } + mask |= XCB_CW_COLORMAP; + values[4] = win_colormap; Rect dims = {-15, -15, 10, 10}; xcb_window_t frame_id = create_window(conn, dims, depth, visual, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCURSOR_CURSOR_POINTER, false, mask, values); @@ -523,6 +508,14 @@ void x_draw_decoration(Con *con) { if (parent->frame_buffer.id == XCB_NONE) goto copy_pixmaps; + /* For the first child, we clear the parent pixmap to ensure there's no + * garbage left on there. This is important to avoid tearing when using + * transparency. */ + if (con == TAILQ_FIRST(&(con->parent->nodes_head))) { + draw_util_clear_surface(conn, &(con->parent->frame_buffer), COLOR_TRANSPARENT); + FREE(con->parent->deco_render_params); + } + /* 4: paint the bar */ draw_util_rectangle(conn, &(parent->frame_buffer), p->color->background, con->deco_rect.x, con->deco_rect.y, con->deco_rect.width, con->deco_rect.height); diff --git a/src/xcb.c b/src/xcb.c index 60fd4212..07f9281a 100644 --- a/src/xcb.c +++ b/src/xcb.c @@ -252,6 +252,11 @@ uint16_t get_visual_depth(xcb_visualid_t visual_id) { } return 0; } + +/* + * Get visual type specified by visualid + * + */ xcb_visualtype_t *get_visualtype_by_id(xcb_visualid_t visual_id) { xcb_depth_iterator_t depth_iter;