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