]> Dogcows Code - chaz/openbox/blob - openbox/actions/desktop.c
a2d4be29fe03112d3973bae9d30159095e7b1eed
[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 /* Escape cancels no matter what */
316 if (ob_keycode_match(e->xkey.keycode, OB_KEY_ESCAPE)) {
317 return FALSE;
318 }
319
320 /* There were no modifiers and they pressed enter */
321 else if (ob_keycode_match(e->xkey.keycode, OB_KEY_RETURN) &&
322 !initial_state)
323 {
324 return FALSE;
325 }
326 }
327 /* They released the modifiers */
328 else if (e->type == KeyRelease && initial_state && !(mods & initial_state))
329 {
330 return FALSE;
331 }
332
333 return TRUE;
334 }
335
336 static gboolean i_pre_func(guint initial_state, gpointer options)
337 {
338 if (!initial_state) {
339 Options *o = options;
340 o->interactive = FALSE;
341 return FALSE;
342 }
343 else {
344 screen_show_desktop_popup(screen_desktop, TRUE);
345 return TRUE;
346 }
347 }
348
349 static void i_post_func(gpointer options)
350 {
351 screen_hide_desktop_popup();
352 }
353
354 /* 3.4-compatilibity */
355 static gpointer setup_follow(xmlNodePtr node)
356 {
357 xmlNodePtr n;
358 Options *o = g_new0(Options, 1);
359 o->send = TRUE;
360 o->follow = TRUE;
361 if ((n = obt_xml_find_node(node, "follow")))
362 o->follow = obt_xml_node_bool(n);
363 return o;
364 }
365
366 static gpointer setup_go_last_func(xmlNodePtr node)
367 {
368 Options *o = g_new0(Options, 1);
369 o->type = LAST;
370 return o;
371 }
372
373 static gpointer setup_send_last_func(xmlNodePtr node)
374 {
375 Options *o = setup_follow(node);
376 o->type = LAST;
377 return o;
378 }
379
380 static gpointer setup_go_abs_func(xmlNodePtr node)
381 {
382 xmlNodePtr n;
383 Options *o = g_new0(Options, 1);
384 o->type = ABSOLUTE;
385 if ((n = obt_xml_find_node(node, "desktop")))
386 o->u.abs.desktop = obt_xml_node_int(n) - 1;
387 else
388 o->u.abs.desktop = screen_desktop;
389 return o;
390 }
391
392 static gpointer setup_send_abs_func(xmlNodePtr node)
393 {
394 xmlNodePtr n;
395 Options *o = setup_follow(node);
396 o->type = ABSOLUTE;
397 if ((n = obt_xml_find_node(node, "desktop")))
398 o->u.abs.desktop = obt_xml_node_int(n) - 1;
399 else
400 o->u.abs.desktop = screen_desktop;
401 return o;
402 }
403
404 static void setup_rel(Options *o, xmlNodePtr node, gboolean lin,
405 ObDirection dir,
406 ObActionsIPreFunc *pre,
407 ObActionsIInputFunc *input,
408 ObActionsIPostFunc *post)
409 {
410 xmlNodePtr n;
411
412 o->type = RELATIVE;
413 o->u.rel.linear = lin;
414 o->u.rel.dir = dir;
415 o->u.rel.wrap = TRUE;
416
417 if ((n = obt_xml_find_node(node, "wrap")))
418 o->u.rel.wrap = obt_xml_node_bool(n);
419
420 if (input) {
421 o->interactive = TRUE;
422 *pre = i_pre_func;
423 *input = i_input_func;
424 *post = i_post_func;
425 }
426 }
427
428 static gpointer setup_go_next_func(xmlNodePtr node,
429 ObActionsIPreFunc *pre,
430 ObActionsIInputFunc *input,
431 ObActionsICancelFunc *cancel,
432 ObActionsIPostFunc *post)
433 {
434 Options *o = g_new0(Options, 1);
435 setup_rel(o, node, TRUE, OB_DIRECTION_EAST, pre, input, post);
436 return o;
437 }
438
439 static gpointer setup_send_next_func(xmlNodePtr node,
440 ObActionsIPreFunc *pre,
441 ObActionsIInputFunc *input,
442 ObActionsICancelFunc *cancel,
443 ObActionsIPostFunc *post)
444 {
445 Options *o = setup_follow(node);
446 setup_rel(o, node, TRUE, OB_DIRECTION_EAST,
447 pre, (o->follow ? input : NULL), post);
448 return o;
449 }
450
451 static gpointer setup_go_prev_func(xmlNodePtr node,
452 ObActionsIPreFunc *pre,
453 ObActionsIInputFunc *input,
454 ObActionsICancelFunc *cancel,
455 ObActionsIPostFunc *post)
456 {
457 Options *o = g_new0(Options, 1);
458 setup_rel(o, node, TRUE, OB_DIRECTION_WEST, pre, input, post);
459 return o;
460 }
461
462 static gpointer setup_send_prev_func(xmlNodePtr node,
463 ObActionsIPreFunc *pre,
464 ObActionsIInputFunc *input,
465 ObActionsICancelFunc *cancel,
466 ObActionsIPostFunc *post)
467 {
468 Options *o = setup_follow(node);
469 setup_rel(o, node, TRUE, OB_DIRECTION_WEST,
470 pre, (o->follow ? input : NULL), post);
471 return o;
472 }
473
474 static gpointer setup_go_left_func(xmlNodePtr node,
475 ObActionsIPreFunc *pre,
476 ObActionsIInputFunc *input,
477 ObActionsICancelFunc *cancel,
478 ObActionsIPostFunc *post)
479 {
480 Options *o = g_new0(Options, 1);
481 setup_rel(o, node, FALSE, OB_DIRECTION_WEST, pre, input, post);
482 return o;
483 }
484
485 static gpointer setup_send_left_func(xmlNodePtr node,
486 ObActionsIPreFunc *pre,
487 ObActionsIInputFunc *input,
488 ObActionsICancelFunc *cancel,
489 ObActionsIPostFunc *post)
490 {
491 Options *o = setup_follow(node);
492 setup_rel(o, node, FALSE, OB_DIRECTION_WEST,
493 pre, (o->follow ? input : NULL), post);
494 return o;
495 }
496
497 static gpointer setup_go_right_func(xmlNodePtr node,
498 ObActionsIPreFunc *pre,
499 ObActionsIInputFunc *input,
500 ObActionsICancelFunc *cancel,
501 ObActionsIPostFunc *post)
502 {
503 Options *o = g_new0(Options, 1);
504 setup_rel(o, node, FALSE, OB_DIRECTION_EAST, pre, input, post);
505 return o;
506 }
507
508 static gpointer setup_send_right_func(xmlNodePtr node,
509 ObActionsIPreFunc *pre,
510 ObActionsIInputFunc *input,
511 ObActionsICancelFunc *cancel,
512 ObActionsIPostFunc *post)
513 {
514 Options *o = setup_follow(node);
515 setup_rel(o, node, FALSE, OB_DIRECTION_EAST,
516 pre, (o->follow ? input : NULL), post);
517 return o;
518 }
519
520 static gpointer setup_go_up_func(xmlNodePtr node,
521 ObActionsIPreFunc *pre,
522 ObActionsIInputFunc *input,
523 ObActionsICancelFunc *cancel,
524 ObActionsIPostFunc *post)
525 {
526 Options *o = g_new0(Options, 1);
527 setup_rel(o, node, FALSE, OB_DIRECTION_NORTH, pre, input, post);
528 return o;
529 }
530
531 static gpointer setup_send_up_func(xmlNodePtr node,
532 ObActionsIPreFunc *pre,
533 ObActionsIInputFunc *input,
534 ObActionsICancelFunc *cancel,
535 ObActionsIPostFunc *post)
536 {
537 Options *o = setup_follow(node);
538 setup_rel(o, node, FALSE, OB_DIRECTION_NORTH,
539 pre, (o->follow ? input : NULL), post);
540 return o;
541 }
542
543 static gpointer setup_go_down_func(xmlNodePtr node,
544 ObActionsIPreFunc *pre,
545 ObActionsIInputFunc *input,
546 ObActionsICancelFunc *cancel,
547 ObActionsIPostFunc *post)
548 {
549 Options *o = g_new0(Options, 1);
550 setup_rel(o, node, FALSE, OB_DIRECTION_SOUTH, pre, input, post);
551 return o;
552 }
553
554 static gpointer setup_send_down_func(xmlNodePtr node,
555 ObActionsIPreFunc *pre,
556 ObActionsIInputFunc *input,
557 ObActionsICancelFunc *cancel,
558 ObActionsIPostFunc *post)
559 {
560 Options *o = setup_follow(node);
561 setup_rel(o, node, FALSE, OB_DIRECTION_SOUTH,
562 pre, (o->follow ? input : NULL), post);
563 return o;
564 }
This page took 0.053518 seconds and 3 git commands to generate.