]> Dogcows Code - chaz/openbox/blob - openbox/actions/directionalwindows.c
0d1476c7936b3c1aab7b037c89524a015f534edc
[chaz/openbox] / openbox / actions / directionalwindows.c
1 #include "openbox/actions.h"
2 #include "openbox/event.h"
3 #include "openbox/stacking.h"
4 #include "openbox/window.h"
5 #include "openbox/focus_cycle.h"
6 #include "openbox/openbox.h"
7 #include "openbox/misc.h"
8 #include "gettext.h"
9
10 typedef struct {
11 gboolean interactive;
12 gboolean dialog;
13 gboolean dock_windows;
14 gboolean desktop_windows;
15 ObDirection direction;
16 gboolean bar;
17 gboolean raise;
18 GSList *actions;
19 } Options;
20
21 static gboolean cycling = FALSE;
22
23 static gpointer setup_func(xmlNodePtr node);
24 static gpointer setup_cycle_func(xmlNodePtr node,
25 ObActionsIPreFunc *pre,
26 ObActionsIInputFunc *input,
27 ObActionsICancelFunc *cancel,
28 ObActionsIPostFunc *post);
29 static gpointer setup_target_func(xmlNodePtr node);
30 static void free_func(gpointer options);
31 static gboolean run_func(ObActionsData *data, gpointer options);
32 static gboolean i_input_func(guint initial_state,
33 XEvent *e,
34 gpointer options,
35 gboolean *used);
36 static void i_cancel_func(gpointer options);
37
38 static void end_cycle(gboolean cancel, guint state, Options *o);
39
40 /* 3.4-compatibility */
41 static gpointer setup_north_cycle_func(xmlNodePtr node,
42 ObActionsIPreFunc *pre,
43 ObActionsIInputFunc *in,
44 ObActionsICancelFunc *c,
45 ObActionsIPostFunc *post);
46 static gpointer setup_south_cycle_func(xmlNodePtr node,
47 ObActionsIPreFunc *pre,
48 ObActionsIInputFunc *in,
49 ObActionsICancelFunc *c,
50 ObActionsIPostFunc *post);
51 static gpointer setup_east_cycle_func(xmlNodePtr node,
52 ObActionsIPreFunc *pre,
53 ObActionsIInputFunc *in,
54 ObActionsICancelFunc *c,
55 ObActionsIPostFunc *post);
56 static gpointer setup_west_cycle_func(xmlNodePtr node,
57 ObActionsIPreFunc *pre,
58 ObActionsIInputFunc *in,
59 ObActionsICancelFunc *c,
60 ObActionsIPostFunc *post);
61 static gpointer setup_northwest_cycle_func(xmlNodePtr node,
62 ObActionsIPreFunc *pre,
63 ObActionsIInputFunc *in,
64 ObActionsICancelFunc *c,
65 ObActionsIPostFunc *post);
66 static gpointer setup_northeast_cycle_func(xmlNodePtr node,
67 ObActionsIPreFunc *pre,
68 ObActionsIInputFunc *in,
69 ObActionsICancelFunc *c,
70 ObActionsIPostFunc *post);
71 static gpointer setup_southwest_cycle_func(xmlNodePtr node,
72 ObActionsIPreFunc *pre,
73 ObActionsIInputFunc *in,
74 ObActionsICancelFunc *c,
75 ObActionsIPostFunc *post);
76 static gpointer setup_southeast_cycle_func(xmlNodePtr node,
77 ObActionsIPreFunc *pre,
78 ObActionsIInputFunc *in,
79 ObActionsICancelFunc *c,
80 ObActionsIPostFunc *post);
81 static gpointer setup_north_target_func(xmlNodePtr node);
82 static gpointer setup_south_target_func(xmlNodePtr node);
83 static gpointer setup_east_target_func(xmlNodePtr node);
84 static gpointer setup_west_target_func(xmlNodePtr node);
85 static gpointer setup_northwest_target_func(xmlNodePtr node);
86 static gpointer setup_northeast_target_func(xmlNodePtr node);
87 static gpointer setup_southwest_target_func(xmlNodePtr node);
88 static gpointer setup_southeast_target_func(xmlNodePtr node);
89
90 void action_directionalwindows_startup(void)
91 {
92 actions_register_i("DirectionalCycleWindows", setup_cycle_func, free_func,
93 run_func);
94 actions_register("DirectionalTargetWindow", setup_target_func, free_func,
95 run_func);
96 /* 3.4-compatibility */
97 actions_register_i("DirectionalFocusNorth", setup_north_cycle_func,
98 free_func, run_func);
99 actions_register_i("DirectionalFocusSouth", setup_south_cycle_func,
100 free_func, run_func);
101 actions_register_i("DirectionalFocusWest", setup_west_cycle_func,
102 free_func, run_func);
103 actions_register_i("DirectionalFocusEast", setup_east_cycle_func,
104 free_func, run_func);
105 actions_register_i("DirectionalFocusNorthWest", setup_northwest_cycle_func,
106 free_func, run_func);
107 actions_register_i("DirectionalFocusNorthEast", setup_northeast_cycle_func,
108 free_func, run_func);
109 actions_register_i("DirectionalFocusSouthWest", setup_southwest_cycle_func,
110 free_func, run_func);
111 actions_register_i("DirectionalFocusSouthEast", setup_southeast_cycle_func,
112 free_func, run_func);
113 actions_register("DirectionalTargetNorth", setup_north_target_func,
114 free_func, run_func);
115 actions_register("DirectionalTargetSouth", setup_south_target_func,
116 free_func, run_func);
117 actions_register("DirectionalTargetWest", setup_west_target_func,
118 free_func, run_func);
119 actions_register("DirectionalTargetEast", setup_east_target_func,
120 free_func, run_func);
121 actions_register("DirectionalTargetNorthWest", setup_northwest_target_func,
122 free_func, run_func);
123 actions_register("DirectionalTargetNorthEast", setup_northeast_target_func,
124 free_func, run_func);
125 actions_register("DirectionalTargetSouthWest", setup_southwest_target_func,
126 free_func, run_func);
127 actions_register("DirectionalTargetSouthEast", setup_southeast_target_func,
128 free_func, run_func);
129 }
130
131 static gpointer setup_func(xmlNodePtr node)
132 {
133 xmlNodePtr n;
134 Options *o;
135
136 o = g_new0(Options, 1);
137 o->dialog = TRUE;
138 o->bar = TRUE;
139
140 if ((n = obt_parse_find_node(node, "dialog")))
141 o->dialog = obt_parse_node_bool(n);
142 if ((n = obt_parse_find_node(node, "bar")))
143 o->bar = obt_parse_node_bool(n);
144 if ((n = obt_parse_find_node(node, "raise")))
145 o->raise = obt_parse_node_bool(n);
146 if ((n = obt_parse_find_node(node, "panels")))
147 o->dock_windows = obt_parse_node_bool(n);
148 if ((n = obt_parse_find_node(node, "desktop")))
149 o->desktop_windows = obt_parse_node_bool(n);
150 if ((n = obt_parse_find_node(node, "direction"))) {
151 gchar *s = obt_parse_node_string(n);
152 if (!g_ascii_strcasecmp(s, "north") ||
153 !g_ascii_strcasecmp(s, "up"))
154 o->direction = OB_DIRECTION_NORTH;
155 else if (!g_ascii_strcasecmp(s, "northwest"))
156 o->direction = OB_DIRECTION_NORTHWEST;
157 else if (!g_ascii_strcasecmp(s, "northeast"))
158 o->direction = OB_DIRECTION_NORTHEAST;
159 else if (!g_ascii_strcasecmp(s, "west") ||
160 !g_ascii_strcasecmp(s, "left"))
161 o->direction = OB_DIRECTION_WEST;
162 else if (!g_ascii_strcasecmp(s, "east") ||
163 !g_ascii_strcasecmp(s, "right"))
164 o->direction = OB_DIRECTION_EAST;
165 else if (!g_ascii_strcasecmp(s, "south") ||
166 !g_ascii_strcasecmp(s, "down"))
167 o->direction = OB_DIRECTION_SOUTH;
168 else if (!g_ascii_strcasecmp(s, "southwest"))
169 o->direction = OB_DIRECTION_SOUTHWEST;
170 else if (!g_ascii_strcasecmp(s, "southeast"))
171 o->direction = OB_DIRECTION_SOUTHEAST;
172 g_free(s);
173 }
174
175 if ((n = obt_parse_find_node(node, "finalactions"))) {
176 xmlNodePtr m;
177
178 m = obt_parse_find_node(n->children, "action");
179 while (m) {
180 ObActionsAct *action = actions_parse(m);
181 if (action) o->actions = g_slist_append(o->actions, action);
182 m = obt_parse_find_node(m->next, "action");
183 }
184 }
185 else {
186 o->actions = g_slist_prepend(o->actions,
187 actions_parse_string("Focus"));
188 o->actions = g_slist_prepend(o->actions,
189 actions_parse_string("Raise"));
190 o->actions = g_slist_prepend(o->actions,
191 actions_parse_string("Unshade"));
192 }
193
194 return o;
195 }
196
197 static gpointer setup_cycle_func(xmlNodePtr node,
198 ObActionsIPreFunc *pre,
199 ObActionsIInputFunc *input,
200 ObActionsICancelFunc *cancel,
201 ObActionsIPostFunc *post)
202 {
203 Options *o = setup_func(node);
204 o->interactive = TRUE;
205 *input = i_input_func;
206 *cancel = i_cancel_func;
207 return o;
208 }
209
210 static gpointer setup_target_func(xmlNodePtr node)
211 {
212 Options *o = setup_func(node);
213 o->interactive = FALSE;
214 return o;
215 }
216
217 static void free_func(gpointer options)
218 {
219 Options *o = options;
220
221 while (o->actions) {
222 actions_act_unref(o->actions->data);
223 o->actions = g_slist_delete_link(o->actions, o->actions);
224 }
225
226 g_free(o);
227 }
228
229 static gboolean run_func(ObActionsData *data, gpointer options)
230 {
231 Options *o = options;
232
233 if (!o->interactive)
234 end_cycle(FALSE, data->state, o);
235 else {
236 struct _ObClient *ft;
237
238 ft = focus_directional_cycle(o->direction,
239 o->dock_windows,
240 o->desktop_windows,
241 TRUE,
242 o->bar,
243 o->dialog,
244 FALSE, FALSE);
245 cycling = TRUE;
246
247 stacking_restore();
248 if (o->raise && ft) stacking_temp_raise(CLIENT_AS_WINDOW(ft));
249 }
250
251 return o->interactive;
252 }
253
254 static gboolean i_input_func(guint initial_state,
255 XEvent *e,
256 gpointer options,
257 gboolean *used)
258 {
259 if (e->type == KeyPress) {
260 /* Escape cancels no matter what */
261 if (ob_keycode_match(e->xkey.keycode, OB_KEY_ESCAPE)) {
262 end_cycle(TRUE, e->xkey.state, options);
263 return FALSE;
264 }
265
266 /* There were no modifiers and they pressed enter */
267 else if (ob_keycode_match(e->xkey.keycode, OB_KEY_RETURN) &&
268 !initial_state)
269 {
270 end_cycle(FALSE, e->xkey.state, options);
271 return FALSE;
272 }
273 }
274 /* They released the modifiers */
275 else if (e->type == KeyRelease && initial_state &&
276 (e->xkey.state & initial_state) == 0)
277 {
278 end_cycle(FALSE, e->xkey.state, options);
279 return FALSE;
280 }
281
282 return TRUE;
283 }
284
285 static void i_cancel_func(gpointer options)
286 {
287 /* we get cancelled when we move focus, but we're not cycling anymore, so
288 just ignore that */
289 if (cycling)
290 end_cycle(TRUE, 0, options);
291 }
292
293 static void end_cycle(gboolean cancel, guint state, Options *o)
294 {
295 struct _ObClient *ft;
296
297 ft = focus_directional_cycle(o->direction,
298 o->dock_windows,
299 o->desktop_windows,
300 o->interactive,
301 o->bar,
302 o->dialog,
303 TRUE, cancel);
304 cycling = FALSE;
305
306 if (ft)
307 actions_run_acts(o->actions, OB_USER_ACTION_KEYBOARD_KEY,
308 state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);
309
310 stacking_restore();
311 }
312
313 /* 3.4-compatibility */
314 static gpointer setup_north_cycle_func(xmlNodePtr node,
315 ObActionsIPreFunc *pre,
316 ObActionsIInputFunc *input,
317 ObActionsICancelFunc *cancel,
318 ObActionsIPostFunc *post)
319 {
320 Options *o = setup_cycle_func(node, pre, input, cancel, post);
321 o->direction = OB_DIRECTION_NORTH;
322 return o;
323 }
324
325 static gpointer setup_south_cycle_func(xmlNodePtr node,
326 ObActionsIPreFunc *pre,
327 ObActionsIInputFunc *input,
328 ObActionsICancelFunc *cancel,
329 ObActionsIPostFunc *post)
330 {
331 Options *o = setup_cycle_func(node, pre, input, cancel, post);
332 o->direction = OB_DIRECTION_SOUTH;
333 return o;
334 }
335
336 static gpointer setup_east_cycle_func(xmlNodePtr node,
337 ObActionsIPreFunc *pre,
338 ObActionsIInputFunc *input,
339 ObActionsICancelFunc *cancel,
340 ObActionsIPostFunc *post)
341 {
342 Options *o = setup_cycle_func(node, pre, input, cancel, post);
343 o->direction = OB_DIRECTION_EAST;
344 return o;
345 }
346
347 static gpointer setup_west_cycle_func(xmlNodePtr node,
348 ObActionsIPreFunc *pre,
349 ObActionsIInputFunc *input,
350 ObActionsICancelFunc *cancel,
351 ObActionsIPostFunc *post)
352 {
353 Options *o = setup_cycle_func(node, pre, input, cancel, post);
354 o->direction = OB_DIRECTION_WEST;
355 return o;
356 }
357
358 static gpointer setup_northwest_cycle_func(xmlNodePtr node,
359 ObActionsIPreFunc *pre,
360 ObActionsIInputFunc *input,
361 ObActionsICancelFunc *cancel,
362 ObActionsIPostFunc *post)
363 {
364 Options *o = setup_cycle_func(node, pre, input, cancel, post);
365 o->direction = OB_DIRECTION_NORTHWEST;
366 return o;
367 }
368
369 static gpointer setup_northeast_cycle_func(xmlNodePtr node,
370 ObActionsIPreFunc *pre,
371 ObActionsIInputFunc *input,
372 ObActionsICancelFunc *cancel,
373 ObActionsIPostFunc *post)
374 {
375 Options *o = setup_cycle_func(node, pre, input, cancel, post);
376 o->direction = OB_DIRECTION_EAST;
377 return o;
378 }
379
380 static gpointer setup_southwest_cycle_func(xmlNodePtr node,
381 ObActionsIPreFunc *pre,
382 ObActionsIInputFunc *input,
383 ObActionsICancelFunc *cancel,
384 ObActionsIPostFunc *post)
385 {
386 Options *o = setup_cycle_func(node, pre, input, cancel, post);
387 o->direction = OB_DIRECTION_SOUTHWEST;
388 return o;
389 }
390
391 static gpointer setup_southeast_cycle_func(xmlNodePtr node,
392 ObActionsIPreFunc *pre,
393 ObActionsIInputFunc *input,
394 ObActionsICancelFunc *cancel,
395 ObActionsIPostFunc *post)
396 {
397 Options *o = setup_cycle_func(node, pre, input, cancel, post);
398 o->direction = OB_DIRECTION_SOUTHEAST;
399 return o;
400 }
401
402 static gpointer setup_north_target_func(xmlNodePtr node)
403 {
404 Options *o = setup_target_func(node);
405 o->direction = OB_DIRECTION_NORTH;
406 return o;
407 }
408
409 static gpointer setup_south_target_func(xmlNodePtr node)
410 {
411 Options *o = setup_target_func(node);
412 o->direction = OB_DIRECTION_SOUTH;
413 return o;
414 }
415
416 static gpointer setup_east_target_func(xmlNodePtr node)
417 {
418 Options *o = setup_target_func(node);
419 o->direction = OB_DIRECTION_EAST;
420 return o;
421 }
422
423 static gpointer setup_west_target_func(xmlNodePtr node)
424 {
425 Options *o = setup_target_func(node);
426 o->direction = OB_DIRECTION_WEST;
427 return o;
428 }
429
430 static gpointer setup_northwest_target_func(xmlNodePtr node)
431 {
432 Options *o = setup_target_func(node);
433 o->direction = OB_DIRECTION_NORTHWEST;
434 return o;
435 }
436
437 static gpointer setup_northeast_target_func(xmlNodePtr node)
438 {
439 Options *o = setup_target_func(node);
440 o->direction = OB_DIRECTION_NORTHEAST;
441 return o;
442 }
443
444 static gpointer setup_southwest_target_func(xmlNodePtr node)
445 {
446 Options *o = setup_target_func(node);
447 o->direction = OB_DIRECTION_SOUTHWEST;
448 return o;
449 }
450
451 static gpointer setup_southeast_target_func(xmlNodePtr node)
452 {
453 Options *o = setup_target_func(node);
454 o->direction = OB_DIRECTION_SOUTHEAST;
455 return o;
456 }
457
This page took 0.052275 seconds and 3 git commands to generate.