]> git.sur5r.net Git - i3/i3/blobdiff - src/con.c
Merge pull request #1805 from lasers/next
[i3/i3] / src / con.c
index 266b4d33b222e598a3be8569eabe2c84a5c7bcbf..08c720015bd40b3099dc55fb55148fb4e7089214 100644 (file)
--- a/src/con.c
+++ b/src/con.c
@@ -4,7 +4,7 @@
  * vim:ts=4:sw=4:expandtab
  *
  * i3 - an improved dynamic tiling window manager
- * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE)
+ * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
  *
  * con.c: Functions which deal with containers directly (creating containers,
  *        searching containers, getting specific properties from containers,
@@ -70,20 +70,10 @@ Con *con_new(Con *parent, i3Window *window) {
     return new;
 }
 
-/*
- * Attaches the given container to the given parent. This happens when moving
- * a container or when inserting a new container at a specific place in the
- * tree.
- *
- * ignore_focus is to just insert the Con at the end (useful when creating a
- * new split container *around* some containers, that is, detaching and
- * attaching them in order without wanting to mess with the focus in between).
- *
- */
-void con_attach(Con *con, Con *parent, bool ignore_focus) {
+static void _con_attach(Con *con, Con *parent, Con *previous, bool ignore_focus) {
     con->parent = parent;
     Con *loop;
-    Con *current = NULL;
+    Con *current = previous;
     struct nodes_head *nodes_head = &(parent->nodes_head);
     struct focus_head *focus_head = &(parent->focus_head);
 
@@ -155,8 +145,7 @@ void con_attach(Con *con, Con *parent, bool ignore_focus) {
         /* 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);
+            DLOG("Inserting con = %p after con %p\n", con, current);
             TAILQ_INSERT_AFTER(nodes_head, current, con, nodes);
         } else
             TAILQ_INSERT_TAIL(nodes_head, con, nodes);
@@ -170,6 +159,20 @@ add_to_focus_head:
     con_force_split_parents_redraw(con);
 }
 
+/*
+ * Attaches the given container to the given parent. This happens when moving
+ * a container or when inserting a new container at a specific place in the
+ * tree.
+ *
+ * ignore_focus is to just insert the Con at the end (useful when creating a
+ * new split container *around* some containers, that is, detaching and
+ * attaching them in order without wanting to mess with the focus in between).
+ *
+ */
+void con_attach(Con *con, Con *parent, bool ignore_focus) {
+    _con_attach(con, parent, NULL, ignore_focus);
+}
+
 /*
  * Detaches the given container from its current parent
  *
@@ -257,6 +260,29 @@ bool con_is_split(Con *con) {
     }
 }
 
+/*
+ * This will only return true for containers which have some parent with
+ * a tabbed / stacked parent of which they are not the currently focused child.
+ *
+ */
+bool con_is_hidden(Con *con) {
+    Con *current = con;
+
+    /* ascend to the workspace level and memorize the highest-up container
+     * which is stacked or tabbed. */
+    while (current != NULL && current->type != CT_WORKSPACE) {
+        Con *parent = current->parent;
+        if (parent != NULL && (parent->layout == L_TABBED || parent->layout == L_STACKED)) {
+            if (TAILQ_FIRST(&(parent->focus_head)) != current)
+                return true;
+        }
+
+        current = parent;
+    }
+
+    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).
@@ -697,16 +723,18 @@ void con_disable_fullscreen(Con *con) {
     con_set_fullscreen_mode(con, CF_NONE);
 }
 
-static bool _con_move_to_con(Con *con, Con *target, bool fix_coordinates, bool dont_warp) {
+static bool _con_move_to_con(Con *con, Con *target, bool behind_focused, bool fix_coordinates, bool dont_warp) {
+    Con *orig_target = target;
+
     /* Prevent moving if this would violate the fullscreen focus restrictions. */
     Con *target_ws = con_get_workspace(target);
     if (!con_fullscreen_permits_focusing(target_ws)) {
-        LOG("Cannot move out of a fullscreen container");
+        LOG("Cannot move out of a fullscreen container.\n");
         return false;
     }
 
     if (con_is_floating(con)) {
-        DLOG("Using FLOATINGCON instead\n");
+        DLOG("Container is floating, using parent instead.\n");
         con = con->parent;
     }
 
@@ -801,7 +829,7 @@ static bool _con_move_to_con(Con *con, Con *target, bool fix_coordinates, bool d
     /* 4: re-attach the con to the parent of this focused container */
     Con *parent = con->parent;
     con_detach(con);
-    con_attach(con, target, false);
+    _con_attach(con, target, behind_focused ? NULL : orig_target, !behind_focused);
 
     /* 5: fix the percentages */
     con_fix_percent(parent);
@@ -882,6 +910,40 @@ static bool _con_move_to_con(Con *con, Con *target, bool fix_coordinates, bool d
     return true;
 }
 
+/*
+ * Moves the given container to the given mark.
+ *
+ */
+bool con_move_to_mark(Con *con, const char *mark) {
+    Con *target = con_by_mark(mark);
+    if (target == NULL) {
+        DLOG("found no container with mark \"%s\"\n", mark);
+        return false;
+    }
+
+    /* For floating target containers, we just send the window to the same workspace. */
+    if (con_is_floating(target)) {
+        DLOG("target container is floating, moving container to target's workspace.\n");
+        con_move_to_workspace(con, con_get_workspace(target), true, false);
+        return true;
+    }
+
+    /* For split containers, we use the currently focused container within it.
+     * This allows setting marks on, e.g., tabbed containers which will move
+     * con to a new tab behind the focused tab. */
+    if (con_is_split(target)) {
+        DLOG("target is a split container, descending to the currently focused child.\n");
+        target = TAILQ_FIRST(&(target->focus_head));
+    }
+
+    if (con == target) {
+        DLOG("cannot move the container to itself, aborting.\n");
+        return false;
+    }
+
+    return _con_move_to_con(con, target, false, true, false);
+}
+
 /*
  * Moves the given container to the currently focused container on the given
  * workspace.
@@ -900,6 +962,8 @@ static bool _con_move_to_con(Con *con, Con *target, bool fix_coordinates, bool d
  *
  */
 void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool dont_warp) {
+    assert(workspace->type == CT_WORKSPACE);
+
     Con *source_ws = con_get_workspace(con);
     if (workspace == source_ws) {
         DLOG("Not moving, already there\n");
@@ -907,7 +971,7 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool
     }
 
     Con *target = con_descend_focused(workspace);
-    _con_move_to_con(con, target, fix_coordinates, dont_warp);
+    _con_move_to_con(con, target, true, fix_coordinates, dont_warp);
 }
 
 /*