i3
match.c
Go to the documentation of this file.
1 #undef I3__FILE__
2 #define I3__FILE__ "match.c"
3 /*
4  * vim:ts=4:sw=4:expandtab
5  *
6  * i3 - an improved dynamic tiling window manager
7  * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE)
8  *
9  * A "match" is a data structure which acts like a mask or expression to match
10  * certain windows or not. For example, when using commands, you can specify a
11  * command like this: [title="*Firefox*"] kill. The title member of the match
12  * data structure will then be filled and i3 will check each window using
13  * match_matches_window() to find the windows affected by this command.
14  *
15  */
16 #include "all.h"
17 
18 /* From sys/time.h, not sure if it’s available on all systems. */
19 # define _i3_timercmp(a, b, CMP) \
20  (((a).tv_sec == (b).tv_sec) ? \
21  ((a).tv_usec CMP (b).tv_usec) : \
22  ((a).tv_sec CMP (b).tv_sec))
23 
24 /*
25  * Initializes the Match data structure. This function is necessary because the
26  * members representing boolean values (like dock) need to be initialized with
27  * -1 instead of 0.
28  *
29  */
30 void match_init(Match *match) {
31  memset(match, 0, sizeof(Match));
32  match->dock = -1;
33  match->urgent = U_DONTCHECK;
34 }
35 
36 /*
37  * Check if a match is empty. This is necessary while parsing commands to see
38  * whether the user specified a match at all.
39  *
40  */
41 bool match_is_empty(Match *match) {
42  /* we cannot simply use memcmp() because the structure is part of a
43  * TAILQ and I don’t want to start with things like assuming that the
44  * last member of a struct really is at the end in memory… */
45  return (match->title == NULL &&
46  match->mark == NULL &&
47  match->application == NULL &&
48  match->class == NULL &&
49  match->instance == NULL &&
50  match->role == NULL &&
51  match->urgent == U_DONTCHECK &&
52  match->id == XCB_NONE &&
53  match->con_id == NULL &&
54  match->dock == -1 &&
55  match->floating == M_ANY);
56 }
57 
58 /*
59  * Copies the data of a match from src to dest.
60  *
61  */
62 void match_copy(Match *dest, Match *src) {
63  memcpy(dest, src, sizeof(Match));
64 
65 /* The DUPLICATE_REGEX macro creates a new regular expression from the
66  * ->pattern of the old one. It therefore does use a little more memory then
67  * with a refcounting system, but it’s easier this way. */
68 #define DUPLICATE_REGEX(field) do { \
69  if (src->field != NULL) \
70  dest->field = regex_new(src->field->pattern); \
71 } while (0)
72 
73  DUPLICATE_REGEX(title);
74  DUPLICATE_REGEX(mark);
75  DUPLICATE_REGEX(application);
76  DUPLICATE_REGEX(class);
77  DUPLICATE_REGEX(instance);
78  DUPLICATE_REGEX(role);
79 }
80 
81 /*
82  * Check if a match data structure matches the given window.
83  *
84  */
85 bool match_matches_window(Match *match, i3Window *window) {
86  LOG("Checking window 0x%08x (class %s)\n", window->id, window->class_class);
87 
88  if (match->class != NULL) {
89  if (window->class_class != NULL &&
90  regex_matches(match->class, window->class_class)) {
91  LOG("window class matches (%s)\n", window->class_class);
92  } else {
93  return false;
94  }
95  }
96 
97  if (match->instance != NULL) {
98  if (window->class_instance != NULL &&
99  regex_matches(match->instance, window->class_instance)) {
100  LOG("window instance matches (%s)\n", window->class_instance);
101  } else {
102  return false;
103  }
104  }
105 
106  if (match->id != XCB_NONE) {
107  if (window->id == match->id) {
108  LOG("match made by window id (%d)\n", window->id);
109  } else {
110  LOG("window id does not match\n");
111  return false;
112  }
113  }
114 
115  if (match->title != NULL) {
116  if (window->name != NULL &&
117  regex_matches(match->title, i3string_as_utf8(window->name))) {
118  LOG("title matches (%s)\n", i3string_as_utf8(window->name));
119  } else {
120  return false;
121  }
122  }
123 
124  if (match->role != NULL) {
125  if (window->role != NULL &&
126  regex_matches(match->role, window->role)) {
127  LOG("window_role matches (%s)\n", window->role);
128  } else {
129  return false;
130  }
131  }
132 
133  Con *con = NULL;
134  if (match->urgent == U_LATEST) {
135  /* if the window isn't urgent, no sense in searching */
136  if (window->urgent.tv_sec == 0) {
137  return false;
138  }
139  /* if we find a window that is newer than this one, bail */
141  if ((con->window != NULL) &&
142  _i3_timercmp(con->window->urgent, window->urgent, >)) {
143  return false;
144  }
145  }
146  LOG("urgent matches latest\n");
147  }
148 
149  if (match->urgent == U_OLDEST) {
150  /* if the window isn't urgent, no sense in searching */
151  if (window->urgent.tv_sec == 0) {
152  return false;
153  }
154  /* if we find a window that is older than this one (and not 0), bail */
156  if ((con->window != NULL) &&
157  (con->window->urgent.tv_sec != 0) &&
158  _i3_timercmp(con->window->urgent, window->urgent, <)) {
159  return false;
160  }
161  }
162  LOG("urgent matches oldest\n");
163  }
164 
165  if (match->dock != -1) {
166  if ((window->dock == W_DOCK_TOP && match->dock == M_DOCK_TOP) ||
167  (window->dock == W_DOCK_BOTTOM && match->dock == M_DOCK_BOTTOM) ||
168  ((window->dock == W_DOCK_TOP || window->dock == W_DOCK_BOTTOM) &&
169  match->dock == M_DOCK_ANY) ||
170  (window->dock == W_NODOCK && match->dock == M_NODOCK)) {
171  LOG("dock status matches\n");
172  } else {
173  LOG("dock status does not match\n");
174  return false;
175  }
176  }
177 
178  /* We don’t check the mark because this function is not even called when
179  * the mark would have matched - it is checked in cmdparse.y itself */
180  if (match->mark != NULL) {
181  LOG("mark does not match\n");
182  return false;
183  }
184 
185  return true;
186 }
187 
188 /*
189  * Frees the given match. It must not be used afterwards!
190  *
191  */
192 void match_free(Match *match) {
193  /* First step: free the regex fields / patterns */
194  regex_free(match->title);
195  regex_free(match->application);
196  regex_free(match->class);
197  regex_free(match->instance);
198  regex_free(match->mark);
199  regex_free(match->role);
200 
201  /* Second step: free the regex helper struct itself */
202  FREE(match->title);
203  FREE(match->application);
204  FREE(match->class);
205  FREE(match->instance);
206  FREE(match->mark);
207  FREE(match->role);
208 }
A &#39;Con&#39; represents everything from the X11 root window down to a single X11 window.
Definition: data.h:457
bool match_matches_window(Match *match, i3Window *window)
Check if a match data structure matches the given window.
Definition: match.c:85
struct all_cons_head all_cons
Definition: tree.c:17
char * role
The WM_WINDOW_ROLE of this window (for example, the pidgin buddy window sets &quot;buddy list&quot;)...
Definition: data.h:335
#define _i3_timercmp(a, b, CMP)
Definition: match.c:19
char * class_class
Definition: data.h:326
i3String * name
The name of the window.
Definition: data.h:330
bool match_is_empty(Match *match)
Check if a match is empty.
Definition: match.c:41
A &quot;match&quot; is a data structure which acts like a mask or expression to match certain windows or not...
Definition: data.h:371
struct Window * window
Definition: data.h:525
struct regex * instance
Definition: data.h:375
void regex_free(struct regex *regex)
Frees the given regular expression.
Definition: regex.c:61
#define FREE(pointer)
Definition: util.h:47
const char * i3string_as_utf8(i3String *str)
Returns the UTF-8 encoded version of the i3String.
xcb_window_t id
Definition: data.h:390
Con * con_id
Definition: data.h:392
void match_init(Match *match)
Definition: match.c:30
void match_free(Match *match)
Frees the given match.
Definition: match.c:192
struct regex * role
Definition: data.h:377
struct regex * mark
Definition: data.h:376
A &#39;Window&#39; is a type which contains an xcb_window_t and all the related information (hints like _NET_...
Definition: data.h:313
#define DUPLICATE_REGEX(field)
struct timeval urgent
When this window was marked urgent.
Definition: data.h:354
enum Match::@14 floating
xcb_window_t id
Definition: data.h:314
struct regex * application
Definition: data.h:373
char * class_instance
Definition: data.h:327
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:335
void match_copy(Match *dest, Match *src)
Copies the data of a match from src to dest.
Definition: match.c:62
bool regex_matches(struct regex *regex, const char *input)
Checks if the given regular expression matches the given input and returns true if it does...
Definition: regex.c:75
enum Window::@11 dock
Whether the window says it is a dock window.
struct regex * class
Definition: data.h:374
enum Match::@13 dock
#define LOG(fmt,...)
Definition: libi3.h:76
enum Match::@12 urgent
struct regex * title
Definition: data.h:372