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