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