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