]> git.sur5r.net Git - i3/i3/blobdiff - src/workspace.c
Bring back some more EWMH support.
[i3/i3] / src / workspace.c
index b5095d118341080a1a646873fd62663d847bdb7c..77b5ceb2eca52b91276ecd13d3d0ce7214ef9f42 100644 (file)
  * memory and initializing the data structures correctly).
  *
  */
-Con *workspace_get(const char *num) {
-    Con *output, *workspace = NULL, *current;
+Con *workspace_get(const char *num, bool *created) {
+    Con *output, *workspace = NULL, *child;
 
     /* TODO: could that look like this in the future?
     GET_MATCHING_NODE(workspace, croot, strcasecmp(current->name, num) != 0);
     */
-    TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
-        TAILQ_FOREACH(current, &(output->nodes_head), nodes) {
-            if (strcasecmp(current->name, num) != 0)
+    TAILQ_FOREACH(output, &(croot->nodes_head), nodes)
+        TAILQ_FOREACH(child, &(output_get_content(output)->nodes_head), nodes) {
+            if (strcasecmp(child->name, num) != 0)
                 continue;
 
-            workspace = current;
+            workspace = child;
             break;
         }
-    }
 
     LOG("getting ws %s\n", num);
     if (workspace == NULL) {
         LOG("need to create this one\n");
         output = con_get_output(focused);
-        LOG("got output %p\n", output);
+        Con *content = output_get_content(output);
+        LOG("got output %p with content %p\n", output, content);
         /* We need to attach this container after setting its type. con_attach
          * will handle CT_WORKSPACEs differently */
         workspace = con_new(NULL);
@@ -60,12 +60,15 @@ Con *workspace_get(const char *num) {
         else workspace->num = parsed_num;
         LOG("num = %d\n", workspace->num);
         workspace->orientation = HORIZ;
-        con_attach(workspace, output, false);
+        con_attach(workspace, content, false);
 
         ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"init\"}");
+        if (created != NULL)
+            *created = true;
+    }
+    else if (created != NULL) {
+        *created = false;
     }
-
-    //ewmh_update_workarea();
 
     return workspace;
 }
@@ -199,33 +202,45 @@ static void workspace_reassign_sticky(Con *con) {
  *
  */
 void workspace_show(const char *num) {
-    Con *workspace, *current, *old;
+    Con *workspace, *current, *old = NULL;
+
+    bool changed_num_workspaces;
+    workspace = workspace_get(num, &changed_num_workspaces);
+
+    /* disable fullscreen for the other workspaces and get the workspace we are
+     * currently on. */
+    TAILQ_FOREACH(current, &(workspace->parent->nodes_head), nodes) {
+        if (current->fullscreen_mode == CF_OUTPUT)
+            old = current;
+        current->fullscreen_mode = CF_NONE;
+    }
+    assert(old != NULL);
 
-    old = con_get_workspace(focused);
+    /* Check if the the currently focused con is on the same Output as the
+     * workspace we chose as 'old'. If not, use the workspace of the currently
+     * focused con */
+    Con *ws = con_get_workspace(focused);
+    if (ws && ws->parent != old->parent)
+        old = ws;
 
-    workspace = workspace_get(num);
+    /* enable fullscreen for the target workspace. If it happens to be the
+     * same one we are currently on anyways, we can stop here. */
+    workspace->fullscreen_mode = CF_OUTPUT;
     if (workspace == old)
         return;
-    workspace->fullscreen_mode = CF_OUTPUT;
-    /* disable fullscreen */
-    TAILQ_FOREACH(current, &(workspace->parent->nodes_head), nodes)
-        current->fullscreen_mode = CF_NONE;
 
     workspace_reassign_sticky(workspace);
 
     LOG("switching to %p\n", workspace);
-    Con *next = workspace;
-
-    while (!TAILQ_EMPTY(&(next->focus_head)))
-        next = TAILQ_FIRST(&(next->focus_head));
-
+    Con *next = con_descend_focused(workspace);
 
-    if (TAILQ_EMPTY(&(old->nodes_head)) && TAILQ_EMPTY(&(old->floating_head))) {
+    if (old && TAILQ_EMPTY(&(old->nodes_head)) && TAILQ_EMPTY(&(old->floating_head))) {
         /* check if this workspace is currently visible */
         if (!workspace_is_visible(old)) {
             LOG("Closing old workspace (%p / %s), it is empty\n", old, old->name);
             tree_close(old, false, false);
             ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"empty\"}");
+            changed_num_workspaces = true;
         }
     }
 
@@ -233,6 +248,11 @@ void workspace_show(const char *num) {
     workspace->fullscreen_mode = CF_OUTPUT;
     LOG("focused now = %p / %s\n", focused, focused->name);
 
+    /* Update the EWMH hints */
+    if (changed_num_workspaces)
+        ewmh_update_workarea();
+    ewmh_update_current_desktop();
+
     ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"focus\"}");
 #if 0
 
@@ -444,7 +464,7 @@ Workspace *get_first_workspace_for_output(Output *output) {
                 int last_ws = 0;
                 TAILQ_FOREACH(ws, workspaces, workspaces)
                         last_ws = ws->num;
-                result = workspace_get(last_ws + 1);
+                result = workspace_get(last_ws + 1, NULL);
         }
 
         workspace_initialize(result, output, false);
@@ -479,3 +499,42 @@ void workspace_update_urgent_flag(Con *ws) {
     if (old_flag != ws->urgent)
         ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"urgent\"}");
 }
+
+/*
+ * 'Forces' workspace orientation by moving all cons into a new split-con with
+ * the same orientation as the workspace and then changing the workspace
+ * orientation.
+ *
+ */
+void ws_force_orientation(Con *ws, orientation_t orientation) {
+    /* 1: create a new split container */
+    Con *split = con_new(NULL);
+    split->parent = ws;
+
+    /* 2: copy layout and orientation from workspace */
+    split->layout = ws->layout;
+    split->orientation = ws->orientation;
+
+    Con *old_focused = TAILQ_FIRST(&(ws->focus_head));
+
+    /* 3: move the existing cons of this workspace below the new con */
+    DLOG("Moving cons\n");
+    while (!TAILQ_EMPTY(&(ws->nodes_head))) {
+        Con *child = TAILQ_FIRST(&(ws->nodes_head));
+        con_detach(child);
+        con_attach(child, split, true);
+    }
+
+    /* 4: switch workspace orientation */
+    ws->orientation = orientation;
+
+    /* 5: attach the new split container to the workspace */
+    DLOG("Attaching new split to ws\n");
+    con_attach(split, ws, false);
+
+    /* 6: fix the percentages */
+    con_fix_percent(ws);
+
+    if (old_focused)
+        con_focus(old_focused);
+}