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