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"
13 gboolean dock_windows;
14 gboolean desktop_windows;
15 ObDirection direction;
21 static gboolean cycling = FALSE;
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,
36 static void i_cancel_func(gpointer options);
38 static void end_cycle(gboolean cancel, guint state, Options *o);
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);
90 void action_directionalwindows_startup(void)
92 actions_register_i("DirectionalCycleWindows", setup_cycle_func, free_func,
94 actions_register("DirectionalTargetWindow", setup_target_func, free_func,
96 /* 3.4-compatibility */
97 actions_register_i("DirectionalFocusNorth", setup_north_cycle_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);
131 static gpointer setup_func(xmlNodePtr node)
136 o = g_new0(Options, 1);
140 if ((n = obt_xml_find_node(node, "dialog")))
141 o->dialog = obt_xml_node_bool(n);
142 if ((n = obt_xml_find_node(node, "bar")))
143 o->bar = obt_xml_node_bool(n);
144 if ((n = obt_xml_find_node(node, "raise")))
145 o->raise = obt_xml_node_bool(n);
146 if ((n = obt_xml_find_node(node, "panels")))
147 o->dock_windows = obt_xml_node_bool(n);
148 if ((n = obt_xml_find_node(node, "desktop")))
149 o->desktop_windows = obt_xml_node_bool(n);
150 if ((n = obt_xml_find_node(node, "direction"))) {
151 gchar *s = obt_xml_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;
175 if ((n = obt_xml_find_node(node, "finalactions"))) {
178 m = obt_xml_find_node(n->children, "action");
180 ObActionsAct *action = actions_parse(m);
181 if (action) o->actions = g_slist_append(o->actions, action);
182 m = obt_xml_find_node(m->next, "action");
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"));
197 static gpointer setup_cycle_func(xmlNodePtr node,
198 ObActionsIPreFunc *pre,
199 ObActionsIInputFunc *input,
200 ObActionsICancelFunc *cancel,
201 ObActionsIPostFunc *post)
203 Options *o = setup_func(node);
204 o->interactive = TRUE;
205 *input = i_input_func;
206 *cancel = i_cancel_func;
210 static gpointer setup_target_func(xmlNodePtr node)
212 Options *o = setup_func(node);
213 o->interactive = FALSE;
217 static void free_func(gpointer options)
219 Options *o = options;
222 actions_act_unref(o->actions->data);
223 o->actions = g_slist_delete_link(o->actions, o->actions);
229 static gboolean run_func(ObActionsData *data, gpointer options)
231 Options *o = options;
234 end_cycle(FALSE, data->state, o);
236 struct _ObClient *ft;
238 ft = focus_directional_cycle(o->direction,
248 if (o->raise && ft) stacking_temp_raise(CLIENT_AS_WINDOW(ft));
251 return o->interactive;
254 static gboolean i_input_func(guint initial_state,
261 mods = obt_keyboard_only_modmasks(e->xkey.state);
262 if (e->type == KeyRelease) {
263 /* remove from the state the mask of the modifier key being
264 released, if it is a modifier key being released that is */
265 mods &= ~obt_keyboard_keycode_to_modmask(e->xkey.keycode);
268 if (e->type == KeyPress) {
269 /* Escape cancels no matter what */
270 if (ob_keycode_match(e->xkey.keycode, OB_KEY_ESCAPE)) {
271 end_cycle(TRUE, e->xkey.state, options);
275 /* There were no modifiers and they pressed enter */
276 else if (ob_keycode_match(e->xkey.keycode, OB_KEY_RETURN) &&
279 end_cycle(FALSE, e->xkey.state, options);
283 /* They released the modifiers */
284 else if (e->type == KeyRelease && initial_state &&
285 (mods & initial_state) == 0)
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;