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