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