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