]> Dogcows Code - chaz/openbox/blob - openbox/actions/directionalwindows.c
ignore .rej files
[chaz/openbox] / openbox / actions / directionalwindows.c
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"
8 #include "gettext.h"
9 #include "obt/keyboard.h"
10
11 typedef struct {
12 gboolean interactive;
13 gboolean dialog;
14 gboolean dock_windows;
15 gboolean desktop_windows;
16 ObDirection direction;
17 gboolean bar;
18 gboolean raise;
19 GSList *actions;
20 } Options;
21
22 static gboolean cycling = FALSE;
23
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,
34 XEvent *e,
35 ObtIC *ic,
36 gpointer options,
37 gboolean *used);
38 static void i_cancel_func(gpointer options);
39
40 static void end_cycle(gboolean cancel, guint state, Options *o);
41
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);
91
92 void action_directionalwindows_startup(void)
93 {
94 actions_register_i("DirectionalCycleWindows", setup_cycle_func, free_func,
95 run_func);
96 actions_register("DirectionalTargetWindow", setup_target_func, free_func,
97 run_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);
131 }
132
133 static gpointer setup_func(xmlNodePtr node)
134 {
135 xmlNodePtr n;
136 Options *o;
137
138 o = g_slice_new0(Options);
139 o->dialog = TRUE;
140 o->bar = TRUE;
141
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;
174 g_free(s);
175 }
176
177 if ((n = obt_xml_find_node(node, "finalactions"))) {
178 xmlNodePtr m;
179
180 m = obt_xml_find_node(n->children, "action");
181 while (m) {
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");
185 }
186 }
187 else {
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"));
194 }
195
196 return o;
197 }
198
199 static gpointer setup_cycle_func(xmlNodePtr node,
200 ObActionsIPreFunc *pre,
201 ObActionsIInputFunc *input,
202 ObActionsICancelFunc *cancel,
203 ObActionsIPostFunc *post)
204 {
205 Options *o = setup_func(node);
206 o->interactive = TRUE;
207 *input = i_input_func;
208 *cancel = i_cancel_func;
209 return o;
210 }
211
212 static gpointer setup_target_func(xmlNodePtr node)
213 {
214 Options *o = setup_func(node);
215 o->interactive = FALSE;
216 return o;
217 }
218
219 static void free_func(gpointer options)
220 {
221 Options *o = options;
222
223 while (o->actions) {
224 actions_act_unref(o->actions->data);
225 o->actions = g_slist_delete_link(o->actions, o->actions);
226 }
227
228 g_slice_free(Options, o);
229 }
230
231 static gboolean run_func(ObActionsData *data, gpointer options)
232 {
233 Options *o = options;
234
235 if (!o->interactive)
236 end_cycle(FALSE, data->state, o);
237 else {
238 struct _ObClient *ft;
239
240 ft = focus_directional_cycle(o->direction,
241 o->dock_windows,
242 o->desktop_windows,
243 TRUE,
244 o->bar,
245 o->dialog,
246 FALSE, FALSE);
247 cycling = TRUE;
248
249 stacking_restore();
250 if (o->raise && ft) stacking_temp_raise(CLIENT_AS_WINDOW(ft));
251 }
252
253 return o->interactive;
254 }
255
256 static gboolean i_input_func(guint initial_state,
257 XEvent *e,
258 ObtIC *ic,
259 gpointer options,
260 gboolean *used)
261 {
262 guint mods;
263
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);
269 }
270
271 if (e->type == KeyPress) {
272 KeySym sym = obt_keyboard_keypress_to_keysym(e);
273
274 /* Escape cancels no matter what */
275 if (sym == XK_Escape) {
276 end_cycle(TRUE, e->xkey.state, options);
277 return FALSE;
278 }
279
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);
283 return FALSE;
284 }
285 }
286 /* They released the modifiers */
287 else if (e->type == KeyRelease && initial_state && !(mods & initial_state))
288 {
289 end_cycle(FALSE, e->xkey.state, options);
290 return FALSE;
291 }
292
293 return TRUE;
294 }
295
296 static void i_cancel_func(gpointer options)
297 {
298 /* we get cancelled when we move focus, but we're not cycling anymore, so
299 just ignore that */
300 if (cycling)
301 end_cycle(TRUE, 0, options);
302 }
303
304 static void end_cycle(gboolean cancel, guint state, Options *o)
305 {
306 struct _ObClient *ft;
307
308 ft = focus_directional_cycle(o->direction,
309 o->dock_windows,
310 o->desktop_windows,
311 o->interactive,
312 o->bar,
313 o->dialog,
314 TRUE, cancel);
315 cycling = FALSE;
316
317 if (ft)
318 actions_run_acts(o->actions, OB_USER_ACTION_KEYBOARD_KEY,
319 state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);
320
321 stacking_restore();
322 }
323
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)
330 {
331 Options *o = setup_cycle_func(node, pre, input, cancel, post);
332 o->direction = OB_DIRECTION_NORTH;
333 return o;
334 }
335
336 static gpointer setup_south_cycle_func(xmlNodePtr node,
337 ObActionsIPreFunc *pre,
338 ObActionsIInputFunc *input,
339 ObActionsICancelFunc *cancel,
340 ObActionsIPostFunc *post)
341 {
342 Options *o = setup_cycle_func(node, pre, input, cancel, post);
343 o->direction = OB_DIRECTION_SOUTH;
344 return o;
345 }
346
347 static gpointer setup_east_cycle_func(xmlNodePtr node,
348 ObActionsIPreFunc *pre,
349 ObActionsIInputFunc *input,
350 ObActionsICancelFunc *cancel,
351 ObActionsIPostFunc *post)
352 {
353 Options *o = setup_cycle_func(node, pre, input, cancel, post);
354 o->direction = OB_DIRECTION_EAST;
355 return o;
356 }
357
358 static gpointer setup_west_cycle_func(xmlNodePtr node,
359 ObActionsIPreFunc *pre,
360 ObActionsIInputFunc *input,
361 ObActionsICancelFunc *cancel,
362 ObActionsIPostFunc *post)
363 {
364 Options *o = setup_cycle_func(node, pre, input, cancel, post);
365 o->direction = OB_DIRECTION_WEST;
366 return o;
367 }
368
369 static gpointer setup_northwest_cycle_func(xmlNodePtr node,
370 ObActionsIPreFunc *pre,
371 ObActionsIInputFunc *input,
372 ObActionsICancelFunc *cancel,
373 ObActionsIPostFunc *post)
374 {
375 Options *o = setup_cycle_func(node, pre, input, cancel, post);
376 o->direction = OB_DIRECTION_NORTHWEST;
377 return o;
378 }
379
380 static gpointer setup_northeast_cycle_func(xmlNodePtr node,
381 ObActionsIPreFunc *pre,
382 ObActionsIInputFunc *input,
383 ObActionsICancelFunc *cancel,
384 ObActionsIPostFunc *post)
385 {
386 Options *o = setup_cycle_func(node, pre, input, cancel, post);
387 o->direction = OB_DIRECTION_EAST;
388 return o;
389 }
390
391 static gpointer setup_southwest_cycle_func(xmlNodePtr node,
392 ObActionsIPreFunc *pre,
393 ObActionsIInputFunc *input,
394 ObActionsICancelFunc *cancel,
395 ObActionsIPostFunc *post)
396 {
397 Options *o = setup_cycle_func(node, pre, input, cancel, post);
398 o->direction = OB_DIRECTION_SOUTHWEST;
399 return o;
400 }
401
402 static gpointer setup_southeast_cycle_func(xmlNodePtr node,
403 ObActionsIPreFunc *pre,
404 ObActionsIInputFunc *input,
405 ObActionsICancelFunc *cancel,
406 ObActionsIPostFunc *post)
407 {
408 Options *o = setup_cycle_func(node, pre, input, cancel, post);
409 o->direction = OB_DIRECTION_SOUTHEAST;
410 return o;
411 }
412
413 static gpointer setup_north_target_func(xmlNodePtr node)
414 {
415 Options *o = setup_target_func(node);
416 o->direction = OB_DIRECTION_NORTH;
417 return o;
418 }
419
420 static gpointer setup_south_target_func(xmlNodePtr node)
421 {
422 Options *o = setup_target_func(node);
423 o->direction = OB_DIRECTION_SOUTH;
424 return o;
425 }
426
427 static gpointer setup_east_target_func(xmlNodePtr node)
428 {
429 Options *o = setup_target_func(node);
430 o->direction = OB_DIRECTION_EAST;
431 return o;
432 }
433
434 static gpointer setup_west_target_func(xmlNodePtr node)
435 {
436 Options *o = setup_target_func(node);
437 o->direction = OB_DIRECTION_WEST;
438 return o;
439 }
440
441 static gpointer setup_northwest_target_func(xmlNodePtr node)
442 {
443 Options *o = setup_target_func(node);
444 o->direction = OB_DIRECTION_NORTHWEST;
445 return o;
446 }
447
448 static gpointer setup_northeast_target_func(xmlNodePtr node)
449 {
450 Options *o = setup_target_func(node);
451 o->direction = OB_DIRECTION_NORTHEAST;
452 return o;
453 }
454
455 static gpointer setup_southwest_target_func(xmlNodePtr node)
456 {
457 Options *o = setup_target_func(node);
458 o->direction = OB_DIRECTION_SOUTHWEST;
459 return o;
460 }
461
462 static gpointer setup_southeast_target_func(xmlNodePtr node)
463 {
464 Options *o = setup_target_func(node);
465 o->direction = OB_DIRECTION_SOUTHEAST;
466 return o;
467 }
468
This page took 0.063174 seconds and 4 git commands to generate.