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