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