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
This commit is contained in:
parent
6e6af01b7a
commit
d26ddcbfe5
@ -564,9 +564,7 @@ split container.
|
|||||||
==== Default layout
|
==== Default layout
|
||||||
|
|
||||||
In default layout, containers are placed horizontally or vertically next to
|
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
|
each other (depending on the +con->orientation+).
|
||||||
opposed to a split container) and has border style "normal", appropriate space
|
|
||||||
will be reserved for its window decoration.
|
|
||||||
|
|
||||||
==== Stacked layout
|
==== Stacked layout
|
||||||
|
|
||||||
|
8
docs/ipc
8
docs/ipc
@ -410,6 +410,14 @@ deco_rect (map)::
|
|||||||
The coordinates of the *window decoration* inside its container. These
|
The coordinates of the *window decoration* inside its container. These
|
||||||
coordinates are relative to the container and do not include the actual
|
coordinates are relative to the container and do not include the actual
|
||||||
client window.
|
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)::
|
geometry (map)::
|
||||||
The original geometry the window specified when i3 mapped it. Used when
|
The original geometry the window specified when i3 mapped it. Used when
|
||||||
switching a window to floating mode, for example.
|
switching a window to floating mode, for example.
|
||||||
|
@ -1501,23 +1501,6 @@ Tip: You can find an
|
|||||||
https://github.com/Airblader/i3/wiki/Example-Configuration[example
|
https://github.com/Airblader/i3/wiki/Example-Configuration[example
|
||||||
configuration] that uses modes to illustrate various gap configurations.
|
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
|
== Configuring i3bar
|
||||||
|
|
||||||
The bar at the bottom of your monitor is drawn by a separate process called
|
The bar at the bottom of your monitor is drawn by a separate process called
|
||||||
|
@ -420,6 +420,14 @@ Con *con_descend_tiling_focused(Con *con);
|
|||||||
*/
|
*/
|
||||||
Con *con_descend_direction(Con *con, direction_t direction);
|
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
|
* 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
|
* be added to the original Rect to get the final position (obviously the
|
||||||
|
19
src/click.c
19
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 */
|
/* Check if the click was on the decoration of a child */
|
||||||
Con *child;
|
if (con->window != NULL) {
|
||||||
TAILQ_FOREACH_REVERSE (child, &(con->nodes_head), nodes_head, nodes) {
|
if (rect_contains(con->deco_rect, event->event_x, event->event_y)) {
|
||||||
if (!rect_contains(child->deco_rect, event->event_x, event->event_y))
|
route_click(con, event, mod_pressed, CLICK_DECORATION);
|
||||||
continue;
|
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);
|
route_click(child, event, mod_pressed, CLICK_DECORATION);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event->child != XCB_NONE) {
|
if (event->child != XCB_NONE) {
|
||||||
|
29
src/con.c
29
src/con.c
@ -1692,6 +1692,20 @@ static bool has_outer_gaps(gaps_t gaps) {
|
|||||||
gaps.left > 0;
|
gaps.left > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
* 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
|
* be added to the original Rect to get the final position (obviously the
|
||||||
@ -1724,7 +1738,16 @@ Rect con_border_style_rect(Con *con) {
|
|||||||
if (border_style == BS_NONE)
|
if (border_style == BS_NONE)
|
||||||
return (Rect){0, 0, 0, 0};
|
return (Rect){0, 0, 0, 0};
|
||||||
if (border_style == BS_NORMAL) {
|
if (border_style == BS_NORMAL) {
|
||||||
|
const int deco_height = render_deco_height();
|
||||||
result = (Rect){border_width, 0, -(2 * border_width), -(border_width)};
|
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 {
|
} else {
|
||||||
result = (Rect){border_width, border_width, -(2 * border_width), -(2 * border_width)};
|
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. */
|
* pixels. For the parent, we do the same also for the decoration. */
|
||||||
Con *parent = con->parent;
|
Con *parent = con->parent;
|
||||||
Rect bsr = con_border_style_rect(con);
|
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);
|
con->rect = rect_add(con->rect, bsr);
|
||||||
parent->rect = rect_add(parent->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. */
|
/* Change the border style, get new border/decoration values. */
|
||||||
con->border_style = border_style;
|
con->border_style = border_style;
|
||||||
con->current_border_width = border_width;
|
con->current_border_width = border_width;
|
||||||
bsr = con_border_style_rect(con);
|
bsr = con_border_style_rect(con);
|
||||||
deco_height = (con->border_style == BS_NORMAL ? render_deco_height() : 0);
|
|
||||||
|
|
||||||
con->rect = rect_sub(con->rect, bsr);
|
con->rect = rect_sub(con->rect, bsr);
|
||||||
parent->rect = rect_sub(parent->rect, bsr);
|
parent->rect = rect_sub(parent->rect, bsr);
|
||||||
parent->rect.y -= deco_height;
|
|
||||||
parent->rect.height += deco_height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -79,16 +79,22 @@ void floating_check_size(Con *floating_con, bool prefer_height) {
|
|||||||
Rect floating_sane_max_dimensions;
|
Rect floating_sane_max_dimensions;
|
||||||
Con *focused_con = con_descend_focused(floating_con);
|
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);
|
Rect border_rect = con_border_style_rect(focused_con);
|
||||||
/* We have to do the opposite calculations that render_con() do
|
/* We have to do the opposite calculations that render_con() do
|
||||||
* to get the exact size we want. */
|
* to get the exact size we want. */
|
||||||
border_rect.width = -border_rect.width;
|
border_rect.width = -border_rect.width;
|
||||||
border_rect.width += 2 * focused_con->border_width;
|
|
||||||
border_rect.height = -border_rect.height;
|
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;
|
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;
|
i3Window *window = focused_con->window;
|
||||||
if (window != NULL) {
|
if (window != NULL) {
|
||||||
@ -319,9 +325,6 @@ bool floating_enable(Con *con, bool automatic) {
|
|||||||
x_set_name(nc, name);
|
x_set_name(nc, name);
|
||||||
free(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("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);
|
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;
|
nc->rect = con->geometry;
|
||||||
@ -352,15 +355,10 @@ bool floating_enable(Con *con, bool automatic) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Add pixels for the decoration. */
|
/* Add pixels for the decoration. */
|
||||||
Rect border_style_rect = con_border_style_rect(con);
|
Rect bsr = con_border_style_rect(con);
|
||||||
|
|
||||||
nc->rect.height -= border_style_rect.height;
|
nc->rect.height -= bsr.height;
|
||||||
nc->rect.width -= border_style_rect.width;
|
nc->rect.width -= bsr.width;
|
||||||
|
|
||||||
/* Add some more pixels for the title bar */
|
|
||||||
if (con_border_style(con) == BS_NORMAL) {
|
|
||||||
nc->rect.height += deco_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Honor the X11 border */
|
/* Honor the X11 border */
|
||||||
nc->rect.height += con->border_width * 2;
|
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);
|
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 the cons to get initial window_rect correct */
|
||||||
render_con(nc);
|
render_con(nc);
|
||||||
|
|
||||||
|
@ -214,18 +214,30 @@ static void handle_motion_notify(xcb_motion_notify_event_t *event) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/* see over which rect the user is */
|
/* see over which rect the user is */
|
||||||
Con *current;
|
if (con->window != NULL) {
|
||||||
TAILQ_FOREACH_REVERSE (current, &(con->nodes_head), nodes_head, nodes) {
|
if (rect_contains(con->deco_rect, event->event_x, event->event_y)) {
|
||||||
if (!rect_contains(current->deco_rect, event->event_x, event->event_y))
|
/* We found the rect, let’s see if this window is focused */
|
||||||
continue;
|
if (TAILQ_FIRST(&(con->parent->focus_head)) == con)
|
||||||
|
return;
|
||||||
|
|
||||||
/* We found the rect, let’s see if this window is focused */
|
con_focus(con);
|
||||||
if (TAILQ_FIRST(&(con->focus_head)) == current)
|
x_push_changes(croot);
|
||||||
return;
|
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);
|
/* We found the rect, let’s see if this window is focused */
|
||||||
x_push_changes(croot);
|
if (TAILQ_FIRST(&(con->focus_head)) == current)
|
||||||
return;
|
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);
|
Con *fullscreen = con_get_fullscreen_covering_ws(workspace);
|
||||||
|
|
||||||
if (fullscreen != con && con_is_floating(con) && con_is_leaf(con)) {
|
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*
|
/* we actually need to apply the size/position changes to the *parent*
|
||||||
* container */
|
* container */
|
||||||
Rect bsr = con_border_style_rect(con);
|
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;
|
Con *floatingcon = con->parent;
|
||||||
Rect newrect = floatingcon->rect;
|
Rect newrect = floatingcon->rect;
|
||||||
|
|
||||||
|
10
src/ipc.c
10
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);
|
y(integer, con->current_border_width);
|
||||||
|
|
||||||
dump_rect(gen, "rect", con->rect);
|
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, "window_rect", con->window_rect);
|
||||||
dump_rect(gen, "geometry", con->geometry);
|
dump_rect(gen, "geometry", con->geometry);
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ static Con *to_focus;
|
|||||||
static bool parsing_gaps;
|
static bool parsing_gaps;
|
||||||
static bool parsing_swallows;
|
static bool parsing_swallows;
|
||||||
static bool parsing_rect;
|
static bool parsing_rect;
|
||||||
|
static bool parsing_actual_deco_rect;
|
||||||
static bool parsing_deco_rect;
|
static bool parsing_deco_rect;
|
||||||
static bool parsing_window_rect;
|
static bool parsing_window_rect;
|
||||||
static bool parsing_geometry;
|
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);
|
TAILQ_INSERT_TAIL(&(json_node->swallow_head), current_swallow, matches);
|
||||||
swallow_is_empty = true;
|
swallow_is_empty = true;
|
||||||
} else {
|
} 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) {
|
if (last_key && strcasecmp(last_key, "floating_nodes") == 0) {
|
||||||
DLOG("New floating_node\n");
|
DLOG("New floating_node\n");
|
||||||
Con *ws = con_get_workspace(json_node);
|
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) {
|
static int json_end_map(void *ctx) {
|
||||||
LOG("end of map\n");
|
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. */
|
/* Set a few default values to simplify manually crafted layout files. */
|
||||||
if (json_node->layout == L_DEFAULT) {
|
if (json_node->layout == L_DEFAULT) {
|
||||||
DLOG("Setting layout = L_SPLITH\n");
|
DLOG("Setting layout = L_SPLITH\n");
|
||||||
@ -195,6 +207,7 @@ static int json_end_map(void *ctx) {
|
|||||||
|
|
||||||
parsing_gaps = false;
|
parsing_gaps = false;
|
||||||
parsing_rect = false;
|
parsing_rect = false;
|
||||||
|
parsing_actual_deco_rect = false;
|
||||||
parsing_deco_rect = false;
|
parsing_deco_rect = false;
|
||||||
parsing_window_rect = false;
|
parsing_window_rect = false;
|
||||||
parsing_geometry = 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)
|
if (strcasecmp(last_key, "rect") == 0)
|
||||||
parsing_rect = true;
|
parsing_rect = true;
|
||||||
|
|
||||||
|
if (strcasecmp(last_key, "actual_deco_rect") == 0)
|
||||||
|
parsing_actual_deco_rect = true;
|
||||||
|
|
||||||
if (strcasecmp(last_key, "deco_rect") == 0)
|
if (strcasecmp(last_key, "deco_rect") == 0)
|
||||||
parsing_deco_rect = true;
|
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;
|
incomplete = 0;
|
||||||
parsing_swallows = false;
|
parsing_swallows = false;
|
||||||
parsing_rect = false;
|
parsing_rect = false;
|
||||||
|
parsing_actual_deco_rect = false;
|
||||||
parsing_deco_rect = false;
|
parsing_deco_rect = false;
|
||||||
parsing_window_rect = false;
|
parsing_window_rect = false;
|
||||||
parsing_geometry = false;
|
parsing_geometry = false;
|
||||||
|
47
src/render.c
47
src/render.c
@ -69,9 +69,6 @@ void render_con(Con *con) {
|
|||||||
con->rect = rect_add(con->rect, inset);
|
con->rect = rect_add(con->rect, inset);
|
||||||
}
|
}
|
||||||
inset.height = 0;
|
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.x = con->rect.x;
|
||||||
params.y = con->rect.y;
|
params.y = con->rect.y;
|
||||||
@ -84,17 +81,27 @@ void render_con(Con *con) {
|
|||||||
if (con->window) {
|
if (con->window) {
|
||||||
/* depending on the border style, the rect of the child window
|
/* depending on the border style, the rect of the child window
|
||||||
* needs to be smaller */
|
* needs to be smaller */
|
||||||
Rect *inset = &(con->window_rect);
|
Rect inset = (Rect){
|
||||||
*inset = (Rect){0, 0, con->rect.width, con->rect.height};
|
.x = 0,
|
||||||
|
.y = 0,
|
||||||
|
.width = con->rect.width,
|
||||||
|
.height = con->rect.height,
|
||||||
|
};
|
||||||
if (con->fullscreen_mode == CF_NONE) {
|
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 */
|
/* Obey x11 border */
|
||||||
inset->width -= (2 * con->border_width);
|
inset.width -= (2 * con->border_width);
|
||||||
inset->height -= (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
|
/* NB: We used to respect resize increment size hints for tiling
|
||||||
* windows up until commit 0db93d9 here. However, since all terminal
|
* 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
|
* can (by providing their fake-transparency or background color), this
|
||||||
* code was removed. See also https://bugs.i3wm.org/540 */
|
* 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 */
|
/* 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);
|
child->rect.x, child->rect.y, child->rect.width, child->rect.height);
|
||||||
x_raise_con(child);
|
x_raise_con(child);
|
||||||
render_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++;
|
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 (con_is_leaf(child)) {
|
||||||
if (child->border_style == BS_NORMAL) {
|
if (child->border_style == BS_NORMAL) {
|
||||||
/* TODO: make a function for relative coords? */
|
/* TODO: make a function for relative coords? */
|
||||||
child->deco_rect.x = child->rect.x - con->rect.x;
|
child->deco_rect.x = 0;
|
||||||
child->deco_rect.y = child->rect.y - con->rect.y;
|
child->deco_rect.y = 0;
|
||||||
|
|
||||||
child->rect.y += p->deco_height;
|
|
||||||
child->rect.height -= p->deco_height;
|
|
||||||
|
|
||||||
child->deco_rect.width = child->rect.width;
|
child->deco_rect.width = child->rect.width;
|
||||||
child->deco_rect.height = p->deco_height;
|
child->deco_rect.height = p->deco_height;
|
||||||
|
@ -10,23 +10,6 @@
|
|||||||
#include "all.h"
|
#include "all.h"
|
||||||
static xcb_window_t create_drop_indicator(Rect rect);
|
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) {
|
static bool is_tiling_drop_target(Con *con) {
|
||||||
if (!con_has_managed_window(con) ||
|
if (!con_has_managed_window(con) ||
|
||||||
con_is_floating(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) {
|
static Con *find_drop_target(uint32_t x, uint32_t y) {
|
||||||
Con *con;
|
Con *con;
|
||||||
TAILQ_FOREACH (con, &all_cons, all_cons) {
|
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) ||
|
if (!rect_contains(rect, x, y) ||
|
||||||
!is_tiling_drop_target(con)) {
|
!is_tiling_drop_target(con)) {
|
||||||
continue;
|
continue;
|
||||||
@ -186,7 +169,7 @@ DRAGGING_CB(drag_callback) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rect rect = con_rect_plus_deco_height(target);
|
Rect rect = target->rect;
|
||||||
|
|
||||||
direction_t direction = 0;
|
direction_t direction = 0;
|
||||||
drop_type_t drop_type = DT_CENTER;
|
drop_type_t drop_type = DT_CENTER;
|
||||||
|
59
src/x.c
59
src/x.c
@ -355,29 +355,27 @@ void x_window_kill(xcb_window_t window, kill_window_t kill_window) {
|
|||||||
free(event);
|
free(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void x_draw_title_border(Con *con, struct deco_render_params *p) {
|
static void x_draw_title_border(Con *con, struct deco_render_params *p, surface_t *dest_surface) {
|
||||||
assert(con->parent != NULL);
|
|
||||||
|
|
||||||
Rect *dr = &(con->deco_rect);
|
Rect *dr = &(con->deco_rect);
|
||||||
|
|
||||||
/* Left */
|
/* 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);
|
dr->x, dr->y, 1, dr->height);
|
||||||
|
|
||||||
/* Right */
|
/* 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);
|
dr->x + dr->width - 1, dr->y, 1, dr->height);
|
||||||
|
|
||||||
/* Top */
|
/* 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);
|
dr->x, dr->y, dr->width, 1);
|
||||||
|
|
||||||
/* Bottom */
|
/* 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);
|
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);
|
assert(con->parent != NULL);
|
||||||
|
|
||||||
Rect *dr = &(con->deco_rect);
|
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
|
/* We actually only redraw the far right two pixels as that is the
|
||||||
* distance we keep from the edge (not the entire border width).
|
* distance we keep from the edge (not the entire border width).
|
||||||
* Redrawing the entire border would cause text to be cut off. */
|
* 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->x + dr->width - 2 * logical_px(1),
|
||||||
dr->y,
|
dr->y,
|
||||||
2 * logical_px(1),
|
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. */
|
/* 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
|
/* If the parent hasn't been set up yet, skip the decoration rendering
|
||||||
* for now. */
|
* for now. */
|
||||||
if (parent->frame_buffer.id == XCB_NONE)
|
if (dest_surface->id == XCB_NONE)
|
||||||
goto copy_pixmaps;
|
goto copy_pixmaps;
|
||||||
|
|
||||||
/* For the first child, we clear the parent pixmap to ensure there's no
|
/* 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
|
* garbage left on there. This is important to avoid tearing when using
|
||||||
* transparency. */
|
* transparency. */
|
||||||
if (con == TAILQ_FIRST(&(con->parent->nodes_head))) {
|
if (con == TAILQ_FIRST(&(con->parent->nodes_head))) {
|
||||||
draw_util_clear_surface(&(con->parent->frame_buffer), COLOR_TRANSPARENT);
|
|
||||||
FREE(con->parent->deco_render_params);
|
FREE(con->parent->deco_render_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -612,11 +618,13 @@ void x_draw_decoration(Con *con) {
|
|||||||
goto copy_pixmaps;
|
goto copy_pixmaps;
|
||||||
|
|
||||||
/* 4: paint the bar */
|
/* 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);
|
con->deco_rect.x, con->deco_rect.y, con->deco_rect.width, con->deco_rect.height);
|
||||||
|
|
||||||
/* 5: draw title border */
|
/* 5: draw title border */
|
||||||
x_draw_title_border(con, p);
|
x_draw_title_border(con, p, dest_surface);
|
||||||
|
|
||||||
/* 6: draw the icon and title */
|
/* 6: draw the icon and title */
|
||||||
int text_offset_y = (con->deco_rect.height - config.font.height) / 2;
|
int text_offset_y = (con->deco_rect.height - config.font.height) / 2;
|
||||||
@ -651,7 +659,7 @@ void x_draw_decoration(Con *con) {
|
|||||||
? title_padding
|
? title_padding
|
||||||
: deco_width - mark_width - 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,
|
p->color->text, p->color->background,
|
||||||
con->deco_rect.x + mark_offset_x,
|
con->deco_rect.x + mark_offset_x,
|
||||||
con->deco_rect.y + text_offset_y, mark_width);
|
con->deco_rect.y + text_offset_y, mark_width);
|
||||||
@ -725,7 +733,7 @@ void x_draw_decoration(Con *con) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_util_text(title, &(parent->frame_buffer),
|
draw_util_text(title, dest_surface,
|
||||||
p->color->text, p->color->background,
|
p->color->text, p->color->background,
|
||||||
con->deco_rect.x + title_offset_x,
|
con->deco_rect.x + title_offset_x,
|
||||||
con->deco_rect.y + text_offset_y,
|
con->deco_rect.y + text_offset_y,
|
||||||
@ -733,7 +741,7 @@ void x_draw_decoration(Con *con) {
|
|||||||
if (has_icon) {
|
if (has_icon) {
|
||||||
draw_util_image(
|
draw_util_image(
|
||||||
win->icon,
|
win->icon,
|
||||||
&(parent->frame_buffer),
|
dest_surface,
|
||||||
con->deco_rect.x + icon_offset_x,
|
con->deco_rect.x + icon_offset_x,
|
||||||
con->deco_rect.y + logical_px(1),
|
con->deco_rect.y + logical_px(1),
|
||||||
icon_size,
|
icon_size,
|
||||||
@ -744,7 +752,7 @@ void x_draw_decoration(Con *con) {
|
|||||||
I3STRING_FREE(title);
|
I3STRING_FREE(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
x_draw_decoration_after_title(con, p);
|
x_draw_decoration_after_title(con, p, dest_surface);
|
||||||
copy_pixmaps:
|
copy_pixmaps:
|
||||||
draw_util_copy_surface(&(con->frame_buffer), &(con->frame), 0, 0, 0, 0, con->rect.width, con->rect.height);
|
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);
|
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
|
/* Calculate the height of all window decorations which will be drawn on to
|
||||||
* this frame. */
|
* this frame. */
|
||||||
uint32_t max_y = 0, max_height = 0;
|
uint32_t max_y = 0, max_height = 0;
|
||||||
@ -905,6 +913,9 @@ void x_push_node(Con *con) {
|
|||||||
rect.height = max_y + max_height;
|
rect.height = max_y + max_height;
|
||||||
if (rect.height == 0)
|
if (rect.height == 0)
|
||||||
con->mapped = false;
|
con->mapped = false;
|
||||||
|
} else if (con->window == NULL) {
|
||||||
|
/* not a stacked or tabbed split container */
|
||||||
|
con->mapped = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool need_reshape = 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
|
/* The pixmap of a borderless leaf container will not be used except
|
||||||
* for the titlebar in a stack or tabs (issue #1013). */
|
* for the titlebar in a stack or tabs (issue #1013). */
|
||||||
bool is_pixmap_needed = (con->border_style != BS_NONE ||
|
bool is_pixmap_needed = ((con_is_leaf(con) && con->border_style != BS_NONE) ||
|
||||||
!con_is_leaf(con) ||
|
con->layout == L_STACKED ||
|
||||||
con->parent->layout == L_STACKED ||
|
con->layout == L_TABBED);
|
||||||
con->parent->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
|
/* 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
|
* __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 width = MAX((int32_t)rect.width, 1);
|
||||||
int height = MAX((int32_t)rect.height, 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);
|
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,
|
draw_util_surface_init(conn, &(con->frame_buffer), con->frame_buffer.id,
|
||||||
get_visualtype_by_id(get_visualid_by_depth(win_depth)), width, height);
|
get_visualtype_by_id(get_visualid_by_depth(win_depth)), width, height);
|
||||||
|
@ -50,7 +50,7 @@ $target = get_focused($ws);
|
|||||||
$A = $cons[0];
|
$A = $cons[0];
|
||||||
$C = $cons[1]->{nodes}[1];
|
$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
|
# make sure that B is the focus head of its parent
|
||||||
cmd '[id="' . $B->{id} . '"] focus';
|
cmd '[id="' . $B->{id} . '"] focus';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user