]> git.sur5r.net Git - i3/i3/commitdiff
Implement assignments for (named) workspaces, with '~' compatibility (floating)
authorMichael Stapelberg <michael@stapelberg.de>
Mon, 23 May 2011 16:41:17 +0000 (18:41 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Mon, 23 May 2011 16:41:17 +0000 (18:41 +0200)
include/assignments.h
include/data.h
include/i3.h
include/match.h
src/assignments.c
src/cfgparse.l
src/cfgparse.y
src/main.c
src/manage.c
src/match.c

index ecd8b8082f9462af6f43001cc3c27c778e7fd530..f72dd2e5e4c4a0db14c499ae35d57622096cc008 100644 (file)
  */
 void run_assignments(i3Window *window);
 
+/**
+ * Returns the first matching assignment for the given window.
+ *
+ */
+Assignment *assignment_for(i3Window *window, int type);
+
 #endif
index 832200ee85c3ae947488fff128b15d14fab84878..fed4420cab949d744a33aa79487aa5377b31325d 100644 (file)
@@ -2,7 +2,7 @@
  * vim:ts=4:sw=4:expandtab
  *
  * i3 - an improved dynamic tiling window manager
- * © 2009-2010 Michael Stapelberg and contributors (see also: LICENSE)
+ * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE)
  *
  * include/data.h: This file defines all data structures used by i3
  *
@@ -300,8 +300,6 @@ struct Match {
     Con *con_id;
     enum { M_ANY = 0, M_TILING, M_FLOATING } floating;
 
-    char *target_ws;
-
     /* Where the window looking for a match should be inserted:
      *
      * M_HERE   = the matched container will be replaced by the window
@@ -314,9 +312,16 @@ struct Match {
     enum { M_HERE = 0, M_ASSIGN_WS, M_BELOW } insert_where;
 
     TAILQ_ENTRY(Match) matches;
-    TAILQ_ENTRY(Match) assignments;
 };
 
+/**
+ * An Assignment makes specific windows go to a specific workspace/output or
+ * run a command for that window. With this mechanism, the user can -- for
+ * example -- make specific windows floating or assign his browser to workspace
+ * "www". Checking if a window is assigned works by comparing the Match data
+ * structure with the window (see match_matches_window()).
+ *
+ */
 struct Assignment {
     /** type of this assignment:
      *
@@ -324,8 +329,17 @@ struct Assignment {
      * A_TO_WORKSPACE = assign the matching window to the specified workspace
      * A_TO_OUTPUT = assign the matching window to the specified output
      *
+     * While the type is a bitmask, only one value can be set at a time. It is
+     * a bitmask to allow filtering for multiple types, for example in the
+     * assignment_for() function.
+     *
      */
-    enum { A_COMMAND = 0, A_TO_WORKSPACE = 1, A_TO_OUTPUT = 2 } type;
+    enum {
+        A_ANY          = 0,
+        A_COMMAND      = (1 << 0),
+        A_TO_WORKSPACE = (1 << 1),
+        A_TO_OUTPUT    = (1 << 2)
+    } type;
 
     /** the criteria to check if a window matches */
     Match match;
@@ -337,7 +351,7 @@ struct Assignment {
         char *output;
     } dest;
 
-    TAILQ_ENTRY(Assignment) real_assignments;
+    TAILQ_ENTRY(Assignment) assignments;
 };
 
 struct Con {
index 6aeea847fb2755109f62415fa6f764a7d8e53e53..7eb48ecc1ce8a6f994b7e62d30811d18d10a00d4 100644 (file)
@@ -26,9 +26,8 @@ extern Display *xlibdpy, *xkbdpy;
 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 TAILQ_HEAD(real_assignments_head, Assignment) real_assignments;
+extern TAILQ_HEAD(assignments_head, Assignment) assignments;
 extern SLIST_HEAD(stack_wins_head, Stack_Window) stack_wins;
 extern uint8_t root_depth;
 extern bool xcursor_supported, xkb_supported;
index 4f0e9bdc291f3f17df7d9f80dec5dbbf8f355a0f..2786c66a8be7792cd25485f48ca7ea971b8d0667 100644 (file)
@@ -17,15 +17,15 @@ void match_init(Match *match);
 bool match_is_empty(Match *match);
 
 /**
- * Check if a match data structure matches the given window.
+ * Copies the data of a match from src to dest.
  *
  */
-bool match_matches_window(Match *match, i3Window *window);
+void match_copy(Match *dest, Match *src);
 
 /**
- * Returns the first match in 'assignments' that matches the given window.
+ * Check if a match data structure matches the given window.
  *
  */
-Match *match_by_assignment(i3Window *window);
+bool match_matches_window(Match *match, i3Window *window);
 
 #endif
index f41877f0a0b9eec59e56777f82f08499bc0fd427..f171dc3b2fe0cc48f51a49a6074ad9f65bb56ea3 100644 (file)
@@ -17,7 +17,7 @@ void run_assignments(i3Window *window) {
 
     /* Check if any assignments match */
     Assignment *current;
-    TAILQ_FOREACH(current, &real_assignments, real_assignments) {
+    TAILQ_FOREACH(current, &assignments, assignments) {
         if (!match_matches_window(&(current->match), window))
             continue;
 
@@ -48,3 +48,21 @@ void run_assignments(i3Window *window) {
         window->ran_assignments[window->nr_assignments-1] = current;
     }
 }
+
+/*
+ * Returns the first matching assignment for the given window.
+ *
+ */
+Assignment *assignment_for(i3Window *window, int type) {
+    Assignment *assignment;
+
+    TAILQ_FOREACH(assignment, &assignments, assignments) {
+        if ((type != A_ANY && (assignment->type & type) == 0) ||
+            !match_matches_window(&(assignment->match), window))
+            continue;
+        DLOG("got a matching assignment (to %s)\n", assignment->dest.workspace);
+        return assignment;
+    }
+
+    return NULL;
+}
index 41445944653d6b633d04f02ea7c1a1fb4b860df1..fd9613f05c23201133284762f377f3e16198e982 100644 (file)
@@ -44,6 +44,7 @@ EOL     (\r?\n)
 %s WANT_QSTRING
 %s BINDSYM_COND
 %s ASSIGN_COND
+%s ASSIGN_TARGET_COND
 %s COLOR_COND
 %s OUTPUT_COND
 %s FOR_WINDOW_COND
@@ -87,6 +88,8 @@ EOL     (\r?\n)
 <OUTPUT_COND>[a-zA-Z0-9_-]+     { yylval.string = sstrdup(yytext); return OUTPUT; }
 ^[ \t]*#[^\n]*                  { return TOKCOMMENT; }
 <COLOR_COND>[0-9a-fA-F]+        { yylval.string = sstrdup(yytext); return HEX; }
+<ASSIGN_TARGET_COND>[ \t]*→[ \t]*     { BEGIN(WANT_STRING); }
+<ASSIGN_TARGET_COND>[ \t]+      { BEGIN(WANT_STRING); }
 [0-9]+                          { yylval.number = atoi(yytext); return NUMBER; }
 mode                            { return TOKMODE; }
 bind                            { yy_push_state(WANT_STRING); yy_push_state(EAT_WHITESPACE); yy_push_state(EAT_WHITESPACE); return TOKBINDCODE; }
@@ -104,7 +107,7 @@ screen                          {
                                 }
 terminal                        { WS_STRING; return TOKTERMINAL; }
 font                            { WS_STRING; return TOKFONT; }
-assign                          { BEGIN(ASSIGN_COND); return TOKASSIGN; }
+assign                          { yy_push_state(ASSIGN_TARGET_COND); yy_push_state(ASSIGN_COND); return TOKASSIGN; }
 set[^\n]*                       { return TOKCOMMENT; }
 ipc-socket                      { WS_STRING; return TOKIPCSOCKET; }
 ipc_socket                      { WS_STRING; return TOKIPCSOCKET; }
@@ -160,7 +163,6 @@ Mode_switch                     { yylval.number = BIND_MODE_SWITCH; return MODIF
 control                         { return TOKCONTROL; }
 ctrl                            { return TOKCONTROL; }
 shift                           { return TOKSHIFT; }
-→                               { return TOKARROW; }
 
 class                           { yy_push_state(WANT_QSTRING); return TOK_CLASS; }
 id                              { yy_push_state(WANT_QSTRING); return TOK_ID; }
@@ -179,14 +181,16 @@ title                           { yy_push_state(WANT_QSTRING); return TOK_TITLE;
 [ \t]+                          { /* ignore whitespace */ ; }
 \"[^\"]+\"                      {
                                   /* if ASSIGN_COND then */
-                                  BEGIN(INITIAL);
+                                  if (yy_start_stack_ptr > 0)
+                                      yy_pop_state();
+                                  else BEGIN(INITIAL);
                                   /* yylval will be the string, but without quotes */
                                   char *copy = sstrdup(yytext+1);
                                   copy[strlen(copy)-1] = '\0';
                                   yylval.string = copy;
                                   return QUOTEDSTRING;
                                 }
-<ASSIGN_COND>[^ \t]+            { BEGIN(INITIAL); yylval.string = sstrdup(yytext); return STR_NG; }
+<ASSIGN_COND>[^ \t\"]+          { BEGIN(ASSIGN_TARGET_COND); yylval.string = sstrdup(yytext); return STR_NG; }
 <BINDSYM_COND>[a-zA-Z0-9_]+     { yylval.string = sstrdup(yytext); return WORD; }
 [a-zA-Z]+                       { yylval.string = sstrdup(yytext); return WORD; }
 .                               { return (int)yytext[0]; }
index 346f9476785435c83ce4010179540536bc1daaf5..d6eb12cd3dcded7eaf35719e61e8966b3cb9b5db 100644 (file)
@@ -268,7 +268,6 @@ void parse_file(const char *f) {
 %type   <string>        optional_workspace_name
 %type   <string>        workspace_name
 %type   <string>        window_class
-%type   <match>         assign_target
 
 %%
 
@@ -356,7 +355,7 @@ for_window:
         assignment->type = A_COMMAND;
         assignment->match = current_match;
         assignment->dest.command = $3;
-        TAILQ_INSERT_TAIL(&real_assignments, assignment, real_assignments);
+        TAILQ_INSERT_TAIL(&assignments, assignment, assignments);
     }
     ;
 
@@ -651,57 +650,54 @@ workspace_name:
     ;
 
 assign:
-    TOKASSIGN window_class optional_arrow assign_target
+    TOKASSIGN window_class STR
     {
-        printf("assignment of %s\n", $2);
+        printf("assignment of %s to *%s*\n", $2, $3);
+        char *workspace = $3;
+        char *criteria = $2;
 
-        struct Match *match = $4;
+        Assignment *assignment = scalloc(sizeof(Assignment));
+        Match *match = &(assignment->match);
+        match_init(match);
 
         char *separator = NULL;
-        if ((separator = strchr($2, '/')) != NULL) {
+        if ((separator = strchr(criteria, '/')) != NULL) {
             *(separator++) = '\0';
             match->title = sstrdup(separator);
         }
-        if (*$2 != '\0')
-            match->class = sstrdup($2);
-        free($2);
+        if (*criteria != '\0')
+            match->class = sstrdup(criteria);
+        free(criteria);
 
         printf("  class = %s\n", match->class);
         printf("  title = %s\n", match->title);
-        if (match->insert_where == M_ASSIGN_WS)
-            printf("  to ws %s\n", match->target_ws);
-        TAILQ_INSERT_TAIL(&assignments, match, assignments);
-    }
-    ;
 
-assign_target:
-    NUMBER
-    {
-        /* TODO: named workspaces */
-        Match *match = smalloc(sizeof(Match));
-        match_init(match);
-        match->insert_where = M_ASSIGN_WS;
-        asprintf(&(match->target_ws), "%d", $1);
-        $$ = match;
-    }
-    | '~'
-    {
-        /* TODO: compatiblity */
-#if 0
-        struct Assignment *new = scalloc(sizeof(struct Assignment));
-        new->floating = ASSIGN_FLOATING_ONLY;
-        $<assignment>$ = new;
-#endif
-    }
-    | '~' NUMBER
-    {
-        /* TODO: compatiblity */
-#if 0
-        struct Assignment *new = scalloc(sizeof(struct Assignment));
-        new->workspace = $<number>2;
-        new->floating = ASSIGN_FLOATING;
-        $<assignment>$ = new;
-#endif
+        /* Compatibility with older versions: If the assignment target starts
+         * with ~, we create the equivalent of:
+         *
+         * for_window [class="foo"] mode floating
+         */
+        if (*workspace == '~') {
+            workspace++;
+            if (*workspace == '\0') {
+                /* This assignment was *only* for floating */
+                assignment->type = A_COMMAND;
+                assignment->dest.command = sstrdup("mode floating");
+                TAILQ_INSERT_TAIL(&assignments, assignment, assignments);
+                break;
+            } else {
+                /* Create a new assignment and continue afterwards */
+                Assignment *floating = scalloc(sizeof(Assignment));
+                match_copy(&(floating->match), match);
+                floating->type = A_COMMAND;
+                floating->dest.command = sstrdup("mode floating");
+                TAILQ_INSERT_TAIL(&assignments, floating, assignments);
+            }
+        }
+
+        assignment->type = A_TO_WORKSPACE;
+        assignment->dest.workspace = workspace;
+        TAILQ_INSERT_TAIL(&assignments, assignment, assignments);
     }
     ;
 
@@ -710,11 +706,6 @@ window_class:
     | STR_NG
     ;
 
-optional_arrow:
-    /* NULL */
-    | TOKARROW
-    ;
-
 ipcsocket:
     TOKIPCSOCKET STR
     {
index 39702223b6904027399f364d9f80cc5e73646e88..c079d8dce8cd1fbbeeadbdb7a5e95a4a84d8ee97 100644 (file)
@@ -37,8 +37,6 @@ struct assignments_head assignments = TAILQ_HEAD_INITIALIZER(assignments);
  * output) */
 struct ws_assignments_head ws_assignments = TAILQ_HEAD_INITIALIZER(ws_assignments);
 
-struct real_assignments_head real_assignments = TAILQ_HEAD_INITIALIZER(real_assignments);
-
 /* We hope that those are supported and set them to true */
 bool xcursor_supported = true;
 bool xkb_supported = true;
index 7d240f4234b7afecf519864eb43d839ee9b24317..9ccdc19a9519f839177f06a4ec6bd6a3653beabd 100644 (file)
@@ -205,17 +205,19 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
 
     Con *nc = NULL;
     Match *match;
+    Assignment *assignment;
 
     /* check assignments first */
-    if ((match = match_by_assignment(cwindow))) {
+    if ((assignment = assignment_for(cwindow, A_TO_WORKSPACE | A_TO_OUTPUT))) {
         DLOG("Assignment matches (%p)\n", match);
-        if (match->insert_where == M_ASSIGN_WS) {
-            nc = con_descend_focused(workspace_get(match->target_ws, NULL));
-            DLOG("focused on ws %s: %p / %s\n", match->target_ws, nc, nc->name);
+        if (assignment->type == A_TO_WORKSPACE) {
+            nc = con_descend_focused(workspace_get(assignment->dest.workspace, NULL));
+            DLOG("focused on ws %s: %p / %s\n", assignment->dest.workspace, nc, nc->name);
             if (nc->type == CT_WORKSPACE)
                 nc = tree_open_con(nc);
             else nc = tree_open_con(nc->parent);
         }
+        /* TODO: handle assignments with type == A_TO_OUTPUT */
     } else {
         /* TODO: two matches for one container */
 
index fd024d59e3ffbdb0937d05df1c75cb9bef8035af..2449bad7a7e67f2eb755a91679f01f82d73936c2 100644 (file)
@@ -45,6 +45,25 @@ bool match_is_empty(Match *match) {
             match->floating == M_ANY);
 }
 
+/*
+ * Copies the data of a match from src to dest.
+ *
+ */
+void match_copy(Match *dest, Match *src) {
+    memcpy(dest, src, sizeof(Match));
+
+#define STRDUP(field) do { \
+    if (src->field != NULL) \
+        dest->field = sstrdup(src->field); \
+} while (0)
+
+    STRDUP(title);
+    STRDUP(mark);
+    STRDUP(application);
+    STRDUP(class);
+    STRDUP(instance);
+}
+
 /*
  * Check if a match data structure matches the given window.
  *
@@ -87,20 +106,3 @@ bool match_matches_window(Match *match, i3Window *window) {
 
     return false;
 }
-
-/*
- * Returns the first match in 'assignments' that matches the given window.
- *
- */
-Match *match_by_assignment(i3Window *window) {
-    Match *match;
-
-    TAILQ_FOREACH(match, &assignments, assignments) {
-        if (!match_matches_window(match, window))
-            continue;
-        DLOG("got a matching assignment (to %s)\n", match->target_ws);
-        return match;
-    }
-
-    return NULL;
-}