]> Dogcows Code - chaz/openbox/blob - openbox/action.c
8ad60931f9f40b2f709b00dcba7eb27455a17664
[chaz/openbox] / openbox / action.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3 action.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003 Ben Jansens
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include "debug.h"
21 #include "client.h"
22 #include "focus.h"
23 #include "moveresize.h"
24 #include "menu.h"
25 #include "prop.h"
26 #include "stacking.h"
27 #include "screen.h"
28 #include "action.h"
29 #include "openbox.h"
30 #include "grab.h"
31 #include "keyboard.h"
32 #include "event.h"
33 #include "dock.h"
34 #include "config.h"
35 #include "mainloop.h"
36
37 #include <glib.h>
38
39 inline void client_action_start(union ActionData *data)
40 {
41 if (config_focus_follow)
42 if (data->any.context != OB_FRAME_CONTEXT_CLIENT && !data->any.button)
43 grab_pointer(TRUE, OB_CURSOR_NONE);
44 }
45
46 inline void client_action_end(union ActionData *data)
47 {
48 if (config_focus_follow)
49 if (data->any.context != OB_FRAME_CONTEXT_CLIENT) {
50 if (!data->any.button) {
51 grab_pointer(FALSE, OB_CURSOR_NONE);
52 } else {
53 ObClient *c;
54
55 /* usually this is sorta redundant, but with a press action
56 the enter event will come as a GrabNotify which is
57 ignored, so this will handle that case */
58 if ((c = client_under_pointer()))
59 event_enter_client(c);
60 }
61 }
62 }
63
64 typedef struct
65 {
66 const gchar *name;
67 void (*func)(union ActionData *);
68 void (*setup)(ObAction **, ObUserAction uact);
69 } ActionString;
70
71 static ObAction *action_new(void (*func)(union ActionData *data))
72 {
73 ObAction *a = g_new0(ObAction, 1);
74 a->ref = 1;
75 a->func = func;
76
77 return a;
78 }
79
80 void action_ref(ObAction *a)
81 {
82 ++a->ref;
83 }
84
85 void action_unref(ObAction *a)
86 {
87 if (a == NULL) return;
88
89 if (--a->ref > 0) return;
90
91 /* deal with pointers */
92 if (a->func == action_execute || a->func == action_restart)
93 g_free(a->data.execute.path);
94 else if (a->func == action_showmenu)
95 g_free(a->data.showmenu.name);
96
97 g_free(a);
98 }
99
100 ObAction* action_copy(const ObAction *src)
101 {
102 ObAction *a = action_new(src->func);
103
104 a->data = src->data;
105
106 /* deal with pointers */
107 if (a->func == action_execute || a->func == action_restart)
108 a->data.execute.path = g_strdup(a->data.execute.path);
109 else if (a->func == action_showmenu)
110 a->data.showmenu.name = g_strdup(a->data.showmenu.name);
111
112 return a;
113 }
114
115 void setup_action_directional_focus_north(ObAction **a, ObUserAction uact)
116 {
117 (*a)->data.interdiraction.inter.any.interactive = TRUE;
118 (*a)->data.interdiraction.direction = OB_DIRECTION_NORTH;
119 (*a)->data.interdiraction.dialog = TRUE;
120 }
121
122 void setup_action_directional_focus_east(ObAction **a, ObUserAction uact)
123 {
124 (*a)->data.interdiraction.inter.any.interactive = TRUE;
125 (*a)->data.interdiraction.direction = OB_DIRECTION_EAST;
126 (*a)->data.interdiraction.dialog = TRUE;
127 }
128
129 void setup_action_directional_focus_south(ObAction **a, ObUserAction uact)
130 {
131 (*a)->data.interdiraction.inter.any.interactive = TRUE;
132 (*a)->data.interdiraction.direction = OB_DIRECTION_SOUTH;
133 (*a)->data.interdiraction.dialog = TRUE;
134 }
135
136 void setup_action_directional_focus_west(ObAction **a, ObUserAction uact)
137 {
138 (*a)->data.interdiraction.inter.any.interactive = TRUE;
139 (*a)->data.interdiraction.direction = OB_DIRECTION_WEST;
140 (*a)->data.interdiraction.dialog = TRUE;
141 }
142
143 void setup_action_directional_focus_northeast(ObAction **a, ObUserAction uact)
144 {
145 (*a)->data.interdiraction.inter.any.interactive = TRUE;
146 (*a)->data.interdiraction.direction = OB_DIRECTION_NORTHEAST;
147 (*a)->data.interdiraction.dialog = TRUE;
148 }
149
150 void setup_action_directional_focus_southeast(ObAction **a, ObUserAction uact)
151 {
152 (*a)->data.interdiraction.inter.any.interactive = TRUE;
153 (*a)->data.interdiraction.direction = OB_DIRECTION_SOUTHEAST;
154 (*a)->data.interdiraction.dialog = TRUE;
155 }
156
157 void setup_action_directional_focus_southwest(ObAction **a, ObUserAction uact)
158 {
159 (*a)->data.interdiraction.inter.any.interactive = TRUE;
160 (*a)->data.interdiraction.direction = OB_DIRECTION_SOUTHWEST;
161 (*a)->data.interdiraction.dialog = TRUE;
162 }
163
164 void setup_action_directional_focus_northwest(ObAction **a, ObUserAction uact)
165 {
166 (*a)->data.interdiraction.inter.any.interactive = TRUE;
167 (*a)->data.interdiraction.direction = OB_DIRECTION_NORTHWEST;
168 (*a)->data.interdiraction.dialog = TRUE;
169 }
170
171 void setup_action_send_to_desktop(ObAction **a, ObUserAction uact)
172 {
173 (*a)->data.sendto.any.client_action = OB_CLIENT_ACTION_ALWAYS;
174 (*a)->data.sendto.follow = TRUE;
175 }
176
177 void setup_action_send_to_desktop_prev(ObAction **a, ObUserAction uact)
178 {
179 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
180 (*a)->data.sendtodir.inter.any.interactive = TRUE;
181 (*a)->data.sendtodir.dir = OB_DIRECTION_WEST;
182 (*a)->data.sendtodir.linear = TRUE;
183 (*a)->data.sendtodir.wrap = TRUE;
184 (*a)->data.sendtodir.follow = TRUE;
185 }
186
187 void setup_action_send_to_desktop_next(ObAction **a, ObUserAction uact)
188 {
189 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
190 (*a)->data.sendtodir.inter.any.interactive = TRUE;
191 (*a)->data.sendtodir.dir = OB_DIRECTION_EAST;
192 (*a)->data.sendtodir.linear = TRUE;
193 (*a)->data.sendtodir.wrap = TRUE;
194 (*a)->data.sendtodir.follow = TRUE;
195 }
196
197 void setup_action_send_to_desktop_left(ObAction **a, ObUserAction uact)
198 {
199 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
200 (*a)->data.sendtodir.inter.any.interactive = TRUE;
201 (*a)->data.sendtodir.dir = OB_DIRECTION_WEST;
202 (*a)->data.sendtodir.linear = FALSE;
203 (*a)->data.sendtodir.wrap = TRUE;
204 (*a)->data.sendtodir.follow = TRUE;
205 }
206
207 void setup_action_send_to_desktop_right(ObAction **a, ObUserAction uact)
208 {
209 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
210 (*a)->data.sendtodir.inter.any.interactive = TRUE;
211 (*a)->data.sendtodir.dir = OB_DIRECTION_EAST;
212 (*a)->data.sendtodir.linear = FALSE;
213 (*a)->data.sendtodir.wrap = TRUE;
214 (*a)->data.sendtodir.follow = TRUE;
215 }
216
217 void setup_action_send_to_desktop_up(ObAction **a, ObUserAction uact)
218 {
219 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
220 (*a)->data.sendtodir.inter.any.interactive = TRUE;
221 (*a)->data.sendtodir.dir = OB_DIRECTION_NORTH;
222 (*a)->data.sendtodir.linear = FALSE;
223 (*a)->data.sendtodir.wrap = TRUE;
224 (*a)->data.sendtodir.follow = TRUE;
225 }
226
227 void setup_action_send_to_desktop_down(ObAction **a, ObUserAction uact)
228 {
229 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
230 (*a)->data.sendtodir.inter.any.interactive = TRUE;
231 (*a)->data.sendtodir.dir = OB_DIRECTION_SOUTH;
232 (*a)->data.sendtodir.linear = FALSE;
233 (*a)->data.sendtodir.wrap = TRUE;
234 (*a)->data.sendtodir.follow = TRUE;
235 }
236
237 void setup_action_desktop(ObAction **a, ObUserAction uact)
238 {
239 (*a)->data.desktop.inter.any.interactive = FALSE;
240 }
241
242 void setup_action_desktop_prev(ObAction **a, ObUserAction uact)
243 {
244 (*a)->data.desktopdir.inter.any.interactive = TRUE;
245 (*a)->data.desktopdir.dir = OB_DIRECTION_WEST;
246 (*a)->data.desktopdir.linear = TRUE;
247 (*a)->data.desktopdir.wrap = TRUE;
248 }
249
250 void setup_action_desktop_next(ObAction **a, ObUserAction uact)
251 {
252 (*a)->data.desktopdir.inter.any.interactive = TRUE;
253 (*a)->data.desktopdir.dir = OB_DIRECTION_EAST;
254 (*a)->data.desktopdir.linear = TRUE;
255 (*a)->data.desktopdir.wrap = TRUE;
256 }
257
258 void setup_action_desktop_left(ObAction **a, ObUserAction uact)
259 {
260 (*a)->data.desktopdir.inter.any.interactive = TRUE;
261 (*a)->data.desktopdir.dir = OB_DIRECTION_WEST;
262 (*a)->data.desktopdir.linear = FALSE;
263 (*a)->data.desktopdir.wrap = TRUE;
264 }
265
266 void setup_action_desktop_right(ObAction **a, ObUserAction uact)
267 {
268 (*a)->data.desktopdir.inter.any.interactive = TRUE;
269 (*a)->data.desktopdir.dir = OB_DIRECTION_EAST;
270 (*a)->data.desktopdir.linear = FALSE;
271 (*a)->data.desktopdir.wrap = TRUE;
272 }
273
274 void setup_action_desktop_up(ObAction **a, ObUserAction uact)
275 {
276 (*a)->data.desktopdir.inter.any.interactive = TRUE;
277 (*a)->data.desktopdir.dir = OB_DIRECTION_NORTH;
278 (*a)->data.desktopdir.linear = FALSE;
279 (*a)->data.desktopdir.wrap = TRUE;
280 }
281
282 void setup_action_desktop_down(ObAction **a, ObUserAction uact)
283 {
284 (*a)->data.desktopdir.inter.any.interactive = TRUE;
285 (*a)->data.desktopdir.dir = OB_DIRECTION_SOUTH;
286 (*a)->data.desktopdir.linear = FALSE;
287 (*a)->data.desktopdir.wrap = TRUE;
288 }
289
290 void setup_action_cycle_windows_next(ObAction **a, ObUserAction uact)
291 {
292 (*a)->data.cycle.inter.any.interactive = TRUE;
293 (*a)->data.cycle.linear = FALSE;
294 (*a)->data.cycle.forward = TRUE;
295 (*a)->data.cycle.dialog = TRUE;
296 }
297
298 void setup_action_cycle_windows_previous(ObAction **a, ObUserAction uact)
299 {
300 (*a)->data.cycle.inter.any.interactive = TRUE;
301 (*a)->data.cycle.linear = FALSE;
302 (*a)->data.cycle.forward = FALSE;
303 (*a)->data.cycle.dialog = TRUE;
304 }
305
306 void setup_action_movefromedge_north(ObAction **a, ObUserAction uact)
307 {
308 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
309 (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
310 (*a)->data.diraction.hang = TRUE;
311 }
312
313 void setup_action_movefromedge_south(ObAction **a, ObUserAction uact)
314 {
315 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
316 (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
317 (*a)->data.diraction.hang = TRUE;
318 }
319
320 void setup_action_movefromedge_east(ObAction **a, ObUserAction uact)
321 {
322 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
323 (*a)->data.diraction.direction = OB_DIRECTION_EAST;
324 (*a)->data.diraction.hang = TRUE;
325 }
326
327 void setup_action_movefromedge_west(ObAction **a, ObUserAction uact)
328 {
329 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
330 (*a)->data.diraction.direction = OB_DIRECTION_WEST;
331 (*a)->data.diraction.hang = TRUE;
332 }
333
334 void setup_action_movetoedge_north(ObAction **a, ObUserAction uact)
335 {
336 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
337 (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
338 (*a)->data.diraction.hang = FALSE;
339 }
340
341 void setup_action_movetoedge_south(ObAction **a, ObUserAction uact)
342 {
343 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
344 (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
345 (*a)->data.diraction.hang = FALSE;
346 }
347
348 void setup_action_movetoedge_east(ObAction **a, ObUserAction uact)
349 {
350 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
351 (*a)->data.diraction.direction = OB_DIRECTION_EAST;
352 (*a)->data.diraction.hang = FALSE;
353 }
354
355 void setup_action_movetoedge_west(ObAction **a, ObUserAction uact)
356 {
357 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
358 (*a)->data.diraction.direction = OB_DIRECTION_WEST;
359 (*a)->data.diraction.hang = FALSE;
360 }
361
362 void setup_action_growtoedge_north(ObAction **a, ObUserAction uact)
363 {
364 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
365 (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
366 }
367
368 void setup_action_growtoedge_south(ObAction **a, ObUserAction uact)
369 {
370 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
371 (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
372 }
373
374 void setup_action_growtoedge_east(ObAction **a, ObUserAction uact)
375 {
376 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
377 (*a)->data.diraction.direction = OB_DIRECTION_EAST;
378 }
379
380 void setup_action_growtoedge_west(ObAction **a, ObUserAction uact)
381 {
382 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
383 (*a)->data.diraction.direction = OB_DIRECTION_WEST;
384 }
385
386 void setup_action_top_layer(ObAction **a, ObUserAction uact)
387 {
388 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
389 (*a)->data.layer.layer = 1;
390 }
391
392 void setup_action_normal_layer(ObAction **a, ObUserAction uact)
393 {
394 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
395 (*a)->data.layer.layer = 0;
396 }
397
398 void setup_action_bottom_layer(ObAction **a, ObUserAction uact)
399 {
400 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
401 (*a)->data.layer.layer = -1;
402 }
403
404 void setup_action_move(ObAction **a, ObUserAction uact)
405 {
406 (*a)->data.moveresize.any.client_action = OB_CLIENT_ACTION_ALWAYS;
407 (*a)->data.moveresize.move = TRUE;
408 (*a)->data.moveresize.keyboard =
409 (uact == OB_USER_ACTION_NONE ||
410 uact == OB_USER_ACTION_KEYBOARD_KEY ||
411 uact == OB_USER_ACTION_MENU_SELECTION);
412 }
413
414 void setup_action_resize(ObAction **a, ObUserAction uact)
415 {
416 (*a)->data.moveresize.any.client_action = OB_CLIENT_ACTION_ALWAYS;
417 (*a)->data.moveresize.move = FALSE;
418 (*a)->data.moveresize.keyboard =
419 (uact == OB_USER_ACTION_NONE ||
420 uact == OB_USER_ACTION_KEYBOARD_KEY ||
421 uact == OB_USER_ACTION_MENU_SELECTION);
422 }
423
424 void setup_action_showmenu(ObAction **a, ObUserAction uact)
425 {
426 (*a)->data.showmenu.any.client_action = OB_CLIENT_ACTION_OPTIONAL;
427 /* you cannot call ShowMenu from inside a menu, cuz the menu code makes
428 assumptions that there is only one menu (and submenus) open at
429 a time! */
430 if (uact == OB_USER_ACTION_MENU_SELECTION) {
431 action_unref(*a);
432 *a = NULL;
433 }
434 }
435
436 void setup_client_action(ObAction **a, ObUserAction uact)
437 {
438 (*a)->data.any.client_action = OB_CLIENT_ACTION_ALWAYS;
439 }
440
441 ActionString actionstrings[] =
442 {
443 {
444 "execute",
445 action_execute,
446 NULL
447 },
448 {
449 "directionalfocusnorth",
450 action_directional_focus,
451 setup_action_directional_focus_north
452 },
453 {
454 "directionalfocuseast",
455 action_directional_focus,
456 setup_action_directional_focus_east
457 },
458 {
459 "directionalfocussouth",
460 action_directional_focus,
461 setup_action_directional_focus_south
462 },
463 {
464 "directionalfocuswest",
465 action_directional_focus,
466 setup_action_directional_focus_west
467 },
468 {
469 "directionalfocusnortheast",
470 action_directional_focus,
471 setup_action_directional_focus_northeast
472 },
473 {
474 "directionalfocussoutheast",
475 action_directional_focus,
476 setup_action_directional_focus_southeast
477 },
478 {
479 "directionalfocussouthwest",
480 action_directional_focus,
481 setup_action_directional_focus_southwest
482 },
483 {
484 "directionalfocusnorthwest",
485 action_directional_focus,
486 setup_action_directional_focus_northwest
487 },
488 {
489 "activate",
490 action_activate,
491 setup_client_action
492 },
493 {
494 "focus",
495 action_focus,
496 setup_client_action
497 },
498 {
499 "unfocus",
500 action_unfocus,
501 setup_client_action
502 },
503 {
504 "iconify",
505 action_iconify,
506 setup_client_action
507 },
508 {
509 "focustobottom",
510 action_focus_order_to_bottom,
511 setup_client_action
512 },
513 {
514 "raiselower",
515 action_raiselower,
516 setup_client_action
517 },
518 {
519 "raise",
520 action_raise,
521 setup_client_action
522 },
523 {
524 "lower",
525 action_lower,
526 setup_client_action
527 },
528 {
529 "close",
530 action_close,
531 setup_client_action
532 },
533 {
534 "kill",
535 action_kill,
536 setup_client_action
537 },
538 {
539 "shadelower",
540 action_shadelower,
541 setup_client_action
542 },
543 {
544 "unshaderaise",
545 action_unshaderaise,
546 setup_client_action
547 },
548 {
549 "shade",
550 action_shade,
551 setup_client_action
552 },
553 {
554 "unshade",
555 action_unshade,
556 setup_client_action
557 },
558 {
559 "toggleshade",
560 action_toggle_shade,
561 setup_client_action
562 },
563 {
564 "toggleomnipresent",
565 action_toggle_omnipresent,
566 setup_client_action
567 },
568 {
569 "moverelativehorz",
570 action_move_relative_horz,
571 setup_client_action
572 },
573 {
574 "moverelativevert",
575 action_move_relative_vert,
576 setup_client_action
577 },
578 {
579 "movetocenter",
580 action_move_to_center,
581 setup_client_action
582 },
583 {
584 "resizerelativehorz",
585 action_resize_relative_horz,
586 setup_client_action
587 },
588 {
589 "resizerelativevert",
590 action_resize_relative_vert,
591 setup_client_action
592 },
593 {
594 "moverelative",
595 action_move_relative,
596 setup_client_action
597 },
598 {
599 "resizerelative",
600 action_resize_relative,
601 setup_client_action
602 },
603 {
604 "maximizefull",
605 action_maximize_full,
606 setup_client_action
607 },
608 {
609 "unmaximizefull",
610 action_unmaximize_full,
611 setup_client_action
612 },
613 {
614 "togglemaximizefull",
615 action_toggle_maximize_full,
616 setup_client_action
617 },
618 {
619 "maximizehorz",
620 action_maximize_horz,
621 setup_client_action
622 },
623 {
624 "unmaximizehorz",
625 action_unmaximize_horz,
626 setup_client_action
627 },
628 {
629 "togglemaximizehorz",
630 action_toggle_maximize_horz,
631 setup_client_action
632 },
633 {
634 "maximizevert",
635 action_maximize_vert,
636 setup_client_action
637 },
638 {
639 "unmaximizevert",
640 action_unmaximize_vert,
641 setup_client_action
642 },
643 {
644 "togglemaximizevert",
645 action_toggle_maximize_vert,
646 setup_client_action
647 },
648 {
649 "togglefullscreen",
650 action_toggle_fullscreen,
651 setup_client_action
652 },
653 {
654 "sendtodesktop",
655 action_send_to_desktop,
656 setup_action_send_to_desktop
657 },
658 {
659 "sendtodesktopnext",
660 action_send_to_desktop_dir,
661 setup_action_send_to_desktop_next
662 },
663 {
664 "sendtodesktopprevious",
665 action_send_to_desktop_dir,
666 setup_action_send_to_desktop_prev
667 },
668 {
669 "sendtodesktopright",
670 action_send_to_desktop_dir,
671 setup_action_send_to_desktop_right
672 },
673 {
674 "sendtodesktopleft",
675 action_send_to_desktop_dir,
676 setup_action_send_to_desktop_left
677 },
678 {
679 "sendtodesktopup",
680 action_send_to_desktop_dir,
681 setup_action_send_to_desktop_up
682 },
683 {
684 "sendtodesktopdown",
685 action_send_to_desktop_dir,
686 setup_action_send_to_desktop_down
687 },
688 {
689 "desktop",
690 action_desktop,
691 setup_action_desktop
692 },
693 {
694 "desktopnext",
695 action_desktop_dir,
696 setup_action_desktop_next
697 },
698 {
699 "desktopprevious",
700 action_desktop_dir,
701 setup_action_desktop_prev
702 },
703 {
704 "desktopright",
705 action_desktop_dir,
706 setup_action_desktop_right
707 },
708 {
709 "desktopleft",
710 action_desktop_dir,
711 setup_action_desktop_left
712 },
713 {
714 "desktopup",
715 action_desktop_dir,
716 setup_action_desktop_up
717 },
718 {
719 "desktopdown",
720 action_desktop_dir,
721 setup_action_desktop_down
722 },
723 {
724 "toggledecorations",
725 action_toggle_decorations,
726 setup_client_action
727 },
728 {
729 "move",
730 action_moveresize,
731 setup_action_move
732 },
733 {
734 "resize",
735 action_moveresize,
736 setup_action_resize
737 },
738 {
739 "toggledockautohide",
740 action_toggle_dockautohide,
741 NULL
742 },
743 {
744 "toggleshowdesktop",
745 action_toggle_show_desktop,
746 NULL
747 },
748 {
749 "showdesktop",
750 action_show_desktop,
751 NULL
752 },
753 {
754 "unshowdesktop",
755 action_unshow_desktop,
756 NULL
757 },
758 {
759 "desktoplast",
760 action_desktop_last,
761 NULL
762 },
763 {
764 "reconfigure",
765 action_reconfigure,
766 NULL
767 },
768 {
769 "restart",
770 action_restart,
771 NULL
772 },
773 {
774 "exit",
775 action_exit,
776 NULL
777 },
778 {
779 "showmenu",
780 action_showmenu,
781 setup_action_showmenu
782 },
783 {
784 "sendtotoplayer",
785 action_send_to_layer,
786 setup_action_top_layer
787 },
788 {
789 "togglealwaysontop",
790 action_toggle_layer,
791 setup_action_top_layer
792 },
793 {
794 "sendtonormallayer",
795 action_send_to_layer,
796 setup_action_normal_layer
797 },
798 {
799 "sendtobottomlayer",
800 action_send_to_layer,
801 setup_action_bottom_layer
802 },
803 {
804 "togglealwaysonbottom",
805 action_toggle_layer,
806 setup_action_bottom_layer
807 },
808 {
809 "nextwindow",
810 action_cycle_windows,
811 setup_action_cycle_windows_next
812 },
813 {
814 "previouswindow",
815 action_cycle_windows,
816 setup_action_cycle_windows_previous
817 },
818 {
819 "movefromedgenorth",
820 action_movetoedge,
821 setup_action_movefromedge_north
822 },
823 {
824 "movefromedgesouth",
825 action_movetoedge,
826 setup_action_movefromedge_south
827 },
828 {
829 "movefromedgewest",
830 action_movetoedge,
831 setup_action_movefromedge_west
832 },
833 {
834 "movefromedgeeast",
835 action_movetoedge,
836 setup_action_movefromedge_east
837 },
838 {
839 "movetoedgenorth",
840 action_movetoedge,
841 setup_action_movetoedge_north
842 },
843 {
844 "movetoedgesouth",
845 action_movetoedge,
846 setup_action_movetoedge_south
847 },
848 {
849 "movetoedgewest",
850 action_movetoedge,
851 setup_action_movetoedge_west
852 },
853 {
854 "movetoedgeeast",
855 action_movetoedge,
856 setup_action_movetoedge_east
857 },
858 {
859 "growtoedgenorth",
860 action_growtoedge,
861 setup_action_growtoedge_north
862 },
863 {
864 "growtoedgesouth",
865 action_growtoedge,
866 setup_action_growtoedge_south
867 },
868 {
869 "growtoedgewest",
870 action_growtoedge,
871 setup_action_growtoedge_west
872 },
873 {
874 "growtoedgeeast",
875 action_growtoedge,
876 setup_action_growtoedge_east
877 },
878 {
879 NULL,
880 NULL,
881 NULL
882 }
883 };
884
885 /* only key bindings can be interactive. thus saith the xor.
886 because of how the mouse is grabbed, mouse events dont even get
887 read during interactive events, so no dice! >:) */
888 #define INTERACTIVE_LIMIT(a, uact) \
889 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
890 a->data.any.interactive = FALSE;
891
892 ObAction *action_from_string(const gchar *name, ObUserAction uact)
893 {
894 ObAction *a = NULL;
895 gboolean exist = FALSE;
896 gint i;
897
898 for (i = 0; actionstrings[i].name; i++)
899 if (!g_ascii_strcasecmp(name, actionstrings[i].name)) {
900 exist = TRUE;
901 a = action_new(actionstrings[i].func);
902 if (actionstrings[i].setup)
903 actionstrings[i].setup(&a, uact);
904 if (a)
905 INTERACTIVE_LIMIT(a, uact);
906 break;
907 }
908 if (!exist)
909 g_warning("Invalid action '%s' requested. No such action exists.",
910 name);
911 if (!a)
912 g_warning("Invalid use of action '%s'. Action will be ignored.", name);
913 return a;
914 }
915
916 ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
917 ObUserAction uact)
918 {
919 gchar *actname;
920 ObAction *act = NULL;
921 xmlNodePtr n;
922
923 if (parse_attr_string("name", node, &actname)) {
924 if ((act = action_from_string(actname, uact))) {
925 if (act->func == action_execute || act->func == action_restart) {
926 if ((n = parse_find_node("execute", node->xmlChildrenNode))) {
927 gchar *s = parse_string(doc, n);
928 act->data.execute.path = parse_expand_tilde(s);
929 g_free(s);
930 }
931 } else if (act->func == action_showmenu) {
932 if ((n = parse_find_node("menu", node->xmlChildrenNode)))
933 act->data.showmenu.name = parse_string(doc, n);
934 } else if (act->func == action_move_relative_horz ||
935 act->func == action_move_relative_vert ||
936 act->func == action_resize_relative_horz ||
937 act->func == action_resize_relative_vert) {
938 if ((n = parse_find_node("delta", node->xmlChildrenNode)))
939 act->data.relative.deltax = parse_int(doc, n);
940 } else if (act->func == action_move_relative) {
941 if ((n = parse_find_node("x", node->xmlChildrenNode)))
942 act->data.relative.deltax = parse_int(doc, n);
943 if ((n = parse_find_node("y", node->xmlChildrenNode)))
944 act->data.relative.deltay = parse_int(doc, n);
945 } else if (act->func == action_resize_relative) {
946 if ((n = parse_find_node("left", node->xmlChildrenNode)))
947 act->data.relative.deltaxl = parse_int(doc, n);
948 if ((n = parse_find_node("up", node->xmlChildrenNode)))
949 act->data.relative.deltayu = parse_int(doc, n);
950 if ((n = parse_find_node("right", node->xmlChildrenNode)))
951 act->data.relative.deltax = parse_int(doc, n);
952 if ((n = parse_find_node("down", node->xmlChildrenNode)))
953 act->data.relative.deltay = parse_int(doc, n);
954 } else if (act->func == action_desktop) {
955 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
956 act->data.desktop.desk = parse_int(doc, n);
957 if (act->data.desktop.desk > 0) act->data.desktop.desk--;
958 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
959 act->data.desktop.inter.any.interactive =
960 parse_bool(doc, n);
961 } else if (act->func == action_send_to_desktop) {
962 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
963 act->data.sendto.desk = parse_int(doc, n);
964 if (act->data.sendto.desk > 0) act->data.sendto.desk--;
965 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
966 act->data.sendto.follow = parse_bool(doc, n);
967 } else if (act->func == action_desktop_dir) {
968 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
969 act->data.desktopdir.wrap = parse_bool(doc, n);
970 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
971 act->data.desktopdir.inter.any.interactive =
972 parse_bool(doc, n);
973 } else if (act->func == action_send_to_desktop_dir) {
974 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
975 act->data.sendtodir.wrap = parse_bool(doc, n);
976 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
977 act->data.sendtodir.follow = parse_bool(doc, n);
978 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
979 act->data.sendtodir.inter.any.interactive =
980 parse_bool(doc, n);
981 } else if (act->func == action_activate) {
982 if ((n = parse_find_node("here", node->xmlChildrenNode)))
983 act->data.activate.here = parse_bool(doc, n);
984 } else if (act->func == action_cycle_windows) {
985 if ((n = parse_find_node("linear", node->xmlChildrenNode)))
986 act->data.cycle.linear = parse_bool(doc, n);
987 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
988 act->data.cycle.dialog = parse_bool(doc, n);
989 } else if (act->func == action_directional_focus) {
990 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
991 act->data.cycle.dialog = parse_bool(doc, n);
992 } else if (act->func == action_raise ||
993 act->func == action_lower ||
994 act->func == action_raiselower ||
995 act->func == action_shadelower ||
996 act->func == action_unshaderaise) {
997 if ((n = parse_find_node("group", node->xmlChildrenNode)))
998 act->data.stacking.group = parse_bool(doc, n);
999 }
1000 INTERACTIVE_LIMIT(act, uact);
1001 }
1002 g_free(actname);
1003 }
1004 return act;
1005 }
1006
1007 void action_run_list(GSList *acts, ObClient *c, ObFrameContext context,
1008 guint state, guint button, gint x, gint y,
1009 gboolean cancel, gboolean done)
1010 {
1011 GSList *it;
1012 ObAction *a;
1013 gboolean inter = FALSE;
1014
1015 if (!acts)
1016 return;
1017
1018 if (x < 0 && y < 0)
1019 screen_pointer_pos(&x, &y);
1020
1021 if (grab_on_keyboard())
1022 inter = TRUE;
1023 else
1024 for (it = acts; it; it = g_slist_next(it)) {
1025 a = it->data;
1026 if (a->data.any.interactive) {
1027 inter = TRUE;
1028 break;
1029 }
1030 }
1031
1032 if (!inter) {
1033 /* sometimes when we execute another app as an action,
1034 it won't work right unless we XUngrabKeyboard first,
1035 even though we grabbed the key/button Asychronously.
1036 e.g. "gnome-panel-control --main-menu" */
1037 XUngrabKeyboard(ob_display, event_curtime);
1038 }
1039
1040 for (it = acts; it; it = g_slist_next(it)) {
1041 a = it->data;
1042
1043 if (!(a->data.any.client_action == OB_CLIENT_ACTION_ALWAYS && !c)) {
1044 a->data.any.c = a->data.any.client_action ? c : NULL;
1045 a->data.any.context = context;
1046 a->data.any.x = x;
1047 a->data.any.y = y;
1048
1049 a->data.any.button = button;
1050
1051 if (a->data.any.interactive) {
1052 a->data.inter.cancel = cancel;
1053 a->data.inter.final = done;
1054 if (!(cancel || done))
1055 if (!keyboard_interactive_grab(state, a->data.any.c, a))
1056 continue;
1057 }
1058
1059 /* XXX UGLY HACK race with motion event starting a move and the
1060 button release gettnig processed first. answer: don't queue
1061 moveresize starts. UGLY HACK XXX */
1062 if (a->data.any.interactive || a->func == action_moveresize) {
1063 /* interactive actions are not queued */
1064 a->func(&a->data);
1065 } else
1066 ob_main_loop_queue_action(ob_main_loop, a);
1067 }
1068 }
1069 }
1070
1071 void action_run_string(const gchar *name, struct _ObClient *c)
1072 {
1073 ObAction *a;
1074 GSList *l;
1075
1076 a = action_from_string(name, OB_USER_ACTION_NONE);
1077 g_assert(a);
1078
1079 l = g_slist_append(NULL, a);
1080
1081 action_run(l, c, 0);
1082 }
1083
1084 void action_execute(union ActionData *data)
1085 {
1086 GError *e = NULL;
1087 gchar *cmd, **argv = 0;
1088 if (data->execute.path) {
1089 cmd = g_filename_from_utf8(data->execute.path, -1, NULL, NULL, NULL);
1090 if (cmd) {
1091 if (!g_shell_parse_argv (cmd, NULL, &argv, &e)) {
1092 g_warning("failed to execute '%s': %s",
1093 cmd, e->message);
1094 g_error_free(e);
1095 } else {
1096 if (!g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH |
1097 G_SPAWN_DO_NOT_REAP_CHILD,
1098 NULL, NULL, NULL, &e)) {
1099 g_warning("failed to execute '%s': %s",
1100 cmd, e->message);
1101 g_error_free(e);
1102 }
1103 g_strfreev(argv);
1104 }
1105 g_free(cmd);
1106 } else {
1107 g_warning("failed to convert '%s' from utf8", data->execute.path);
1108 }
1109 }
1110 }
1111
1112 void action_activate(union ActionData *data)
1113 {
1114 /* similar to the openbox dock for dockapps, don't let user actions give
1115 focus to 3rd-party docks (panels) either (unless they ask for it
1116 themselves). */
1117 if (data->client.any.c->type != OB_CLIENT_TYPE_DOCK) {
1118 /* if using focus_delay, stop the timer now so that focus doesn't go
1119 moving on us */
1120 event_halt_focus_delay();
1121
1122 client_activate(data->activate.any.c, data->activate.here, TRUE);
1123 }
1124 }
1125
1126 void action_focus(union ActionData *data)
1127 {
1128 /* similar to the openbox dock for dockapps, don't let user actions give
1129 focus to 3rd-party docks (panels) either (unless they ask for it
1130 themselves). */
1131 if (data->client.any.c->type != OB_CLIENT_TYPE_DOCK) {
1132 /* if using focus_delay, stop the timer now so that focus doesn't go
1133 moving on us */
1134 event_halt_focus_delay();
1135
1136 client_focus(data->client.any.c);
1137 }
1138 }
1139
1140 void action_unfocus (union ActionData *data)
1141 {
1142 if (data->client.any.c == focus_client)
1143 focus_fallback(OB_FOCUS_FALLBACK_UNFOCUSING);
1144 }
1145
1146 void action_iconify(union ActionData *data)
1147 {
1148 client_action_start(data);
1149 client_iconify(data->client.any.c, TRUE, TRUE);
1150 client_action_end(data);
1151 }
1152
1153 void action_focus_order_to_bottom(union ActionData *data)
1154 {
1155 focus_order_to_bottom(data->client.any.c);
1156 }
1157
1158 void action_raiselower(union ActionData *data)
1159 {
1160 ObClient *c = data->client.any.c;
1161 GList *it;
1162 gboolean raise = FALSE;
1163
1164 for (it = stacking_list; it; it = g_list_next(it)) {
1165 if (WINDOW_IS_CLIENT(it->data)) {
1166 ObClient *cit = it->data;
1167
1168 if (cit == c) break;
1169 if (client_normal(cit) == client_normal(c) &&
1170 cit->layer == c->layer &&
1171 cit->frame->visible &&
1172 !client_search_transient(c, cit))
1173 {
1174 if (RECT_INTERSECTS_RECT(cit->frame->area, c->frame->area)) {
1175 raise = TRUE;
1176 break;
1177 }
1178 }
1179 }
1180 }
1181
1182 if (raise)
1183 action_raise(data);
1184 else
1185 action_lower(data);
1186 }
1187
1188 void action_raise(union ActionData *data)
1189 {
1190 client_action_start(data);
1191 stacking_raise(CLIENT_AS_WINDOW(data->client.any.c), data->stacking.group);
1192 client_action_end(data);
1193 }
1194
1195 void action_unshaderaise(union ActionData *data)
1196 {
1197 if (data->client.any.c->shaded)
1198 action_unshade(data);
1199 else
1200 action_raise(data);
1201 }
1202
1203 void action_shadelower(union ActionData *data)
1204 {
1205 if (data->client.any.c->shaded)
1206 action_lower(data);
1207 else
1208 action_shade(data);
1209 }
1210
1211 void action_lower(union ActionData *data)
1212 {
1213 client_action_start(data);
1214 stacking_lower(CLIENT_AS_WINDOW(data->client.any.c), data->stacking.group);
1215 client_action_end(data);
1216 }
1217
1218 void action_close(union ActionData *data)
1219 {
1220 client_close(data->client.any.c);
1221 }
1222
1223 void action_kill(union ActionData *data)
1224 {
1225 client_kill(data->client.any.c);
1226 }
1227
1228 void action_shade(union ActionData *data)
1229 {
1230 client_action_start(data);
1231 client_shade(data->client.any.c, TRUE);
1232 client_action_end(data);
1233 }
1234
1235 void action_unshade(union ActionData *data)
1236 {
1237 client_action_start(data);
1238 client_shade(data->client.any.c, FALSE);
1239 client_action_end(data);
1240 }
1241
1242 void action_toggle_shade(union ActionData *data)
1243 {
1244 client_action_start(data);
1245 client_shade(data->client.any.c, !data->client.any.c->shaded);
1246 client_action_end(data);
1247 }
1248
1249 void action_toggle_omnipresent(union ActionData *data)
1250 {
1251 client_set_desktop(data->client.any.c,
1252 data->client.any.c->desktop == DESKTOP_ALL ?
1253 screen_desktop : DESKTOP_ALL, FALSE);
1254 }
1255
1256 void action_move_relative_horz(union ActionData *data)
1257 {
1258 ObClient *c = data->relative.any.c;
1259 client_action_start(data);
1260 client_move(c, c->area.x + data->relative.deltax, c->area.y);
1261 client_action_end(data);
1262 }
1263
1264 void action_move_relative_vert(union ActionData *data)
1265 {
1266 ObClient *c = data->relative.any.c;
1267 client_action_start(data);
1268 client_move(c, c->area.x, c->area.y + data->relative.deltax);
1269 client_action_end(data);
1270 }
1271
1272 void action_move_to_center(union ActionData *data)
1273 {
1274 ObClient *c = data->client.any.c;
1275 Rect *area;
1276 area = screen_area_monitor(c->desktop, 0);
1277 client_action_start(data);
1278 client_move(c, area->width / 2 - c->area.width / 2,
1279 area->height / 2 - c->area.height / 2);
1280 client_action_end(data);
1281 }
1282
1283 void action_resize_relative_horz(union ActionData *data)
1284 {
1285 ObClient *c = data->relative.any.c;
1286 client_action_start(data);
1287 client_resize(c,
1288 c->area.width + data->relative.deltax * c->size_inc.width,
1289 c->area.height);
1290 client_action_end(data);
1291 }
1292
1293 void action_resize_relative_vert(union ActionData *data)
1294 {
1295 ObClient *c = data->relative.any.c;
1296 if (!c->shaded) {
1297 client_action_start(data);
1298 client_resize(c, c->area.width, c->area.height +
1299 data->relative.deltax * c->size_inc.height);
1300 client_action_end(data);
1301 }
1302 }
1303
1304 void action_move_relative(union ActionData *data)
1305 {
1306 ObClient *c = data->relative.any.c;
1307 client_action_start(data);
1308 client_move(c, c->area.x + data->relative.deltax, c->area.y +
1309 data->relative.deltay);
1310 client_action_end(data);
1311 }
1312
1313 void action_resize_relative(union ActionData *data)
1314 {
1315 ObClient *c = data->relative.any.c;
1316 client_action_start(data);
1317 client_move_resize(c,
1318 c->area.x - data->relative.deltaxl * c->size_inc.width,
1319 c->area.y - data->relative.deltayu * c->size_inc.height,
1320 c->area.width + data->relative.deltax * c->size_inc.width
1321 + data->relative.deltaxl * c->size_inc.width,
1322 c->area.height + data->relative.deltay * c->size_inc.height
1323 + data->relative.deltayu * c->size_inc.height);
1324 client_action_end(data);
1325 }
1326
1327 void action_maximize_full(union ActionData *data)
1328 {
1329 client_action_start(data);
1330 client_maximize(data->client.any.c, TRUE, 0, TRUE);
1331 client_action_end(data);
1332 }
1333
1334 void action_unmaximize_full(union ActionData *data)
1335 {
1336 client_action_start(data);
1337 client_maximize(data->client.any.c, FALSE, 0, TRUE);
1338 client_action_end(data);
1339 }
1340
1341 void action_toggle_maximize_full(union ActionData *data)
1342 {
1343 client_action_start(data);
1344 client_maximize(data->client.any.c,
1345 !(data->client.any.c->max_horz ||
1346 data->client.any.c->max_vert),
1347 0, TRUE);
1348 client_action_end(data);
1349 }
1350
1351 void action_maximize_horz(union ActionData *data)
1352 {
1353 client_action_start(data);
1354 client_maximize(data->client.any.c, TRUE, 1, TRUE);
1355 client_action_end(data);
1356 }
1357
1358 void action_unmaximize_horz(union ActionData *data)
1359 {
1360 client_action_start(data);
1361 client_maximize(data->client.any.c, FALSE, 1, TRUE);
1362 client_action_end(data);
1363 }
1364
1365 void action_toggle_maximize_horz(union ActionData *data)
1366 {
1367 client_action_start(data);
1368 client_maximize(data->client.any.c,
1369 !data->client.any.c->max_horz, 1, TRUE);
1370 client_action_end(data);
1371 }
1372
1373 void action_maximize_vert(union ActionData *data)
1374 {
1375 client_action_start(data);
1376 client_maximize(data->client.any.c, TRUE, 2, TRUE);
1377 client_action_end(data);
1378 }
1379
1380 void action_unmaximize_vert(union ActionData *data)
1381 {
1382 client_action_start(data);
1383 client_maximize(data->client.any.c, FALSE, 2, TRUE);
1384 client_action_end(data);
1385 }
1386
1387 void action_toggle_maximize_vert(union ActionData *data)
1388 {
1389 client_action_start(data);
1390 client_maximize(data->client.any.c,
1391 !data->client.any.c->max_vert, 2, TRUE);
1392 client_action_end(data);
1393 }
1394
1395 void action_toggle_fullscreen(union ActionData *data)
1396 {
1397 client_action_start(data);
1398 client_fullscreen(data->client.any.c,
1399 !(data->client.any.c->fullscreen), TRUE);
1400 client_action_end(data);
1401 }
1402
1403 void action_send_to_desktop(union ActionData *data)
1404 {
1405 ObClient *c = data->sendto.any.c;
1406
1407 if (!client_normal(c)) return;
1408
1409 if (data->sendto.desk < screen_num_desktops ||
1410 data->sendto.desk == DESKTOP_ALL) {
1411 client_set_desktop(c, data->sendto.desk, data->sendto.follow);
1412 if (data->sendto.follow)
1413 screen_set_desktop(data->sendto.desk);
1414 }
1415 }
1416
1417 void action_desktop(union ActionData *data)
1418 {
1419 static guint first = (unsigned) -1;
1420
1421 if (data->inter.any.interactive && first == (unsigned) -1)
1422 first = screen_desktop;
1423
1424 if (!data->inter.any.interactive ||
1425 (!data->inter.cancel && !data->inter.final))
1426 {
1427 if (data->desktop.desk < screen_num_desktops ||
1428 data->desktop.desk == DESKTOP_ALL)
1429 {
1430 screen_set_desktop(data->desktop.desk);
1431 if (data->inter.any.interactive)
1432 screen_desktop_popup(data->desktop.desk, TRUE);
1433 }
1434 } else if (data->inter.cancel) {
1435 screen_set_desktop(first);
1436 }
1437
1438 if (!data->inter.any.interactive || data->inter.final) {
1439 screen_desktop_popup(0, FALSE);
1440 first = (unsigned) -1;
1441 }
1442 }
1443
1444 void action_desktop_dir(union ActionData *data)
1445 {
1446 guint d;
1447
1448 d = screen_cycle_desktop(data->desktopdir.dir,
1449 data->desktopdir.wrap,
1450 data->desktopdir.linear,
1451 data->desktopdir.inter.any.interactive,
1452 data->desktopdir.inter.final,
1453 data->desktopdir.inter.cancel);
1454 if (!data->sendtodir.inter.any.interactive ||
1455 !data->sendtodir.inter.final ||
1456 data->sendtodir.inter.cancel)
1457 {
1458 screen_set_desktop(d);
1459 }
1460 }
1461
1462 void action_send_to_desktop_dir(union ActionData *data)
1463 {
1464 ObClient *c = data->sendtodir.inter.any.c;
1465 guint d;
1466
1467 if (!client_normal(c)) return;
1468
1469 d = screen_cycle_desktop(data->sendtodir.dir, data->sendtodir.wrap,
1470 data->sendtodir.linear,
1471 data->sendtodir.inter.any.interactive,
1472 data->sendtodir.inter.final,
1473 data->sendtodir.inter.cancel);
1474 if (!data->sendtodir.inter.any.interactive ||
1475 !data->sendtodir.inter.final ||
1476 data->sendtodir.inter.cancel)
1477 {
1478 client_set_desktop(c, d, data->sendtodir.follow);
1479 if (data->sendtodir.follow)
1480 screen_set_desktop(d);
1481 }
1482 }
1483
1484 void action_desktop_last(union ActionData *data)
1485 {
1486 screen_set_desktop(screen_last_desktop);
1487 }
1488
1489 void action_toggle_decorations(union ActionData *data)
1490 {
1491 ObClient *c = data->client.any.c;
1492
1493 client_action_start(data);
1494 client_set_undecorated(c, !c->undecorated);
1495 client_action_end(data);
1496 }
1497
1498 static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch)
1499 {
1500 if (config_resize_four_corners) {
1501 if (x - cx > cw / 2) {
1502 if (y - cy > ch / 2)
1503 return prop_atoms.net_wm_moveresize_size_bottomright;
1504 else
1505 return prop_atoms.net_wm_moveresize_size_topright;
1506 } else {
1507 if (y - cy > ch / 2)
1508 return prop_atoms.net_wm_moveresize_size_bottomleft;
1509 else
1510 return prop_atoms.net_wm_moveresize_size_topleft;
1511 }
1512 } else {
1513 if (x - cx > cw * 2 / 3) {
1514 if (y - cy > ch * 2 / 3)
1515 return prop_atoms.net_wm_moveresize_size_bottomright;
1516 else if (y - cy < ch / 3)
1517 return prop_atoms.net_wm_moveresize_size_topright;
1518 else
1519 return prop_atoms.net_wm_moveresize_size_right;
1520 } else if (x - cx < cw / 3) {
1521 if (y - cy > ch * 2 / 3)
1522 return prop_atoms.net_wm_moveresize_size_bottomleft;
1523 else if (y - cy < ch / 3)
1524 return prop_atoms.net_wm_moveresize_size_topleft;
1525 else
1526 return prop_atoms.net_wm_moveresize_size_left;
1527 } else
1528 if (y - cy > ch * 2 / 3)
1529 return prop_atoms.net_wm_moveresize_size_bottom;
1530 else if (y - cy < ch / 3)
1531 return prop_atoms.net_wm_moveresize_size_top;
1532 else
1533 return prop_atoms.net_wm_moveresize_move;
1534 }
1535 }
1536
1537 void action_moveresize(union ActionData *data)
1538 {
1539 ObClient *c = data->moveresize.any.c;
1540 guint32 corner;
1541
1542 if (!client_normal(c)) return;
1543
1544 if (data->moveresize.keyboard) {
1545 corner = (data->moveresize.move ?
1546 prop_atoms.net_wm_moveresize_move_keyboard :
1547 prop_atoms.net_wm_moveresize_size_keyboard);
1548 } else {
1549 corner = (data->moveresize.move ?
1550 prop_atoms.net_wm_moveresize_move :
1551 pick_corner(data->any.x, data->any.y,
1552 c->frame->area.x, c->frame->area.y,
1553 /* use the client size because the frame
1554 can be differently sized (shaded
1555 windows) and we want this based on the
1556 clients size */
1557 c->area.width + c->frame->size.left +
1558 c->frame->size.right,
1559 c->area.height + c->frame->size.top +
1560 c->frame->size.bottom));
1561 }
1562
1563 moveresize_start(c, data->any.x, data->any.y, data->any.button, corner);
1564 }
1565
1566 void action_reconfigure(union ActionData *data)
1567 {
1568 ob_reconfigure();
1569 }
1570
1571 void action_restart(union ActionData *data)
1572 {
1573 ob_restart_other(data->execute.path);
1574 }
1575
1576 void action_exit(union ActionData *data)
1577 {
1578 ob_exit(0);
1579 }
1580
1581 void action_showmenu(union ActionData *data)
1582 {
1583 if (data->showmenu.name) {
1584 menu_show(data->showmenu.name, data->any.x, data->any.y,
1585 data->showmenu.any.c);
1586 }
1587 }
1588
1589 void action_cycle_windows(union ActionData *data)
1590 {
1591 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1592 on us */
1593 event_halt_focus_delay();
1594
1595 focus_cycle(data->cycle.forward, data->cycle.linear, data->any.interactive,
1596 data->cycle.dialog,
1597 data->cycle.inter.final, data->cycle.inter.cancel);
1598 }
1599
1600 void action_directional_focus(union ActionData *data)
1601 {
1602 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1603 on us */
1604 event_halt_focus_delay();
1605
1606 focus_directional_cycle(data->interdiraction.direction,
1607 data->any.interactive,
1608 data->interdiraction.dialog,
1609 data->interdiraction.inter.final,
1610 data->interdiraction.inter.cancel);
1611 }
1612
1613 void action_movetoedge(union ActionData *data)
1614 {
1615 gint x, y;
1616 ObClient *c = data->diraction.any.c;
1617
1618 x = c->frame->area.x;
1619 y = c->frame->area.y;
1620
1621 switch(data->diraction.direction) {
1622 case OB_DIRECTION_NORTH:
1623 y = client_directional_edge_search(c, OB_DIRECTION_NORTH,
1624 data->diraction.hang)
1625 - (data->diraction.hang ? c->frame->area.height : 0);
1626 break;
1627 case OB_DIRECTION_WEST:
1628 x = client_directional_edge_search(c, OB_DIRECTION_WEST,
1629 data->diraction.hang)
1630 - (data->diraction.hang ? c->frame->area.width : 0);
1631 break;
1632 case OB_DIRECTION_SOUTH:
1633 y = client_directional_edge_search(c, OB_DIRECTION_SOUTH,
1634 data->diraction.hang)
1635 - (data->diraction.hang ? 0 : c->frame->area.height);
1636 break;
1637 case OB_DIRECTION_EAST:
1638 x = client_directional_edge_search(c, OB_DIRECTION_EAST,
1639 data->diraction.hang)
1640 - (data->diraction.hang ? 0 : c->frame->area.width);
1641 break;
1642 default:
1643 g_assert_not_reached();
1644 }
1645 frame_frame_gravity(c->frame, &x, &y);
1646 client_action_start(data);
1647 client_move(c, x, y);
1648 client_action_end(data);
1649 }
1650
1651 void action_growtoedge(union ActionData *data)
1652 {
1653 gint x, y, width, height, dest;
1654 ObClient *c = data->diraction.any.c;
1655 Rect *a;
1656
1657 //FIXME growtoedge resizes shaded windows to 0 height
1658 if (c->shaded)
1659 return;
1660
1661 a = screen_area(c->desktop);
1662 x = c->frame->area.x;
1663 y = c->frame->area.y;
1664 width = c->frame->area.width;
1665 height = c->frame->area.height;
1666
1667 switch(data->diraction.direction) {
1668 case OB_DIRECTION_NORTH:
1669 dest = client_directional_edge_search(c, OB_DIRECTION_NORTH, FALSE);
1670 if (a->y == y)
1671 height = c->frame->area.height / 2;
1672 else {
1673 height = c->frame->area.y + c->frame->area.height - dest;
1674 y = dest;
1675 }
1676 break;
1677 case OB_DIRECTION_WEST:
1678 dest = client_directional_edge_search(c, OB_DIRECTION_WEST, FALSE);
1679 if (a->x == x)
1680 width = c->frame->area.width / 2;
1681 else {
1682 width = c->frame->area.x + c->frame->area.width - dest;
1683 x = dest;
1684 }
1685 break;
1686 case OB_DIRECTION_SOUTH:
1687 dest = client_directional_edge_search(c, OB_DIRECTION_SOUTH, FALSE);
1688 if (a->y + a->height == y + c->frame->area.height) {
1689 height = c->frame->area.height / 2;
1690 y = a->y + a->height - height;
1691 } else
1692 height = dest - c->frame->area.y;
1693 y += (height - c->frame->area.height) % c->size_inc.height;
1694 height -= (height - c->frame->area.height) % c->size_inc.height;
1695 break;
1696 case OB_DIRECTION_EAST:
1697 dest = client_directional_edge_search(c, OB_DIRECTION_EAST, FALSE);
1698 if (a->x + a->width == x + c->frame->area.width) {
1699 width = c->frame->area.width / 2;
1700 x = a->x + a->width - width;
1701 } else
1702 width = dest - c->frame->area.x;
1703 x += (width - c->frame->area.width) % c->size_inc.width;
1704 width -= (width - c->frame->area.width) % c->size_inc.width;
1705 break;
1706 default:
1707 g_assert_not_reached();
1708 }
1709 frame_frame_gravity(c->frame, &x, &y);
1710 width -= c->frame->size.left + c->frame->size.right;
1711 height -= c->frame->size.top + c->frame->size.bottom;
1712 client_action_start(data);
1713 client_move_resize(c, x, y, width, height);
1714 client_action_end(data);
1715 }
1716
1717 void action_send_to_layer(union ActionData *data)
1718 {
1719 client_set_layer(data->layer.any.c, data->layer.layer);
1720 }
1721
1722 void action_toggle_layer(union ActionData *data)
1723 {
1724 ObClient *c = data->layer.any.c;
1725
1726 client_action_start(data);
1727 if (data->layer.layer < 0)
1728 client_set_layer(c, c->below ? 0 : -1);
1729 else if (data->layer.layer > 0)
1730 client_set_layer(c, c->above ? 0 : 1);
1731 client_action_end(data);
1732 }
1733
1734 void action_toggle_dockautohide(union ActionData *data)
1735 {
1736 config_dock_hide = !config_dock_hide;
1737 dock_configure();
1738 }
1739
1740 void action_toggle_show_desktop(union ActionData *data)
1741 {
1742 screen_show_desktop(!screen_showing_desktop);
1743 }
1744
1745 void action_show_desktop(union ActionData *data)
1746 {
1747 screen_show_desktop(TRUE);
1748 }
1749
1750 void action_unshow_desktop(union ActionData *data)
1751 {
1752 screen_show_desktop(FALSE);
1753 }
This page took 0.105438 seconds and 3 git commands to generate.