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