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
;
69 static gpointer
setup_func(xmlNodePtr node
);
70 static void free_func(gpointer options
);
71 static gboolean
run_func(ObActionsData
*data
, gpointer options
);
73 void action_if_startup(void)
75 actions_register("If", setup_func
, free_func
, run_func
);
78 static inline void set_bool(xmlNodePtr node
,
85 if ((n
= obt_xml_find_node(node
, name
))) {
86 if (obt_xml_node_bool(n
))
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
);
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
);
110 if ((n
= obt_xml_find_node(node
, "desktop"))) {
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
;
118 q
->desktop_number
= atoi(s
);
122 if ((n
= obt_xml_find_node(node
, "activedesktop"))) {
123 q
->screendesktop_number
= obt_xml_node_int(n
);
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"))
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
);
140 if ((n
= obt_xml_find_node(node
, "monitor"))) {
141 q
->client_monitor
= obt_xml_node_int(n
);
145 static gpointer
setup_func(xmlNodePtr node
)
147 Options
*o
= g_slice_new0(Options
);
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
,
156 if ((n
= obt_xml_find_node(node
, "then"))) {
159 m
= obt_xml_find_node(n
->children
, "action");
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");
166 if ((n
= obt_xml_find_node(node
, "else"))) {
169 m
= obt_xml_find_node(n
->children
, "action");
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");
177 xmlNodePtr query_node
= obt_xml_find_node(node
, "query");
179 /* The default query if none is specified. It uses the conditions
180 found in the action's node. */
183 QUERY_TARGET_IS_ACTION_TARGET
);
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
;
190 setup_query(o
, query_node
->children
, query_target
);
192 query_node
= obt_xml_find_node(query_node
->next
, "query");
199 static void free_func(gpointer options
)
201 Options
*o
= options
;
204 for (i
= 0; i
< o
->queries
->len
; ++i
) {
205 Query
*q
= g_array_index(o
->queries
, Query
*, i
);
208 g_pattern_spec_free(q
->matchtitle
);
210 g_regex_unref(q
->regextitle
);
212 g_free(q
->exacttitle
);
214 g_slice_free(Query
, q
);
217 while (o
->thenacts
) {
218 actions_act_unref(o
->thenacts
->data
);
219 o
->thenacts
= g_slist_delete_link(o
->thenacts
, o
->thenacts
);
221 while (o
->elseacts
) {
222 actions_act_unref(o
->elseacts
->data
);
223 o
->elseacts
= g_slist_delete_link(o
->elseacts
, o
->elseacts
);
226 g_array_unref(o
->queries
);
227 g_slice_free(Options
, o
);
230 /* Always return FALSE because its not interactive */
231 static gboolean
run_func(ObActionsData
*data
, gpointer options
)
233 Options
*o
= options
;
234 ObClient
*action_target
= data
->client
;
235 gboolean is_true
= TRUE
;
238 for (i
= 0; i
< o
->queries
->len
; ++i
) {
239 Query
*q
= g_array_index(o
->queries
, Query
*, i
);
240 ObClient
*query_target
= NULL
;
243 case QUERY_TARGET_IS_ACTION_TARGET
:
244 query_target
= data
->client
;
246 case QUERY_TARGET_IS_FOCUS_TARGET
:
247 query_target
= focus_client
;
251 /* If there's no client to query, then false. */
252 is_true
&= query_target
!= NULL
;
255 is_true
&= query_target
->shaded
;
257 is_true
&= !query_target
->shaded
;
260 is_true
&= query_target
->iconic
;
262 is_true
&= !query_target
->iconic
;
265 is_true
&= query_target
->max_horz
;
267 is_true
&= !query_target
->max_horz
;
270 is_true
&= query_target
->max_vert
;
272 is_true
&= !query_target
->max_vert
;
274 gboolean is_max_full
=
275 query_target
->max_vert
&& query_target
->max_horz
;
277 is_true
&= is_max_full
;
279 is_true
&= !is_max_full
;
282 is_true
&= query_target
== focus_client
;
284 is_true
&= query_target
!= focus_client
;
287 query_target
->urgent
|| query_target
->demands_attention
;
289 is_true
&= is_urgent
;
291 is_true
&= !is_urgent
;
293 gboolean has_visible_title_bar
=
294 !query_target
->undecorated
&&
295 (query_target
->decorations
& OB_FRAME_DECOR_TITLEBAR
);
297 is_true
&= has_visible_title_bar
;
299 is_true
&= !has_visible_title_bar
;
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
;
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
;
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
;
321 if (q
->screendesktop_number
)
322 is_true
&= screen_desktop
== q
->screendesktop_number
- 1;
325 is_true
&= g_pattern_match_string(q
->matchtitle
,
326 query_target
->original_title
);
329 is_true
&= g_regex_match(q
->regextitle
,
330 query_target
->original_title
,
335 is_true
&= !strcmp(q
->exacttitle
, query_target
->original_title
);
337 if (q
->client_monitor
)
338 is_true
&= client_monitor(query_target
) == q
->client_monitor
- 1;
348 actions_run_acts(acts
, data
->uact
, data
->state
,
349 data
->x
, data
->y
, data
->button
,
350 data
->context
, action_target
);