]> git.sur5r.net Git - i3/i3/blob - src/match.c
Merge branch 'master' into next
[i3/i3] / src / match.c
1 /*
2  * vim:ts=4:sw=4:expandtab
3  *
4  * i3 - an improved dynamic tiling window manager
5  * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE)
6  *
7  * A "match" is a data structure which acts like a mask or expression to match
8  * certain windows or not. For example, when using commands, you can specify a
9  * command like this: [title="*Firefox*"] kill. The title member of the match
10  * data structure will then be filled and i3 will check each window using
11  * match_matches_window() to find the windows affected by this command.
12  *
13  */
14
15 #include "all.h"
16
17 /*
18  * Initializes the Match data structure. This function is necessary because the
19  * members representing boolean values (like dock) need to be initialized with
20  * -1 instead of 0.
21  *
22  */
23 void match_init(Match *match) {
24     memset(match, 0, sizeof(Match));
25     match->dock = -1;
26 }
27
28 /*
29  * Check if a match is empty. This is necessary while parsing commands to see
30  * whether the user specified a match at all.
31  *
32  */
33 bool match_is_empty(Match *match) {
34     /* we cannot simply use memcmp() because the structure is part of a
35      * TAILQ and I don’t want to start with things like assuming that the
36      * last member of a struct really is at the end in memory… */
37     return (match->title == NULL &&
38             match->mark == NULL &&
39             match->application == NULL &&
40             match->class == NULL &&
41             match->instance == NULL &&
42             match->role == NULL &&
43             match->id == XCB_NONE &&
44             match->con_id == NULL &&
45             match->dock == -1 &&
46             match->floating == M_ANY);
47 }
48
49 /*
50  * Copies the data of a match from src to dest.
51  *
52  */
53 void match_copy(Match *dest, Match *src) {
54     memcpy(dest, src, sizeof(Match));
55
56 /* The DUPLICATE_REGEX macro creates a new regular expression from the
57  * ->pattern of the old one. It therefore does use a little more memory then
58  *  with a refcounting system, but it’s easier this way. */
59 #define DUPLICATE_REGEX(field) do { \
60     if (src->field != NULL) \
61         dest->field = regex_new(src->field->pattern); \
62 } while (0)
63
64     DUPLICATE_REGEX(title);
65     DUPLICATE_REGEX(mark);
66     DUPLICATE_REGEX(application);
67     DUPLICATE_REGEX(class);
68     DUPLICATE_REGEX(instance);
69     DUPLICATE_REGEX(role);
70 }
71
72 /*
73  * Check if a match data structure matches the given window.
74  *
75  */
76 bool match_matches_window(Match *match, i3Window *window) {
77     LOG("checking window %d (%s)\n", window->id, window->class_class);
78
79     if (match->class != NULL) {
80         if (window->class_class != NULL &&
81             regex_matches(match->class, window->class_class)) {
82             LOG("window class matches (%s)\n", window->class_class);
83         } else {
84             LOG("window class does not match\n");
85             return false;
86         }
87     }
88
89     if (match->instance != NULL) {
90         if (window->class_instance != NULL &&
91             regex_matches(match->instance, window->class_instance)) {
92             LOG("window instance matches (%s)\n", window->class_instance);
93         } else {
94             LOG("window instance does not match\n");
95             return false;
96         }
97     }
98
99     if (match->id != XCB_NONE) {
100         if (window->id == match->id) {
101             LOG("match made by window id (%d)\n", window->id);
102         } else {
103             LOG("window id does not match\n");
104             return false;
105         }
106     }
107
108     if (match->title != NULL) {
109         if (window->name_json != NULL &&
110             regex_matches(match->title, window->name_json)) {
111             LOG("title matches (%s)\n", window->name_json);
112         } else {
113             LOG("title does not match\n");
114             return false;
115         }
116     }
117
118     if (match->role != NULL) {
119         if (window->role != NULL &&
120             regex_matches(match->role, window->role)) {
121             LOG("window_role matches (%s)\n", window->role);
122         } else {
123             LOG("window_role does not match\n");
124             return false;
125         }
126     }
127
128     if (match->dock != -1) {
129         LOG("match->dock = %d, window->dock = %d\n", match->dock, window->dock);
130         if ((window->dock == W_DOCK_TOP && match->dock == M_DOCK_TOP) ||
131          (window->dock == W_DOCK_BOTTOM && match->dock == M_DOCK_BOTTOM) ||
132          ((window->dock == W_DOCK_TOP || window->dock == W_DOCK_BOTTOM) &&
133           match->dock == M_DOCK_ANY) ||
134          (window->dock == W_NODOCK && match->dock == M_NODOCK)) {
135             LOG("dock status matches\n");
136         } else {
137             LOG("dock status does not match\n");
138             return false;
139         }
140     }
141
142     /* We don’t check the mark because this function is not even called when
143      * the mark would have matched - it is checked in cmdparse.y itself */
144     if (match->mark != NULL) {
145         LOG("mark does not match\n");
146         return false;
147     }
148
149     return true;
150 }
151
152 /*
153  * Frees the given match. It must not be used afterwards!
154  *
155  */
156 void match_free(Match *match) {
157     /* First step: free the regex fields / patterns */
158     regex_free(match->title);
159     regex_free(match->application);
160     regex_free(match->class);
161     regex_free(match->instance);
162     regex_free(match->mark);
163     regex_free(match->role);
164
165     /* Second step: free the regex helper struct itself */
166     FREE(match->title);
167     FREE(match->application);
168     FREE(match->class);
169     FREE(match->instance);
170     FREE(match->mark);
171     FREE(match->role);
172 }