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