Implement support for top/bottom dock clients (according to _NET_WM_STRUT_PARTIAL or requested position)
This commit is contained in:
parent
0f97b1fef6
commit
ffc71859a3
|
@ -75,6 +75,18 @@ struct Rect {
|
||||||
uint32_t height;
|
uint32_t height;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the reserved pixels on each screen edge read from a
|
||||||
|
* _NET_WM_STRUT_PARTIAL.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct reservedpx {
|
||||||
|
uint32_t left;
|
||||||
|
uint32_t right;
|
||||||
|
uint32_t top;
|
||||||
|
uint32_t bottom;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for the cache of colorpixels.
|
* Used for the cache of colorpixels.
|
||||||
*
|
*
|
||||||
|
@ -242,7 +254,10 @@ struct Window {
|
||||||
bool uses_net_wm_name;
|
bool uses_net_wm_name;
|
||||||
|
|
||||||
/** Whether the window says it is a dock window */
|
/** Whether the window says it is a dock window */
|
||||||
bool dock;
|
enum { W_NODOCK = 0, W_DOCK_TOP = 1, W_DOCK_BOTTOM = 2 } dock;
|
||||||
|
|
||||||
|
/** Pixels the window reserves. left/right/top/bottom */
|
||||||
|
struct reservedpx reserved;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Match {
|
struct Match {
|
||||||
|
@ -254,7 +269,13 @@ struct Match {
|
||||||
char *class;
|
char *class;
|
||||||
char *instance;
|
char *instance;
|
||||||
char *mark;
|
char *mark;
|
||||||
int dock;
|
enum {
|
||||||
|
M_DONTCHECK = -1,
|
||||||
|
M_NODOCK = 0,
|
||||||
|
M_DOCK_ANY = 1,
|
||||||
|
M_DOCK_TOP = 2,
|
||||||
|
M_DOCK_BOTTOM = 3
|
||||||
|
} dock;
|
||||||
xcb_window_t id;
|
xcb_window_t id;
|
||||||
Con *con_id;
|
Con *con_id;
|
||||||
enum { M_ANY = 0, M_TILING, M_FLOATING } floating;
|
enum { M_ANY = 0, M_TILING, M_FLOATING } floating;
|
||||||
|
|
|
@ -36,4 +36,10 @@ void window_update_leader(i3Window *win, xcb_get_property_reply_t *prop);
|
||||||
*/
|
*/
|
||||||
void window_update_transient_for(i3Window *win, xcb_get_property_reply_t *prop);
|
void window_update_transient_for(i3Window *win, xcb_get_property_reply_t *prop);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the _NET_WM_STRUT_PARTIAL (reserved pixels at the screen edges)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void window_update_strut_partial(i3Window *win, xcb_get_property_reply_t *prop);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -123,8 +123,9 @@ void con_attach(Con *con, Con *parent, bool ignore_focus) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert the container after the tiling container, if found */
|
/* Insert the container after the tiling container, if found.
|
||||||
if (current) {
|
* When adding to a CT_OUTPUT, just append one after another. */
|
||||||
|
if (current && parent->type != CT_OUTPUT) {
|
||||||
DLOG("Inserting con = %p after last focused tiling con %p\n",
|
DLOG("Inserting con = %p after last focused tiling con %p\n",
|
||||||
con, current);
|
con, current);
|
||||||
TAILQ_INSERT_AFTER(nodes_head, current, con, nodes);
|
TAILQ_INSERT_AFTER(nodes_head, current, con, nodes);
|
||||||
|
|
41
src/manage.c
41
src/manage.c
|
@ -151,11 +151,39 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
|
||||||
window_update_name(cwindow, xcb_get_property_reply(conn, utf8_title_cookie, NULL));
|
window_update_name(cwindow, xcb_get_property_reply(conn, utf8_title_cookie, NULL));
|
||||||
window_update_leader(cwindow, xcb_get_property_reply(conn, leader_cookie, NULL));
|
window_update_leader(cwindow, xcb_get_property_reply(conn, leader_cookie, NULL));
|
||||||
window_update_transient_for(cwindow, xcb_get_property_reply(conn, transient_cookie, NULL));
|
window_update_transient_for(cwindow, xcb_get_property_reply(conn, transient_cookie, NULL));
|
||||||
|
window_update_strut_partial(cwindow, xcb_get_property_reply(conn, strut_cookie, NULL));
|
||||||
|
|
||||||
|
/* Where to start searching for a container that swallows the new one? */
|
||||||
|
Con *search_at = croot;
|
||||||
|
|
||||||
xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, wm_type_cookie, NULL);
|
xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, wm_type_cookie, NULL);
|
||||||
if (xcb_reply_contains_atom(reply, atoms[_NET_WM_WINDOW_TYPE_DOCK])) {
|
if (xcb_reply_contains_atom(reply, atoms[_NET_WM_WINDOW_TYPE_DOCK])) {
|
||||||
cwindow->dock = true;
|
LOG("This window is of type dock\n");
|
||||||
LOG("this window is a dock\n");
|
Output *output = get_output_containing(geom->x, geom->y);
|
||||||
|
if (output != NULL) {
|
||||||
|
DLOG("Starting search at output %s\n", output->name);
|
||||||
|
search_at = output->con;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find out the desired position of this dock window */
|
||||||
|
if (cwindow->reserved.top > 0 && cwindow->reserved.bottom == 0) {
|
||||||
|
DLOG("Top dock client\n");
|
||||||
|
cwindow->dock = W_DOCK_TOP;
|
||||||
|
} else if (cwindow->reserved.top == 0 && cwindow->reserved.bottom > 0) {
|
||||||
|
DLOG("Bottom dock client\n");
|
||||||
|
cwindow->dock = W_DOCK_BOTTOM;
|
||||||
|
} else {
|
||||||
|
DLOG("Ignoring invalid reserved edges (_NET_WM_STRUT_PARTIAL), using position as fallback:\n");
|
||||||
|
if (geom->y < (search_at->rect.height / 2)) {
|
||||||
|
DLOG("geom->y = %d < rect.height / 2 = %d, it is a top dock client\n",
|
||||||
|
geom->y, (search_at->rect.height / 2));
|
||||||
|
cwindow->dock = W_DOCK_TOP;
|
||||||
|
} else {
|
||||||
|
DLOG("geom->y = %d >= rect.height / 2 = %d, it is a bottom dock client\n",
|
||||||
|
geom->y, (search_at->rect.height / 2));
|
||||||
|
cwindow->dock = W_DOCK_BOTTOM;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DLOG("Initial geometry: (%d, %d, %d, %d)\n", geom->x, geom->y, geom->width, geom->height);
|
DLOG("Initial geometry: (%d, %d, %d, %d)\n", geom->x, geom->y, geom->width, geom->height);
|
||||||
|
@ -167,15 +195,6 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
|
||||||
/* TODO: two matches for one container */
|
/* TODO: two matches for one container */
|
||||||
|
|
||||||
/* See if any container swallows this new window */
|
/* See if any container swallows this new window */
|
||||||
Con *search_at = croot;
|
|
||||||
if (cwindow->dock) {
|
|
||||||
/* for dock windows, we start the search at the appropriate output */
|
|
||||||
Output *output = get_output_containing(geom->x, geom->y);
|
|
||||||
if (output != NULL) {
|
|
||||||
DLOG("Starting search at output %s\n", output->name);
|
|
||||||
search_at = output->con;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nc = con_for_window(search_at, cwindow, &match);
|
nc = con_for_window(search_at, cwindow, &match);
|
||||||
if (nc == NULL) {
|
if (nc == NULL) {
|
||||||
if (focused->type == CT_CON && con_accepts_window(focused)) {
|
if (focused->type == CT_CON && con_accepts_window(focused)) {
|
||||||
|
|
|
@ -67,7 +67,12 @@ bool match_matches_window(Match *match, i3Window *window) {
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("match->dock = %d, window->dock = %d\n", match->dock, window->dock);
|
LOG("match->dock = %d, window->dock = %d\n", match->dock, window->dock);
|
||||||
if (match->dock != -1 && window->dock == match->dock) {
|
if (match->dock != -1 &&
|
||||||
|
((window->dock == W_DOCK_TOP && match->dock == M_DOCK_TOP) ||
|
||||||
|
(window->dock == W_DOCK_BOTTOM && match->dock == M_DOCK_BOTTOM) ||
|
||||||
|
((window->dock == W_DOCK_TOP || window->dock == W_DOCK_BOTTOM) &&
|
||||||
|
match->dock == M_DOCK_ANY) ||
|
||||||
|
(window->dock == W_NODOCK && match->dock == M_NODOCK))) {
|
||||||
LOG("match made by dock\n");
|
LOG("match made by dock\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
24
src/randr.c
24
src/randr.c
|
@ -273,7 +273,7 @@ void output_init_con(Output *output) {
|
||||||
/* this container swallows dock clients */
|
/* this container swallows dock clients */
|
||||||
Match *match = scalloc(sizeof(Match));
|
Match *match = scalloc(sizeof(Match));
|
||||||
match_init(match);
|
match_init(match);
|
||||||
match->dock = true;
|
match->dock = M_DOCK_TOP;
|
||||||
match->insert_where = M_BELOW;
|
match->insert_where = M_BELOW;
|
||||||
TAILQ_INSERT_TAIL(&(topdock->swallow_head), match, matches);
|
TAILQ_INSERT_TAIL(&(topdock->swallow_head), match, matches);
|
||||||
|
|
||||||
|
@ -285,6 +285,8 @@ void output_init_con(Output *output) {
|
||||||
DLOG("attaching\n");
|
DLOG("attaching\n");
|
||||||
con_attach(topdock, con, false);
|
con_attach(topdock, con, false);
|
||||||
|
|
||||||
|
/* content container */
|
||||||
|
|
||||||
DLOG("adding main content container\n");
|
DLOG("adding main content container\n");
|
||||||
Con *content = con_new(NULL);
|
Con *content = con_new(NULL);
|
||||||
content->type = CT_CON;
|
content->type = CT_CON;
|
||||||
|
@ -295,6 +297,26 @@ void output_init_con(Output *output) {
|
||||||
FREE(name);
|
FREE(name);
|
||||||
con_attach(content, con, false);
|
con_attach(content, con, false);
|
||||||
|
|
||||||
|
/* bottom dock container */
|
||||||
|
Con *bottomdock = con_new(NULL);
|
||||||
|
bottomdock->type = CT_DOCKAREA;
|
||||||
|
bottomdock->layout = L_DOCKAREA;
|
||||||
|
bottomdock->orientation = VERT;
|
||||||
|
/* this container swallows dock clients */
|
||||||
|
match = scalloc(sizeof(Match));
|
||||||
|
match_init(match);
|
||||||
|
match->dock = M_DOCK_BOTTOM;
|
||||||
|
match->insert_where = M_BELOW;
|
||||||
|
TAILQ_INSERT_TAIL(&(bottomdock->swallow_head), match, matches);
|
||||||
|
|
||||||
|
bottomdock->name = sstrdup("bottomdock");
|
||||||
|
|
||||||
|
asprintf(&name, "[i3 con] bottom dockarea %s", con->name);
|
||||||
|
x_set_name(bottomdock, name);
|
||||||
|
FREE(name);
|
||||||
|
DLOG("attaching\n");
|
||||||
|
con_attach(bottomdock, con, false);
|
||||||
|
|
||||||
DLOG("Now adding a workspace\n");
|
DLOG("Now adding a workspace\n");
|
||||||
|
|
||||||
/* add a workspace to this output */
|
/* add a workspace to this output */
|
||||||
|
|
24
src/window.c
24
src/window.c
|
@ -106,7 +106,7 @@ void window_update_name_legacy(i3Window *win, xcb_get_property_reply_t *prop) {
|
||||||
win->name_len = strlen(new_name);
|
win->name_len = strlen(new_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Updates the CLIENT_LEADER (logical parent window).
|
* Updates the CLIENT_LEADER (logical parent window).
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -125,7 +125,7 @@ void window_update_leader(i3Window *win, xcb_get_property_reply_t *prop) {
|
||||||
win->leader = *leader;
|
win->leader = *leader;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Updates the TRANSIENT_FOR (logical parent window).
|
* Updates the TRANSIENT_FOR (logical parent window).
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -143,3 +143,23 @@ void window_update_transient_for(i3Window *win, xcb_get_property_reply_t *prop)
|
||||||
|
|
||||||
win->transient_for = transient_for;
|
win->transient_for = transient_for;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Updates the _NET_WM_STRUT_PARTIAL (reserved pixels at the screen edges)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void window_update_strut_partial(i3Window *win, xcb_get_property_reply_t *prop) {
|
||||||
|
if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
|
||||||
|
DLOG("prop == NULL\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t *strut;
|
||||||
|
if (!(strut = xcb_get_property_value(prop)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
DLOG("Reserved pixels changed to: left = %d, right = %d, top = %d, bottom = %d\n",
|
||||||
|
strut[0], strut[1], strut[2], strut[3]);
|
||||||
|
|
||||||
|
win->reserved = (struct reservedpx){ strut[0], strut[1], strut[2], strut[3] };
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue