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