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