]> git.sur5r.net Git - i3/i3/blobdiff - src/con.c
generate-command-parser: make input/output configurable
[i3/i3] / src / con.c
index 0539c7ab6be526dfbbad725e38009dc9497b5060..493707d61cf38343c32ff9a365f4d03542203f1f 100644 (file)
--- a/src/con.c
+++ b/src/con.c
@@ -36,7 +36,7 @@ static void con_force_split_parents_redraw(Con *con) {
     Con *parent = con;
 
     while (parent && parent->type != CT_WORKSPACE && parent->type != CT_DOCKAREA) {
-        if (parent->split)
+        if (!con_is_leaf(parent))
             FREE(parent->deco_render_params);
         parent = parent->parent;
     }
@@ -232,6 +232,24 @@ bool con_is_leaf(Con *con) {
     return TAILQ_EMPTY(&(con->nodes_head));
 }
 
+/*
+ * Returns true if a container should be considered split.
+ *
+ */
+bool con_is_split(Con *con) {
+    if (con_is_leaf(con))
+        return false;
+
+    switch (con->layout) {
+        case L_DOCKAREA:
+        case L_OUTPUT:
+            return false;
+
+        default:
+            return true;
+    }
+}
+
 /*
  * Returns true if this node accepts a window (if the node swallows windows,
  * it might already have swallowed enough and cannot hold any more).
@@ -242,7 +260,7 @@ bool con_accepts_window(Con *con) {
     if (con->type == CT_WORKSPACE)
         return false;
 
-    if (con->split) {
+    if (con_is_split(con)) {
         DLOG("container %p does not accept windows, it is a split container.\n", con);
         return false;
     }
@@ -607,11 +625,6 @@ void con_toggle_fullscreen(Con *con, int fullscreen_mode) {
  *
  */
 void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool dont_warp) {
-    if (con->type == CT_WORKSPACE) {
-        DLOG("Moving workspaces is not yet implemented.\n");
-        return;
-    }
-
     /* Prevent moving if this would violate the fullscreen focus restrictions. */
     if (!con_fullscreen_permits_focusing(workspace)) {
         LOG("Cannot move out of a fullscreen container");
@@ -629,6 +642,21 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool
         return;
     }
 
+    if (con->type == CT_WORKSPACE) {
+        con = workspace_encapsulate(con);
+        if (con == NULL) {
+            ELOG("Workspace failed to move its contents into a container!\n");
+            return;
+        }
+
+        /* Re-parent all of the old workspace's floating windows. */
+        Con *child;
+        while (!TAILQ_EMPTY(&(source_ws->floating_head))) {
+            child = TAILQ_FIRST(&(source_ws->floating_head));
+            con_move_to_workspace(child, workspace, true, true);
+        }
+    }
+
     /* Save the current workspace. So we can call workspace_show() by the end
      * of this function. */
     Con *current_ws = con_get_workspace(focused);
@@ -686,6 +714,14 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool
         }
     }
 
+    /* If moving a fullscreen container and the destination already has a
+     * fullscreen window on it, un-fullscreen the target's fullscreen con. */
+    Con *fullscreen = con_get_fullscreen_con(workspace, CF_OUTPUT);
+    if (con->fullscreen_mode != CF_NONE && fullscreen != NULL) {
+        con_toggle_fullscreen(fullscreen, CF_OUTPUT);
+        fullscreen = NULL;
+    }
+
     DLOG("Re-attaching container to %p / %s\n", next, next->name);
     /* 5: re-attach the con to the parent of this focused container */
     Con *parent = con->parent;
@@ -697,14 +733,23 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool
     con->percent = 0.0;
     con_fix_percent(next);
 
-    /* 7: focus the con on the target workspace (the X focus is only updated by
-     * calling tree_render(), so for the "real" focus this is a no-op).
+    /* 7: focus the con on the target workspace, but only within that
+     * workspace, that is, don’t move focus away if the target workspace is
+     * invisible.
      * We don’t focus the con for i3 pseudo workspaces like __i3_scratch and
      * we don’t focus when there is a fullscreen con on that workspace. */
-    if (!con_is_internal(workspace) &&
-        con_get_fullscreen_con(workspace, CF_OUTPUT) == NULL)
+    if (!con_is_internal(workspace) && !fullscreen) {
+        /* We need to save the focused workspace on the output in case the
+         * new workspace is hidden and it's necessary to immediately switch
+         * back to the originally-focused workspace. */
+        Con *old_focus = TAILQ_FIRST(&(output_get_content(dest_output)->focus_head));
         con_focus(con_descend_focused(con));
 
+        /* Restore focus if the output's focused workspace has changed. */
+        if (con_get_workspace(focused) != old_focus)
+            con_focus(old_focus);
+    }
+
     /* 8: when moving to a visible workspace on a different output, we keep the
      * con focused. Otherwise, we leave the focus on the current workspace as we
      * don’t want to focus invisible workspaces */
@@ -724,6 +769,38 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool
             con_focus(con_descend_focused(focus_next));
     }
 
+    /* If anything within the container is associated with a startup sequence,
+     * delete it so child windows won't be created on the old workspace. */
+    struct Startup_Sequence *sequence;
+    xcb_get_property_cookie_t cookie;
+    xcb_get_property_reply_t *startup_id_reply;
+
+    if (!con_is_leaf(con)) {
+        Con *child;
+        TAILQ_FOREACH(child, &(con->nodes_head), nodes) {
+            if (!child->window)
+                continue;
+
+            cookie = xcb_get_property(conn, false, child->window->id,
+                A__NET_STARTUP_ID, XCB_GET_PROPERTY_TYPE_ANY, 0, 512);
+            startup_id_reply = xcb_get_property_reply(conn, cookie, NULL);
+
+            sequence = startup_sequence_get(child->window, startup_id_reply, true);
+            if (sequence != NULL)
+                startup_sequence_delete(sequence);
+        }
+    }
+
+    if (con->window) {
+        cookie = xcb_get_property(conn, false, con->window->id,
+            A__NET_STARTUP_ID, XCB_GET_PROPERTY_TYPE_ANY, 0, 512);
+        startup_id_reply = xcb_get_property_reply(conn, cookie, NULL);
+
+        sequence = startup_sequence_get(con->window, startup_id_reply, true);
+        if (sequence != NULL)
+            startup_sequence_delete(sequence);
+    }
+
     CALL(parent, on_remove_child);
 }
 
@@ -1136,7 +1213,6 @@ void con_set_layout(Con *con, int layout) {
              * split. */
             new->layout = layout;
             new->last_split_layout = con->last_split_layout;
-            new->split = true;
 
             Con *old_focused = TAILQ_FIRST(&(con->focus_head));
             if (old_focused == TAILQ_END(&(con->focus_head)))
@@ -1309,7 +1385,7 @@ Rect con_minimum_size(Con *con) {
     /* For horizontal/vertical split containers we sum up the width (h-split)
      * or height (v-split) and use the maximum of the height (h-split) or width
      * (v-split) as minimum size. */
-    if (con->split) {
+    if (con_is_split(con)) {
         uint32_t width = 0, height = 0;
         Con *child;
         TAILQ_FOREACH(child, &(con->nodes_head), nodes) {
@@ -1327,7 +1403,7 @@ Rect con_minimum_size(Con *con) {
     }
 
     ELOG("Unhandled case, type = %d, layout = %d, split = %d\n",
-         con->type, con->layout, con->split);
+         con->type, con->layout, con_is_split(con));
     assert(false);
 }