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