]> git.sur5r.net Git - i3/i3/blobdiff - src/tree.c
Merge branch 'master' into next
[i3/i3] / src / tree.c
index 7a5fb9f010081c7a24f28fbac1673b0471a4583b..836183ec114439aa2b5c6cac9092abd3b095dd4d 100644 (file)
@@ -200,6 +200,13 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool
         was_mapped = _is_con_mapped(con);
     }
 
+    /* remove the urgency hint of the workspace (if set) */
+    if (con->urgent) {
+        con->urgent = false;
+        con_update_parents_urgency(con);
+        workspace_update_urgent_flag(con_get_workspace(con));
+    }
+
     /* Get the container which is next focused */
     Con *next = con_next_focused(con);
     DLOG("next = %p, focused = %p\n", next, focused);
@@ -228,7 +235,12 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool
             return false;
         } else {
             xcb_void_cookie_t cookie;
-            /* un-parent the window */
+            /* Ignore any further events by clearing the event mask,
+             * unmap the window,
+             * then reparent it to the root window. */
+            xcb_change_window_attributes(conn, con->window->id,
+                    XCB_CW_EVENT_MASK, (uint32_t[]){ XCB_NONE });
+            xcb_unmap_window(conn, con->window->id);
             cookie = xcb_reparent_window(conn, con->window->id, root, 0, 0);
 
             /* Ignore X11 errors for the ReparentWindow request.
@@ -251,15 +263,28 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool
         free(con->window);
     }
 
-    /* kill the X11 part of this container */
-    x_con_kill(con);
+    Con *ws = con_get_workspace(con);
+
+    /* Figure out which container to focus next before detaching 'con'. */
+    if (con_is_floating(con)) {
+        if (con == focused) {
+            DLOG("This is the focused container, i need to find another one to focus. I start looking at ws = %p\n", ws);
+            next = con_next_focused(parent);
+
+            dont_kill_parent = true;
+            DLOG("Alright, focusing %p\n", next);
+        } else {
+            next = NULL;
+        }
+    }
 
+    /* Detach the container so that it will not be rendered anymore. */
     con_detach(con);
 
     /* disable urgency timer, if needed */
     if (con->urgency_timer != NULL) {
         DLOG("Removing urgency timer of con %p\n", con);
-        workspace_update_urgent_flag(con_get_workspace(con));
+        workspace_update_urgent_flag(ws);
         ev_timer_stop(main_loop, con->urgency_timer);
         FREE(con->urgency_timer);
     }
@@ -270,21 +295,24 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool
         con_fix_percent(parent);
     }
 
+    /* Render the tree so that the surrounding containers take up the space
+     * which 'con' does no longer occupy. If we don’t render here, there will
+     * be a gap in our containers and that could trigger an EnterNotify for an
+     * underlying container, see ticket #660.
+     *
+     * Rendering has to be avoided when dont_kill_parent is set (when
+     * tree_close calls itself recursively) because the tree is in a
+     * non-renderable state during that time. */
+    if (!dont_kill_parent)
+        tree_render();
+
+    /* kill the X11 part of this container */
+    x_con_kill(con);
+
     if (con_is_floating(con)) {
-        Con *ws = con_get_workspace(con);
         DLOG("Container was floating, killing floating container\n");
         tree_close(parent, DONT_KILL_WINDOW, false, (con == focused));
         DLOG("parent container killed\n");
-        if (con == focused) {
-            DLOG("This is the focused container, i need to find another one to focus. I start looking at ws = %p\n", ws);
-            /* go down the focus stack as far as possible */
-            next = con_descend_focused(ws);
-
-            dont_kill_parent = true;
-            DLOG("Alright, focusing %p\n", next);
-        } else {
-            next = NULL;
-        }
     }
 
     free(con->name);
@@ -331,15 +359,24 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool
  */
 void tree_close_con(kill_window_t kill_window) {
     assert(focused != NULL);
-    if (focused->type == CT_WORKSPACE) {
-        LOG("Cannot close workspace\n");
-        return;
-    }
 
     /* There *should* be no possibility to focus outputs / root container */
     assert(focused->type != CT_OUTPUT);
     assert(focused->type != CT_ROOT);
 
+    if (focused->type == CT_WORKSPACE) {
+        DLOG("Workspaces cannot be close, closing all children instead\n");
+        Con *child, *nextchild;
+        for (child = TAILQ_FIRST(&(focused->focus_head)); child; ) {
+            nextchild = TAILQ_NEXT(child, focused);
+            DLOG("killing child=%p\n", child);
+            tree_close(child, kill_window, false, false);
+            child = nextchild;
+        }
+
+        return;
+    }
+
     /* Kill con */
     tree_close(focused, kill_window, false, false);
 }
@@ -350,17 +387,23 @@ void tree_close_con(kill_window_t kill_window) {
  *
  */
 void tree_split(Con *con, orientation_t orientation) {
-    /* for a workspace, we just need to change orientation */
-    if (con->type == CT_WORKSPACE) {
-        DLOG("Workspace, simply changing orientation to %d\n", orientation);
-        con->layout = (orientation == HORIZ) ? L_SPLITH : L_SPLITV;
-        return;
-    }
-    else if (con->type == CT_FLOATING_CON) {
+    if (con->type == CT_FLOATING_CON) {
         DLOG("Floating containers can't be split.\n");
         return;
     }
 
+    if (con->type == CT_WORKSPACE) {
+        if (con_num_children(con) < 2) {
+            DLOG("Just changing orientation of workspace\n");
+            con->layout = (orientation == HORIZ) ? L_SPLITH : L_SPLITV;
+            return;
+        } else {
+            /* if there is more than one container on the workspace
+             * move them into a new container and handle this instead */
+            con = workspace_encapsulate(con);
+        }
+    }
+
     Con *parent = con->parent;
 
     /* Force re-rendering to make the indicator border visible. */
@@ -668,6 +711,8 @@ void tree_flatten(Con *con) {
      * the con’s parent to be redundant */
     if (!con_is_split(con) ||
         !con_is_split(child) ||
+        (con->layout != L_SPLITH && con->layout != L_SPLITV) ||
+        (child->layout != L_SPLITH && child->layout != L_SPLITV) ||
         con_orientation(con) == con_orientation(child) ||
         con_orientation(child) != con_orientation(parent))
         goto recurse;