aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Stapelberg <michael@stapelberg.de>2022-11-03 23:11:32 +0100
committerMichael Stapelberg <stapelberg@users.noreply.github.com>2022-11-05 15:58:15 +0100
commitd26ddcbfe5f0ead61cc55c1f596692d9a89e71f9 (patch)
tree5e4e630b59ead2a30f801f4dbb12eb7cf396f431
parent6e6af01b7a1f2ff1a35f7751c07e51277d4414e2 (diff)
downloadi3-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-howto4
-rw-r--r--docs/ipc8
-rw-r--r--docs/userguide17
-rw-r--r--include/con.h8
-rw-r--r--src/click.c19
-rw-r--r--src/con.c29
-rw-r--r--src/floating.c36
-rw-r--r--src/handlers.c36
-rw-r--r--src/ipc.c10
-rw-r--r--src/load_layout.c21
-rw-r--r--src/render.c47
-rw-r--r--src/tiling_drag.c21
-rw-r--r--src/x.c59
-rw-r--r--testcases/t/246-window-decoration-focus.t2
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
diff --git a/docs/ipc b/docs/ipc
index 0151b24e..c9fee469 100644
--- a/docs/ipc
+++ b/docs/ipc
@@ -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) {
diff --git a/src/con.c b/src/con.c
index b1fdba92..e7757309 100644
--- a/src/con.c
+++ b/src/con.c
@@ -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;
diff --git a/src/ipc.c b/src/ipc.c
index 8c59c2eb..86ff45de 100644
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -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;
diff --git a/src/x.c b/src/x.c
index 42df9966..6d444782 100644
--- a/src/x.c
+++ b/src/x.c
@@ -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';