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 static gpointer setup_target_func(xmlNodePtr node);
26 static void free_func(gpointer options);
27 static gboolean run_func(ObActionsData *data, gpointer options);
28 static gboolean i_input_func(guint initial_state,
32 static void i_cancel_func(gpointer options);
34 static void end_cycle(gboolean cancel, guint state, Options *o);
36 /* 3.4-compatibility */
37 static gpointer setup_north_cycle_func(xmlNodePtr node);
38 static gpointer setup_south_cycle_func(xmlNodePtr node);
39 static gpointer setup_east_cycle_func(xmlNodePtr node);
40 static gpointer setup_west_cycle_func(xmlNodePtr node);
41 static gpointer setup_northwest_cycle_func(xmlNodePtr node);
42 static gpointer setup_northeast_cycle_func(xmlNodePtr node);
43 static gpointer setup_southwest_cycle_func(xmlNodePtr node);
44 static gpointer setup_southeast_cycle_func(xmlNodePtr node);
45 static gpointer setup_north_target_func(xmlNodePtr node);
46 static gpointer setup_south_target_func(xmlNodePtr node);
47 static gpointer setup_east_target_func(xmlNodePtr node);
48 static gpointer setup_west_target_func(xmlNodePtr node);
49 static gpointer setup_northwest_target_func(xmlNodePtr node);
50 static gpointer setup_northeast_target_func(xmlNodePtr node);
51 static gpointer setup_southwest_target_func(xmlNodePtr node);
52 static gpointer setup_southeast_target_func(xmlNodePtr node);
54 void action_directionalwindows_startup(void)
56 actions_register("DirectionalCycleWindows", setup_cycle_func, free_func,
57 run_func, i_input_func, i_cancel_func);
58 actions_register("DirectionalTargetWindow", setup_target_func, free_func,
59 run_func, NULL, NULL);
60 /* 3.4-compatibility */
61 actions_register("DirectionalFocusNorth", setup_north_cycle_func,
62 free_func, run_func, i_input_func, i_cancel_func);
63 actions_register("DirectionalFocusSouth", setup_south_cycle_func,
64 free_func, run_func, i_input_func, i_cancel_func);
65 actions_register("DirectionalFocusWest", setup_west_cycle_func,
66 free_func, run_func, i_input_func, i_cancel_func);
67 actions_register("DirectionalFocusEast", setup_east_cycle_func,
68 free_func, run_func, i_input_func, i_cancel_func);
69 actions_register("DirectionalFocusNorthWest", setup_northwest_cycle_func,
70 free_func, run_func, i_input_func, i_cancel_func);
71 actions_register("DirectionalFocusNorthEast", setup_northeast_cycle_func,
72 free_func, run_func, i_input_func, i_cancel_func);
73 actions_register("DirectionalFocusSouthWest", setup_southwest_cycle_func,
74 free_func, run_func, i_input_func, i_cancel_func);
75 actions_register("DirectionalFocusSouthEast", setup_southeast_cycle_func,
76 free_func, run_func, i_input_func, i_cancel_func);
77 actions_register("DirectionalTargetNorth", setup_north_target_func,
78 free_func, run_func, i_input_func, i_cancel_func);
79 actions_register("DirectionalTargetSouth", setup_south_target_func,
80 free_func, run_func, i_input_func, i_cancel_func);
81 actions_register("DirectionalTargetWest", setup_west_target_func,
82 free_func, run_func, i_input_func, i_cancel_func);
83 actions_register("DirectionalTargetEast", setup_east_target_func,
84 free_func, run_func, i_input_func, i_cancel_func);
85 actions_register("DirectionalTargetNorthWest", setup_northwest_target_func,
86 free_func, run_func, i_input_func, i_cancel_func);
87 actions_register("DirectionalTargetNorthEast", setup_northeast_target_func,
88 free_func, run_func, i_input_func, i_cancel_func);
89 actions_register("DirectionalTargetSouthWest", setup_southwest_target_func,
90 free_func, run_func, i_input_func, i_cancel_func);
91 actions_register("DirectionalTargetSouthEast", setup_southeast_target_func,
92 free_func, run_func, i_input_func, i_cancel_func);
95 static gpointer setup_func(xmlNodePtr node)
100 o = g_new0(Options, 1);
104 if ((n = obt_parse_find_node(node, "dialog")))
105 o->dialog = obt_parse_node_bool(n);
106 if ((n = obt_parse_find_node(node, "bar")))
107 o->bar = obt_parse_node_bool(n);
108 if ((n = obt_parse_find_node(node, "raise")))
109 o->raise = obt_parse_node_bool(n);
110 if ((n = obt_parse_find_node(node, "panels")))
111 o->dock_windows = obt_parse_node_bool(n);
112 if ((n = obt_parse_find_node(node, "desktop")))
113 o->desktop_windows = obt_parse_node_bool(n);
114 if ((n = obt_parse_find_node(node, "direction"))) {
115 gchar *s = obt_parse_node_string(n);
116 if (!g_ascii_strcasecmp(s, "north") ||
117 !g_ascii_strcasecmp(s, "up"))
118 o->direction = OB_DIRECTION_NORTH;
119 else if (!g_ascii_strcasecmp(s, "northwest"))
120 o->direction = OB_DIRECTION_NORTHWEST;
121 else if (!g_ascii_strcasecmp(s, "northeast"))
122 o->direction = OB_DIRECTION_NORTHEAST;
123 else if (!g_ascii_strcasecmp(s, "west") ||
124 !g_ascii_strcasecmp(s, "left"))
125 o->direction = OB_DIRECTION_WEST;
126 else if (!g_ascii_strcasecmp(s, "east") ||
127 !g_ascii_strcasecmp(s, "right"))
128 o->direction = OB_DIRECTION_EAST;
129 else if (!g_ascii_strcasecmp(s, "south") ||
130 !g_ascii_strcasecmp(s, "down"))
131 o->direction = OB_DIRECTION_SOUTH;
132 else if (!g_ascii_strcasecmp(s, "southwest"))
133 o->direction = OB_DIRECTION_SOUTHWEST;
134 else if (!g_ascii_strcasecmp(s, "southeast"))
135 o->direction = OB_DIRECTION_SOUTHEAST;
139 if ((n = obt_parse_find_node(node, "finalactions"))) {
142 m = obt_parse_find_node(n->children, "action");
144 ObActionsAct *action = actions_parse(m);
145 if (action) o->actions = g_slist_append(o->actions, action);
146 m = obt_parse_find_node(m->next, "action");
150 o->actions = g_slist_prepend(o->actions,
151 actions_parse_string("Focus"));
152 o->actions = g_slist_prepend(o->actions,
153 actions_parse_string("Raise"));
154 o->actions = g_slist_prepend(o->actions,
155 actions_parse_string("Unshade"));
161 static gpointer setup_cycle_func(xmlNodePtr node)
163 Options *o = setup_func(node);
164 o->interactive = TRUE;
168 static gpointer setup_target_func(xmlNodePtr node)
170 Options *o = setup_func(node);
171 o->interactive = FALSE;
175 static void free_func(gpointer options)
177 Options *o = options;
180 actions_act_unref(o->actions->data);
181 o->actions = g_slist_delete_link(o->actions, o->actions);
187 static gboolean run_func(ObActionsData *data, gpointer options)
189 Options *o = options;
192 end_cycle(FALSE, data->state, o);
194 struct _ObClient *ft;
196 ft = focus_directional_cycle(o->direction,
206 if (o->raise && ft) stacking_temp_raise(CLIENT_AS_WINDOW(ft));
209 return o->interactive;
212 static gboolean i_input_func(guint initial_state,
217 if (e->type == KeyPress) {
218 /* Escape cancels no matter what */
219 if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) {
220 end_cycle(TRUE, e->xkey.state, options);
224 /* There were no modifiers and they pressed enter */
225 else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN) &&
228 end_cycle(FALSE, e->xkey.state, options);
232 /* They released the modifiers */
233 else if (e->type == KeyRelease && initial_state &&
234 (e->xkey.state & initial_state) == 0)
236 end_cycle(FALSE, e->xkey.state, options);
243 static void i_cancel_func(gpointer options)
245 /* we get cancelled when we move focus, but we're not cycling anymore, so
248 end_cycle(TRUE, 0, options);
251 static void end_cycle(gboolean cancel, guint state, Options *o)
253 struct _ObClient *ft;
255 ft = focus_directional_cycle(o->direction,
265 actions_run_acts(o->actions, OB_USER_ACTION_KEYBOARD_KEY,
266 state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);
271 /* 3.4-compatibility */
272 static gpointer setup_north_cycle_func(xmlNodePtr node)
274 Options *o = setup_cycle_func(node);
275 o->direction = OB_DIRECTION_NORTH;
279 static gpointer setup_south_cycle_func(xmlNodePtr node)
281 Options *o = setup_cycle_func(node);
282 o->direction = OB_DIRECTION_SOUTH;
286 static gpointer setup_east_cycle_func(xmlNodePtr node)
288 Options *o = setup_cycle_func(node);
289 o->direction = OB_DIRECTION_EAST;
293 static gpointer setup_west_cycle_func(xmlNodePtr node)
295 Options *o = setup_cycle_func(node);
296 o->direction = OB_DIRECTION_WEST;
300 static gpointer setup_northwest_cycle_func(xmlNodePtr node)
302 Options *o = setup_cycle_func(node);
303 o->direction = OB_DIRECTION_NORTHWEST;
307 static gpointer setup_northeast_cycle_func(xmlNodePtr node)
309 Options *o = setup_cycle_func(node);
310 o->direction = OB_DIRECTION_EAST;
314 static gpointer setup_southwest_cycle_func(xmlNodePtr node)
316 Options *o = setup_cycle_func(node);
317 o->direction = OB_DIRECTION_SOUTHWEST;
321 static gpointer setup_southeast_cycle_func(xmlNodePtr node)
323 Options *o = setup_cycle_func(node);
324 o->direction = OB_DIRECTION_SOUTHEAST;
328 static gpointer setup_north_target_func(xmlNodePtr node)
330 Options *o = setup_target_func(node);
331 o->direction = OB_DIRECTION_NORTH;
335 static gpointer setup_south_target_func(xmlNodePtr node)
337 Options *o = setup_target_func(node);
338 o->direction = OB_DIRECTION_SOUTH;
342 static gpointer setup_east_target_func(xmlNodePtr node)
344 Options *o = setup_target_func(node);
345 o->direction = OB_DIRECTION_EAST;
349 static gpointer setup_west_target_func(xmlNodePtr node)
351 Options *o = setup_target_func(node);
352 o->direction = OB_DIRECTION_WEST;
356 static gpointer setup_northwest_target_func(xmlNodePtr node)
358 Options *o = setup_target_func(node);
359 o->direction = OB_DIRECTION_NORTHWEST;
363 static gpointer setup_northeast_target_func(xmlNodePtr node)
365 Options *o = setup_target_func(node);
366 o->direction = OB_DIRECTION_NORTHEAST;
370 static gpointer setup_southwest_target_func(xmlNodePtr node)
372 Options *o = setup_target_func(node);
373 o->direction = OB_DIRECTION_SOUTHWEST;
377 static gpointer setup_southeast_target_func(xmlNodePtr node)
379 Options *o = setup_target_func(node);
380 o->direction = OB_DIRECTION_SOUTHEAST;