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