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