* 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,
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);
/* 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);
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
*
}
}
+/*
+ * 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).
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;
}
/* 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);
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.
*
*/
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");
}
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);
}
/*