Merge pull request #1454 from acrisci/feature/i3bar-update-strut-partial-reload
reconfigure dock clients on strut partial change
This commit is contained in:
commit
773f9f52e9
|
@ -1525,6 +1525,50 @@ void realloc_sl_buffer(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Strut partial tells i3 where to reserve space for i3bar. This is determined
|
||||||
|
* by the `position` bar config directive. */
|
||||||
|
xcb_void_cookie_t config_strut_partial(i3_output *output) {
|
||||||
|
/* A local struct to save the strut_partial property */
|
||||||
|
struct {
|
||||||
|
uint32_t left;
|
||||||
|
uint32_t right;
|
||||||
|
uint32_t top;
|
||||||
|
uint32_t bottom;
|
||||||
|
uint32_t left_start_y;
|
||||||
|
uint32_t left_end_y;
|
||||||
|
uint32_t right_start_y;
|
||||||
|
uint32_t right_end_y;
|
||||||
|
uint32_t top_start_x;
|
||||||
|
uint32_t top_end_x;
|
||||||
|
uint32_t bottom_start_x;
|
||||||
|
uint32_t bottom_end_x;
|
||||||
|
} __attribute__((__packed__)) strut_partial;
|
||||||
|
memset(&strut_partial, 0, sizeof(strut_partial));
|
||||||
|
|
||||||
|
switch (config.position) {
|
||||||
|
case POS_NONE:
|
||||||
|
break;
|
||||||
|
case POS_TOP:
|
||||||
|
strut_partial.top = bar_height;
|
||||||
|
strut_partial.top_start_x = output->rect.x;
|
||||||
|
strut_partial.top_end_x = output->rect.x + output->rect.w;
|
||||||
|
break;
|
||||||
|
case POS_BOT:
|
||||||
|
strut_partial.bottom = bar_height;
|
||||||
|
strut_partial.bottom_start_x = output->rect.x;
|
||||||
|
strut_partial.bottom_end_x = output->rect.x + output->rect.w;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return xcb_change_property(xcb_connection,
|
||||||
|
XCB_PROP_MODE_REPLACE,
|
||||||
|
output->bar,
|
||||||
|
atoms[_NET_WM_STRUT_PARTIAL],
|
||||||
|
XCB_ATOM_CARDINAL,
|
||||||
|
32,
|
||||||
|
12,
|
||||||
|
&strut_partial);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reconfigure all bars and create new bars for recently activated outputs
|
* Reconfigure all bars and create new bars for recently activated outputs
|
||||||
*
|
*
|
||||||
|
@ -1624,49 +1668,7 @@ void reconfig_windows(bool redraw_bars) {
|
||||||
1,
|
1,
|
||||||
(unsigned char *)&atoms[_NET_WM_WINDOW_TYPE_DOCK]);
|
(unsigned char *)&atoms[_NET_WM_WINDOW_TYPE_DOCK]);
|
||||||
|
|
||||||
/* We need to tell i3, where to reserve space for i3bar */
|
xcb_void_cookie_t strut_cookie = config_strut_partial(walk);
|
||||||
/* left, right, top, bottom, left_start_y, left_end_y,
|
|
||||||
* right_start_y, right_end_y, top_start_x, top_end_x, bottom_start_x,
|
|
||||||
* bottom_end_x */
|
|
||||||
/* A local struct to save the strut_partial property */
|
|
||||||
struct {
|
|
||||||
uint32_t left;
|
|
||||||
uint32_t right;
|
|
||||||
uint32_t top;
|
|
||||||
uint32_t bottom;
|
|
||||||
uint32_t left_start_y;
|
|
||||||
uint32_t left_end_y;
|
|
||||||
uint32_t right_start_y;
|
|
||||||
uint32_t right_end_y;
|
|
||||||
uint32_t top_start_x;
|
|
||||||
uint32_t top_end_x;
|
|
||||||
uint32_t bottom_start_x;
|
|
||||||
uint32_t bottom_end_x;
|
|
||||||
} __attribute__((__packed__)) strut_partial;
|
|
||||||
memset(&strut_partial, 0, sizeof(strut_partial));
|
|
||||||
|
|
||||||
switch (config.position) {
|
|
||||||
case POS_NONE:
|
|
||||||
break;
|
|
||||||
case POS_TOP:
|
|
||||||
strut_partial.top = bar_height;
|
|
||||||
strut_partial.top_start_x = walk->rect.x;
|
|
||||||
strut_partial.top_end_x = walk->rect.x + walk->rect.w;
|
|
||||||
break;
|
|
||||||
case POS_BOT:
|
|
||||||
strut_partial.bottom = bar_height;
|
|
||||||
strut_partial.bottom_start_x = walk->rect.x;
|
|
||||||
strut_partial.bottom_end_x = walk->rect.x + walk->rect.w;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
xcb_void_cookie_t strut_cookie = xcb_change_property(xcb_connection,
|
|
||||||
XCB_PROP_MODE_REPLACE,
|
|
||||||
walk->bar,
|
|
||||||
atoms[_NET_WM_STRUT_PARTIAL],
|
|
||||||
XCB_ATOM_CARDINAL,
|
|
||||||
32,
|
|
||||||
12,
|
|
||||||
&strut_partial);
|
|
||||||
|
|
||||||
/* We also want a graphics context for the bars (it defines the properties
|
/* We also want a graphics context for the bars (it defines the properties
|
||||||
* with which we draw to them) */
|
* with which we draw to them) */
|
||||||
|
@ -1726,6 +1728,9 @@ void reconfig_windows(bool redraw_bars) {
|
||||||
values[3] = bar_height;
|
values[3] = bar_height;
|
||||||
values[4] = XCB_STACK_MODE_ABOVE;
|
values[4] = XCB_STACK_MODE_ABOVE;
|
||||||
|
|
||||||
|
DLOG("Reconfiguring strut partial property for output %s\n", walk->name);
|
||||||
|
xcb_void_cookie_t strut_cookie = config_strut_partial(walk);
|
||||||
|
|
||||||
DLOG("Destroying buffer for output %s\n", walk->name);
|
DLOG("Destroying buffer for output %s\n", walk->name);
|
||||||
xcb_free_pixmap(xcb_connection, walk->buffer);
|
xcb_free_pixmap(xcb_connection, walk->buffer);
|
||||||
|
|
||||||
|
@ -1774,6 +1779,7 @@ void reconfig_windows(bool redraw_bars) {
|
||||||
if (xcb_request_failed(cfg_cookie, "Could not reconfigure window") ||
|
if (xcb_request_failed(cfg_cookie, "Could not reconfigure window") ||
|
||||||
xcb_request_failed(chg_cookie, "Could not change window") ||
|
xcb_request_failed(chg_cookie, "Could not change window") ||
|
||||||
xcb_request_failed(pm_cookie, "Could not create pixmap") ||
|
xcb_request_failed(pm_cookie, "Could not create pixmap") ||
|
||||||
|
xcb_request_failed(strut_cookie, "Could not set strut") ||
|
||||||
(redraw_bars && (xcb_request_failed(umap_cookie, "Could not unmap window") ||
|
(redraw_bars && (xcb_request_failed(umap_cookie, "Could not unmap window") ||
|
||||||
(config.hide_on_modifier == M_DOCK && xcb_request_failed(map_cookie, "Could not map window"))))) {
|
(config.hide_on_modifier == M_DOCK && xcb_request_failed(map_cookie, "Could not map window"))))) {
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|
|
@ -1159,6 +1159,87 @@ static bool handle_class_change(void *data, xcb_connection_t *conn, uint8_t stat
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handles the _NET_WM_STRUT_PARTIAL property for allocating space for dock clients.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static bool handle_strut_partial_change(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
|
||||||
|
xcb_atom_t name, xcb_get_property_reply_t *prop) {
|
||||||
|
DLOG("strut partial change for window 0x%08x\n", window);
|
||||||
|
|
||||||
|
Con *con;
|
||||||
|
if ((con = con_by_window_id(window)) == NULL || con->window == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prop == NULL) {
|
||||||
|
xcb_generic_error_t *err = NULL;
|
||||||
|
xcb_get_property_cookie_t strut_cookie = xcb_get_property(conn, false, window, A__NET_WM_STRUT_PARTIAL,
|
||||||
|
XCB_GET_PROPERTY_TYPE_ANY, 0, UINT32_MAX);
|
||||||
|
prop = xcb_get_property_reply(conn, strut_cookie, &err);
|
||||||
|
|
||||||
|
if (err != NULL) {
|
||||||
|
DLOG("got error when getting strut partial property: %d\n", err->error_code);
|
||||||
|
free(err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prop == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DLOG("That is con %p / %s\n", con, con->name);
|
||||||
|
|
||||||
|
window_update_strut_partial(con->window, prop);
|
||||||
|
|
||||||
|
/* we only handle this change for dock clients */
|
||||||
|
if (con->parent == NULL || con->parent->type != CT_DOCKAREA) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Con *search_at = croot;
|
||||||
|
Con *output = con_get_output(con);
|
||||||
|
if (output != NULL) {
|
||||||
|
DLOG("Starting search at output %s\n", output->name);
|
||||||
|
search_at = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find out the desired position of this dock window */
|
||||||
|
if (con->window->reserved.top > 0 && con->window->reserved.bottom == 0) {
|
||||||
|
DLOG("Top dock client\n");
|
||||||
|
con->window->dock = W_DOCK_TOP;
|
||||||
|
} else if (con->window->reserved.top == 0 && con->window->reserved.bottom > 0) {
|
||||||
|
DLOG("Bottom dock client\n");
|
||||||
|
con->window->dock = W_DOCK_BOTTOM;
|
||||||
|
} else {
|
||||||
|
DLOG("Ignoring invalid reserved edges (_NET_WM_STRUT_PARTIAL), using position as fallback:\n");
|
||||||
|
if (con->geometry.y < (int16_t)(search_at->rect.height / 2)) {
|
||||||
|
DLOG("geom->y = %d < rect.height / 2 = %d, it is a top dock client\n",
|
||||||
|
con->geometry.y, (search_at->rect.height / 2));
|
||||||
|
con->window->dock = W_DOCK_TOP;
|
||||||
|
} else {
|
||||||
|
DLOG("geom->y = %d >= rect.height / 2 = %d, it is a bottom dock client\n",
|
||||||
|
con->geometry.y, (search_at->rect.height / 2));
|
||||||
|
con->window->dock = W_DOCK_BOTTOM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find the dockarea */
|
||||||
|
Con *dockarea = con_for_window(search_at, con->window, NULL);
|
||||||
|
assert(dockarea != NULL);
|
||||||
|
|
||||||
|
/* attach the dock to the dock area */
|
||||||
|
con_detach(con);
|
||||||
|
con->parent = dockarea;
|
||||||
|
TAILQ_INSERT_HEAD(&(dockarea->focus_head), con, focused);
|
||||||
|
TAILQ_INSERT_HEAD(&(dockarea->nodes_head), con, nodes);
|
||||||
|
|
||||||
|
tree_render();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Returns false if the event could not be processed (e.g. the window could not
|
/* Returns false if the event could not be processed (e.g. the window could not
|
||||||
* be found), true otherwise */
|
* be found), true otherwise */
|
||||||
typedef bool (*cb_property_handler_t)(void *data, xcb_connection_t *c, uint8_t state, xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *property);
|
typedef bool (*cb_property_handler_t)(void *data, xcb_connection_t *c, uint8_t state, xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *property);
|
||||||
|
@ -1177,7 +1258,8 @@ static struct property_handler_t property_handlers[] = {
|
||||||
{0, UINT_MAX, handle_clientleader_change},
|
{0, UINT_MAX, handle_clientleader_change},
|
||||||
{0, UINT_MAX, handle_transient_for},
|
{0, UINT_MAX, handle_transient_for},
|
||||||
{0, 128, handle_windowrole_change},
|
{0, 128, handle_windowrole_change},
|
||||||
{0, 128, handle_class_change}};
|
{0, 128, handle_class_change},
|
||||||
|
{0, UINT_MAX, handle_strut_partial_change}};
|
||||||
#define NUM_HANDLERS (sizeof(property_handlers) / sizeof(struct property_handler_t))
|
#define NUM_HANDLERS (sizeof(property_handlers) / sizeof(struct property_handler_t))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1196,6 +1278,7 @@ void property_handlers_init(void) {
|
||||||
property_handlers[5].atom = XCB_ATOM_WM_TRANSIENT_FOR;
|
property_handlers[5].atom = XCB_ATOM_WM_TRANSIENT_FOR;
|
||||||
property_handlers[6].atom = A_WM_WINDOW_ROLE;
|
property_handlers[6].atom = A_WM_WINDOW_ROLE;
|
||||||
property_handlers[7].atom = XCB_ATOM_WM_CLASS;
|
property_handlers[7].atom = XCB_ATOM_WM_CLASS;
|
||||||
|
property_handlers[8].atom = A__NET_WM_STRUT_PARTIAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void property_notify(uint8_t state, xcb_window_t window, xcb_atom_t atom) {
|
static void property_notify(uint8_t state, xcb_window_t window, xcb_atom_t atom) {
|
||||||
|
|
|
@ -143,6 +143,22 @@ wait_for_map $window;
|
||||||
@docked = get_dock_clients('top');
|
@docked = get_dock_clients('top');
|
||||||
is(@docked, 1, 'dock client on top');
|
is(@docked, 1, 'dock client on top');
|
||||||
|
|
||||||
|
# now change strut_partial to reserve space on the bottom and the dock should
|
||||||
|
# be moved to the bottom dock area
|
||||||
|
$x->change_property(
|
||||||
|
PROP_MODE_REPLACE,
|
||||||
|
$window->id,
|
||||||
|
$atomname->id,
|
||||||
|
$atomtype->id,
|
||||||
|
32, # 32 bit integer
|
||||||
|
12,
|
||||||
|
pack('L12', 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 1280, 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
sync_with_i3;
|
||||||
|
@docked = get_dock_clients('bottom');
|
||||||
|
is(@docked, 1, 'dock client on bottom');
|
||||||
|
|
||||||
$window->destroy;
|
$window->destroy;
|
||||||
|
|
||||||
wait_for_unmap $window;
|
wait_for_unmap $window;
|
||||||
|
|
Loading…
Reference in New Issue