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