]> Dogcows Code - chaz/openbox/blob - openbox/actions/desktop.c
59aae832d4c2cad27c561f60540770f021b02422
[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 gpointer options,
47 gboolean *used);
48 static void i_post_func(gpointer options);
49
50 /* 3.4-compatibility */
51 static gpointer setup_go_last_func(xmlNodePtr node);
52 static gpointer setup_send_last_func(xmlNodePtr node);
53 static gpointer setup_go_abs_func(xmlNodePtr node);
54 static gpointer setup_send_abs_func(xmlNodePtr node);
55 static gpointer setup_go_next_func(xmlNodePtr node,
56 ObActionsIPreFunc *pre,
57 ObActionsIInputFunc *input,
58 ObActionsICancelFunc *cancel,
59 ObActionsIPostFunc *post);
60 static gpointer setup_send_next_func(xmlNodePtr node,
61 ObActionsIPreFunc *pre,
62 ObActionsIInputFunc *input,
63 ObActionsICancelFunc *cancel,
64 ObActionsIPostFunc *post);
65 static gpointer setup_go_prev_func(xmlNodePtr node,
66 ObActionsIPreFunc *pre,
67 ObActionsIInputFunc *input,
68 ObActionsICancelFunc *cancel,
69 ObActionsIPostFunc *post);
70 static gpointer setup_send_prev_func(xmlNodePtr node,
71 ObActionsIPreFunc *pre,
72 ObActionsIInputFunc *input,
73 ObActionsICancelFunc *cancel,
74 ObActionsIPostFunc *post);
75 static gpointer setup_go_left_func(xmlNodePtr node,
76 ObActionsIPreFunc *pre,
77 ObActionsIInputFunc *input,
78 ObActionsICancelFunc *cancel,
79 ObActionsIPostFunc *post);
80 static gpointer setup_send_left_func(xmlNodePtr node,
81 ObActionsIPreFunc *pre,
82 ObActionsIInputFunc *input,
83 ObActionsICancelFunc *cancel,
84 ObActionsIPostFunc *post);
85 static gpointer setup_go_right_func(xmlNodePtr node,
86 ObActionsIPreFunc *pre,
87 ObActionsIInputFunc *input,
88 ObActionsICancelFunc *cancel,
89 ObActionsIPostFunc *post);
90 static gpointer setup_send_right_func(xmlNodePtr node,
91 ObActionsIPreFunc *pre,
92 ObActionsIInputFunc *input,
93 ObActionsICancelFunc *cancel,
94 ObActionsIPostFunc *post);
95 static gpointer setup_go_up_func(xmlNodePtr node,
96 ObActionsIPreFunc *pre,
97 ObActionsIInputFunc *input,
98 ObActionsICancelFunc *cancel,
99 ObActionsIPostFunc *post);
100 static gpointer setup_send_up_func(xmlNodePtr node,
101 ObActionsIPreFunc *pre,
102 ObActionsIInputFunc *input,
103 ObActionsICancelFunc *cancel,
104 ObActionsIPostFunc *post);
105 static gpointer setup_go_down_func(xmlNodePtr node,
106 ObActionsIPreFunc *pre,
107 ObActionsIInputFunc *input,
108 ObActionsICancelFunc *cancel,
109 ObActionsIPostFunc *post);
110 static gpointer setup_send_down_func(xmlNodePtr node,
111 ObActionsIPreFunc *pre,
112 ObActionsIInputFunc *input,
113 ObActionsICancelFunc *cancel,
114 ObActionsIPostFunc *post);
115
116 void action_desktop_startup(void)
117 {
118 actions_register_i("GoToDesktop", setup_go_func, g_free, run_func);
119 actions_register_i("SendToDesktop", setup_send_func, g_free, run_func);
120 /* 3.4-compatibility */
121 actions_register("DesktopLast", setup_go_last_func, g_free, run_func);
122 actions_register("SendToDesktopLast", setup_send_last_func,
123 g_free, run_func);
124 actions_register("Desktop", setup_go_abs_func, g_free, run_func);
125 actions_register("SendToDesktop", setup_send_abs_func, g_free, run_func);
126 actions_register_i("DesktopNext", setup_go_next_func, g_free, run_func);
127 actions_register_i("SendToDesktopNext", setup_send_next_func,
128 g_free, run_func);
129 actions_register_i("DesktopPrevious", setup_go_prev_func,
130 g_free, run_func);
131 actions_register_i("SendToDesktopPrevious", setup_send_prev_func,
132 g_free, run_func);
133 actions_register_i("DesktopLeft", setup_go_left_func, g_free, run_func);
134 actions_register_i("SendToDesktopLeft", setup_send_left_func,
135 g_free, run_func);
136 actions_register_i("DesktopRight", setup_go_right_func, g_free, run_func);
137 actions_register_i("SendToDesktopRight", setup_send_right_func,
138 g_free, run_func);
139 actions_register_i("DesktopUp", setup_go_up_func, g_free, run_func);
140 actions_register_i("SendToDesktopUp", setup_send_up_func,
141 g_free, run_func);
142 actions_register_i("DesktopDown", setup_go_down_func, g_free, run_func);
143 actions_register_i("SendToDesktopDown", setup_send_down_func,
144 g_free, run_func);
145 }
146
147 static gpointer setup_func(xmlNodePtr node,
148 ObActionsIPreFunc *pre,
149 ObActionsIInputFunc *input,
150 ObActionsICancelFunc *cancel,
151 ObActionsIPostFunc *post)
152 {
153 xmlNodePtr n;
154 Options *o;
155
156 o = g_new0(Options, 1);
157 /* don't go anywhere if there are no options given */
158 o->type = ABSOLUTE;
159 o->u.abs.desktop = screen_desktop;
160 /* wrap by default - it's handy! */
161 o->u.rel.wrap = TRUE;
162
163 if ((n = obt_xml_find_node(node, "to"))) {
164 gchar *s = obt_xml_node_string(n);
165 if (!g_ascii_strcasecmp(s, "last"))
166 o->type = LAST;
167 else if (!g_ascii_strcasecmp(s, "next")) {
168 o->type = RELATIVE;
169 o->u.rel.linear = TRUE;
170 o->u.rel.dir = OB_DIRECTION_EAST;
171 }
172 else if (!g_ascii_strcasecmp(s, "previous")) {
173 o->type = RELATIVE;
174 o->u.rel.linear = TRUE;
175 o->u.rel.dir = OB_DIRECTION_WEST;
176 }
177 else if (!g_ascii_strcasecmp(s, "north") ||
178 !g_ascii_strcasecmp(s, "up")) {
179 o->type = RELATIVE;
180 o->u.rel.dir = OB_DIRECTION_NORTH;
181 }
182 else if (!g_ascii_strcasecmp(s, "south") ||
183 !g_ascii_strcasecmp(s, "down")) {
184 o->type = RELATIVE;
185 o->u.rel.dir = OB_DIRECTION_SOUTH;
186 }
187 else if (!g_ascii_strcasecmp(s, "west") ||
188 !g_ascii_strcasecmp(s, "left")) {
189 o->type = RELATIVE;
190 o->u.rel.dir = OB_DIRECTION_WEST;
191 }
192 else if (!g_ascii_strcasecmp(s, "east") ||
193 !g_ascii_strcasecmp(s, "right")) {
194 o->type = RELATIVE;
195 o->u.rel.dir = OB_DIRECTION_EAST;
196 }
197 else {
198 o->type = ABSOLUTE;
199 o->u.abs.desktop = atoi(s) - 1;
200 }
201 g_free(s);
202 }
203
204 if ((n = obt_xml_find_node(node, "wrap")))
205 o->u.rel.wrap = obt_xml_node_bool(n);
206
207 return o;
208 }
209
210
211 static gpointer setup_go_func(xmlNodePtr node,
212 ObActionsIPreFunc *pre,
213 ObActionsIInputFunc *input,
214 ObActionsICancelFunc *cancel,
215 ObActionsIPostFunc *post)
216 {
217 Options *o;
218
219 o = setup_func(node, pre, input, cancel, post);
220 if (o->type == RELATIVE) {
221 o->interactive = TRUE;
222 *pre = i_pre_func;
223 *input = i_input_func;
224 *post = i_post_func;
225 }
226
227 return o;
228 }
229
230 static gpointer setup_send_func(xmlNodePtr node,
231 ObActionsIPreFunc *pre,
232 ObActionsIInputFunc *input,
233 ObActionsICancelFunc *cancel,
234 ObActionsIPostFunc *post)
235 {
236 xmlNodePtr n;
237 Options *o;
238
239 o = setup_func(node, pre, input, cancel, post);
240 o->send = TRUE;
241 o->follow = TRUE;
242
243 if ((n = obt_xml_find_node(node, "follow")))
244 o->follow = obt_xml_node_bool(n);
245
246 if (o->type == RELATIVE && o->follow) {
247 o->interactive = TRUE;
248 *pre = i_pre_func;
249 *input = i_input_func;
250 *post = i_post_func;
251 }
252
253 return o;
254 }
255
256 /* Always return FALSE because its not interactive */
257 static gboolean run_func(ObActionsData *data, gpointer options)
258 {
259 Options *o = options;
260 guint d;
261
262 switch (o->type) {
263 case LAST:
264 d = screen_last_desktop;
265 break;
266 case ABSOLUTE:
267 d = o->u.abs.desktop;
268 break;
269 case RELATIVE:
270 d = screen_find_desktop(screen_desktop,
271 o->u.rel.dir, o->u.rel.wrap, o->u.rel.linear);
272 break;
273 default:
274 g_assert_not_reached();
275 }
276
277 if (d < screen_num_desktops && d != screen_desktop) {
278 gboolean go = TRUE;
279
280 actions_client_move(data, TRUE);
281 if (o->send && data->client && client_normal(data->client)) {
282 client_set_desktop(data->client, d, o->follow, FALSE);
283 go = o->follow;
284 }
285
286 if (go) {
287 screen_set_desktop(d, TRUE);
288 if (data->client)
289 client_bring_helper_windows(data->client);
290 }
291
292 actions_client_move(data, FALSE);
293 }
294
295 return o->interactive;
296 }
297
298 static gboolean i_input_func(guint initial_state,
299 XEvent *e,
300 gpointer options,
301 gboolean *used)
302 {
303 guint mods;
304
305 mods = obt_keyboard_only_modmasks(e->xkey.state);
306 if (e->type == KeyRelease) {
307 /* remove from the state the mask of the modifier key being
308 released, if it is a modifier key being released that is */
309 mods &= ~obt_keyboard_keycode_to_modmask(e->xkey.keycode);
310 }
311
312 if (e->type == KeyPress) {
313 /* Escape cancels no matter what */
314 if (ob_keycode_match(e->xkey.keycode, OB_KEY_ESCAPE)) {
315 return FALSE;
316 }
317
318 /* There were no modifiers and they pressed enter */
319 else if (ob_keycode_match(e->xkey.keycode, OB_KEY_RETURN) &&
320 !initial_state)
321 {
322 return FALSE;
323 }
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.063616 seconds and 3 git commands to generate.