]> git.sur5r.net Git - i3/i3/blob - src/match.c
Merge branch 'fix-i3bar-multi-dpy'
[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 0x%08x (class %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             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             return false;
93         }
94     }
95
96     if (match->id != XCB_NONE) {
97         if (window->id == match->id) {
98             LOG("match made by window id (%d)\n", window->id);
99         } else {
100             LOG("window id does not match\n");
101             return false;
102         }
103     }
104
105     if (match->title != NULL) {
106         if (window->name_json != NULL &&
107             regex_matches(match->title, window->name_json)) {
108             LOG("title matches (%s)\n", window->name_json);
109         } else {
110             return false;
111         }
112     }
113
114     if (match->role != NULL) {
115         if (window->role != NULL &&
116             regex_matches(match->role, window->role)) {
117             LOG("window_role matches (%s)\n", window->role);
118         } else {
119             return false;
120         }
121     }
122
123     if (match->dock != -1) {
124         if ((window->dock == W_DOCK_TOP && match->dock == M_DOCK_TOP) ||
125          (window->dock == W_DOCK_BOTTOM && match->dock == M_DOCK_BOTTOM) ||
126          ((window->dock == W_DOCK_TOP || window->dock == W_DOCK_BOTTOM) &&
127           match->dock == M_DOCK_ANY) ||
128          (window->dock == W_NODOCK && match->dock == M_NODOCK)) {
129             LOG("dock status matches\n");
130         } else {
131             LOG("dock status does not match\n");
132             return false;
133         }
134     }
135
136     /* We don’t check the mark because this function is not even called when
137      * the mark would have matched - it is checked in cmdparse.y itself */
138     if (match->mark != NULL) {
139         LOG("mark does not match\n");
140         return false;
141     }
142
143     return true;
144 }
145
146 /*
147  * Frees the given match. It must not be used afterwards!
148  *
149  */
150 void match_free(Match *match) {
151     /* First step: free the regex fields / patterns */
152     regex_free(match->title);
153     regex_free(match->application);
154     regex_free(match->class);
155     regex_free(match->instance);
156     regex_free(match->mark);
157     regex_free(match->role);
158
159     /* Second step: free the regex helper struct itself */
160     FREE(match->title);
161     FREE(match->application);
162     FREE(match->class);
163     FREE(match->instance);
164     FREE(match->mark);
165     FREE(match->role);
166 }