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
;