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"
9 #include "obt/keyboard.h"
14 gboolean dock_windows;
15 gboolean desktop_windows;
16 ObDirection direction;
22 static gboolean cycling = FALSE;
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,
38 static void i_cancel_func(gpointer options);
40 static void end_cycle(gboolean cancel, guint state, Options *o);
42 /* 3.4-compatibility */
43 static gpointer setup_north_cycle_func(xmlNodePtr node,
44 ObActionsIPreFunc *pre,
45 ObActionsIInputFunc *in,
46 ObActionsICancelFunc *c,
47 ObActionsIPostFunc *post);
48 static gpointer setup_south_cycle_func(xmlNodePtr node,
49 ObActionsIPreFunc *pre,
50 ObActionsIInputFunc *in,
51 ObActionsICancelFunc *c,
52 ObActionsIPostFunc *post);
53 static gpointer setup_east_cycle_func(xmlNodePtr node,
54 ObActionsIPreFunc *pre,
55 ObActionsIInputFunc *in,
56 ObActionsICancelFunc *c,
57 ObActionsIPostFunc *post);
58 static gpointer setup_west_cycle_func(xmlNodePtr node,
59 ObActionsIPreFunc *pre,
60 ObActionsIInputFunc *in,
61 ObActionsICancelFunc *c,
62 ObActionsIPostFunc *post);
63 static gpointer setup_northwest_cycle_func(xmlNodePtr node,
64 ObActionsIPreFunc *pre,
65 ObActionsIInputFunc *in,
66 ObActionsICancelFunc *c,
67 ObActionsIPostFunc *post);
68 static gpointer setup_northeast_cycle_func(xmlNodePtr node,
69 ObActionsIPreFunc *pre,
70 ObActionsIInputFunc *in,
71 ObActionsICancelFunc *c,
72 ObActionsIPostFunc *post);
73 static gpointer setup_southwest_cycle_func(xmlNodePtr node,
74 ObActionsIPreFunc *pre,
75 ObActionsIInputFunc *in,
76 ObActionsICancelFunc *c,
77 ObActionsIPostFunc *post);
78 static gpointer setup_southeast_cycle_func(xmlNodePtr node,
79 ObActionsIPreFunc *pre,
80 ObActionsIInputFunc *in,
81 ObActionsICancelFunc *c,
82 ObActionsIPostFunc *post);
83 static gpointer setup_north_target_func(xmlNodePtr node);
84 static gpointer setup_south_target_func(xmlNodePtr node);
85 static gpointer setup_east_target_func(xmlNodePtr node);
86 static gpointer setup_west_target_func(xmlNodePtr node);
87 static gpointer setup_northwest_target_func(xmlNodePtr node);
88 static gpointer setup_northeast_target_func(xmlNodePtr node);
89 static gpointer setup_southwest_target_func(xmlNodePtr node);
90 static gpointer setup_southeast_target_func(xmlNodePtr node);
92 void action_directionalwindows_startup(void)
94 actions_register_i("DirectionalCycleWindows", setup_cycle_func, free_func,
96 actions_register("DirectionalTargetWindow", setup_target_func, free_func,
98 /* 3.4-compatibility */
99 actions_register_i("DirectionalFocusNorth", setup_north_cycle_func,
100 free_func, run_func);
101 actions_register_i("DirectionalFocusSouth", setup_south_cycle_func,
102 free_func, run_func);
103 actions_register_i("DirectionalFocusWest", setup_west_cycle_func,
104 free_func, run_func);
105 actions_register_i("DirectionalFocusEast", setup_east_cycle_func,
106 free_func, run_func);
107 actions_register_i("DirectionalFocusNorthWest", setup_northwest_cycle_func,
108 free_func, run_func);
109 actions_register_i("DirectionalFocusNorthEast", setup_northeast_cycle_func,
110 free_func, run_func);
111 actions_register_i("DirectionalFocusSouthWest", setup_southwest_cycle_func,
112 free_func, run_func);
113 actions_register_i("DirectionalFocusSouthEast", setup_southeast_cycle_func,
114 free_func, run_func);
115 actions_register("DirectionalTargetNorth", setup_north_target_func,
116 free_func, run_func);
117 actions_register("DirectionalTargetSouth", setup_south_target_func,
118 free_func, run_func);
119 actions_register("DirectionalTargetWest", setup_west_target_func,
120 free_func, run_func);
121 actions_register("DirectionalTargetEast", setup_east_target_func,
122 free_func, run_func);
123 actions_register("DirectionalTargetNorthWest", setup_northwest_target_func,
124 free_func, run_func);
125 actions_register("DirectionalTargetNorthEast", setup_northeast_target_func,
126 free_func, run_func);
127 actions_register("DirectionalTargetSouthWest", setup_southwest_target_func,
128 free_func, run_func);
129 actions_register("DirectionalTargetSouthEast", setup_southeast_target_func,
130 free_func, run_func);
133 static gpointer setup_func(xmlNodePtr node)
138 o = g_slice_new0(Options);
142 if ((n = obt_xml_find_node(node, "dialog")))
143 o->dialog = obt_xml_node_bool(n);
144 if ((n = obt_xml_find_node(node, "bar")))
145 o->bar = obt_xml_node_bool(n);
146 if ((n = obt_xml_find_node(node, "raise")))
147 o->raise = obt_xml_node_bool(n);
148 if ((n = obt_xml_find_node(node, "panels")))
149 o->dock_windows = obt_xml_node_bool(n);
150 if ((n = obt_xml_find_node(node, "desktop")))
151 o->desktop_windows = obt_xml_node_bool(n);
152 if ((n = obt_xml_find_node(node, "direction"))) {
153 gchar *s = obt_xml_node_string(n);
154 if (!g_ascii_strcasecmp(s, "north") ||
155 !g_ascii_strcasecmp(s, "up"))
156 o->direction = OB_DIRECTION_NORTH;
157 else if (!g_ascii_strcasecmp(s, "northwest"))
158 o->direction = OB_DIRECTION_NORTHWEST;
159 else if (!g_ascii_strcasecmp(s, "northeast"))
160 o->direction = OB_DIRECTION_NORTHEAST;
161 else if (!g_ascii_strcasecmp(s, "west") ||
162 !g_ascii_strcasecmp(s, "left"))
163 o->direction = OB_DIRECTION_WEST;
164 else if (!g_ascii_strcasecmp(s, "east") ||
165 !g_ascii_strcasecmp(s, "right"))
166 o->direction = OB_DIRECTION_EAST;
167 else if (!g_ascii_strcasecmp(s, "south") ||
168 !g_ascii_strcasecmp(s, "down"))
169 o->direction = OB_DIRECTION_SOUTH;
170 else if (!g_ascii_strcasecmp(s, "southwest"))
171 o->direction = OB_DIRECTION_SOUTHWEST;
172 else if (!g_ascii_strcasecmp(s, "southeast"))
173 o->direction = OB_DIRECTION_SOUTHEAST;
177 if ((n = obt_xml_find_node(node, "finalactions"))) {
180 m = obt_xml_find_node(n->children, "action");
182 ObActionsAct *action = actions_parse(m);
183 if (action) o->actions = g_slist_append(o->actions, action);
184 m = obt_xml_find_node(m->next, "action");
188 o->actions = g_slist_prepend(o->actions,
189 actions_parse_string("Focus"));
190 o->actions = g_slist_prepend(o->actions,
191 actions_parse_string("Raise"));
192 o->actions = g_slist_prepend(o->actions,
193 actions_parse_string("Unshade"));
199 static gpointer setup_cycle_func(xmlNodePtr node,
200 ObActionsIPreFunc *pre,
201 ObActionsIInputFunc *input,
202 ObActionsICancelFunc *cancel,
203 ObActionsIPostFunc *post)
205 Options *o = setup_func(node);
206 o->interactive = TRUE;
207 *input = i_input_func;
208 *cancel = i_cancel_func;
212 static gpointer setup_target_func(xmlNodePtr node)
214 Options *o = setup_func(node);
215 o->interactive = FALSE;
219 static void free_func(gpointer options)
221 Options *o = options;
224 actions_act_unref(o->actions->data);
225 o->actions = g_slist_delete_link(o->actions, o->actions);
228 g_slice_free(Options, o);
231 static gboolean run_func(ObActionsData *data, gpointer options)
233 Options *o = options;
236 end_cycle(FALSE, data->state, o);
238 struct _ObClient *ft;
240 ft = focus_directional_cycle(o->direction,
250 if (o->raise && ft) stacking_temp_raise(CLIENT_AS_WINDOW(ft));
253 return o->interactive;
256 static gboolean i_input_func(guint initial_state,
264 mods = obt_keyboard_only_modmasks(e->xkey.state);
265 if (e->type == KeyRelease) {
266 /* remove from the state the mask of the modifier key being
267 released, if it is a modifier key being released that is */
268 mods &= ~obt_keyboard_keyevent_to_modmask(e);
271 if (e->type == KeyPress) {
272 KeySym sym = obt_keyboard_keypress_to_keysym(e);
274 /* Escape cancels no matter what */
275 if (sym == XK_Escape) {
276 end_cycle(TRUE, e->xkey.state, options);
280 /* There were no modifiers and they pressed enter */
281 else if ((sym == XK_Return || sym == XK_KP_Enter) && !initial_state) {
282 end_cycle(FALSE, e->xkey.state, options);
286 /* They released the modifiers */
287 else if (e->type == KeyRelease && initial_state && !(mods & initial_state))
289 end_cycle(FALSE, e->xkey.state, options);
296 static void i_cancel_func(gpointer options)
298 /* we get cancelled when we move focus, but we're not cycling anymore, so
301 end_cycle(TRUE, 0, options);
304 static void end_cycle(gboolean cancel, guint state, Options *o)
306 struct _ObClient *ft;
308 ft = focus_directional_cycle(o->direction,
318 actions_run_acts(o->actions, OB_USER_ACTION_KEYBOARD_KEY,
319 state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);
324 /* 3.4-compatibility */
325 static gpointer setup_north_cycle_func(xmlNodePtr node,
326 ObActionsIPreFunc *pre,
327 ObActionsIInputFunc *input,
328 ObActionsICancelFunc *cancel,
329 ObActionsIPostFunc *post)
331 Options *o = setup_cycle_func(node, pre, input, cancel, post);
332 o->direction = OB_DIRECTION_NORTH;
336 static gpointer setup_south_cycle_func(xmlNodePtr node,
337 ObActionsIPreFunc *pre,
338 ObActionsIInputFunc *input,
339 ObActionsICancelFunc *cancel,
340 ObActionsIPostFunc *post)
342 Options *o = setup_cycle_func(node, pre, input, cancel, post);
343 o->direction = OB_DIRECTION_SOUTH;
347 static gpointer setup_east_cycle_func(xmlNodePtr node,
348 ObActionsIPreFunc *pre,
349 ObActionsIInputFunc *input,
350 ObActionsICancelFunc *cancel,
351 ObActionsIPostFunc *post)
353 Options *o = setup_cycle_func(node, pre, input, cancel, post);
354 o->direction = OB_DIRECTION_EAST;
358 static gpointer setup_west_cycle_func(xmlNodePtr node,
359 ObActionsIPreFunc *pre,
360 ObActionsIInputFunc *input,
361 ObActionsICancelFunc *cancel,
362 ObActionsIPostFunc *post)
364 Options *o = setup_cycle_func(node, pre, input, cancel, post);
365 o->direction = OB_DIRECTION_WEST;
369 static gpointer setup_northwest_cycle_func(xmlNodePtr node,
370 ObActionsIPreFunc *pre,
371 ObActionsIInputFunc *input,
372 ObActionsICancelFunc *cancel,
373 ObActionsIPostFunc *post)
375 Options *o = setup_cycle_func(node, pre, input, cancel, post);
376 o->direction = OB_DIRECTION_NORTHWEST;
380 static gpointer setup_northeast_cycle_func(xmlNodePtr node,
381 ObActionsIPreFunc *pre,
382 ObActionsIInputFunc *input,
383 ObActionsICancelFunc *cancel,
384 ObActionsIPostFunc *post)
386 Options *o = setup_cycle_func(node, pre, input, cancel, post);
387 o->direction = OB_DIRECTION_EAST;
391 static gpointer setup_southwest_cycle_func(xmlNodePtr node,
392 ObActionsIPreFunc *pre,
393 ObActionsIInputFunc *input,
394 ObActionsICancelFunc *cancel,
395 ObActionsIPostFunc *post)
397 Options *o = setup_cycle_func(node, pre, input, cancel, post);
398 o->direction = OB_DIRECTION_SOUTHWEST;
402 static gpointer setup_southeast_cycle_func(xmlNodePtr node,
403 ObActionsIPreFunc *pre,
404 ObActionsIInputFunc *input,
405 ObActionsICancelFunc *cancel,
406 ObActionsIPostFunc *post)
408 Options *o = setup_cycle_func(node, pre, input, cancel, post);
409 o->direction = OB_DIRECTION_SOUTHEAST;
413 static gpointer setup_north_target_func(xmlNodePtr node)
415 Options *o = setup_target_func(node);
416 o->direction = OB_DIRECTION_NORTH;
420 static gpointer setup_south_target_func(xmlNodePtr node)
422 Options *o = setup_target_func(node);
423 o->direction = OB_DIRECTION_SOUTH;
427 static gpointer setup_east_target_func(xmlNodePtr node)
429 Options *o = setup_target_func(node);
430 o->direction = OB_DIRECTION_EAST;
434 static gpointer setup_west_target_func(xmlNodePtr node)
436 Options *o = setup_target_func(node);
437 o->direction = OB_DIRECTION_WEST;
441 static gpointer setup_northwest_target_func(xmlNodePtr node)
443 Options *o = setup_target_func(node);
444 o->direction = OB_DIRECTION_NORTHWEST;
448 static gpointer setup_northeast_target_func(xmlNodePtr node)
450 Options *o = setup_target_func(node);
451 o->direction = OB_DIRECTION_NORTHEAST;
455 static gpointer setup_southwest_target_func(xmlNodePtr node)
457 Options *o = setup_target_func(node);
458 o->direction = OB_DIRECTION_SOUTHWEST;
462 static gpointer setup_southeast_target_func(xmlNodePtr node)
464 Options *o = setup_target_func(node);
465 o->direction = OB_DIRECTION_SOUTHEAST;