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