]> git.sur5r.net Git - i3/i3/commitdiff
Implement support for top/bottom dock clients (according to _NET_WM_STRUT_PARTIAL...
authorMichael Stapelberg <michael@stapelberg.de>
Mon, 21 Feb 2011 13:27:32 +0000 (14:27 +0100)
committerMichael Stapelberg <michael@stapelberg.de>
Mon, 21 Feb 2011 13:27:32 +0000 (14:27 +0100)
include/data.h
include/window.h
src/con.c
src/manage.c
src/match.c
src/randr.c
src/window.c

index e8a796cc947a06ad2eea18a52500b26e335a01bc..71347364972b86a602aa30566698d0c846dc3110 100644 (file)
@@ -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;
index 6621a16969ce5776cdb67f69d3c4c64d84d07e8d..1c48c012e0c0626187bffdd31fd6320fa12828e5 100644 (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);
 
+/**
+ * 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
index 07fb0c65e9bd1bd1d5788649c2be00f7b692370e..da41f944bc342c80fb8436d6ce3d5e26447ef2e3 100644 (file)
--- 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);
index f41ab41286ec183f6f2ffd38ef3b0a75191b366d..c602ee4108b9b9a896bc043346715cdf46c632e5 100644 (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_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)) {
index 42eba26ea9ffda46a054365f1979f10f27829821..da58047e0c419d088d7a3a3ecbaa8ee00c790ad3 100644 (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);
-    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;
     }
index 20e4f54e89b86447ff65979b676c2c677ca79ea7..d4dc770bf097b07fd8b92bb22bcb52924fdba857 100644 (file)
@@ -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 */
index 82c881a405aad1ebbd609ac24664a5ba5b29ac84..11be7c6f01b5b76cbc9bd379a7852bd53e980ff4 100644 (file)
@@ -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] };
+}