From ffc71859a3b9ee54410dfdbe733aba8b01b4b46c Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 21 Feb 2011 14:27:32 +0100 Subject: [PATCH] Implement support for top/bottom dock clients (according to _NET_WM_STRUT_PARTIAL or requested position) --- include/data.h | 25 +++++++++++++++++++++++-- include/window.h | 6 ++++++ src/con.c | 5 +++-- src/manage.c | 41 ++++++++++++++++++++++++++++++----------- src/match.c | 7 ++++++- src/randr.c | 24 +++++++++++++++++++++++- src/window.c | 24 ++++++++++++++++++++++-- 7 files changed, 113 insertions(+), 19 deletions(-) diff --git a/include/data.h b/include/data.h index e8a796cc..71347364 100644 --- a/include/data.h +++ b/include/data.h @@ -75,6 +75,18 @@ struct Rect { uint32_t height; } __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. * @@ -242,7 +254,10 @@ struct Window { bool uses_net_wm_name; /** 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 { @@ -254,7 +269,13 @@ struct Match { char *class; char *instance; 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; Con *con_id; enum { M_ANY = 0, M_TILING, M_FLOATING } floating; diff --git a/include/window.h b/include/window.h index 6621a169..1c48c012 100644 --- a/include/window.h +++ b/include/window.h @@ -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); +/** + * 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 diff --git a/src/con.c b/src/con.c index 07fb0c65..da41f944 100644 --- a/src/con.c +++ b/src/con.c @@ -123,8 +123,9 @@ void con_attach(Con *con, Con *parent, bool ignore_focus) { } } - /* Insert the container after the tiling container, if found */ - if (current) { + /* Insert the container after the tiling container, if found. + * 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", con, current); TAILQ_INSERT_AFTER(nodes_head, current, con, nodes); diff --git a/src/manage.c b/src/manage.c index f41ab412..c602ee41 100644 --- a/src/manage.c +++ b/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_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_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); if (xcb_reply_contains_atom(reply, atoms[_NET_WM_WINDOW_TYPE_DOCK])) { - cwindow->dock = true; - LOG("this window is a dock\n"); + LOG("This window is of type 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); @@ -167,15 +195,6 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki /* TODO: two matches for one container */ /* 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); if (nc == NULL) { if (focused->type == CT_CON && con_accepts_window(focused)) { diff --git a/src/match.c b/src/match.c index 42eba26e..da58047e 100644 --- a/src/match.c +++ b/src/match.c @@ -67,7 +67,12 @@ bool match_matches_window(Match *match, i3Window *window) { } 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"); return true; } diff --git a/src/randr.c b/src/randr.c index 20e4f54e..d4dc770b 100644 --- a/src/randr.c +++ b/src/randr.c @@ -273,7 +273,7 @@ void output_init_con(Output *output) { /* this container swallows dock clients */ Match *match = scalloc(sizeof(Match)); match_init(match); - match->dock = true; + match->dock = M_DOCK_TOP; match->insert_where = M_BELOW; TAILQ_INSERT_TAIL(&(topdock->swallow_head), match, matches); @@ -285,6 +285,8 @@ void output_init_con(Output *output) { DLOG("attaching\n"); con_attach(topdock, con, false); + /* content container */ + DLOG("adding main content container\n"); Con *content = con_new(NULL); content->type = CT_CON; @@ -295,6 +297,26 @@ void output_init_con(Output *output) { FREE(name); 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"); /* add a workspace to this output */ diff --git a/src/window.c b/src/window.c index 82c881a4..11be7c6f 100644 --- a/src/window.c +++ b/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); } -/** +/* * 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; } -/** +/* * 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; } + +/* + * 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] }; +}