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