]> 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->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 }
69
70 /*
71  * Check if a match data structure matches the given window.
72  *
73  */
74 bool match_matches_window(Match *match, i3Window *window) {
75     LOG("checking window %d (%s)\n", window->id, window->class_class);
76
77     if (match->class != NULL) {
78         if (window->class_class != NULL &&
79             regex_matches(match->class, window->class_class)) {
80             LOG("window class matches (%s)\n", window->class_class);
81         } else {
82             LOG("window class does not match\n");
83             return false;
84         }
85     }
86
87     if (match->instance != NULL) {
88         if (window->class_instance != NULL &&
89             regex_matches(match->instance, window->class_instance)) {
90             LOG("window instance matches (%s)\n", window->class_instance);
91         } else {
92             LOG("window instance does not match\n");
93             return false;
94         }
95     }
96
97     if (match->id != XCB_NONE) {
98         if (window->id == match->id) {
99             LOG("match made by window id (%d)\n", window->id);
100         } else {
101             LOG("window id does not match\n");
102             return false;
103         }
104     }
105
106     if (match->title != NULL) {
107         if (window->name_json != NULL &&
108             regex_matches(match->title, window->name_json)) {
109             LOG("title matches (%s)\n", window->name_json);
110         } else {
111             LOG("title does not match\n");
112             return false;
113         }
114     }
115
116     if (match->dock != -1) {
117         LOG("match->dock = %d, window->dock = %d\n", match->dock, window->dock);
118         if ((window->dock == W_DOCK_TOP && match->dock == M_DOCK_TOP) ||
119          (window->dock == W_DOCK_BOTTOM && match->dock == M_DOCK_BOTTOM) ||
120          ((window->dock == W_DOCK_TOP || window->dock == W_DOCK_BOTTOM) &&
121           match->dock == M_DOCK_ANY) ||
122          (window->dock == W_NODOCK && match->dock == M_NODOCK)) {
123             LOG("dock status matches\n");
124         } else {
125             LOG("dock status does not match\n");
126             return false;
127         }
128     }
129
130     /* We don’t check the mark because this function is not even called when
131      * the mark would have matched - it is checked in cmdparse.y itself */
132     if (match->mark != NULL) {
133         LOG("mark does not match\n");
134         return false;
135     }
136
137     return true;
138 }
139
140 /*
141  * Frees the given match. It must not be used afterwards!
142  *
143  */
144 void match_free(Match *match) {
145     /* First step: free the regex fields / patterns */
146     regex_free(match->title);
147     regex_free(match->application);
148     regex_free(match->class);
149     regex_free(match->instance);
150     regex_free(match->mark);
151
152     /* Second step: free the regex helper struct itself */
153     FREE(match->title);
154     FREE(match->application);
155     FREE(match->class);
156     FREE(match->instance);
157     FREE(match->mark);
158 }