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