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,
37 static void i_cancel_func(gpointer options);
39 static void end_cycle(gboolean cancel, guint state, Options *o);
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);
91 void action_directionalwindows_startup(void)
93 actions_register_i("DirectionalCycleWindows", setup_cycle_func, free_func,
95 actions_register("DirectionalTargetWindow", setup_target_func, free_func,
97 /* 3.4-compatibility */
98 actions_register_i("DirectionalFocusNorth", setup_north_cycle_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);
132 static gpointer setup_func(xmlNodePtr node)
137 o = g_new0(Options, 1);
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;
176 if ((n = obt_xml_find_node(node, "finalactions"))) {
179 m = obt_xml_find_node(n->children, "action");
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");
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"));
198 static gpointer setup_cycle_func(xmlNodePtr node,
199 ObActionsIPreFunc *pre,
200 ObActionsIInputFunc *input,
201 ObActionsICancelFunc *cancel,
202 ObActionsIPostFunc *post)
204 Options *o = setup_func(node);
205 o->interactive = TRUE;
206 *input = i_input_func;
207 *cancel = i_cancel_func;
211 static gpointer setup_target_func(xmlNodePtr node)
213 Options *o = setup_func(node);
214 o->interactive = FALSE;
218 static void free_func(gpointer options)
220 Options *o = options;
223 actions_act_unref(o->actions->data);
224 o->actions = g_slist_delete_link(o->actions, o->actions);
230 static gboolean run_func(ObActionsData *data, gpointer options)
232 Options *o = options;
235 end_cycle(FALSE, data->state, o);
237 struct _ObClient *ft;
239 ft = focus_directional_cycle(o->direction,
249 if (o->raise && ft) stacking_temp_raise(CLIENT_AS_WINDOW(ft));
252 return o->interactive;
255 static gboolean i_input_func(guint initial_state,
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);
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);
276 /* There were no modifiers and they pressed enter */
277 else if (ob_keycode_match(e->xkey.keycode, OB_KEY_RETURN) &&
280 end_cycle(FALSE, e->xkey.state, options);
284 /* They released the modifiers */
285 else if (e->type == KeyRelease && initial_state && !(mods & initial_state))
287 end_cycle(FALSE, e->xkey.state, options);
294 static void i_cancel_func(gpointer options)
296 /* we get cancelled when we move focus, but we're not cycling anymore, so
299 end_cycle(TRUE, 0, options);
302 static void end_cycle(gboolean cancel, guint state, Options *o)
304 struct _ObClient *ft;
306 ft = focus_directional_cycle(o->direction,
316 actions_run_acts(o->actions, OB_USER_ACTION_KEYBOARD_KEY,
317 state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);
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)
329 Options *o = setup_cycle_func(node, pre, input, cancel, post);
330 o->direction = OB_DIRECTION_NORTH;
334 static gpointer setup_south_cycle_func(xmlNodePtr node,
335 ObActionsIPreFunc *pre,
336 ObActionsIInputFunc *input,
337 ObActionsICancelFunc *cancel,
338 ObActionsIPostFunc *post)
340 Options *o = setup_cycle_func(node, pre, input, cancel, post);
341 o->direction = OB_DIRECTION_SOUTH;
345 static gpointer setup_east_cycle_func(xmlNodePtr node,
346 ObActionsIPreFunc *pre,
347 ObActionsIInputFunc *input,
348 ObActionsICancelFunc *cancel,
349 ObActionsIPostFunc *post)
351 Options *o = setup_cycle_func(node, pre, input, cancel, post);
352 o->direction = OB_DIRECTION_EAST;
356 static gpointer setup_west_cycle_func(xmlNodePtr node,
357 ObActionsIPreFunc *pre,
358 ObActionsIInputFunc *input,
359 ObActionsICancelFunc *cancel,
360 ObActionsIPostFunc *post)
362 Options *o = setup_cycle_func(node, pre, input, cancel, post);
363 o->direction = OB_DIRECTION_WEST;
367 static gpointer setup_northwest_cycle_func(xmlNodePtr node,
368 ObActionsIPreFunc *pre,
369 ObActionsIInputFunc *input,
370 ObActionsICancelFunc *cancel,
371 ObActionsIPostFunc *post)
373 Options *o = setup_cycle_func(node, pre, input, cancel, post);
374 o->direction = OB_DIRECTION_NORTHWEST;
378 static gpointer setup_northeast_cycle_func(xmlNodePtr node,
379 ObActionsIPreFunc *pre,
380 ObActionsIInputFunc *input,
381 ObActionsICancelFunc *cancel,
382 ObActionsIPostFunc *post)
384 Options *o = setup_cycle_func(node, pre, input, cancel, post);
385 o->direction = OB_DIRECTION_EAST;
389 static gpointer setup_southwest_cycle_func(xmlNodePtr node,
390 ObActionsIPreFunc *pre,
391 ObActionsIInputFunc *input,
392 ObActionsICancelFunc *cancel,
393 ObActionsIPostFunc *post)
395 Options *o = setup_cycle_func(node, pre, input, cancel, post);
396 o->direction = OB_DIRECTION_SOUTHWEST;
400 static gpointer setup_southeast_cycle_func(xmlNodePtr node,
401 ObActionsIPreFunc *pre,
402 ObActionsIInputFunc *input,
403 ObActionsICancelFunc *cancel,
404 ObActionsIPostFunc *post)
406 Options *o = setup_cycle_func(node, pre, input, cancel, post);
407 o->direction = OB_DIRECTION_SOUTHEAST;
411 static gpointer setup_north_target_func(xmlNodePtr node)
413 Options *o = setup_target_func(node);
414 o->direction = OB_DIRECTION_NORTH;
418 static gpointer setup_south_target_func(xmlNodePtr node)
420 Options *o = setup_target_func(node);
421 o->direction = OB_DIRECTION_SOUTH;
425 static gpointer setup_east_target_func(xmlNodePtr node)
427 Options *o = setup_target_func(node);
428 o->direction = OB_DIRECTION_EAST;
432 static gpointer setup_west_target_func(xmlNodePtr node)
434 Options *o = setup_target_func(node);
435 o->direction = OB_DIRECTION_WEST;
439 static gpointer setup_northwest_target_func(xmlNodePtr node)
441 Options *o = setup_target_func(node);
442 o->direction = OB_DIRECTION_NORTHWEST;
446 static gpointer setup_northeast_target_func(xmlNodePtr node)
448 Options *o = setup_target_func(node);
449 o->direction = OB_DIRECTION_NORTHEAST;
453 static gpointer setup_southwest_target_func(xmlNodePtr node)
455 Options *o = setup_target_func(node);
456 o->direction = OB_DIRECTION_SOUTHWEST;
460 static gpointer setup_southeast_target_func(xmlNodePtr node)
462 Options *o = setup_target_func(node);
463 o->direction = OB_DIRECTION_SOUTHEAST;