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