]> git.sur5r.net Git - i3/i3/commitdiff
re-implement assignments of workspace to specific outputs
authorMichael Stapelberg <michael@stapelberg.de>
Sat, 14 May 2011 20:13:29 +0000 (22:13 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Sat, 14 May 2011 20:19:58 +0000 (22:19 +0200)
include/data.h
include/i3.h
src/cfgparse.y
src/main.c
src/randr.c
src/workspace.c

index 1165da990388ce4856f4f8e7dcad1addfec2fd9e..c408d3f6fed3c8283806b8991ebb65f81ad5d438 100644 (file)
@@ -117,6 +117,17 @@ struct deco_render_params {
     xcb_font_t font;
 };
 
+/**
+ * Stores which workspace (by name) goes to which output.
+ *
+ */
+struct Workspace_Assignment {
+    char *name;
+    char *output;
+
+    TAILQ_ENTRY(Workspace_Assignment) ws_assignments;
+};
+
 struct Ignore_Event {
     int sequence;
     int response_type;
index 2f18ce7062f74a3763fffad52c02f1ab145e7eb2..a18cd6bc8c5a2d53d684496bc9e4b84f54396019 100644 (file)
@@ -27,6 +27,7 @@ extern int xkb_current_group;
 extern TAILQ_HEAD(bindings_head, Binding) *bindings;
 extern TAILQ_HEAD(autostarts_head, Autostart) autostarts;
 extern TAILQ_HEAD(assignments_head, Match) assignments;
+extern TAILQ_HEAD(ws_assignments_head, Workspace_Assignment) ws_assignments;
 extern SLIST_HEAD(stack_wins_head, Stack_Window) stack_wins;
 extern uint8_t root_depth;
 extern bool xcursor_supported, xkb_supported;
index 61b6768767d2f57241ef56dfd14496551d8bb2a1..a5e0f0baca70f3860a78e388a3f4d31fbe974e56 100644 (file)
@@ -517,14 +517,18 @@ workspace:
         if (ws_num < 1) {
             DLOG("Invalid workspace assignment, workspace number %d out of range\n", ws_num);
         } else {
-#if 0
-            Workspace *ws = workspace_get(ws_num - 1);
-            ws->preferred_output = $<string>7;
-            if ($<string>8 != NULL) {
-                    workspace_set_name(ws, $<string>8);
-                    free($<string>8);
+            char *ws_name = NULL;
+            if ($8 == NULL) {
+                asprintf(&ws_name, "%d", ws_num);
+            } else {
+                ws_name = $8;
             }
-#endif
+
+            DLOG("Should assign workspace %s to output %s\n", ws_name, $7);
+            struct Workspace_Assignment *assignment = scalloc(sizeof(struct Workspace_Assignment));
+            assignment->name = ws_name;
+            assignment->output = $7;
+            TAILQ_INSERT_TAIL(&ws_assignments, assignment, ws_assignments);
         }
     }
     | TOKWORKSPACE WHITESPACE NUMBER WHITESPACE workspace_name
index 91bd5d688de66a3280ae14a61444931c3fe58eae..c079d8dce8cd1fbbeeadbdb7a5e95a4a84d8ee97 100644 (file)
@@ -33,6 +33,10 @@ struct autostarts_head autostarts = TAILQ_HEAD_INITIALIZER(autostarts);
 /* The list of assignments */
 struct assignments_head assignments = TAILQ_HEAD_INITIALIZER(assignments);
 
+/* The list of workspace assignments (which workspace should end up on which
+ * output) */
+struct ws_assignments_head ws_assignments = TAILQ_HEAD_INITIALIZER(ws_assignments);
+
 /* We hope that those are supported and set them to true */
 bool xcursor_supported = true;
 bool xkb_supported = true;
index b61e309056f9516dff8cd318bd36d362ee4910bc..af0af334097215b694992447a9134236bc1c5445 100644 (file)
@@ -223,9 +223,6 @@ void disable_randr(xcb_connection_t *conn) {
  * Initializes a CT_OUTPUT Con (searches existing ones from inplace restart
  * before) to use for the given Output.
  *
- * XXX: for assignments, we probably need to move workspace creation from here
- * to after the loop in randr_query_outputs().
- *
  */
 void output_init_con(Output *output) {
     Con *con = NULL, *current;
@@ -316,7 +313,81 @@ void output_init_con(Output *output) {
     FREE(name);
     DLOG("attaching\n");
     con_attach(bottomdock, con, false);
+}
+
+/*
+ * Initializes at least one workspace for this output, trying the following
+ * steps until there is at least one workspace:
+ *
+ * • Move existing workspaces, which are assigned to be on the given output, to
+ *   the output.
+ * • Create the first assigned workspace for this output.
+ * • Create the first unused workspace.
+ *
+ */
+static void init_ws_for_output(Output *output, Con *content) {
+    char *name;
+
+    /* go through all assignments and move the existing workspaces to this output */
+    struct Workspace_Assignment *assignment;
+    TAILQ_FOREACH(assignment, &ws_assignments, ws_assignments) {
+        if (strcmp(assignment->output, output->name) != 0)
+            continue;
+
+        /* check if this workspace actually exists */
+        Con *workspace = NULL, *out;
+        TAILQ_FOREACH(out, &(croot->nodes_head), nodes)
+            GREP_FIRST(workspace, output_get_content(out),
+                       !strcasecmp(child->name, assignment->name));
+        if (workspace == NULL)
+            continue;
+
+        /* check that this workspace is not already attached (that means the
+         * user configured this assignment twice) */
+        Con *workspace_out = con_get_output(workspace);
+        if (workspace_out == output->con) {
+            LOG("Workspace \"%s\" assigned to output \"%s\", but it is already "
+                "there. Do you have two assignment directives for the same "
+                "workspace in your configuration file?\n",
+                workspace->name, output->name);
+            continue;
+        }
+
+        /* if so, move it over */
+        LOG("Moving workspace \"%s\" from output \"%s\" to \"%s\" due to assignment\n",
+            workspace->name, workspace_out->name, output->name);
+        DLOG("Detaching workspace = %p / %s\n", workspace, workspace->name);
+        con_detach(workspace);
+        DLOG("Re-attaching current = %p / %s\n", workspace, workspace->name);
+        con_attach(workspace, content, false);
+        DLOG("Done, next\n");
+    }
+
+    /* if a workspace exists, we are done now */
+    if (!TAILQ_EMPTY(&(content->nodes_head))) {
+        /* ensure that one of the workspaces is actually visible (in fullscreen
+         * mode), if they were invisible before, this might not be the case. */
+        Con *visible = NULL;
+        GREP_FIRST(visible, content, child->fullscreen_mode == CF_OUTPUT);
+        if (!visible) {
+            visible = TAILQ_FIRST(&(content->nodes_head));
+            workspace_show(visible->name);
+        }
+        return;
+    }
+
+    /* otherwise, we create the first assigned ws for this output */
+    TAILQ_FOREACH(assignment, &ws_assignments, ws_assignments) {
+        if (strcmp(assignment->output, output->name) != 0)
+            continue;
+
+        LOG("Initializing first assigned workspace \"%s\" for output \"%s\"\n",
+            assignment->name, assignment->output);
+        workspace_show(assignment->name);
+        return;
+    }
 
+    /* if there is still no workspace, we create the first free workspace */
     DLOG("Now adding a workspace\n");
 
     /* add a workspace to this output */
@@ -731,15 +802,16 @@ void randr_query_outputs() {
 
     ewmh_update_workarea();
 
-#if 0
-    /* Just go through each active output and associate one workspace */
+    /* Just go through each active output and assign one workspace */
     TAILQ_FOREACH(output, &outputs, outputs) {
-            if (!output->active || output->current_workspace != NULL)
-                    continue;
-            ws = get_first_workspace_for_output(output);
-            initialize_output(conn, output, ws);
+        if (!output->active)
+            continue;
+        Con *content = output_get_content(output->con);
+        if (!TAILQ_EMPTY(&(content->nodes_head)))
+            continue;
+        DLOG("Should add ws for output %s\n", output->name);
+        init_ws_for_output(output, content);
     }
-#endif
 
     /* Focus the primary screen, if possible */
     TAILQ_FOREACH(output, &outputs, outputs) {
index 7ff31157f8d7c22443e5eab0cefe5e354970c62b..5127fb0069cb5c40705fbb84a1c679c4ba6585d8 100644 (file)
  *
  */
 Con *workspace_get(const char *num, bool *created) {
-    Con *output, *workspace = NULL, *child;
+    Con *output, *workspace = NULL;
 
-    /* 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(child, &(output_get_content(output)->nodes_head), nodes) {
-            if (strcasecmp(child->name, num) != 0)
+        GREP_FIRST(workspace, output_get_content(output), !strcasecmp(child->name, num));
+
+    if (workspace == NULL) {
+        LOG("Creating new workspace \"%s\"\n", num);
+        /* unless an assignment is found, we will create this workspace on the current output */
+        output = con_get_output(focused);
+        /* look for assignments */
+        struct Workspace_Assignment *assignment;
+        TAILQ_FOREACH(assignment, &ws_assignments, ws_assignments) {
+            if (strcmp(assignment->name, num) != 0)
                 continue;
 
-            workspace = child;
+            LOG("Found workspace assignment to output \"%s\"\n", assignment->output);
+            GREP_FIRST(output, croot, !strcmp(child->name, assignment->output));
             break;
         }
-
-    LOG("getting ws %s\n", num);
-    if (workspace == NULL) {
-        LOG("need to create this one\n");
-        output = con_get_output(focused);
         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
@@ -225,7 +226,6 @@ void workspace_show(const char *num) {
             old = current;
         current->fullscreen_mode = CF_NONE;
     }
-    assert(old != NULL);
 
     /* enable fullscreen for the target workspace. If it happens to be the
      * same one we are currently on anyways, we can stop here. */