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