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