diff options
author | Michael Stapelberg <michael@stapelberg.de> | 2022-11-03 23:11:32 +0100 |
---|---|---|
committer | Michael Stapelberg <stapelberg@users.noreply.github.com> | 2022-11-05 15:58:15 +0100 |
commit | d26ddcbfe5f0ead61cc55c1f596692d9a89e71f9 (patch) | |
tree | 5e4e630b59ead2a30f801f4dbb12eb7cf396f431 | |
parent | 6e6af01b7a1f2ff1a35f7751c07e51277d4414e2 (diff) | |
download | i3-d26ddcbfe5f0ead61cc55c1f596692d9a89e71f9.tar.gz i3-d26ddcbfe5f0ead61cc55c1f596692d9a89e71f9.zip |
draw leaf window decorations on ->frame instead of ->parent->frame
related to https://github.com/i3/i3/issues/3724
fixes https://github.com/i3/i3/issues/1966
-rw-r--r-- | docs/hacking-howto | 4 | ||||
-rw-r--r-- | docs/ipc | 8 | ||||
-rw-r--r-- | docs/userguide | 17 | ||||
-rw-r--r-- | include/con.h | 8 | ||||
-rw-r--r-- | src/click.c | 19 | ||||
-rw-r--r-- | src/con.c | 29 | ||||
-rw-r--r-- | src/floating.c | 36 | ||||
-rw-r--r-- | src/handlers.c | 36 | ||||
-rw-r--r-- | src/ipc.c | 10 | ||||
-rw-r--r-- | src/load_layout.c | 21 | ||||
-rw-r--r-- | src/render.c | 47 | ||||
-rw-r--r-- | src/tiling_drag.c | 21 | ||||
-rw-r--r-- | src/x.c | 59 | ||||
-rw-r--r-- | testcases/t/246-window-decoration-focus.t | 2 |
14 files changed, 186 insertions, 131 deletions
diff --git a/docs/hacking-howto b/docs/hacking-howto index 01e5c7fd..c6dd6fa4 100644 --- a/docs/hacking-howto +++ b/docs/hacking-howto @@ -564,9 +564,7 @@ split container. ==== Default layout In default layout, containers are placed horizontally or vertically next to -each other (depending on the +con->orientation+). If a child is a leaf node (as -opposed to a split container) and has border style "normal", appropriate space -will be reserved for its window decoration. +each other (depending on the +con->orientation+). ==== Stacked layout @@ -410,6 +410,14 @@ deco_rect (map):: The coordinates of the *window decoration* inside its container. These coordinates are relative to the container and do not include the actual client window. +actual_deco_rect (map):: + See +deco_rect+. i3 v4.22 changed the way title bars are rendered. Before + i3 v4.22, the deco_rect was always relative to the parent coordinates. + Starting with i3 v4.22, this remains true for tabbed/stacked containers + (actual_deco_rect is identical to deco_rect), but for normal-border leaf + containers within vertical/horizontal split containers, actual_deco_rect + is relative to the container itself. For more background, see + https://github.com/i3/i3/issues/1966 geometry (map):: The original geometry the window specified when i3 mapped it. Used when switching a window to floating mode, for example. diff --git a/docs/userguide b/docs/userguide index 5005005e..dc8a5ff7 100644 --- a/docs/userguide +++ b/docs/userguide @@ -1501,23 +1501,6 @@ Tip: You can find an https://github.com/Airblader/i3/wiki/Example-Configuration[example configuration] that uses modes to illustrate various gap configurations. -[[gaps_artifacts]] -==== ⚠ Known issue with gaps: graphical artifacts (black rectangles) - -The way i3 renders window title bars results in graphical artifacts (black -rectangles behind windows) when enabling gaps. In some circumstances, running a -compositor such as `picom` works around the artifacts. - -Another workaround is to disable window title bars entirely: - ------------------------- -# You can also use any non-zero value if you'd like to have a border -default_border pixel 0 ------------------------- - -See https://github.com/i3/i3/issues/3724[Issue #3724] for more details and -updates on this issue. - == Configuring i3bar The bar at the bottom of your monitor is drawn by a separate process called diff --git a/include/con.h b/include/con.h index 8d344994..f97ddaec 100644 --- a/include/con.h +++ b/include/con.h @@ -421,6 +421,14 @@ Con *con_descend_tiling_focused(Con *con); Con *con_descend_direction(Con *con, direction_t direction); /** + * Returns whether the window decoration (title bar) should be drawn into the + * X11 frame window of this container (default) or into the X11 frame window of + * the parent container (for stacked/tabbed containers). + * + */ +bool con_draw_decoration_into_frame(Con *con); + +/** * Returns a "relative" Rect which contains the amount of pixels that need to * be added to the original Rect to get the final position (obviously the * amount of pixels for normal, 1pixel and borderless are different). diff --git a/src/click.c b/src/click.c index e262516f..a5e50632 100644 --- a/src/click.c +++ b/src/click.c @@ -404,13 +404,20 @@ void handle_button_press(xcb_button_press_event_t *event) { } /* Check if the click was on the decoration of a child */ - Con *child; - TAILQ_FOREACH_REVERSE (child, &(con->nodes_head), nodes_head, nodes) { - if (!rect_contains(child->deco_rect, event->event_x, event->event_y)) - continue; + if (con->window != NULL) { + if (rect_contains(con->deco_rect, event->event_x, event->event_y)) { + route_click(con, event, mod_pressed, CLICK_DECORATION); + return; + } + } else { + Con *child; + TAILQ_FOREACH_REVERSE (child, &(con->nodes_head), nodes_head, nodes) { + if (!rect_contains(child->deco_rect, event->event_x, event->event_y)) + continue; - route_click(child, event, mod_pressed, CLICK_DECORATION); - return; + route_click(child, event, mod_pressed, CLICK_DECORATION); + return; + } } if (event->child != XCB_NONE) { @@ -1693,6 +1693,20 @@ static bool has_outer_gaps(gaps_t gaps) { } /* + * Returns whether the window decoration (title bar) should be drawn into the + * X11 frame window of this container (default) or into the X11 frame window of + * the parent container (for stacked/tabbed containers). + * + */ +bool con_draw_decoration_into_frame(Con *con) { + return con_is_leaf(con) && + con->border_style == BS_NORMAL && + (con->parent == NULL || + (con->parent->layout != L_TABBED && + con->parent->layout != L_STACKED)); +} + +/* * Returns a "relative" Rect which contains the amount of pixels that need to * be added to the original Rect to get the final position (obviously the * amount of pixels for normal, 1pixel and borderless are different). @@ -1724,7 +1738,16 @@ Rect con_border_style_rect(Con *con) { if (border_style == BS_NONE) return (Rect){0, 0, 0, 0}; if (border_style == BS_NORMAL) { + const int deco_height = render_deco_height(); result = (Rect){border_width, 0, -(2 * border_width), -(border_width)}; + if (con_draw_decoration_into_frame(con)) { + result = (Rect){ + .x = border_width /* left */, + .y = deco_height, + .width = -(border_width /* left */ + border_width /* right */), + .height = -(border_width /* bottom */ + deco_height), + }; + } } else { result = (Rect){border_width, border_width, -(2 * border_width), -(2 * border_width)}; } @@ -1828,23 +1851,17 @@ void con_set_border_style(Con *con, border_style_t border_style, int border_widt * pixels. For the parent, we do the same also for the decoration. */ Con *parent = con->parent; Rect bsr = con_border_style_rect(con); - int deco_height = (con->border_style == BS_NORMAL ? render_deco_height() : 0); con->rect = rect_add(con->rect, bsr); parent->rect = rect_add(parent->rect, bsr); - parent->rect.y += deco_height; - parent->rect.height -= deco_height; /* Change the border style, get new border/decoration values. */ con->border_style = border_style; con->current_border_width = border_width; bsr = con_border_style_rect(con); - deco_height = (con->border_style == BS_NORMAL ? render_deco_height() : 0); con->rect = rect_sub(con->rect, bsr); parent->rect = rect_sub(parent->rect, bsr); - parent->rect.y -= deco_height; - parent->rect.height += deco_height; } /* diff --git a/src/floating.c b/src/floating.c index 992ca23c..f52f27bc 100644 --- a/src/floating.c +++ b/src/floating.c @@ -79,16 +79,22 @@ void floating_check_size(Con *floating_con, bool prefer_height) { Rect floating_sane_max_dimensions; Con *focused_con = con_descend_focused(floating_con); + DLOG("deco_rect.height = %d\n", focused_con->deco_rect.height); Rect border_rect = con_border_style_rect(focused_con); /* We have to do the opposite calculations that render_con() do * to get the exact size we want. */ border_rect.width = -border_rect.width; - border_rect.width += 2 * focused_con->border_width; border_rect.height = -border_rect.height; + + /* undo x11 border */ + border_rect.width += 2 * focused_con->border_width; border_rect.height += 2 * focused_con->border_width; - if (con_border_style(focused_con) == BS_NORMAL) { - border_rect.height += render_deco_height(); - } + + DLOG("floating_check_size, want min width %d, min height %d, border extra: w=%d, h=%d\n", + floating_sane_min_width, + floating_sane_min_height, + border_rect.width, + border_rect.height); i3Window *window = focused_con->window; if (window != NULL) { @@ -319,9 +325,6 @@ bool floating_enable(Con *con, bool automatic) { x_set_name(nc, name); free(name); - /* find the height for the decorations */ - int deco_height = render_deco_height(); - DLOG("Original rect: (%d, %d) with %d x %d\n", con->rect.x, con->rect.y, con->rect.width, con->rect.height); DLOG("Geometry = (%d, %d) with %d x %d\n", con->geometry.x, con->geometry.y, con->geometry.width, con->geometry.height); nc->rect = con->geometry; @@ -352,15 +355,10 @@ bool floating_enable(Con *con, bool automatic) { } /* Add pixels for the decoration. */ - Rect border_style_rect = con_border_style_rect(con); - - nc->rect.height -= border_style_rect.height; - nc->rect.width -= border_style_rect.width; + Rect bsr = con_border_style_rect(con); - /* Add some more pixels for the title bar */ - if (con_border_style(con) == BS_NORMAL) { - nc->rect.height += deco_height; - } + nc->rect.height -= bsr.height; + nc->rect.width -= bsr.width; /* Honor the X11 border */ nc->rect.height += con->border_width * 2; @@ -406,14 +404,6 @@ bool floating_enable(Con *con, bool automatic) { DLOG("Floating rect: (%d, %d) with %d x %d\n", nc->rect.x, nc->rect.y, nc->rect.width, nc->rect.height); - /* 5: Subtract the deco_height in order to make the floating window appear - * at precisely the position it specified in its original geometry (which - * is what applications might remember). */ - deco_height = (con->border_style == BS_NORMAL ? render_deco_height() : 0); - nc->rect.y -= deco_height; - - DLOG("Corrected y = %d (deco_height = %d)\n", nc->rect.y, deco_height); - /* render the cons to get initial window_rect correct */ render_con(nc); diff --git a/src/handlers.c b/src/handlers.c index b0354d1c..17968a43 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -214,18 +214,30 @@ static void handle_motion_notify(xcb_motion_notify_event_t *event) { return; /* see over which rect the user is */ - Con *current; - TAILQ_FOREACH_REVERSE (current, &(con->nodes_head), nodes_head, nodes) { - if (!rect_contains(current->deco_rect, event->event_x, event->event_y)) - continue; + if (con->window != NULL) { + if (rect_contains(con->deco_rect, event->event_x, event->event_y)) { + /* We found the rect, let’s see if this window is focused */ + if (TAILQ_FIRST(&(con->parent->focus_head)) == con) + return; - /* We found the rect, let’s see if this window is focused */ - if (TAILQ_FIRST(&(con->focus_head)) == current) + con_focus(con); + x_push_changes(croot); return; + } + } else { + Con *current; + TAILQ_FOREACH_REVERSE (current, &(con->nodes_head), nodes_head, nodes) { + if (!rect_contains(current->deco_rect, event->event_x, event->event_y)) + continue; - con_focus(current); - x_push_changes(croot); - return; + /* We found the rect, let’s see if this window is focused */ + if (TAILQ_FIRST(&(con->focus_head)) == current) + return; + + con_focus(current); + x_push_changes(croot); + return; + } } } @@ -318,15 +330,9 @@ static void handle_configure_request(xcb_configure_request_event_t *event) { Con *fullscreen = con_get_fullscreen_covering_ws(workspace); if (fullscreen != con && con_is_floating(con) && con_is_leaf(con)) { - /* find the height for the decorations */ - int deco_height = con->deco_rect.height; /* we actually need to apply the size/position changes to the *parent* * container */ Rect bsr = con_border_style_rect(con); - if (con->border_style == BS_NORMAL) { - bsr.y += deco_height; - bsr.height -= deco_height; - } Con *floatingcon = con->parent; Rect newrect = floatingcon->rect; @@ -503,7 +503,15 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) { y(integer, con->current_border_width); dump_rect(gen, "rect", con->rect); - dump_rect(gen, "deco_rect", con->deco_rect); + if (con_draw_decoration_into_frame(con)) { + Rect simulated_deco_rect = con->deco_rect; + simulated_deco_rect.x = con->rect.x - con->parent->rect.x; + simulated_deco_rect.y = con->rect.y - con->parent->rect.y; + dump_rect(gen, "deco_rect", simulated_deco_rect); + dump_rect(gen, "actual_deco_rect", con->deco_rect); + } else { + dump_rect(gen, "deco_rect", con->deco_rect); + } dump_rect(gen, "window_rect", con->window_rect); dump_rect(gen, "geometry", con->geometry); diff --git a/src/load_layout.c b/src/load_layout.c index 9789fb33..053649d0 100644 --- a/src/load_layout.c +++ b/src/load_layout.c @@ -23,6 +23,7 @@ static Con *to_focus; static bool parsing_gaps; static bool parsing_swallows; static bool parsing_rect; +static bool parsing_actual_deco_rect; static bool parsing_deco_rect; static bool parsing_window_rect; static bool parsing_geometry; @@ -61,7 +62,12 @@ static int json_start_map(void *ctx) { TAILQ_INSERT_TAIL(&(json_node->swallow_head), current_swallow, matches); swallow_is_empty = true; } else { - if (!parsing_rect && !parsing_deco_rect && !parsing_window_rect && !parsing_geometry && !parsing_gaps) { + if (!parsing_rect && + !parsing_actual_deco_rect && + !parsing_deco_rect && + !parsing_window_rect && + !parsing_geometry && + !parsing_gaps) { if (last_key && strcasecmp(last_key, "floating_nodes") == 0) { DLOG("New floating_node\n"); Con *ws = con_get_workspace(json_node); @@ -85,7 +91,13 @@ static int json_start_map(void *ctx) { static int json_end_map(void *ctx) { LOG("end of map\n"); - if (!parsing_swallows && !parsing_rect && !parsing_deco_rect && !parsing_window_rect && !parsing_geometry && !parsing_gaps) { + if (!parsing_swallows && + !parsing_rect && + !parsing_actual_deco_rect && + !parsing_deco_rect && + !parsing_window_rect && + !parsing_geometry && + !parsing_gaps) { /* Set a few default values to simplify manually crafted layout files. */ if (json_node->layout == L_DEFAULT) { DLOG("Setting layout = L_SPLITH\n"); @@ -195,6 +207,7 @@ static int json_end_map(void *ctx) { parsing_gaps = false; parsing_rect = false; + parsing_actual_deco_rect = false; parsing_deco_rect = false; parsing_window_rect = false; parsing_geometry = false; @@ -253,6 +266,9 @@ static int json_key(void *ctx, const unsigned char *val, size_t len) { if (strcasecmp(last_key, "rect") == 0) parsing_rect = true; + if (strcasecmp(last_key, "actual_deco_rect") == 0) + parsing_actual_deco_rect = true; + if (strcasecmp(last_key, "deco_rect") == 0) parsing_deco_rect = true; @@ -674,6 +690,7 @@ void tree_append_json(Con *con, const char *buf, const size_t len, char **errorm incomplete = 0; parsing_swallows = false; parsing_rect = false; + parsing_actual_deco_rect = false; parsing_deco_rect = false; parsing_window_rect = false; parsing_geometry = false; diff --git a/src/render.c b/src/render.c index af7cafd6..61948980 100644 --- a/src/render.c +++ b/src/render.c @@ -69,9 +69,6 @@ void render_con(Con *con) { con->rect = rect_add(con->rect, inset); } inset.height = 0; - if (con->deco_rect.width != 0 && con->deco_rect.height != 0) { - con->deco_rect = rect_add(con->deco_rect, inset); - } params.x = con->rect.x; params.y = con->rect.y; @@ -84,17 +81,27 @@ void render_con(Con *con) { if (con->window) { /* depending on the border style, the rect of the child window * needs to be smaller */ - Rect *inset = &(con->window_rect); - *inset = (Rect){0, 0, con->rect.width, con->rect.height}; + Rect inset = (Rect){ + .x = 0, + .y = 0, + .width = con->rect.width, + .height = con->rect.height, + }; if (con->fullscreen_mode == CF_NONE) { - *inset = rect_add(*inset, con_border_style_rect(con)); + DLOG("deco_rect.height = %d\n", con->deco_rect.height); + Rect bsr = con_border_style_rect(con); + DLOG("bsr at %dx%d with size %dx%d\n", + bsr.x, bsr.y, bsr.width, bsr.height); + + inset = rect_add(inset, bsr); } /* Obey x11 border */ - inset->width -= (2 * con->border_width); - inset->height -= (2 * con->border_width); + inset.width -= (2 * con->border_width); + inset.height -= (2 * con->border_width); - *inset = rect_sanitize_dimensions(*inset); + inset = rect_sanitize_dimensions(inset); + con->window_rect = inset; /* NB: We used to respect resize increment size hints for tiling * windows up until commit 0db93d9 here. However, since all terminal @@ -102,7 +109,8 @@ void render_con(Con *con) { * can (by providing their fake-transparency or background color), this * code was removed. See also https://bugs.i3wm.org/540 */ - DLOG("child will be at %dx%d with size %dx%d\n", inset->x, inset->y, inset->width, inset->height); + DLOG("child will be at %dx%d with size %dx%d\n", + inset.x, inset.y, inset.width, inset.height); } /* Check for fullscreen nodes */ @@ -159,6 +167,18 @@ void render_con(Con *con) { child->rect.x, child->rect.y, child->rect.width, child->rect.height); x_raise_con(child); render_con(child); + + /* render_con_split() sets the deco_rect width based on the rect + * width, but the render_con() call updates the rect width by + * applying gaps, so we need to update deco_rect. */ + if (con->layout == L_SPLITH || con->layout == L_SPLITV) { + if (con_is_leaf(child)) { + if (child->border_style == BS_NORMAL) { + child->deco_rect.width = child->rect.width; + } + } + } + i++; } @@ -381,11 +401,8 @@ static void render_con_split(Con *con, Con *child, render_params *p, int i) { if (con_is_leaf(child)) { if (child->border_style == BS_NORMAL) { /* TODO: make a function for relative coords? */ - child->deco_rect.x = child->rect.x - con->rect.x; - child->deco_rect.y = child->rect.y - con->rect.y; - - child->rect.y += p->deco_height; - child->rect.height -= p->deco_height; + child->deco_rect.x = 0; + child->deco_rect.y = 0; child->deco_rect.width = child->rect.width; child->deco_rect.height = p->deco_height; diff --git a/src/tiling_drag.c b/src/tiling_drag.c index a35a66e6..e4babe3b 100644 --- a/src/tiling_drag.c +++ b/src/tiling_drag.c @@ -10,23 +10,6 @@ #include "all.h" static xcb_window_t create_drop_indicator(Rect rect); -/* - * Includes decoration (container title) to the container's rect. This way we - * can find the correct drop target if the mouse is on a container's - * decoration. - * - */ -static Rect con_rect_plus_deco_height(Con *con) { - Rect rect = con->rect; - rect.height += con->deco_rect.height; - if (rect.y < con->deco_rect.height) { - rect.y = 0; - } else { - rect.y -= con->deco_rect.height; - } - return rect; -} - static bool is_tiling_drop_target(Con *con) { if (!con_has_managed_window(con) || con_is_floating(con) || @@ -90,7 +73,7 @@ bool has_drop_targets(void) { static Con *find_drop_target(uint32_t x, uint32_t y) { Con *con; TAILQ_FOREACH (con, &all_cons, all_cons) { - Rect rect = con_rect_plus_deco_height(con); + Rect rect = con->rect; if (!rect_contains(rect, x, y) || !is_tiling_drop_target(con)) { continue; @@ -186,7 +169,7 @@ DRAGGING_CB(drag_callback) { return; } - Rect rect = con_rect_plus_deco_height(target); + Rect rect = target->rect; direction_t direction = 0; drop_type_t drop_type = DT_CENTER; @@ -355,29 +355,27 @@ void x_window_kill(xcb_window_t window, kill_window_t kill_window) { free(event); } -static void x_draw_title_border(Con *con, struct deco_render_params *p) { - assert(con->parent != NULL); - +static void x_draw_title_border(Con *con, struct deco_render_params *p, surface_t *dest_surface) { Rect *dr = &(con->deco_rect); /* Left */ - draw_util_rectangle(&(con->parent->frame_buffer), p->color->border, + draw_util_rectangle(dest_surface, p->color->border, dr->x, dr->y, 1, dr->height); /* Right */ - draw_util_rectangle(&(con->parent->frame_buffer), p->color->border, + draw_util_rectangle(dest_surface, p->color->border, dr->x + dr->width - 1, dr->y, 1, dr->height); /* Top */ - draw_util_rectangle(&(con->parent->frame_buffer), p->color->border, + draw_util_rectangle(dest_surface, p->color->border, dr->x, dr->y, dr->width, 1); /* Bottom */ - draw_util_rectangle(&(con->parent->frame_buffer), p->color->border, + draw_util_rectangle(dest_surface, p->color->border, dr->x, dr->y + dr->height - 1, dr->width, 1); } -static void x_draw_decoration_after_title(Con *con, struct deco_render_params *p) { +static void x_draw_decoration_after_title(Con *con, struct deco_render_params *p, surface_t *dest_surface) { assert(con->parent != NULL); Rect *dr = &(con->deco_rect); @@ -389,7 +387,7 @@ static void x_draw_decoration_after_title(Con *con, struct deco_render_params *p /* We actually only redraw the far right two pixels as that is the * distance we keep from the edge (not the entire border width). * Redrawing the entire border would cause text to be cut off. */ - draw_util_rectangle(&(con->parent->frame_buffer), p->color->background, + draw_util_rectangle(dest_surface, p->color->background, dr->x + dr->width - 2 * logical_px(1), dr->y, 2 * logical_px(1), @@ -397,7 +395,7 @@ static void x_draw_decoration_after_title(Con *con, struct deco_render_params *p } /* Redraw the border. */ - x_draw_title_border(con, p); + x_draw_title_border(con, p, dest_surface); } /* @@ -593,16 +591,24 @@ void x_draw_decoration(Con *con) { } } + surface_t *dest_surface = &(parent->frame_buffer); + if (con_draw_decoration_into_frame(con)) { + DLOG("using con->frame_buffer (for con->name=%s) as dest_surface\n", con->name); + dest_surface = &(con->frame_buffer); + } else { + DLOG("sticking to parent->frame_buffer = %p\n", dest_surface); + } + DLOG("dest_surface %p is %d x %d (id=0x%08x)\n", dest_surface, dest_surface->width, dest_surface->height, dest_surface->id); + /* If the parent hasn't been set up yet, skip the decoration rendering * for now. */ - if (parent->frame_buffer.id == XCB_NONE) + if (dest_surface->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(&(con->parent->frame_buffer), COLOR_TRANSPARENT); FREE(con->parent->deco_render_params); } @@ -612,11 +618,13 @@ void x_draw_decoration(Con *con) { goto copy_pixmaps; /* 4: paint the bar */ - draw_util_rectangle(&(parent->frame_buffer), p->color->background, + DLOG("con->deco_rect = (x=%d, y=%d, w=%d, h=%d)\n", + con->deco_rect.x, con->deco_rect.y, con->deco_rect.width, con->deco_rect.height); + draw_util_rectangle(dest_surface, p->color->background, con->deco_rect.x, con->deco_rect.y, con->deco_rect.width, con->deco_rect.height); /* 5: draw title border */ - x_draw_title_border(con, p); + x_draw_title_border(con, p, dest_surface); /* 6: draw the icon and title */ int text_offset_y = (con->deco_rect.height - config.font.height) / 2; @@ -651,7 +659,7 @@ void x_draw_decoration(Con *con) { ? title_padding : deco_width - mark_width - title_padding; - draw_util_text(mark, &(parent->frame_buffer), + draw_util_text(mark, dest_surface, p->color->text, p->color->background, con->deco_rect.x + mark_offset_x, con->deco_rect.y + text_offset_y, mark_width); @@ -725,7 +733,7 @@ void x_draw_decoration(Con *con) { break; } - draw_util_text(title, &(parent->frame_buffer), + draw_util_text(title, dest_surface, p->color->text, p->color->background, con->deco_rect.x + title_offset_x, con->deco_rect.y + text_offset_y, @@ -733,7 +741,7 @@ void x_draw_decoration(Con *con) { if (has_icon) { draw_util_image( win->icon, - &(parent->frame_buffer), + dest_surface, con->deco_rect.x + icon_offset_x, con->deco_rect.y + logical_px(1), icon_size, @@ -744,7 +752,7 @@ void x_draw_decoration(Con *con) { I3STRING_FREE(title); } - x_draw_decoration_after_title(con, p); + x_draw_decoration_after_title(con, p, dest_surface); copy_pixmaps: draw_util_copy_surface(&(con->frame_buffer), &(con->frame), 0, 0, 0, 0, con->rect.width, con->rect.height); } @@ -891,7 +899,7 @@ void x_push_node(Con *con) { FREE(state->name); } - if (con->window == NULL) { + if (con->window == NULL && (con->layout == L_STACKED || con->layout == L_TABBED)) { /* Calculate the height of all window decorations which will be drawn on to * this frame. */ uint32_t max_y = 0, max_height = 0; @@ -905,6 +913,9 @@ void x_push_node(Con *con) { rect.height = max_y + max_height; if (rect.height == 0) con->mapped = false; + } else if (con->window == NULL) { + /* not a stacked or tabbed split container */ + con->mapped = false; } bool need_reshape = false; @@ -949,10 +960,11 @@ void x_push_node(Con *con) { /* The pixmap of a borderless leaf container will not be used except * for the titlebar in a stack or tabs (issue #1013). */ - bool is_pixmap_needed = (con->border_style != BS_NONE || - !con_is_leaf(con) || - con->parent->layout == L_STACKED || - con->parent->layout == L_TABBED); + bool is_pixmap_needed = ((con_is_leaf(con) && con->border_style != BS_NONE) || + con->layout == L_STACKED || + con->layout == L_TABBED); + DLOG("Con %p (layout %d), is_pixmap_needed = %s, rect.height = %d\n", + con, con->layout, is_pixmap_needed ? "yes" : "no", con->rect.height); /* The root con and output cons will never require a pixmap. In particular for the * __i3 output, this will likely not work anyway because it might be ridiculously @@ -999,6 +1011,7 @@ void x_push_node(Con *con) { int width = MAX((int32_t)rect.width, 1); int height = MAX((int32_t)rect.height, 1); + DLOG("creating %d x %d pixmap for con %p (con->frame_buffer.id = (pixmap_t)0x%08x) (con->frame.id (drawable_t)0x%08x)\n", width, height, con, con->frame_buffer.id, con->frame.id); xcb_create_pixmap(conn, win_depth, con->frame_buffer.id, con->frame.id, width, height); draw_util_surface_init(conn, &(con->frame_buffer), con->frame_buffer.id, get_visualtype_by_id(get_visualid_by_depth(win_depth)), width, height); diff --git a/testcases/t/246-window-decoration-focus.t b/testcases/t/246-window-decoration-focus.t index 4d479f83..265cb87a 100644 --- a/testcases/t/246-window-decoration-focus.t +++ b/testcases/t/246-window-decoration-focus.t @@ -50,7 +50,7 @@ $target = get_focused($ws); $A = $cons[0]; $C = $cons[1]->{nodes}[1]; -$y = $C->{rect}->{y} - 0.5 * $C->{deco_rect}->{height}; +$y = $C->{rect}->{y} + 0.5 * $C->{deco_rect}->{height}; # make sure that B is the focus head of its parent cmd '[id="' . $B->{id} . '"] focus'; |