1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 action_list_run.c for the Openbox window manager
4 Copyright (c) 2011 Dana Jansens
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 See the COPYING file for a copy of the GNU General Public License.
19 #include "action_list_run.h"
21 #include "action_filter.h"
22 #include "action_list.h"
24 #include "client_set.h"
28 static gboolean run_list(ObActionList *acts, const ObActionListRun *data,
30 static gboolean run_filter(ObActionList *acts, const ObActionListRun *data,
33 gboolean action_list_run(ObActionList *acts,
40 struct _ObClient *client)
42 ObActionListRun action_data;
44 if (acts == NULL) return FALSE;
46 /* Don't save the initial mod state when running things from the menu */
47 if (uact == OB_USER_ACTION_MENU_SELECTION)
49 /* If x and y are < 0 then use the current pointer position */
51 screen_pointer_pos(&x, &y);
53 action_data.user_act = uact;
54 action_data.mod_state = state;
55 action_data.pointer_x = x;
56 action_data.pointer_y = y;
57 action_data.pointer_button = button;
58 action_data.pointer_context = con;
59 action_data.target = client;
60 /* if a pointer started the event clicking on a window, it must be under
62 action_data.pointer_over = client ? client : client_under_pointer();
64 return run_list(acts, &action_data, NULL);
67 static gboolean run_list(ObActionList *acts, const ObActionListRun *data,
73 if (!acts) return FALSE;
74 if (acts->isfilterset) return run_filter(acts, data, set);
76 /* if we're not given a filter, then make a default filter set,
77 but don't pass it on to our siblings in the list. */
80 switch (action_default_filter(acts->u.action)) {
81 case OB_ACTION_DEFAULT_FILTER_SINGLE:
82 myset = client_set_single(data->target); break;
83 case OB_ACTION_DEFAULT_FILTER_EMPTY:
84 myset = client_set_empty(); break;
85 case OB_ACTION_DEFAULT_FILTER_ALL:
86 myset = client_set_all(); break;
87 case OB_NUM_ACTION_DEFAULT_FILTERS:
88 default: g_assert_not_reached();
92 interactive = action_run(acts->u.action, data, myset);
93 if (set != myset) client_set_destroy(myset);
95 if (interactive) return TRUE;
96 return run_list(acts->next, data, set);
99 static gboolean run_filter(ObActionList *acts, const ObActionListRun *data,
100 ObClientSet *incoming_set)
102 ObActionListTest *test = acts->u.f.test;
103 ObClientSet *set, *and_set;
105 gboolean interactive;
107 /* (a ^ b) | c | (d ^ e ^ f) | (g ^ h)
109 - for each test in the filter:
110 1) when we are at the first test, we make the test's set our current
112 2) when we are between two ORs, we add the test's set to our current
114 3) when we are to the left of an OR (or at the last test), we
115 intersect our test's set to the and_set, and then add the add_set
117 4) otherwise, we are to the left of an AND
118 a) if we are to the right of an OR, we make and_set our test's set
119 b) else we are between two ANDs, so we intersect and_set with
121 - finally, we take the intersection of our created set with the
125 g_assert(test != NULL);
129 set = action_filter_set(test->filter, data);
130 prev_and = test->and;
133 ObClientSet *const test_set = action_filter_set(test->filter, data);
135 if (!prev_and && test->next && !test->and)
136 set = client_set_union(set, test_set);
137 else if (!test->and || !test->next) {
139 and_set = client_set_intersection(and_set, test_set);
142 set = client_set_union(set, and_set);
147 and_set = client_set_intersection(and_set, test_set);
155 /* we don't want to destroy the incoming set so make a copy of it */
156 set = client_set_intersection(set, client_set_clone(incoming_set));
159 if (client_set_test_boolean(set))
160 interactive = run_list(acts->u.f.thendo, data, set);
162 interactive = run_list(acts->u.f.elsedo, data, set);
163 client_set_destroy(set);
165 if (interactive) return TRUE;
166 return run_list(acts->next, data, incoming_set);