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