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