i3
Main Page
Data Structures
Files
File List
Globals
src
match.c
Go to the documentation of this file.
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
/* From sys/time.h, not sure if it’s available on all systems. */
17
# define _i3_timercmp(a, b, CMP) \
18
(((a).tv_sec == (b).tv_sec) ? \
19
((a).tv_usec CMP (b).tv_usec) : \
20
((a).tv_sec CMP (b).tv_sec))
21
22
/*
23
* Initializes the Match data structure. This function is necessary because the
24
* members representing boolean values (like dock) need to be initialized with
25
* -1 instead of 0.
26
*
27
*/
28
void
match_init
(
Match
*match) {
29
memset(match, 0,
sizeof
(
Match
));
30
match->
dock
= -1;
31
match->
urgent
= U_DONTCHECK;
32
}
33
34
/*
35
* Check if a match is empty. This is necessary while parsing commands to see
36
* whether the user specified a match at all.
37
*
38
*/
39
bool
match_is_empty
(
Match
*match) {
40
/* we cannot simply use memcmp() because the structure is part of a
41
* TAILQ and I don’t want to start with things like assuming that the
42
* last member of a struct really is at the end in memory… */
43
return
(match->
title
== NULL &&
44
match->
mark
== NULL &&
45
match->
application
== NULL &&
46
match->
class
== NULL &&
47
match->
instance
== NULL &&
48
match->
role
== NULL &&
49
match->
urgent
== U_DONTCHECK &&
50
match->
id
== XCB_NONE &&
51
match->
con_id
== NULL &&
52
match->
dock
== -1 &&
53
match->
floating
== M_ANY);
54
}
55
56
/*
57
* Copies the data of a match from src to dest.
58
*
59
*/
60
void
match_copy
(
Match
*dest,
Match
*src) {
61
memcpy(dest, src,
sizeof
(
Match
));
62
63
/* The DUPLICATE_REGEX macro creates a new regular expression from the
64
* ->pattern of the old one. It therefore does use a little more memory then
65
* with a refcounting system, but it’s easier this way. */
66
#define DUPLICATE_REGEX(field) do { \
67
if (src->field != NULL) \
68
dest->field = regex_new(src->field->pattern); \
69
} while (0)
70
71
DUPLICATE_REGEX
(title);
72
DUPLICATE_REGEX
(mark);
73
DUPLICATE_REGEX
(application);
74
DUPLICATE_REGEX
(
class
);
75
DUPLICATE_REGEX
(instance);
76
DUPLICATE_REGEX
(role);
77
}
78
79
/*
80
* Check if a match data structure matches the given window.
81
*
82
*/
83
bool
match_matches_window
(
Match
*match,
i3Window
*window) {
84
LOG
(
"Checking window 0x%08x (class %s)\n"
, window->
id
, window->
class_class
);
85
86
if
(match->
class
!= NULL) {
87
if
(window->
class_class
!= NULL &&
88
regex_matches
(match->
class
, window->
class_class
)) {
89
LOG
(
"window class matches (%s)\n"
, window->
class_class
);
90
}
else
{
91
return
false
;
92
}
93
}
94
95
if
(match->
instance
!= NULL) {
96
if
(window->
class_instance
!= NULL &&
97
regex_matches
(match->
instance
, window->
class_instance
)) {
98
LOG
(
"window instance matches (%s)\n"
, window->
class_instance
);
99
}
else
{
100
return
false
;
101
}
102
}
103
104
if
(match->
id
!= XCB_NONE) {
105
if
(window->
id
== match->
id
) {
106
LOG
(
"match made by window id (%d)\n"
, window->
id
);
107
}
else
{
108
LOG
(
"window id does not match\n"
);
109
return
false
;
110
}
111
}
112
113
if
(match->
title
!= NULL) {
114
if
(window->
name_json
!= NULL &&
115
regex_matches
(match->
title
, window->
name_json
)) {
116
LOG
(
"title matches (%s)\n"
, window->
name_json
);
117
}
else
{
118
return
false
;
119
}
120
}
121
122
if
(match->
role
!= NULL) {
123
if
(window->
role
!= NULL &&
124
regex_matches
(match->
role
, window->
role
)) {
125
LOG
(
"window_role matches (%s)\n"
, window->
role
);
126
}
else
{
127
return
false
;
128
}
129
}
130
131
Con
*con = NULL;
132
if
(match->
urgent
== U_LATEST) {
133
/* if the window isn't urgent, no sense in searching */
134
if
(window->
urgent
.tv_sec == 0) {
135
return
false
;
136
}
137
/* if we find a window that is newer than this one, bail */
138
TAILQ_FOREACH
(con, &
all_cons
,
all_cons
) {
139
if
((con->
window
!= NULL) &&
140
_i3_timercmp
(con->
window
->
urgent
, window->
urgent
, >)) {
141
return
false
;
142
}
143
}
144
LOG
(
"urgent matches latest\n"
);
145
}
146
147
if
(match->
urgent
== U_OLDEST) {
148
/* if the window isn't urgent, no sense in searching */
149
if
(window->
urgent
.tv_sec == 0) {
150
return
false
;
151
}
152
/* if we find a window that is older than this one (and not 0), bail */
153
TAILQ_FOREACH
(con, &
all_cons
,
all_cons
) {
154
if
((con->
window
!= NULL) &&
155
(con->
window
->
urgent
.tv_sec != 0) &&
156
_i3_timercmp
(con->
window
->
urgent
, window->
urgent
, <)) {
157
return
false
;
158
}
159
}
160
LOG
(
"urgent matches oldest\n"
);
161
}
162
163
if
(match->
dock
!= -1) {
164
if
((window->
dock
== W_DOCK_TOP && match->
dock
== M_DOCK_TOP) ||
165
(window->
dock
== W_DOCK_BOTTOM && match->
dock
== M_DOCK_BOTTOM) ||
166
((window->
dock
== W_DOCK_TOP || window->
dock
== W_DOCK_BOTTOM) &&
167
match->
dock
== M_DOCK_ANY) ||
168
(window->
dock
== W_NODOCK && match->
dock
== M_NODOCK)) {
169
LOG
(
"dock status matches\n"
);
170
}
else
{
171
LOG
(
"dock status does not match\n"
);
172
return
false
;
173
}
174
}
175
176
/* We don’t check the mark because this function is not even called when
177
* the mark would have matched - it is checked in cmdparse.y itself */
178
if
(match->
mark
!= NULL) {
179
LOG
(
"mark does not match\n"
);
180
return
false
;
181
}
182
183
return
true
;
184
}
185
186
/*
187
* Frees the given match. It must not be used afterwards!
188
*
189
*/
190
void
match_free
(
Match
*match) {
191
/* First step: free the regex fields / patterns */
192
regex_free
(match->
title
);
193
regex_free
(match->
application
);
194
regex_free
(match->
class
);
195
regex_free
(match->
instance
);
196
regex_free
(match->
mark
);
197
regex_free
(match->
role
);
198
199
/* Second step: free the regex helper struct itself */
200
FREE
(match->
title
);
201
FREE
(match->
application
);
202
FREE
(match->
class
);
203
FREE
(match->
instance
);
204
FREE
(match->
mark
);
205
FREE
(match->
role
);
206
}
Generated by
1.8.3.1