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