]> git.sur5r.net Git - i3/i3/commitdiff
Handle _NET_WM_STATE_STICKY, but only for floating containers. If this atom is set...
authorIngo Bürk <ingo.buerk@tngtech.com>
Sun, 23 Aug 2015 11:36:12 +0000 (13:36 +0200)
committerIngo Bürk <ingo.buerk@tngtech.com>
Sun, 13 Sep 2015 18:40:20 +0000 (20:40 +0200)
We will respect this atom upon managing a window as well as when we receive a request that changes the sticky state.

fixes #1455

include/atoms.xmacro
include/con.h
include/data.h
src/con.c
src/ewmh.c
src/handlers.c
src/ipc.c
src/load_layout.c
src/manage.c
src/workspace.c
testcases/t/116-nestedcons.t

index 80e3bbf09a96dee763dc1bf34cc35ffd907eb291..f856559cf9367533c2271713ef02af7e2ece527e 100644 (file)
@@ -3,6 +3,7 @@ xmacro(_NET_SUPPORTING_WM_CHECK)
 xmacro(_NET_WM_NAME)
 xmacro(_NET_WM_VISIBLE_NAME)
 xmacro(_NET_WM_MOVERESIZE)
+xmacro(_NET_WM_STATE_STICKY)
 xmacro(_NET_WM_STATE_FULLSCREEN)
 xmacro(_NET_WM_STATE_DEMANDS_ATTENTION)
 xmacro(_NET_WM_STATE_MODAL)
index 4813b77673a77c59a68034aff469f9b8db2ef45d..c0a3a46bee13d0c631c37736d0f8c6bd9ba108b3 100644 (file)
@@ -55,6 +55,12 @@ bool con_is_split(Con *con);
  */
 bool con_is_hidden(Con *con);
 
+/**
+ * Returns whether the container or any of its children is sticky.
+ *
+ */
+bool con_is_sticky(Con *con);
+
 /**
  * Returns true if this node has regular or floating children.
  *
index d75622ec6f4decec97c02609f7fbe2fa9c17eb1d..58e4a00d8a01fc904c70e6cbdcf7a097aada5047 100644 (file)
@@ -603,6 +603,12 @@ struct Con {
     TAILQ_HEAD(swallow_head, Match) swallow_head;
 
     fullscreen_mode_t fullscreen_mode;
+
+    /* Whether this window should stick to the glass. This corresponds to
+     * the _NET_WM_STATE_STICKY atom and will only be respected if the
+     * window is floating. */
+    bool sticky;
+
     /* layout is the layout of this container: one of split[v|h], stacked or
      * tabbed. Special containers in the tree (above workspaces) have special
      * layouts like dockarea or output.
index 9a5d36c13c4e32bd9aa858f73171ba724b172cd0..24d563a59c90620d1342403de0b0ddbdbf114f9c 100644 (file)
--- a/src/con.c
+++ b/src/con.c
@@ -284,6 +284,23 @@ bool con_is_hidden(Con *con) {
     return false;
 }
 
+/*
+ * Returns whether the container or any of its children is sticky.
+ *
+ */
+bool con_is_sticky(Con *con) {
+    if (con->sticky)
+        return true;
+
+    Con *child;
+    TAILQ_FOREACH(child, &(con->nodes_head), nodes) {
+        if (con_is_sticky(child))
+            return true;
+    }
+
+    return false;
+}
+
 /*
  * Returns true if this node accepts a window (if the node swallows windows,
  * it might already have swallowed enough and cannot hold any more).
index d60bbb50ad3f24da648494d515a85dae0fb00be6..36c6a16080d263569bda9b4daa4c99625a870bea 100644 (file)
@@ -250,7 +250,7 @@ void ewmh_setup_hints(void) {
     xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_WM_NAME, A_UTF8_STRING, 8, strlen("i3"), "i3");
 
     /* only send the first 31 atoms (last one is _NET_CLOSE_WINDOW) increment that number when adding supported atoms */
-    xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, /* number of atoms */ 31, supported_atoms);
+    xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, /* number of atoms */ 32, supported_atoms);
 
     /* We need to map this window to be able to set the input focus to it if no other window is available to be focused. */
     xcb_map_window(conn, ewmh_window);
index f3c2350e5c75e2961ceb3a88b27dbc309e50d409..4b01cb5ec68c3b7fb61de29306b5e54dc3d6c6d2 100644 (file)
@@ -695,7 +695,8 @@ static void handle_client_message(xcb_client_message_event_t *event) {
     if (event->type == A__NET_WM_STATE) {
         if (event->format != 32 ||
             (event->data.data32[1] != A__NET_WM_STATE_FULLSCREEN &&
-             event->data.data32[1] != A__NET_WM_STATE_DEMANDS_ATTENTION)) {
+             event->data.data32[1] != A__NET_WM_STATE_DEMANDS_ATTENTION &&
+             event->data.data32[1] != A__NET_WM_STATE_STICKY)) {
             DLOG("Unknown atom in clientmessage of type %d\n", event->data.data32[1]);
             return;
         }
@@ -725,6 +726,16 @@ static void handle_client_message(xcb_client_message_event_t *event) {
                 con_set_urgency(con, false);
             else if (event->data.data32[0] == _NET_WM_STATE_TOGGLE)
                 con_set_urgency(con, !con->urgent);
+        } else if (event->data.data32[1] == A__NET_WM_STATE_STICKY) {
+            DLOG("Received a client message to modify _NET_WM_STATE_STICKY.\n");
+            if (event->data.data32[0] == _NET_WM_STATE_ADD)
+                con->sticky = true;
+            else if (event->data.data32[0] == _NET_WM_STATE_REMOVE)
+                con->sticky = false;
+            else if (event->data.data32[0] == _NET_WM_STATE_TOGGLE)
+                con->sticky = !con->sticky;
+
+            DLOG("New sticky status for con = %p is %i.\n", con, con->sticky);
         }
 
         tree_render();
index ad7ef1cb14d8dadede9e40927b8924eb8adba53b..1a8d28ed218189c073be4c40e9113cf8a56d9414 100644 (file)
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -436,6 +436,9 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
     ystr("fullscreen_mode");
     y(integer, con->fullscreen_mode);
 
+    ystr("sticky");
+    y(bool, con->sticky);
+
     ystr("floating");
     switch (con->floating) {
         case FLOATING_AUTO_OFF:
index 5a139bf223d6cca2853cbe414dc2b281718e985f..e0dc4fa01c7dda210bd8e50e6a0cd1f95b725101 100644 (file)
@@ -435,6 +435,9 @@ static int json_bool(void *ctx, int val) {
         to_focus = json_node;
     }
 
+    if (strcasecmp(last_key, "sticky") == 0)
+        json_node->sticky = val;
+
     if (parsing_swallows) {
         if (strcasecmp(last_key, "restart_mode") == 0)
             current_swallow->restart_mode = val;
index 08e11b57fc73d2bf244806e8ef409a29249b56ef..e3769670fd0644684d3412cd8af2a3679f0f7f52 100644 (file)
@@ -384,6 +384,9 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
         want_floating = true;
     }
 
+    if (xcb_reply_contains_atom(state_reply, A__NET_WM_STATE_STICKY))
+        nc->sticky = true;
+
     FREE(state_reply);
     FREE(type_reply);
 
index 70022151117c7392f1de4bff97ee8e776322e79e..2b2c3cbf0c83c5f1422e52222457f5bc4c7b8841 100644 (file)
@@ -450,6 +450,45 @@ static void _workspace_show(Con *workspace) {
 
     /* Update the EWMH hints */
     ewmh_update_current_desktop();
+
+    /* Floating containers which are sticky need to be moved to the new workspace,
+     * but only on the same output. */
+    if (current != NULL && old_output == new_output) {
+        Con *prev = focused;
+        Con *child;
+
+        /* We can't simply iterate over the floating containers since moving a
+         * sticky container to the target workspace will modify that list.
+         * Instead, we first count the number of sticky containers, then memorize
+         * all of them and finally loop over that list to move them to the new
+         * workspace. */
+        int num_sticky = 0;
+        TAILQ_FOREACH(child, &(current->floating_head), floating_windows) {
+            if (con_is_sticky(child))
+                num_sticky++;
+        }
+
+        Con *sticky_cons[num_sticky];
+        int ctr = 0;
+        TAILQ_FOREACH(child, &(current->floating_head), floating_windows) {
+            if (con_is_sticky(child))
+                sticky_cons[ctr++] = child;
+        }
+
+        for (int i = 0; i < num_sticky; i++) {
+            con_move_to_workspace(sticky_cons[i], workspace, true, false);
+
+            /* We want sticky containers to be at the end of the focus head. */
+            TAILQ_REMOVE(&(workspace->focus_head), sticky_cons[i], focused);
+            TAILQ_INSERT_TAIL(&(workspace->focus_head), sticky_cons[i], focused);
+        }
+
+        /* Focus the correct container since moving the sticky containers
+         * changed the focus. However, if no container was focused before,
+         * we can leave the focus at the sticky container. */
+        if (prev != croot)
+            con_focus(prev);
+    }
 }
 
 /*
index d9ff1c39fbf53fe624424339697a460ad7229b93..5e3110adcad16ba649c8bfe3b284df91ff7ff809 100644 (file)
@@ -47,6 +47,7 @@ my $ignore = \"";
 
 my $expected = {
     fullscreen_mode => 0,
+    sticky => $ignore,
     nodes => $ignore,
     window => undef,
     name => 'root',