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