1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 if.c for the Openbox window manager
4 Copyright (c) 2007 Mikael Magnusson
5 Copyright (c) 2007 Dana Jansens
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.
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.
17 See the COPYING file for a copy of the GNU General Public License.
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"
29 QUERY_TARGET_IS_ACTION_TARGET
,
30 QUERY_TARGET_IS_FOCUS_TARGET
,
51 gboolean omnipresent_on
;
52 gboolean omnipresent_off
;
53 gboolean desktop_current
;
54 gboolean desktop_other
;
56 guint screendesktop_number
;
58 GPatternSpec
*matchtitle
;
70 static gpointer
setup_func(xmlNodePtr node
);
71 static void free_func(gpointer options
);
72 static gboolean
run_func_if(ObActionsData
*data
, gpointer options
);
73 static gboolean
run_func_stop(ObActionsData
*data
, gpointer options
);
74 static gboolean
run_func_foreach(ObActionsData
*data
, gpointer options
);
76 void action_if_startup(void)
78 actions_register("If", setup_func
, free_func
, run_func_if
);
79 actions_register("Stop", NULL
, NULL
, run_func_stop
);
80 actions_register("ForEach", setup_func
, free_func
, run_func_foreach
);
82 actions_set_can_stop("Stop", TRUE
);
85 static inline void set_bool(xmlNodePtr node
,
92 if ((n
= obt_xml_find_node(node
, name
))) {
93 if (obt_xml_node_bool(n
))
100 static void setup_query(Options
* o
, xmlNodePtr node
, QueryTarget target
) {
101 Query
*q
= g_slice_new0(Query
);
102 g_array_append_val(o
->queries
, q
);
106 set_bool(node
, "shaded", &q
->shaded_on
, &q
->shaded_off
);
107 set_bool(node
, "maximized", &q
->maxfull_on
, &q
->maxfull_off
);
108 set_bool(node
, "maximizedhorizontal", &q
->maxhorz_on
, &q
->maxhorz_off
);
109 set_bool(node
, "maximizedvertical", &q
->maxvert_on
, &q
->maxvert_off
);
110 set_bool(node
, "iconified", &q
->iconic_on
, &q
->iconic_off
);
111 set_bool(node
, "focused", &q
->focused
, &q
->unfocused
);
112 set_bool(node
, "urgent", &q
->urgent_on
, &q
->urgent_off
);
113 set_bool(node
, "undecorated", &q
->decor_off
, &q
->decor_on
);
114 set_bool(node
, "omnipresent", &q
->omnipresent_on
, &q
->omnipresent_off
);
117 if ((n
= obt_xml_find_node(node
, "desktop"))) {
119 if ((s
= obt_xml_node_string(n
))) {
120 if (!g_ascii_strcasecmp(s
, "current"))
121 q
->desktop_current
= TRUE
;
122 if (!g_ascii_strcasecmp(s
, "other"))
123 q
->desktop_other
= TRUE
;
125 q
->desktop_number
= atoi(s
);
129 if ((n
= obt_xml_find_node(node
, "activedesktop"))) {
130 q
->screendesktop_number
= obt_xml_node_int(n
);
132 if ((n
= obt_xml_find_node(node
, "title"))) {
133 gchar
*s
, *type
= NULL
;
134 if ((s
= obt_xml_node_string(n
))) {
135 if (!obt_xml_attr_string(n
, "type", &type
) ||
136 !g_ascii_strcasecmp(type
, "pattern"))
138 q
->matchtitle
= g_pattern_spec_new(s
);
139 } else if (type
&& !g_ascii_strcasecmp(type
, "regex")) {
140 q
->regextitle
= g_regex_new(s
, 0, 0, NULL
);
141 } else if (type
&& !g_ascii_strcasecmp(type
, "exact")) {
142 q
->exacttitle
= g_strdup(s
);
147 if ((n
= obt_xml_find_node(node
, "monitor"))) {
148 q
->client_monitor
= obt_xml_node_int(n
);
152 static gpointer
setup_func(xmlNodePtr node
)
154 Options
*o
= g_slice_new0(Options
);
156 gboolean zero_terminated
= FALSE
;
157 gboolean clear_to_zero_on_alloc
= FALSE
;
158 o
->queries
= g_array_new(zero_terminated
,
159 clear_to_zero_on_alloc
,
163 if ((n
= obt_xml_find_node(node
, "then"))) {
166 m
= obt_xml_find_node(n
->children
, "action");
168 ObActionsAct
*action
= actions_parse(m
);
169 if (action
) o
->thenacts
= g_slist_append(o
->thenacts
, action
);
170 m
= obt_xml_find_node(m
->next
, "action");
173 if ((n
= obt_xml_find_node(node
, "else"))) {
176 m
= obt_xml_find_node(n
->children
, "action");
178 ObActionsAct
*action
= actions_parse(m
);
179 if (action
) o
->elseacts
= g_slist_append(o
->elseacts
, action
);
180 m
= obt_xml_find_node(m
->next
, "action");
184 xmlNodePtr query_node
= obt_xml_find_node(node
, "query");
186 /* The default query if none is specified. It uses the conditions
187 found in the action's node. */
190 QUERY_TARGET_IS_ACTION_TARGET
);
193 QueryTarget query_target
= QUERY_TARGET_IS_ACTION_TARGET
;
194 if (obt_xml_attr_contains(query_node
, "target", "focus"))
195 query_target
= QUERY_TARGET_IS_FOCUS_TARGET
;
197 setup_query(o
, query_node
->children
, query_target
);
199 query_node
= obt_xml_find_node(query_node
->next
, "query");
206 static void free_func(gpointer options
)
208 Options
*o
= options
;
211 for (i
= 0; i
< o
->queries
->len
; ++i
) {
212 Query
*q
= g_array_index(o
->queries
, Query
*, i
);
215 g_pattern_spec_free(q
->matchtitle
);
217 g_regex_unref(q
->regextitle
);
219 g_free(q
->exacttitle
);
221 g_slice_free(Query
, q
);
224 while (o
->thenacts
) {
225 actions_act_unref(o
->thenacts
->data
);
226 o
->thenacts
= g_slist_delete_link(o
->thenacts
, o
->thenacts
);
228 while (o
->elseacts
) {
229 actions_act_unref(o
->elseacts
->data
);
230 o
->elseacts
= g_slist_delete_link(o
->elseacts
, o
->elseacts
);
233 g_array_unref(o
->queries
);
234 g_slice_free(Options
, o
);
237 /* Always return FALSE because its not interactive */
238 static gboolean
run_func_if(ObActionsData
*data
, gpointer options
)
240 Options
*o
= options
;
241 ObClient
*action_target
= data
->client
;
242 gboolean is_true
= TRUE
;
245 for (i
= 0; i
< o
->queries
->len
; ++i
) {
246 Query
*q
= g_array_index(o
->queries
, Query
*, i
);
247 ObClient
*query_target
= NULL
;
250 case QUERY_TARGET_IS_ACTION_TARGET
:
251 query_target
= data
->client
;
253 case QUERY_TARGET_IS_FOCUS_TARGET
:
254 query_target
= focus_client
;
258 /* If there's no client to query, then false. */
259 is_true
&= query_target
!= NULL
;
262 is_true
&= query_target
->shaded
;
264 is_true
&= !query_target
->shaded
;
267 is_true
&= query_target
->iconic
;
269 is_true
&= !query_target
->iconic
;
272 is_true
&= query_target
->max_horz
;
274 is_true
&= !query_target
->max_horz
;
277 is_true
&= query_target
->max_vert
;
279 is_true
&= !query_target
->max_vert
;
281 gboolean is_max_full
=
282 query_target
->max_vert
&& query_target
->max_horz
;
284 is_true
&= is_max_full
;
286 is_true
&= !is_max_full
;
289 is_true
&= query_target
== focus_client
;
291 is_true
&= query_target
!= focus_client
;
294 query_target
->urgent
|| query_target
->demands_attention
;
296 is_true
&= is_urgent
;
298 is_true
&= !is_urgent
;
300 gboolean has_visible_title_bar
=
301 !query_target
->undecorated
&&
302 (query_target
->decorations
& OB_FRAME_DECOR_TITLEBAR
);
304 is_true
&= has_visible_title_bar
;
306 is_true
&= !has_visible_title_bar
;
308 if (q
->omnipresent_on
)
309 is_true
&= query_target
->desktop
== DESKTOP_ALL
;
310 if (q
->omnipresent_off
)
311 is_true
&= query_target
->desktop
!= DESKTOP_ALL
;
313 gboolean is_on_current_desktop
=
314 query_target
->desktop
== screen_desktop
||
315 query_target
->desktop
== DESKTOP_ALL
;
316 if (q
->desktop_current
)
317 is_true
&= is_on_current_desktop
;
318 if (q
->desktop_other
)
319 is_true
&= !is_on_current_desktop
;
321 if (q
->desktop_number
) {
322 gboolean is_on_desktop
=
323 query_target
->desktop
== q
->desktop_number
- 1 ||
324 query_target
->desktop
== DESKTOP_ALL
;
325 is_true
&= is_on_desktop
;
328 if (q
->screendesktop_number
)
329 is_true
&= screen_desktop
== q
->screendesktop_number
- 1;
332 is_true
&= g_pattern_match_string(q
->matchtitle
,
333 query_target
->original_title
);
336 is_true
&= g_regex_match(q
->regextitle
,
337 query_target
->original_title
,
342 is_true
&= !strcmp(q
->exacttitle
, query_target
->original_title
);
344 if (q
->client_monitor
)
345 is_true
&= client_monitor(query_target
) == q
->client_monitor
- 1;
355 actions_run_acts(acts
, data
->uact
, data
->state
,
356 data
->x
, data
->y
, data
->button
,
357 data
->context
, action_target
);
362 static gboolean
run_func_foreach(ObActionsData
*data
, gpointer options
)
365 Options
*o
= options
;
369 for (it
= client_list
; it
; it
= g_list_next(it
)) {
370 data
->client
= it
->data
;
371 run_func_if(data
, options
);
380 static gboolean
run_func_stop(ObActionsData
*data
, gpointer options
)
382 Options
*o
= options
;
384 /* This stops the loop above so we don't invoke actions on any more
388 /* TRUE causes actions_run_acts to not run further actions on the current