*/
void run_assignments(i3Window *window);
+/**
+ * Returns the first matching assignment for the given window.
+ *
+ */
+Assignment *assignment_for(i3Window *window, int type);
+
#endif
* 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
*
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
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:
*
* 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;
char *output;
} dest;
- TAILQ_ENTRY(Assignment) real_assignments;
+ TAILQ_ENTRY(Assignment) assignments;
};
struct Con {
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;
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
/* 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;
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;
+}
%s WANT_QSTRING
%s BINDSYM_COND
%s ASSIGN_COND
+%s ASSIGN_TARGET_COND
%s COLOR_COND
%s OUTPUT_COND
%s FOR_WINDOW_COND
<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; }
}
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; }
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; }
[ \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]; }
%type <string> optional_workspace_name
%type <string> workspace_name
%type <string> window_class
-%type <match> assign_target
%%
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);
}
;
;
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);
}
;
| STR_NG
;
-optional_arrow:
- /* NULL */
- | TOKARROW
- ;
-
ipcsocket:
TOKIPCSOCKET STR
{
* 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;
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 */
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.
*
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;
-}