]> icculus.org git repositories - mikachu/openbox.git/blob - openbox/actions/directionalwindows.c
Merge branch 'master' into 3.4
[mikachu/openbox.git] / openbox / actions / directionalwindows.c
1 #include "openbox/actions.h"
2 #include "openbox/event.h"
3 #include "openbox/focus_cycle.h"
4 #include "openbox/openbox.h"
5 #include "openbox/client.h"
6 #include "openbox/misc.h"
7 #include "gettext.h"
8
9 typedef struct {
10     gboolean interactive;
11     gboolean dialog;
12     gboolean dock_windows;
13     gboolean desktop_windows;
14     ObDirection direction;
15     GSList *actions;
16 } Options;
17
18 static gboolean cycling = FALSE;
19
20 static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
21 static gpointer setup_north_cycle_func(ObParseInst *i,
22                                        xmlDocPtr doc, xmlNodePtr node);
23 static gpointer setup_south_cycle_func(ObParseInst *i,
24                                        xmlDocPtr doc, xmlNodePtr node);
25 static gpointer setup_east_cycle_func(ObParseInst *i,
26                                       xmlDocPtr doc, xmlNodePtr node);
27 static gpointer setup_west_cycle_func(ObParseInst *i,
28                                       xmlDocPtr doc, xmlNodePtr node);
29 static gpointer setup_northwest_cycle_func(ObParseInst *i,
30                                            xmlDocPtr doc, xmlNodePtr node);
31 static gpointer setup_northeast_cycle_func(ObParseInst *i,
32                                            xmlDocPtr doc, xmlNodePtr node);
33 static gpointer setup_southwest_cycle_func(ObParseInst *i,
34                                            xmlDocPtr doc, xmlNodePtr node);
35 static gpointer setup_southeast_cycle_func(ObParseInst *i,
36                                            xmlDocPtr doc, xmlNodePtr node);
37 static gpointer setup_north_target_func(ObParseInst *i,
38                                         xmlDocPtr doc, xmlNodePtr node);
39 static gpointer setup_south_target_func(ObParseInst *i,
40                                         xmlDocPtr doc, xmlNodePtr node);
41 static gpointer setup_east_target_func(ObParseInst *i,
42                                        xmlDocPtr doc, xmlNodePtr node);
43 static gpointer setup_west_target_func(ObParseInst *i,
44                                        xmlDocPtr doc, xmlNodePtr node);
45 static gpointer setup_northwest_target_func(ObParseInst *i,
46                                             xmlDocPtr doc, xmlNodePtr node);
47 static gpointer setup_northeast_target_func(ObParseInst *i,
48                                             xmlDocPtr doc, xmlNodePtr node);
49 static gpointer setup_southwest_target_func(ObParseInst *i,
50                                             xmlDocPtr doc, xmlNodePtr node);
51 static gpointer setup_southeast_target_func(ObParseInst *i,
52                                             xmlDocPtr doc, xmlNodePtr node);
53 static void     free_func(gpointer options);
54 static gboolean run_func(ObActionsData *data, gpointer options);
55 static gboolean i_input_func(guint initial_state,
56                              XEvent *e,
57                              gpointer options,
58                              gboolean *used);
59 static void     i_cancel_func(gpointer options);
60
61 static void     end_cycle(gboolean cancel, guint state, Options *o);
62
63 void action_directionalwindows_startup()
64 {
65     actions_register("DirectionalFocusNorth", setup_north_cycle_func,
66                      free_func, run_func, i_input_func, i_cancel_func);
67     actions_register("DirectionalFocusSouth", setup_south_cycle_func,
68                      free_func, run_func, i_input_func, i_cancel_func);
69     actions_register("DirectionalFocusWest", setup_west_cycle_func,
70                      free_func, run_func, i_input_func, i_cancel_func);
71     actions_register("DirectionalFocusEast", setup_east_cycle_func,
72                      free_func, run_func, i_input_func, i_cancel_func);
73     actions_register("DirectionalFocusNorthWest", setup_northwest_cycle_func,
74                      free_func, run_func, i_input_func, i_cancel_func);
75     actions_register("DirectionalFocusNorthEast", setup_northeast_cycle_func,
76                      free_func, run_func, i_input_func, i_cancel_func);
77     actions_register("DirectionalFocusSouthWest", setup_southwest_cycle_func,
78                      free_func, run_func, i_input_func, i_cancel_func);
79     actions_register("DirectionalFocusSouthEast", setup_southeast_cycle_func,
80                      free_func, run_func, i_input_func, i_cancel_func);
81     actions_register("DirectionalTargetNorth", setup_north_target_func,
82                      free_func, run_func, i_input_func, i_cancel_func);
83     actions_register("DirectionalTargetSouth", setup_south_target_func,
84                      free_func, run_func, i_input_func, i_cancel_func);
85     actions_register("DirectionalTargetWest", setup_west_target_func,
86                      free_func, run_func, i_input_func, i_cancel_func);
87     actions_register("DirectionalTargetEast", setup_east_target_func,
88                      free_func, run_func, i_input_func, i_cancel_func);
89     actions_register("DirectionalTargetNorthWest", setup_northwest_target_func,
90                      free_func, run_func, i_input_func, i_cancel_func);
91     actions_register("DirectionalTargetNorthEast", setup_northeast_target_func,
92                      free_func, run_func, i_input_func, i_cancel_func);
93     actions_register("DirectionalTargetSouthWest", setup_southwest_target_func,
94                      free_func, run_func, i_input_func, i_cancel_func);
95     actions_register("DirectionalTargetSouthEast", setup_southeast_target_func,
96                      free_func, run_func, i_input_func, i_cancel_func);
97 }
98
99 static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
100 {
101     xmlNodePtr n;
102     Options *o;
103
104     o = g_new0(Options, 1);
105     o->dialog = TRUE;
106
107     if ((n = parse_find_node("dialog", node)))
108         o->dialog = parse_bool(doc, n);
109     if ((n = parse_find_node("panels", node)))
110         o->dock_windows = parse_bool(doc, n);
111     if ((n = parse_find_node("desktop", node)))
112         o->desktop_windows = parse_bool(doc, n);
113
114     if ((n = parse_find_node("finalactions", node))) {
115         xmlNodePtr m;
116
117         m = parse_find_node("action", n->xmlChildrenNode);
118         while (m) {
119             ObActionsAct *action = actions_parse(i, doc, m);
120             if (action) o->actions = g_slist_prepend(o->actions, action);
121             m = parse_find_node("action", m->next);
122         }
123     }
124     else {
125         o->actions = g_slist_prepend(o->actions,
126                                      actions_parse_string("Focus"));
127         o->actions = g_slist_prepend(o->actions,
128                                      actions_parse_string("Raise"));
129         o->actions = g_slist_prepend(o->actions,
130                                      actions_parse_string("Unshade"));
131     }
132
133     return o;
134 }
135
136 static gpointer setup_north_cycle_func(ObParseInst *i,
137                                        xmlDocPtr doc, xmlNodePtr node)
138 {
139     Options *o = setup_func(i, doc, node);
140     o->interactive = TRUE;
141     o->direction = OB_DIRECTION_NORTH;
142     return o;
143 }
144
145 static gpointer setup_south_cycle_func(ObParseInst *i,
146                                        xmlDocPtr doc, xmlNodePtr node)
147 {
148     Options *o = setup_func(i, doc, node);
149     o->interactive = TRUE;
150     o->direction = OB_DIRECTION_SOUTH;
151     return o;
152 }
153
154 static gpointer setup_east_cycle_func(ObParseInst *i,
155                                       xmlDocPtr doc, xmlNodePtr node)
156 {
157     Options *o = setup_func(i, doc, node);
158     o->interactive = TRUE;
159     o->direction = OB_DIRECTION_EAST;
160     return o;
161 }
162
163 static gpointer setup_west_cycle_func(ObParseInst *i,
164                                       xmlDocPtr doc, xmlNodePtr node)
165 {
166     Options *o = setup_func(i, doc, node);
167     o->interactive = TRUE;
168     o->direction = OB_DIRECTION_WEST;
169     return o;
170 }
171
172 static gpointer setup_northwest_cycle_func(ObParseInst *i,
173                                            xmlDocPtr doc, xmlNodePtr node)
174 {
175     Options *o = setup_func(i, doc, node);
176     o->interactive = TRUE;
177     o->direction = OB_DIRECTION_NORTHWEST;
178     return o;
179 }
180
181 static gpointer setup_northeast_cycle_func(ObParseInst *i,
182                                            xmlDocPtr doc, xmlNodePtr node)
183 {
184     Options *o = setup_func(i, doc, node);
185     o->interactive = TRUE;
186     o->direction = OB_DIRECTION_EAST;
187     return o;
188 }
189
190 static gpointer setup_southwest_cycle_func(ObParseInst *i,
191                                            xmlDocPtr doc, xmlNodePtr node)
192 {
193     Options *o = setup_func(i, doc, node);
194     o->interactive = TRUE;
195     o->direction = OB_DIRECTION_SOUTHWEST;
196     return o;
197 }
198
199 static gpointer setup_southeast_cycle_func(ObParseInst *i,
200                                            xmlDocPtr doc, xmlNodePtr node)
201 {
202     Options *o = setup_func(i, doc, node);
203     o->interactive = TRUE;
204     o->direction = OB_DIRECTION_SOUTHEAST;
205     return o;
206 }
207
208 static gpointer setup_north_target_func(ObParseInst *i,
209                                         xmlDocPtr doc, xmlNodePtr node)
210 {
211     Options *o = setup_func(i, doc, node);
212     o->interactive = FALSE;
213     o->direction = OB_DIRECTION_NORTH;
214     return o;
215 }
216
217 static gpointer setup_south_target_func(ObParseInst *i,
218                                         xmlDocPtr doc, xmlNodePtr node)
219 {
220     Options *o = setup_func(i, doc, node);
221     o->interactive = FALSE;
222     o->direction = OB_DIRECTION_SOUTH;
223     return o;
224 }
225
226 static gpointer setup_east_target_func(ObParseInst *i,
227                                        xmlDocPtr doc, xmlNodePtr node)
228 {
229     Options *o = setup_func(i, doc, node);
230     o->interactive = FALSE;
231     o->direction = OB_DIRECTION_EAST;
232     return o;
233 }
234
235 static gpointer setup_west_target_func(ObParseInst *i,
236                                        xmlDocPtr doc, xmlNodePtr node)
237 {
238     Options *o = setup_func(i, doc, node);
239     o->interactive = FALSE;
240     o->direction = OB_DIRECTION_WEST;
241     return o;
242 }
243
244 static gpointer setup_northwest_target_func(ObParseInst *i,
245                                             xmlDocPtr doc, xmlNodePtr node)
246 {
247     Options *o = setup_func(i, doc, node);
248     o->interactive = FALSE;
249     o->direction = OB_DIRECTION_NORTHWEST;
250     return o;
251 }
252
253 static gpointer setup_northeast_target_func(ObParseInst *i,
254                                             xmlDocPtr doc, xmlNodePtr node)
255 {
256     Options *o = setup_func(i, doc, node);
257     o->interactive = FALSE;
258     o->direction = OB_DIRECTION_NORTHEAST;
259     return o;
260 }
261
262 static gpointer setup_southwest_target_func(ObParseInst *i,
263                                             xmlDocPtr doc, xmlNodePtr node)
264 {
265     Options *o = setup_func(i, doc, node);
266     o->interactive = FALSE;
267     o->direction = OB_DIRECTION_SOUTHWEST;
268     return o;
269 }
270
271 static gpointer setup_southeast_target_func(ObParseInst *i,
272                                             xmlDocPtr doc, xmlNodePtr node)
273 {
274     Options *o = setup_func(i, doc, node);
275     o->interactive = FALSE;
276     o->direction = OB_DIRECTION_SOUTHEAST;
277     return o;
278 }
279
280 static void free_func(gpointer options)
281 {
282     Options *o = options;
283
284     while (o->actions) {
285         actions_act_unref(o->actions->data);
286         o->actions = g_slist_delete_link(o->actions, o->actions);
287     }
288
289     g_free(o);
290 }
291
292 static gboolean run_func(ObActionsData *data, gpointer options)
293 {
294     Options *o = options;
295
296     if (!o->interactive)
297         end_cycle(FALSE, data->state, o);
298     else {
299         focus_directional_cycle(o->direction,
300                                 o->dock_windows,
301                                 o->desktop_windows,
302                                 TRUE,
303                                 o->dialog,
304                                 FALSE, FALSE);
305         cycling = TRUE;
306     }
307
308     return o->interactive;
309 }
310
311 static gboolean i_input_func(guint initial_state,
312                              XEvent *e,
313                              gpointer options,
314                              gboolean *used)
315 {
316     if (e->type == KeyPress) {
317         /* Escape cancels no matter what */
318         if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) {
319             end_cycle(TRUE, e->xkey.state, options);
320             return FALSE;
321         }
322
323         /* There were no modifiers and they pressed enter */
324         else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN) &&
325                  !initial_state)
326         {
327             end_cycle(FALSE, e->xkey.state, options);
328             return FALSE;
329         }
330     }
331     /* They released the modifiers */
332     else if (e->type == KeyRelease && initial_state &&
333              (e->xkey.state & initial_state) == 0)
334     {
335         end_cycle(FALSE, e->xkey.state, options);
336         return FALSE;
337     }
338
339     return TRUE;
340 }
341
342 static void i_cancel_func(gpointer options)
343 {
344     /* we get cancelled when we move focus, but we're not cycling anymore, so
345        just ignore that */
346     if (cycling)
347         end_cycle(TRUE, 0, options);
348 }
349
350 static void end_cycle(gboolean cancel, guint state, Options *o)
351 {
352     struct _ObClient *ft;
353
354     ft = focus_directional_cycle(o->direction,
355                                  o->dock_windows,
356                                  o->desktop_windows,
357                                  o->interactive,
358                                  o->dialog,
359                                  TRUE, cancel);
360     cycling = FALSE;
361
362     if (ft)
363         actions_run_acts(o->actions, OB_USER_ACTION_KEYBOARD_KEY,
364                          state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);
365 }