]> git.sur5r.net Git - i3/i3/blob - src/match.c
Merge branch 'tree' 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 #define STRDUP(field) do { \
56     if (src->field != NULL) \
57         dest->field = sstrdup(src->field); \
58 } while (0)
59
60     STRDUP(title);
61     STRDUP(mark);
62     STRDUP(application);
63     STRDUP(class);
64     STRDUP(instance);
65 }
66
67 /*
68  * Check if a match data structure matches the given window.
69  *
70  */
71 bool match_matches_window(Match *match, i3Window *window) {
72     LOG("checking window %d (%s)\n", window->id, window->class_class);
73
74     /* TODO: pcre, full matching, … */
75     if (match->class != NULL) {
76         if (window->class_class != NULL && strcasecmp(match->class, window->class_class) == 0) {
77             LOG("window class matches (%s)\n", window->class_class);
78         } else {
79             LOG("window class does not match\n");
80             return false;
81         }
82     }
83
84     if (match->instance != NULL) {
85         if (window->class_instance != NULL && strcasecmp(match->instance, window->class_instance) == 0) {
86             LOG("window instance matches (%s)\n", window->class_instance);
87         } else {
88             LOG("window instance does not match\n");
89             return false;
90         }
91     }
92
93     if (match->id != XCB_NONE) {
94         if (window->id == match->id) {
95             LOG("match made by window id (%d)\n", window->id);
96         } else {
97             LOG("window id does not match\n");
98             return false;
99         }
100     }
101
102     /* TODO: pcre match */
103     if (match->title != NULL) {
104         if (window->name_json != NULL && strcasecmp(match->title, window->name_json) == 0) {
105             LOG("title matches (%s)\n", window->name_json);
106         } else {
107             LOG("title does not match\n");
108             return false;
109         }
110     }
111
112     if (match->dock != -1) {
113         LOG("match->dock = %d, window->dock = %d\n", match->dock, window->dock);
114         if ((window->dock == W_DOCK_TOP && match->dock == M_DOCK_TOP) ||
115          (window->dock == W_DOCK_BOTTOM && match->dock == M_DOCK_BOTTOM) ||
116          ((window->dock == W_DOCK_TOP || window->dock == W_DOCK_BOTTOM) &&
117           match->dock == M_DOCK_ANY) ||
118          (window->dock == W_NODOCK && match->dock == M_NODOCK)) {
119             LOG("dock status matches\n");
120         } else {
121             LOG("dock status does not match\n");
122             return false;
123         }
124     }
125
126     /* We don’t check the mark because this function is not even called when
127      * the mark would have matched - it is checked in cmdparse.y itself */
128     if (match->mark != NULL) {
129         LOG("mark does not match\n");
130         return false;
131     }
132
133     return true;
134 }