]> Dogcows Code - chaz/openbox/blob - openbox/action.c
use the new window.title.separator.width
[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
1333 client_action_start(data);
1334 stacking_restack_request(c, NULL, Opposite, FALSE);
1335 client_action_end(data);
1336 }
1337
1338 void action_raise(union ActionData *data)
1339 {
1340 client_action_start(data);
1341 stacking_raise(CLIENT_AS_WINDOW(data->client.any.c));
1342 client_action_end(data);
1343 }
1344
1345 void action_unshaderaise(union ActionData *data)
1346 {
1347 if (data->client.any.c->shaded)
1348 action_unshade(data);
1349 else
1350 action_raise(data);
1351 }
1352
1353 void action_shadelower(union ActionData *data)
1354 {
1355 if (data->client.any.c->shaded)
1356 action_lower(data);
1357 else
1358 action_shade(data);
1359 }
1360
1361 void action_lower(union ActionData *data)
1362 {
1363 client_action_start(data);
1364 stacking_lower(CLIENT_AS_WINDOW(data->client.any.c));
1365 client_action_end(data);
1366 }
1367
1368 void action_close(union ActionData *data)
1369 {
1370 client_close(data->client.any.c);
1371 }
1372
1373 void action_kill(union ActionData *data)
1374 {
1375 client_kill(data->client.any.c);
1376 }
1377
1378 void action_shade(union ActionData *data)
1379 {
1380 client_action_start(data);
1381 client_shade(data->client.any.c, TRUE);
1382 client_action_end(data);
1383 }
1384
1385 void action_unshade(union ActionData *data)
1386 {
1387 client_action_start(data);
1388 client_shade(data->client.any.c, FALSE);
1389 client_action_end(data);
1390 }
1391
1392 void action_toggle_shade(union ActionData *data)
1393 {
1394 client_action_start(data);
1395 client_shade(data->client.any.c, !data->client.any.c->shaded);
1396 client_action_end(data);
1397 }
1398
1399 void action_toggle_omnipresent(union ActionData *data)
1400 {
1401 client_set_desktop(data->client.any.c,
1402 data->client.any.c->desktop == DESKTOP_ALL ?
1403 screen_desktop : DESKTOP_ALL, FALSE);
1404 }
1405
1406 void action_move_relative_horz(union ActionData *data)
1407 {
1408 ObClient *c = data->relative.any.c;
1409 client_action_start(data);
1410 client_move(c, c->area.x + data->relative.deltax, c->area.y);
1411 client_action_end(data);
1412 }
1413
1414 void action_move_relative_vert(union ActionData *data)
1415 {
1416 ObClient *c = data->relative.any.c;
1417 client_action_start(data);
1418 client_move(c, c->area.x, c->area.y + data->relative.deltax);
1419 client_action_end(data);
1420 }
1421
1422 void action_move_to_center(union ActionData *data)
1423 {
1424 ObClient *c = data->client.any.c;
1425 Rect *area;
1426 area = screen_area_monitor(c->desktop, 0);
1427 client_action_start(data);
1428 client_move(c, area->width / 2 - c->area.width / 2,
1429 area->height / 2 - c->area.height / 2);
1430 client_action_end(data);
1431 }
1432
1433 void action_resize_relative_horz(union ActionData *data)
1434 {
1435 ObClient *c = data->relative.any.c;
1436 client_action_start(data);
1437 client_resize(c,
1438 c->area.width + data->relative.deltax * c->size_inc.width,
1439 c->area.height);
1440 client_action_end(data);
1441 }
1442
1443 void action_resize_relative_vert(union ActionData *data)
1444 {
1445 ObClient *c = data->relative.any.c;
1446 if (!c->shaded) {
1447 client_action_start(data);
1448 client_resize(c, c->area.width, c->area.height +
1449 data->relative.deltax * c->size_inc.height);
1450 client_action_end(data);
1451 }
1452 }
1453
1454 void action_move_relative(union ActionData *data)
1455 {
1456 ObClient *c = data->relative.any.c;
1457 client_action_start(data);
1458 client_move(c, c->area.x + data->relative.deltax, c->area.y +
1459 data->relative.deltay);
1460 client_action_end(data);
1461 }
1462
1463 void action_resize_relative(union ActionData *data)
1464 {
1465 ObClient *c = data->relative.any.c;
1466 gint x, y, ow, w, oh, h, lw, lh;
1467
1468 client_action_start(data);
1469
1470 x = c->area.x;
1471 y = c->area.y;
1472 ow = c->area.width;
1473 w = ow + data->relative.deltax * c->size_inc.width
1474 + data->relative.deltaxl * c->size_inc.width;
1475 oh = c->area.height;
1476 h = oh + data->relative.deltay * c->size_inc.height
1477 + data->relative.deltayu * c->size_inc.height;
1478
1479 client_try_configure(c, &x, &y, &w, &h, &lw, &lh, TRUE);
1480 client_move_resize(c, x + (ow - w), y + (oh - h), w, h);
1481 client_action_end(data);
1482 }
1483
1484 void action_maximize_full(union ActionData *data)
1485 {
1486 client_action_start(data);
1487 client_maximize(data->client.any.c, TRUE, 0);
1488 client_action_end(data);
1489 }
1490
1491 void action_unmaximize_full(union ActionData *data)
1492 {
1493 client_action_start(data);
1494 client_maximize(data->client.any.c, FALSE, 0);
1495 client_action_end(data);
1496 }
1497
1498 void action_toggle_maximize_full(union ActionData *data)
1499 {
1500 client_action_start(data);
1501 client_maximize(data->client.any.c,
1502 !(data->client.any.c->max_horz ||
1503 data->client.any.c->max_vert),
1504 0);
1505 client_action_end(data);
1506 }
1507
1508 void action_maximize_horz(union ActionData *data)
1509 {
1510 client_action_start(data);
1511 client_maximize(data->client.any.c, TRUE, 1);
1512 client_action_end(data);
1513 }
1514
1515 void action_unmaximize_horz(union ActionData *data)
1516 {
1517 client_action_start(data);
1518 client_maximize(data->client.any.c, FALSE, 1);
1519 client_action_end(data);
1520 }
1521
1522 void action_toggle_maximize_horz(union ActionData *data)
1523 {
1524 client_action_start(data);
1525 client_maximize(data->client.any.c,
1526 !data->client.any.c->max_horz, 1);
1527 client_action_end(data);
1528 }
1529
1530 void action_maximize_vert(union ActionData *data)
1531 {
1532 client_action_start(data);
1533 client_maximize(data->client.any.c, TRUE, 2);
1534 client_action_end(data);
1535 }
1536
1537 void action_unmaximize_vert(union ActionData *data)
1538 {
1539 client_action_start(data);
1540 client_maximize(data->client.any.c, FALSE, 2);
1541 client_action_end(data);
1542 }
1543
1544 void action_toggle_maximize_vert(union ActionData *data)
1545 {
1546 client_action_start(data);
1547 client_maximize(data->client.any.c,
1548 !data->client.any.c->max_vert, 2);
1549 client_action_end(data);
1550 }
1551
1552 void action_toggle_fullscreen(union ActionData *data)
1553 {
1554 client_action_start(data);
1555 client_fullscreen(data->client.any.c, !(data->client.any.c->fullscreen));
1556 client_action_end(data);
1557 }
1558
1559 void action_send_to_desktop(union ActionData *data)
1560 {
1561 ObClient *c = data->sendto.any.c;
1562
1563 if (!client_normal(c)) return;
1564
1565 if (data->sendto.desk < screen_num_desktops ||
1566 data->sendto.desk == DESKTOP_ALL) {
1567 client_set_desktop(c, data->sendto.desk, data->sendto.follow);
1568 if (data->sendto.follow && data->sendto.desk != screen_desktop)
1569 screen_set_desktop(data->sendto.desk, TRUE);
1570 }
1571 }
1572
1573 void action_desktop(union ActionData *data)
1574 {
1575 /* XXX add the interactive/dialog option back again once the dialog
1576 has been made to not use grabs */
1577 if (data->desktop.desk < screen_num_desktops ||
1578 data->desktop.desk == DESKTOP_ALL)
1579 {
1580 screen_set_desktop(data->desktop.desk, TRUE);
1581 if (data->inter.any.interactive)
1582 screen_desktop_popup(data->desktop.desk, TRUE);
1583 }
1584 }
1585
1586 void action_desktop_dir(union ActionData *data)
1587 {
1588 guint d;
1589
1590 d = screen_cycle_desktop(data->desktopdir.dir,
1591 data->desktopdir.wrap,
1592 data->desktopdir.linear,
1593 data->desktopdir.inter.any.interactive,
1594 data->desktopdir.inter.final,
1595 data->desktopdir.inter.cancel);
1596 /* only move the desktop when the action is complete. if we switch
1597 desktops during the interactive action, focus will move but with
1598 NotifyWhileGrabbed and applications don't like that. */
1599 if (!data->sendtodir.inter.any.interactive ||
1600 (data->sendtodir.inter.final && !data->sendtodir.inter.cancel))
1601 {
1602 if (d != screen_desktop)
1603 screen_set_desktop(d, TRUE);
1604 }
1605 }
1606
1607 void action_send_to_desktop_dir(union ActionData *data)
1608 {
1609 ObClient *c = data->sendtodir.inter.any.c;
1610 guint d;
1611
1612 if (!client_normal(c)) return;
1613
1614 d = screen_cycle_desktop(data->sendtodir.dir, data->sendtodir.wrap,
1615 data->sendtodir.linear,
1616 data->sendtodir.inter.any.interactive,
1617 data->sendtodir.inter.final,
1618 data->sendtodir.inter.cancel);
1619 /* only move the desktop when the action is complete. if we switch
1620 desktops during the interactive action, focus will move but with
1621 NotifyWhileGrabbed and applications don't like that. */
1622 if (!data->sendtodir.inter.any.interactive ||
1623 (data->sendtodir.inter.final && !data->sendtodir.inter.cancel))
1624 {
1625 client_set_desktop(c, d, data->sendtodir.follow);
1626 if (data->sendtodir.follow && d != screen_desktop)
1627 screen_set_desktop(d, TRUE);
1628 }
1629 }
1630
1631 void action_desktop_last(union ActionData *data)
1632 {
1633 screen_set_desktop(screen_last_desktop, TRUE);
1634 }
1635
1636 void action_toggle_decorations(union ActionData *data)
1637 {
1638 ObClient *c = data->client.any.c;
1639
1640 client_action_start(data);
1641 client_set_undecorated(c, !c->undecorated);
1642 client_action_end(data);
1643 }
1644
1645 static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch,
1646 gboolean shaded)
1647 {
1648 /* let's make x and y client relative instead of screen relative */
1649 x = x - cx;
1650 y = ch - (y - cy); /* y is inverted, 0 is at the bottom of the window */
1651
1652 #define X x*ch/cw
1653 #define A -4*X + 7*ch/3
1654 #define B 4*X -15*ch/9
1655 #define C -X/4 + 2*ch/3
1656 #define D X/4 + 5*ch/12
1657 #define E X/4 + ch/3
1658 #define F -X/4 + 7*ch/12
1659 #define G 4*X - 4*ch/3
1660 #define H -4*X + 8*ch/3
1661 #define a (y > 5*ch/9)
1662 #define b (x < 4*cw/9)
1663 #define c (x > 5*cw/9)
1664 #define d (y < 4*ch/9)
1665
1666 /*
1667 Each of these defines (except X which is just there for fun), represents
1668 the equation of a line. The lines they represent are shown in the diagram
1669 below. Checking y against these lines, we are able to choose a region
1670 of the window as shown.
1671
1672 +---------------------A-------|-------|-------B---------------------+
1673 | |A B| |
1674 | |A | | B| |
1675 | | A B | |
1676 | | A | | B | |
1677 | | A B | |
1678 | | A | | B | |
1679 | northwest | A north B | northeast |
1680 | | A | | B | |
1681 | | A B | |
1682 C---------------------+----A--+-------+--B----+---------------------D
1683 |CCCCCCC | A B | DDDDDDD|
1684 | CCCCCCCC | A | | B | DDDDDDDD |
1685 | CCCCCCC A B DDDDDDD |
1686 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
1687 | | b c | | sh
1688 | west | b move c | east | ad
1689 | | b c | | ed
1690 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
1691 | EEEEEEE G H FFFFFFF |
1692 | EEEEEEEE | G | | H | FFFFFFFF |
1693 |EEEEEEE | G H | FFFFFFF|
1694 E---------------------+----G--+-------+--H----+---------------------F
1695 | | G H | |
1696 | | G | | H | |
1697 | southwest | G south H | southeast |
1698 | | G | | H | |
1699 | | G H | |
1700 | | G | | H | |
1701 | | G H | |
1702 | |G | | H| |
1703 | |G H| |
1704 +---------------------G-------|-------|-------H---------------------+
1705 */
1706
1707 if (shaded) {
1708 /* for shaded windows, you can only resize west/east and move */
1709 if (b)
1710 return prop_atoms.net_wm_moveresize_size_left;
1711 if (c)
1712 return prop_atoms.net_wm_moveresize_size_right;
1713 return prop_atoms.net_wm_moveresize_move;
1714 }
1715
1716 if (y < A && y >= C)
1717 return prop_atoms.net_wm_moveresize_size_topleft;
1718 else if (y >= A && y >= B && a)
1719 return prop_atoms.net_wm_moveresize_size_top;
1720 else if (y < B && y >= D)
1721 return prop_atoms.net_wm_moveresize_size_topright;
1722 else if (y < C && y >= E && b)
1723 return prop_atoms.net_wm_moveresize_size_left;
1724 else if (y < D && y >= F && c)
1725 return prop_atoms.net_wm_moveresize_size_right;
1726 else if (y < E && y >= G)
1727 return prop_atoms.net_wm_moveresize_size_bottomleft;
1728 else if (y < G && y < H && d)
1729 return prop_atoms.net_wm_moveresize_size_bottom;
1730 else if (y >= H && y < F)
1731 return prop_atoms.net_wm_moveresize_size_bottomright;
1732 else
1733 return prop_atoms.net_wm_moveresize_move;
1734
1735 #undef X
1736 #undef A
1737 #undef B
1738 #undef C
1739 #undef D
1740 #undef E
1741 #undef F
1742 #undef G
1743 #undef H
1744 #undef a
1745 #undef b
1746 #undef c
1747 #undef d
1748 }
1749
1750 void action_move(union ActionData *data)
1751 {
1752 ObClient *c = data->moveresize.any.c;
1753 guint32 corner;
1754
1755 if (data->moveresize.keyboard)
1756 corner = prop_atoms.net_wm_moveresize_move_keyboard;
1757 else
1758 corner = prop_atoms.net_wm_moveresize_move;
1759
1760 moveresize_start(c, data->any.x, data->any.y, data->any.button, corner);
1761 }
1762
1763 void action_resize(union ActionData *data)
1764 {
1765 ObClient *c = data->moveresize.any.c;
1766 guint32 corner;
1767
1768 if (data->moveresize.keyboard)
1769 corner = prop_atoms.net_wm_moveresize_size_keyboard;
1770 else if (data->moveresize.corner)
1771 corner = data->moveresize.corner; /* it was specified in the binding */
1772 else
1773 corner = pick_corner(data->any.x, data->any.y,
1774 c->frame->area.x, c->frame->area.y,
1775 /* use the client size because the frame
1776 can be differently sized (shaded
1777 windows) and we want this based on the
1778 clients size */
1779 c->area.width + c->frame->size.left +
1780 c->frame->size.right,
1781 c->area.height + c->frame->size.top +
1782 c->frame->size.bottom, c->shaded);
1783
1784 moveresize_start(c, data->any.x, data->any.y, data->any.button, corner);
1785 }
1786
1787 void action_reconfigure(union ActionData *data)
1788 {
1789 ob_reconfigure();
1790 }
1791
1792 void action_restart(union ActionData *data)
1793 {
1794 ob_restart_other(data->execute.path);
1795 }
1796
1797 void action_exit(union ActionData *data)
1798 {
1799 ob_exit(0);
1800 }
1801
1802 void action_showmenu(union ActionData *data)
1803 {
1804 if (data->showmenu.name) {
1805 menu_show(data->showmenu.name, data->any.x, data->any.y,
1806 data->any.button, data->showmenu.any.c);
1807 }
1808 }
1809
1810 void action_cycle_windows(union ActionData *data)
1811 {
1812 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1813 on us */
1814 event_halt_focus_delay();
1815
1816 focus_cycle(data->cycle.forward,
1817 data->cycle.all_desktops,
1818 data->cycle.dock_windows,
1819 data->cycle.desktop_windows,
1820 data->cycle.linear, data->any.interactive,
1821 data->cycle.dialog,
1822 data->cycle.inter.final, data->cycle.inter.cancel);
1823 }
1824
1825 void action_directional_focus(union ActionData *data)
1826 {
1827 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1828 on us */
1829 event_halt_focus_delay();
1830
1831 focus_directional_cycle(data->interdiraction.direction,
1832 data->interdiraction.dock_windows,
1833 data->interdiraction.desktop_windows,
1834 data->any.interactive,
1835 data->interdiraction.dialog,
1836 data->interdiraction.inter.final,
1837 data->interdiraction.inter.cancel);
1838 }
1839
1840 void action_movetoedge(union ActionData *data)
1841 {
1842 gint x, y;
1843 ObClient *c = data->diraction.any.c;
1844
1845 x = c->frame->area.x;
1846 y = c->frame->area.y;
1847
1848 switch(data->diraction.direction) {
1849 case OB_DIRECTION_NORTH:
1850 y = client_directional_edge_search(c, OB_DIRECTION_NORTH,
1851 data->diraction.hang)
1852 - (data->diraction.hang ? c->frame->area.height : 0);
1853 break;
1854 case OB_DIRECTION_WEST:
1855 x = client_directional_edge_search(c, OB_DIRECTION_WEST,
1856 data->diraction.hang)
1857 - (data->diraction.hang ? c->frame->area.width : 0);
1858 break;
1859 case OB_DIRECTION_SOUTH:
1860 y = client_directional_edge_search(c, OB_DIRECTION_SOUTH,
1861 data->diraction.hang)
1862 - (data->diraction.hang ? 0 : c->frame->area.height);
1863 break;
1864 case OB_DIRECTION_EAST:
1865 x = client_directional_edge_search(c, OB_DIRECTION_EAST,
1866 data->diraction.hang)
1867 - (data->diraction.hang ? 0 : c->frame->area.width);
1868 break;
1869 default:
1870 g_assert_not_reached();
1871 }
1872 frame_frame_gravity(c->frame, &x, &y, c->area.width, c->area.height);
1873 client_action_start(data);
1874 client_move(c, x, y);
1875 client_action_end(data);
1876 }
1877
1878 void action_growtoedge(union ActionData *data)
1879 {
1880 gint x, y, width, height, dest;
1881 ObClient *c = data->diraction.any.c;
1882 Rect *a;
1883
1884 a = screen_area(c->desktop);
1885 x = c->frame->area.x;
1886 y = c->frame->area.y;
1887 /* get the unshaded frame's dimensions..if it is shaded */
1888 width = c->area.width + c->frame->size.left + c->frame->size.right;
1889 height = c->area.height + c->frame->size.top + c->frame->size.bottom;
1890
1891 switch(data->diraction.direction) {
1892 case OB_DIRECTION_NORTH:
1893 if (c->shaded) break; /* don't allow vertical resize if shaded */
1894
1895 dest = client_directional_edge_search(c, OB_DIRECTION_NORTH, FALSE);
1896 if (a->y == y)
1897 height = height / 2;
1898 else {
1899 height = c->frame->area.y + height - dest;
1900 y = dest;
1901 }
1902 break;
1903 case OB_DIRECTION_WEST:
1904 dest = client_directional_edge_search(c, OB_DIRECTION_WEST, FALSE);
1905 if (a->x == x)
1906 width = width / 2;
1907 else {
1908 width = c->frame->area.x + width - dest;
1909 x = dest;
1910 }
1911 break;
1912 case OB_DIRECTION_SOUTH:
1913 if (c->shaded) break; /* don't allow vertical resize if shaded */
1914
1915 dest = client_directional_edge_search(c, OB_DIRECTION_SOUTH, FALSE);
1916 if (a->y + a->height == y + c->frame->area.height) {
1917 height = c->frame->area.height / 2;
1918 y = a->y + a->height - height;
1919 } else
1920 height = dest - c->frame->area.y;
1921 y += (height - c->frame->area.height) % c->size_inc.height;
1922 height -= (height - c->frame->area.height) % c->size_inc.height;
1923 break;
1924 case OB_DIRECTION_EAST:
1925 dest = client_directional_edge_search(c, OB_DIRECTION_EAST, FALSE);
1926 if (a->x + a->width == x + c->frame->area.width) {
1927 width = c->frame->area.width / 2;
1928 x = a->x + a->width - width;
1929 } else
1930 width = dest - c->frame->area.x;
1931 x += (width - c->frame->area.width) % c->size_inc.width;
1932 width -= (width - c->frame->area.width) % c->size_inc.width;
1933 break;
1934 default:
1935 g_assert_not_reached();
1936 }
1937 width -= c->frame->size.left + c->frame->size.right;
1938 height -= c->frame->size.top + c->frame->size.bottom;
1939 frame_frame_gravity(c->frame, &x, &y, width, height);
1940 client_action_start(data);
1941 client_move_resize(c, x, y, width, height);
1942 client_action_end(data);
1943 }
1944
1945 void action_send_to_layer(union ActionData *data)
1946 {
1947 client_set_layer(data->layer.any.c, data->layer.layer);
1948 }
1949
1950 void action_toggle_layer(union ActionData *data)
1951 {
1952 ObClient *c = data->layer.any.c;
1953
1954 client_action_start(data);
1955 if (data->layer.layer < 0)
1956 client_set_layer(c, c->below ? 0 : -1);
1957 else if (data->layer.layer > 0)
1958 client_set_layer(c, c->above ? 0 : 1);
1959 client_action_end(data);
1960 }
1961
1962 void action_toggle_dockautohide(union ActionData *data)
1963 {
1964 config_dock_hide = !config_dock_hide;
1965 dock_configure();
1966 }
1967
1968 void action_toggle_show_desktop(union ActionData *data)
1969 {
1970 screen_show_desktop(!screen_showing_desktop, NULL);
1971 }
1972
1973 void action_show_desktop(union ActionData *data)
1974 {
1975 screen_show_desktop(TRUE, NULL);
1976 }
1977
1978 void action_unshow_desktop(union ActionData *data)
1979 {
1980 screen_show_desktop(FALSE, NULL);
1981 }
1982
1983 void action_break_chroot(union ActionData *data)
1984 {
1985 /* break out of one chroot */
1986 keyboard_reset_chains(1);
1987 }
This page took 0.120474 seconds and 4 git commands to generate.