]> Dogcows Code - chaz/openbox/blob - openbox/actions/if.c
8a31c9a08d3dd5d1abae8e2e5484441c1541bf5d
[chaz/openbox] / openbox / actions / if.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3 if.c for the Openbox window manager
4 Copyright (c) 2007 Mikael Magnusson
5 Copyright (c) 2007 Dana Jansens
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include "openbox/actions.h"
21 #include "openbox/misc.h"
22 #include "openbox/client.h"
23 #include "openbox/frame.h"
24 #include "openbox/screen.h"
25 #include "openbox/focus.h"
26 #include <glib.h>
27
28 typedef enum {
29 QUERY_TARGET_IS_ACTION_TARGET,
30 QUERY_TARGET_IS_FOCUS_TARGET,
31 } QueryTarget;
32
33 typedef struct {
34 QueryTarget target;
35 gboolean shaded_on;
36 gboolean shaded_off;
37 gboolean maxvert_on;
38 gboolean maxvert_off;
39 gboolean maxhorz_on;
40 gboolean maxhorz_off;
41 gboolean maxfull_on;
42 gboolean maxfull_off;
43 gboolean iconic_on;
44 gboolean iconic_off;
45 gboolean focused;
46 gboolean unfocused;
47 gboolean urgent_on;
48 gboolean urgent_off;
49 gboolean decor_off;
50 gboolean decor_on;
51 gboolean omnipresent_on;
52 gboolean omnipresent_off;
53 gboolean desktop_current;
54 gboolean desktop_other;
55 guint desktop_number;
56 guint screendesktop_number;
57 guint client_monitor;
58 GPatternSpec *matchtitle;
59 GRegex *regextitle;
60 gchar *exacttitle;
61 } Query;
62
63 typedef struct {
64 GArray* queries;
65 GSList *thenacts;
66 GSList *elseacts;
67 } Options;
68
69 static gpointer setup_func(xmlNodePtr node);
70 static void free_func(gpointer options);
71 static gboolean run_func(ObActionsData *data, gpointer options);
72
73 void action_if_startup(void)
74 {
75 actions_register("If", setup_func, free_func, run_func);
76 }
77
78 static inline void set_bool(xmlNodePtr node,
79 const char *name,
80 gboolean *on,
81 gboolean *off)
82 {
83 xmlNodePtr n;
84
85 if ((n = obt_xml_find_node(node, name))) {
86 if (obt_xml_node_bool(n))
87 *on = TRUE;
88 else
89 *off = TRUE;
90 }
91 }
92
93 static void setup_query(Options* o, xmlNodePtr node, QueryTarget target) {
94 Query *q = g_slice_new0(Query);
95 g_array_append_val(o->queries, q);
96
97 q->target = target;
98
99 set_bool(node, "shaded", &q->shaded_on, &q->shaded_off);
100 set_bool(node, "maximized", &q->maxfull_on, &q->maxfull_off);
101 set_bool(node, "maximizedhorizontal", &q->maxhorz_on, &q->maxhorz_off);
102 set_bool(node, "maximizedvertical", &q->maxvert_on, &q->maxvert_off);
103 set_bool(node, "iconified", &q->iconic_on, &q->iconic_off);
104 set_bool(node, "focused", &q->focused, &q->unfocused);
105 set_bool(node, "urgent", &q->urgent_on, &q->urgent_off);
106 set_bool(node, "undecorated", &q->decor_off, &q->decor_on);
107 set_bool(node, "omnipresent", &q->omnipresent_on, &q->omnipresent_off);
108
109 xmlNodePtr n;
110 if ((n = obt_xml_find_node(node, "desktop"))) {
111 gchar *s;
112 if ((s = obt_xml_node_string(n))) {
113 if (!g_ascii_strcasecmp(s, "current"))
114 q->desktop_current = TRUE;
115 if (!g_ascii_strcasecmp(s, "other"))
116 q->desktop_other = TRUE;
117 else
118 q->desktop_number = atoi(s);
119 g_free(s);
120 }
121 }
122 if ((n = obt_xml_find_node(node, "activedesktop"))) {
123 q->screendesktop_number = obt_xml_node_int(n);
124 }
125 if ((n = obt_xml_find_node(node, "title"))) {
126 gchar *s, *type = NULL;
127 if ((s = obt_xml_node_string(n))) {
128 if (!obt_xml_attr_string(n, "type", &type) ||
129 !g_ascii_strcasecmp(type, "pattern"))
130 {
131 q->matchtitle = g_pattern_spec_new(s);
132 } else if (type && !g_ascii_strcasecmp(type, "regex")) {
133 q->regextitle = g_regex_new(s, 0, 0, NULL);
134 } else if (type && !g_ascii_strcasecmp(type, "exact")) {
135 q->exacttitle = g_strdup(s);
136 }
137 g_free(s);
138 }
139 }
140 if ((n = obt_xml_find_node(node, "monitor"))) {
141 q->client_monitor = obt_xml_node_int(n);
142 }
143 }
144
145 static gpointer setup_func(xmlNodePtr node)
146 {
147 Options *o = g_slice_new0(Options);
148
149 gboolean zero_terminated = FALSE;
150 gboolean clear_to_zero_on_alloc = FALSE;
151 o->queries = g_array_new(zero_terminated,
152 clear_to_zero_on_alloc,
153 sizeof(Query*));
154
155 xmlNodePtr n;
156 if ((n = obt_xml_find_node(node, "then"))) {
157 xmlNodePtr m;
158
159 m = obt_xml_find_node(n->children, "action");
160 while (m) {
161 ObActionsAct *action = actions_parse(m);
162 if (action) o->thenacts = g_slist_append(o->thenacts, action);
163 m = obt_xml_find_node(m->next, "action");
164 }
165 }
166 if ((n = obt_xml_find_node(node, "else"))) {
167 xmlNodePtr m;
168
169 m = obt_xml_find_node(n->children, "action");
170 while (m) {
171 ObActionsAct *action = actions_parse(m);
172 if (action) o->elseacts = g_slist_append(o->elseacts, action);
173 m = obt_xml_find_node(m->next, "action");
174 }
175 }
176
177 xmlNodePtr query_node = obt_xml_find_node(node, "query");
178 if (!query_node) {
179 /* The default query if none is specified. It uses the conditions
180 found in the action's node. */
181 setup_query(o,
182 node,
183 QUERY_TARGET_IS_ACTION_TARGET);
184 } else {
185 while (query_node) {
186 QueryTarget query_target = QUERY_TARGET_IS_ACTION_TARGET;
187 if (obt_xml_attr_contains(query_node, "target", "focus"))
188 query_target = QUERY_TARGET_IS_FOCUS_TARGET;
189
190 setup_query(o, query_node->children, query_target);
191
192 query_node = obt_xml_find_node(query_node->next, "query");
193 }
194 }
195
196 return o;
197 }
198
199 static void free_func(gpointer options)
200 {
201 Options *o = options;
202
203 guint i;
204 for (i = 0; i < o->queries->len; ++i) {
205 Query *q = g_array_index(o->queries, Query*, i);
206
207 if (q->matchtitle)
208 g_pattern_spec_free(q->matchtitle);
209 if (q->regextitle)
210 g_regex_unref(q->regextitle);
211 if (q->exacttitle)
212 g_free(q->exacttitle);
213
214 g_slice_free(Query, q);
215 }
216
217 while (o->thenacts) {
218 actions_act_unref(o->thenacts->data);
219 o->thenacts = g_slist_delete_link(o->thenacts, o->thenacts);
220 }
221 while (o->elseacts) {
222 actions_act_unref(o->elseacts->data);
223 o->elseacts = g_slist_delete_link(o->elseacts, o->elseacts);
224 }
225
226 g_array_unref(o->queries);
227 g_slice_free(Options, o);
228 }
229
230 /* Always return FALSE because its not interactive */
231 static gboolean run_func(ObActionsData *data, gpointer options)
232 {
233 Options *o = options;
234 ObClient *action_target = data->client;
235 gboolean is_true = TRUE;
236
237 guint i;
238 for (i = 0; i < o->queries->len; ++i) {
239 Query *q = g_array_index(o->queries, Query*, i);
240 ObClient *query_target = NULL;
241
242 switch (q->target) {
243 case QUERY_TARGET_IS_ACTION_TARGET:
244 query_target = data->client;
245 break;
246 case QUERY_TARGET_IS_FOCUS_TARGET:
247 query_target = focus_client;
248 break;
249 }
250
251 /* If there's no client to query, then false. */
252 is_true &= query_target != NULL;
253
254 if (q->shaded_on)
255 is_true &= query_target->shaded;
256 if (q->shaded_off)
257 is_true &= !query_target->shaded;
258
259 if (q->iconic_on)
260 is_true &= query_target->iconic;
261 if (q->iconic_off)
262 is_true &= !query_target->iconic;
263
264 if (q->maxhorz_on)
265 is_true &= query_target->max_horz;
266 if (q->maxhorz_off)
267 is_true &= !query_target->max_horz;
268
269 if (q->maxvert_on)
270 is_true &= query_target->max_vert;
271 if (q->maxvert_off)
272 is_true &= !query_target->max_vert;
273
274 gboolean is_max_full =
275 query_target->max_vert && query_target->max_horz;
276 if (q->maxfull_on)
277 is_true &= is_max_full;
278 if (q->maxfull_off)
279 is_true &= !is_max_full;
280
281 if (q->focused)
282 is_true &= query_target == focus_client;
283 if (q->unfocused)
284 is_true &= query_target != focus_client;
285
286 gboolean is_urgent =
287 query_target->urgent || query_target->demands_attention;
288 if (q->urgent_on)
289 is_true &= is_urgent;
290 if (q->urgent_off)
291 is_true &= !is_urgent;
292
293 gboolean has_visible_title_bar =
294 !query_target->undecorated &&
295 (query_target->decorations & OB_FRAME_DECOR_TITLEBAR);
296 if (q->decor_on)
297 is_true &= has_visible_title_bar;
298 if (q->decor_off)
299 is_true &= !has_visible_title_bar;
300
301 if (q->omnipresent_on)
302 is_true &= query_target->desktop == DESKTOP_ALL;
303 if (q->omnipresent_off)
304 is_true &= query_target->desktop != DESKTOP_ALL;
305
306 gboolean is_on_current_desktop =
307 query_target->desktop == screen_desktop ||
308 query_target->desktop == DESKTOP_ALL;
309 if (q->desktop_current)
310 is_true &= is_on_current_desktop;
311 if (q->desktop_other)
312 is_true &= !is_on_current_desktop;
313
314 if (q->desktop_number) {
315 gboolean is_on_desktop =
316 query_target->desktop == q->desktop_number - 1 ||
317 query_target->desktop == DESKTOP_ALL;
318 is_true &= is_on_desktop;
319 }
320
321 if (q->screendesktop_number)
322 is_true &= screen_desktop == q->screendesktop_number - 1;
323
324 if (q->matchtitle) {
325 is_true &= g_pattern_match_string(q->matchtitle,
326 query_target->original_title);
327 }
328 if (q->regextitle) {
329 is_true &= g_regex_match(q->regextitle,
330 query_target->original_title,
331 0,
332 NULL);
333 }
334 if (q->exacttitle)
335 is_true &= !strcmp(q->exacttitle, query_target->original_title);
336
337 if (q->client_monitor)
338 is_true &= client_monitor(query_target) == q->client_monitor - 1;
339
340 }
341
342 GSList *acts;
343 if (is_true)
344 acts = o->thenacts;
345 else
346 acts = o->elseacts;
347
348 actions_run_acts(acts, data->uact, data->state,
349 data->x, data->y, data->button,
350 data->context, action_target);
351
352 return FALSE;
353 }
This page took 0.045724 seconds and 3 git commands to generate.