Implement support for top/bottom dock clients (according to _NET_WM_STRUT_PARTIAL or requested position)

This commit is contained in:
Michael Stapelberg 2011-02-21 14:27:32 +01:00
parent 0f97b1fef6
commit ffc71859a3
7 changed files with 113 additions and 19 deletions

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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)) {

View File

@ -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;
} }

View File

@ -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 */

View File

@ -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] };
}