]> Dogcows Code - chaz/openbox/blob - openbox/actions/desktop.c
make control keys work in menus/dialogs/etc with the new obt code, using XLookup...
[chaz/openbox] / openbox / actions / desktop.c
1 #include "openbox/actions.h"
2 #include "openbox/screen.h"
3 #include "openbox/client.h"
4 #include "openbox/openbox.h"
5 #include "obt/keyboard.h"
6
7 typedef enum {
8 LAST,
9 RELATIVE,
10 ABSOLUTE
11 } SwitchType;
12
13 typedef struct {
14 SwitchType type;
15 union {
16 struct {
17 guint desktop;
18 } abs;
19
20 struct {
21 gboolean linear;
22 gboolean wrap;
23 ObDirection dir;
24 } rel;
25 } u;
26 gboolean send;
27 gboolean follow;
28 gboolean interactive;
29 } Options;
30
31 static gpointer setup_go_func(xmlNodePtr node,
32 ObActionsIPreFunc *pre,
33 ObActionsIInputFunc *input,
34 ObActionsICancelFunc *cancel,
35 ObActionsIPostFunc *post);
36 static gpointer setup_send_func(xmlNodePtr node,
37 ObActionsIPreFunc *pre,
38 ObActionsIInputFunc *input,
39 ObActionsICancelFunc *cancel,
40 ObActionsIPostFunc *post);
41 static gboolean run_func(ObActionsData *data, gpointer options);
42
43 static gboolean i_pre_func(guint state, gpointer options);
44 static gboolean i_input_func(guint initial_state,
45 XEvent *e,
46 ObtIC *ic,
47 gpointer options,
48 gboolean *used);
49 static void i_post_func(gpointer options);
50
51 /* 3.4-compatibility */
52 static gpointer setup_go_last_func(xmlNodePtr node);
53 static gpointer setup_send_last_func(xmlNodePtr node);
54 static gpointer setup_go_abs_func(xmlNodePtr node);
55 static gpointer setup_send_abs_func(xmlNodePtr node);
56 static gpointer setup_go_next_func(xmlNodePtr node,
57 ObActionsIPreFunc *pre,
58 ObActionsIInputFunc *input,
59 ObActionsICancelFunc *cancel,
60 ObActionsIPostFunc *post);
61 static gpointer setup_send_next_func(xmlNodePtr node,
62 ObActionsIPreFunc *pre,
63 ObActionsIInputFunc *input,
64 ObActionsICancelFunc *cancel,
65 ObActionsIPostFunc *post);
66 static gpointer setup_go_prev_func(xmlNodePtr node,
67 ObActionsIPreFunc *pre,
68 ObActionsIInputFunc *input,
69 ObActionsICancelFunc *cancel,
70 ObActionsIPostFunc *post);
71 static gpointer setup_send_prev_func(xmlNodePtr node,
72 ObActionsIPreFunc *pre,
73 ObActionsIInputFunc *input,
74 ObActionsICancelFunc *cancel,
75 ObActionsIPostFunc *post);
76 static gpointer setup_go_left_func(xmlNodePtr node,
77 ObActionsIPreFunc *pre,
78 ObActionsIInputFunc *input,
79 ObActionsICancelFunc *cancel,
80 ObActionsIPostFunc *post);
81 static gpointer setup_send_left_func(xmlNodePtr node,
82 ObActionsIPreFunc *pre,
83 ObActionsIInputFunc *input,
84 ObActionsICancelFunc *cancel,
85 ObActionsIPostFunc *post);
86 static gpointer setup_go_right_func(xmlNodePtr node,
87 ObActionsIPreFunc *pre,
88 ObActionsIInputFunc *input,
89 ObActionsICancelFunc *cancel,
90 ObActionsIPostFunc *post);
91 static gpointer setup_send_right_func(xmlNodePtr node,
92 ObActionsIPreFunc *pre,
93 ObActionsIInputFunc *input,
94 ObActionsICancelFunc *cancel,
95 ObActionsIPostFunc *post);
96 static gpointer setup_go_up_func(xmlNodePtr node,
97 ObActionsIPreFunc *pre,
98 ObActionsIInputFunc *input,
99 ObActionsICancelFunc *cancel,
100 ObActionsIPostFunc *post);
101 static gpointer setup_send_up_func(xmlNodePtr node,
102 ObActionsIPreFunc *pre,
103 ObActionsIInputFunc *input,
104 ObActionsICancelFunc *cancel,
105 ObActionsIPostFunc *post);
106 static gpointer setup_go_down_func(xmlNodePtr node,
107 ObActionsIPreFunc *pre,
108 ObActionsIInputFunc *input,
109 ObActionsICancelFunc *cancel,
110 ObActionsIPostFunc *post);
111 static gpointer setup_send_down_func(xmlNodePtr node,
112 ObActionsIPreFunc *pre,
113 ObActionsIInputFunc *input,
114 ObActionsICancelFunc *cancel,
115 ObActionsIPostFunc *post);
116
117 void action_desktop_startup(void)
118 {
119 actions_register_i("GoToDesktop", setup_go_func, g_free, run_func);
120 actions_register_i("SendToDesktop", setup_send_func, g_free, run_func);
121 /* 3.4-compatibility */
122 actions_register("DesktopLast", setup_go_last_func, g_free, run_func);
123 actions_register("SendToDesktopLast", setup_send_last_func,
124 g_free, run_func);
125 actions_register("Desktop", setup_go_abs_func, g_free, run_func);
126 actions_register("SendToDesktop", setup_send_abs_func, g_free, run_func);
127 actions_register_i("DesktopNext", setup_go_next_func, g_free, run_func);
128 actions_register_i("SendToDesktopNext", setup_send_next_func,
129 g_free, run_func);
130 actions_register_i("DesktopPrevious", setup_go_prev_func,
131 g_free, run_func);
132 actions_register_i("SendToDesktopPrevious", setup_send_prev_func,
133 g_free, run_func);
134 actions_register_i("DesktopLeft", setup_go_left_func, g_free, run_func);
135 actions_register_i("SendToDesktopLeft", setup_send_left_func,
136 g_free, run_func);
137 actions_register_i("DesktopRight", setup_go_right_func, g_free, run_func);
138 actions_register_i("SendToDesktopRight", setup_send_right_func,
139 g_free, run_func);
140 actions_register_i("DesktopUp", setup_go_up_func, g_free, run_func);
141 actions_register_i("SendToDesktopUp", setup_send_up_func,
142 g_free, run_func);
143 actions_register_i("DesktopDown", setup_go_down_func, g_free, run_func);
144 actions_register_i("SendToDesktopDown", setup_send_down_func,
145 g_free, run_func);
146 }
147
148 static gpointer setup_func(xmlNodePtr node,
149 ObActionsIPreFunc *pre,
150 ObActionsIInputFunc *input,
151 ObActionsICancelFunc *cancel,
152 ObActionsIPostFunc *post)
153 {
154 xmlNodePtr n;
155 Options *o;
156
157 o = g_new0(Options, 1);
158 /* don't go anywhere if there are no options given */
159 o->type = ABSOLUTE;
160 o->u.abs.desktop = screen_desktop;
161 /* wrap by default - it's handy! */
162 o->u.rel.wrap = TRUE;
163
164 if ((n = obt_xml_find_node(node, "to"))) {
165 gchar *s = obt_xml_node_string(n);
166 if (!g_ascii_strcasecmp(s, "last"))
167 o->type = LAST;
168 else if (!g_ascii_strcasecmp(s, "next")) {
169 o->type = RELATIVE;
170 o->u.rel.linear = TRUE;
171 o->u.rel.dir = OB_DIRECTION_EAST;
172 }
173 else if (!g_ascii_strcasecmp(s, "previous")) {
174 o->type = RELATIVE;
175 o->u.rel.linear = TRUE;
176 o->u.rel.dir = OB_DIRECTION_WEST;
177 }
178 else if (!g_ascii_strcasecmp(s, "north") ||
179 !g_ascii_strcasecmp(s, "up")) {
180 o->type = RELATIVE;
181 o->u.rel.dir = OB_DIRECTION_NORTH;
182 }
183 else if (!g_ascii_strcasecmp(s, "south") ||
184 !g_ascii_strcasecmp(s, "down")) {
185 o->type = RELATIVE;
186 o->u.rel.dir = OB_DIRECTION_SOUTH;
187 }
188 else if (!g_ascii_strcasecmp(s, "west") ||
189 !g_ascii_strcasecmp(s, "left")) {
190 o->type = RELATIVE;
191 o->u.rel.dir = OB_DIRECTION_WEST;
192 }
193 else if (!g_ascii_strcasecmp(s, "east") ||
194 !g_ascii_strcasecmp(s, "right")) {
195 o->type = RELATIVE;
196 o->u.rel.dir = OB_DIRECTION_EAST;
197 }
198 else {
199 o->type = ABSOLUTE;
200 o->u.abs.desktop = atoi(s) - 1;
201 }
202 g_free(s);
203 }
204
205 if ((n = obt_xml_find_node(node, "wrap")))
206 o->u.rel.wrap = obt_xml_node_bool(n);
207
208 return o;
209 }
210
211
212 static gpointer setup_go_func(xmlNodePtr node,
213 ObActionsIPreFunc *pre,
214 ObActionsIInputFunc *input,
215 ObActionsICancelFunc *cancel,
216 ObActionsIPostFunc *post)
217 {
218 Options *o;
219
220 o = setup_func(node, pre, input, cancel, post);
221 if (o->type == RELATIVE) {
222 o->interactive = TRUE;
223 *pre = i_pre_func;
224 *input = i_input_func;
225 *post = i_post_func;
226 }
227
228 return o;
229 }
230
231 static gpointer setup_send_func(xmlNodePtr node,
232 ObActionsIPreFunc *pre,
233 ObActionsIInputFunc *input,
234 ObActionsICancelFunc *cancel,
235 ObActionsIPostFunc *post)
236 {
237 xmlNodePtr n;
238 Options *o;
239
240 o = setup_func(node, pre, input, cancel, post);
241 o->send = TRUE;
242 o->follow = TRUE;
243
244 if ((n = obt_xml_find_node(node, "follow")))
245 o->follow = obt_xml_node_bool(n);
246
247 if (o->type == RELATIVE && o->follow) {
248 o->interactive = TRUE;
249 *pre = i_pre_func;
250 *input = i_input_func;
251 *post = i_post_func;
252 }
253
254 return o;
255 }
256
257 /* Always return FALSE because its not interactive */
258 static gboolean run_func(ObActionsData *data, gpointer options)
259 {
260 Options *o = options;
261 guint d;
262
263 switch (o->type) {
264 case LAST:
265 d = screen_last_desktop;
266 break;
267 case ABSOLUTE:
268 d = o->u.abs.desktop;
269 break;
270 case RELATIVE:
271 d = screen_find_desktop(screen_desktop,
272 o->u.rel.dir, o->u.rel.wrap, o->u.rel.linear);
273 break;
274 default:
275 g_assert_not_reached();
276 }
277
278 if (d < screen_num_desktops && d != screen_desktop) {
279 gboolean go = TRUE;
280
281 actions_client_move(data, TRUE);
282 if (o->send && data->client && client_normal(data->client)) {
283 client_set_desktop(data->client, d, o->follow, FALSE);
284 go = o->follow;
285 }
286
287 if (go) {
288 screen_set_desktop(d, TRUE);
289 if (data->client)
290 client_bring_helper_windows(data->client);
291 }
292
293 actions_client_move(data, FALSE);
294 }
295
296 return o->interactive;
297 }
298
299 static gboolean i_input_func(guint initial_state,
300 XEvent *e,
301 ObtIC *ic,
302 gpointer options,
303 gboolean *used)
304 {
305 guint mods;
306
307 mods = obt_keyboard_only_modmasks(e->xkey.state);
308 if (e->type == KeyRelease) {
309 /* remove from the state the mask of the modifier key being
310 released, if it is a modifier key being released that is */
311 mods &= ~obt_keyboard_keycode_to_modmask(e->xkey.keycode);
312 }
313
314 if (e->type == KeyPress) {
315 KeySym sym = obt_keyboard_keypress_to_keysym(e);
316
317 /* Escape cancels no matter what */
318 if (sym == XK_Escape)
319 return FALSE;
320
321 /* There were no modifiers and they pressed enter */
322 else if (sym == XK_Return && !initial_state)
323 return FALSE;
324 }
325 /* They released the modifiers */
326 else if (e->type == KeyRelease && initial_state && !(mods & initial_state))
327 {
328 return FALSE;
329 }
330
331 return TRUE;
332 }
333
334 static gboolean i_pre_func(guint initial_state, gpointer options)
335 {
336 if (!initial_state) {
337 Options *o = options;
338 o->interactive = FALSE;
339 return FALSE;
340 }
341 else {
342 screen_show_desktop_popup(screen_desktop, TRUE);
343 return TRUE;
344 }
345 }
346
347 static void i_post_func(gpointer options)
348 {
349 screen_hide_desktop_popup();
350 }
351
352 /* 3.4-compatilibity */
353 static gpointer setup_follow(xmlNodePtr node)
354 {
355 xmlNodePtr n;
356 Options *o = g_new0(Options, 1);
357 o->send = TRUE;
358 o->follow = TRUE;
359 if ((n = obt_xml_find_node(node, "follow")))
360 o->follow = obt_xml_node_bool(n);
361 return o;
362 }
363
364 static gpointer setup_go_last_func(xmlNodePtr node)
365 {
366 Options *o = g_new0(Options, 1);
367 o->type = LAST;
368 return o;
369 }
370
371 static gpointer setup_send_last_func(xmlNodePtr node)
372 {
373 Options *o = setup_follow(node);
374 o->type = LAST;
375 return o;
376 }
377
378 static gpointer setup_go_abs_func(xmlNodePtr node)
379 {
380 xmlNodePtr n;
381 Options *o = g_new0(Options, 1);
382 o->type = ABSOLUTE;
383 if ((n = obt_xml_find_node(node, "desktop")))
384 o->u.abs.desktop = obt_xml_node_int(n) - 1;
385 else
386 o->u.abs.desktop = screen_desktop;
387 return o;
388 }
389
390 static gpointer setup_send_abs_func(xmlNodePtr node)
391 {
392 xmlNodePtr n;
393 Options *o = setup_follow(node);
394 o->type = ABSOLUTE;
395 if ((n = obt_xml_find_node(node, "desktop")))
396 o->u.abs.desktop = obt_xml_node_int(n) - 1;
397 else
398 o->u.abs.desktop = screen_desktop;
399 return o;
400 }
401
402 static void setup_rel(Options *o, xmlNodePtr node, gboolean lin,
403 ObDirection dir,
404 ObActionsIPreFunc *pre,
405 ObActionsIInputFunc *input,
406 ObActionsIPostFunc *post)
407 {
408 xmlNodePtr n;
409
410 o->type = RELATIVE;
411 o->u.rel.linear = lin;
412 o->u.rel.dir = dir;
413 o->u.rel.wrap = TRUE;
414
415 if ((n = obt_xml_find_node(node, "wrap")))
416 o->u.rel.wrap = obt_xml_node_bool(n);
417
418 if (input) {
419 o->interactive = TRUE;
420 *pre = i_pre_func;
421 *input = i_input_func;
422 *post = i_post_func;
423 }
424 }
425
426 static gpointer setup_go_next_func(xmlNodePtr node,
427 ObActionsIPreFunc *pre,
428 ObActionsIInputFunc *input,
429 ObActionsICancelFunc *cancel,
430 ObActionsIPostFunc *post)
431 {
432 Options *o = g_new0(Options, 1);
433 setup_rel(o, node, TRUE, OB_DIRECTION_EAST, pre, input, post);
434 return o;
435 }
436
437 static gpointer setup_send_next_func(xmlNodePtr node,
438 ObActionsIPreFunc *pre,
439 ObActionsIInputFunc *input,
440 ObActionsICancelFunc *cancel,
441 ObActionsIPostFunc *post)
442 {
443 Options *o = setup_follow(node);
444 setup_rel(o, node, TRUE, OB_DIRECTION_EAST,
445 pre, (o->follow ? input : NULL), post);
446 return o;
447 }
448
449 static gpointer setup_go_prev_func(xmlNodePtr node,
450 ObActionsIPreFunc *pre,
451 ObActionsIInputFunc *input,
452 ObActionsICancelFunc *cancel,
453 ObActionsIPostFunc *post)
454 {
455 Options *o = g_new0(Options, 1);
456 setup_rel(o, node, TRUE, OB_DIRECTION_WEST, pre, input, post);
457 return o;
458 }
459
460 static gpointer setup_send_prev_func(xmlNodePtr node,
461 ObActionsIPreFunc *pre,
462 ObActionsIInputFunc *input,
463 ObActionsICancelFunc *cancel,
464 ObActionsIPostFunc *post)
465 {
466 Options *o = setup_follow(node);
467 setup_rel(o, node, TRUE, OB_DIRECTION_WEST,
468 pre, (o->follow ? input : NULL), post);
469 return o;
470 }
471
472 static gpointer setup_go_left_func(xmlNodePtr node,
473 ObActionsIPreFunc *pre,
474 ObActionsIInputFunc *input,
475 ObActionsICancelFunc *cancel,
476 ObActionsIPostFunc *post)
477 {
478 Options *o = g_new0(Options, 1);
479 setup_rel(o, node, FALSE, OB_DIRECTION_WEST, pre, input, post);
480 return o;
481 }
482
483 static gpointer setup_send_left_func(xmlNodePtr node,
484 ObActionsIPreFunc *pre,
485 ObActionsIInputFunc *input,
486 ObActionsICancelFunc *cancel,
487 ObActionsIPostFunc *post)
488 {
489 Options *o = setup_follow(node);
490 setup_rel(o, node, FALSE, OB_DIRECTION_WEST,
491 pre, (o->follow ? input : NULL), post);
492 return o;
493 }
494
495 static gpointer setup_go_right_func(xmlNodePtr node,
496 ObActionsIPreFunc *pre,
497 ObActionsIInputFunc *input,
498 ObActionsICancelFunc *cancel,
499 ObActionsIPostFunc *post)
500 {
501 Options *o = g_new0(Options, 1);
502 setup_rel(o, node, FALSE, OB_DIRECTION_EAST, pre, input, post);
503 return o;
504 }
505
506 static gpointer setup_send_right_func(xmlNodePtr node,
507 ObActionsIPreFunc *pre,
508 ObActionsIInputFunc *input,
509 ObActionsICancelFunc *cancel,
510 ObActionsIPostFunc *post)
511 {
512 Options *o = setup_follow(node);
513 setup_rel(o, node, FALSE, OB_DIRECTION_EAST,
514 pre, (o->follow ? input : NULL), post);
515 return o;
516 }
517
518 static gpointer setup_go_up_func(xmlNodePtr node,
519 ObActionsIPreFunc *pre,
520 ObActionsIInputFunc *input,
521 ObActionsICancelFunc *cancel,
522 ObActionsIPostFunc *post)
523 {
524 Options *o = g_new0(Options, 1);
525 setup_rel(o, node, FALSE, OB_DIRECTION_NORTH, pre, input, post);
526 return o;
527 }
528
529 static gpointer setup_send_up_func(xmlNodePtr node,
530 ObActionsIPreFunc *pre,
531 ObActionsIInputFunc *input,
532 ObActionsICancelFunc *cancel,
533 ObActionsIPostFunc *post)
534 {
535 Options *o = setup_follow(node);
536 setup_rel(o, node, FALSE, OB_DIRECTION_NORTH,
537 pre, (o->follow ? input : NULL), post);
538 return o;
539 }
540
541 static gpointer setup_go_down_func(xmlNodePtr node,
542 ObActionsIPreFunc *pre,
543 ObActionsIInputFunc *input,
544 ObActionsICancelFunc *cancel,
545 ObActionsIPostFunc *post)
546 {
547 Options *o = g_new0(Options, 1);
548 setup_rel(o, node, FALSE, OB_DIRECTION_SOUTH, pre, input, post);
549 return o;
550 }
551
552 static gpointer setup_send_down_func(xmlNodePtr node,
553 ObActionsIPreFunc *pre,
554 ObActionsIInputFunc *input,
555 ObActionsICancelFunc *cancel,
556 ObActionsIPostFunc *post)
557 {
558 Options *o = setup_follow(node);
559 setup_rel(o, node, FALSE, OB_DIRECTION_SOUTH,
560 pre, (o->follow ? input : NULL), post);
561 return o;
562 }
This page took 0.057048 seconds and 4 git commands to generate.