1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 action.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
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.
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.
17 See the COPYING file for a copy of the GNU General Public License.
23 #include "focus_cycle.h"
24 #include "moveresize.h"
37 #include "startupnotify.h"
42 static gulong ignore_start = 0;
44 static void client_action_start(union ActionData *data)
46 ignore_start = event_start_ignore_all_enters();
49 static void client_action_end(union ActionData *data, gboolean allow_enters)
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);
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
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);
76 void (*func)(union ActionData *);
77 void (*setup)(ObAction **, ObUserAction uact);
80 static ObAction *action_new(void (*func)(union ActionData *data))
82 ObAction *a = g_new0(ObAction, 1);
89 void action_ref(ObAction *a)
94 void action_unref(ObAction *a)
96 if (a == NULL) return;
98 if (--a->ref > 0) return;
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);
111 ObAction* action_copy(const ObAction *src)
113 ObAction *a = action_new(src->func);
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);
128 void setup_action_directional_focus_north(ObAction **a, ObUserAction uact)
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;
137 void setup_action_directional_focus_east(ObAction **a, ObUserAction uact)
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;
146 void setup_action_directional_focus_south(ObAction **a, ObUserAction uact)
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;
155 void setup_action_directional_focus_west(ObAction **a, ObUserAction uact)
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;
164 void setup_action_directional_focus_northeast(ObAction **a, ObUserAction uact)
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;
173 void setup_action_directional_focus_southeast(ObAction **a, ObUserAction uact)
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;
182 void setup_action_directional_focus_southwest(ObAction **a, ObUserAction uact)
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;
191 void setup_action_directional_focus_northwest(ObAction **a, ObUserAction uact)
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;
200 void setup_action_send_to_desktop(ObAction **a, ObUserAction uact)
202 (*a)->data.sendto.any.client_action = OB_CLIENT_ACTION_ALWAYS;
203 (*a)->data.sendto.follow = TRUE;
206 void setup_action_send_to_desktop_prev(ObAction **a, ObUserAction uact)
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;
216 void setup_action_send_to_desktop_next(ObAction **a, ObUserAction uact)
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;
226 void setup_action_send_to_desktop_left(ObAction **a, ObUserAction uact)
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;
236 void setup_action_send_to_desktop_right(ObAction **a, ObUserAction uact)
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;
246 void setup_action_send_to_desktop_up(ObAction **a, ObUserAction uact)
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;
256 void setup_action_send_to_desktop_down(ObAction **a, ObUserAction uact)
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;
266 void setup_action_desktop(ObAction **a, ObUserAction uact)
269 (*a)->data.desktop.inter.any.interactive = FALSE;
273 void setup_action_desktop_prev(ObAction **a, ObUserAction uact)
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;
281 void setup_action_desktop_next(ObAction **a, ObUserAction uact)
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;
289 void setup_action_desktop_left(ObAction **a, ObUserAction uact)
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;
297 void setup_action_desktop_right(ObAction **a, ObUserAction uact)
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;
305 void setup_action_desktop_up(ObAction **a, ObUserAction uact)
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;
313 void setup_action_desktop_down(ObAction **a, ObUserAction uact)
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;
321 void setup_action_cycle_windows_next(ObAction **a, ObUserAction uact)
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;
332 void setup_action_cycle_windows_previous(ObAction **a, ObUserAction uact)
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;
343 void setup_action_movefromedge_north(ObAction **a, ObUserAction uact)
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;
350 void setup_action_movefromedge_south(ObAction **a, ObUserAction uact)
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;
357 void setup_action_movefromedge_east(ObAction **a, ObUserAction uact)
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;
364 void setup_action_movefromedge_west(ObAction **a, ObUserAction uact)
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;
371 void setup_action_movetoedge_north(ObAction **a, ObUserAction uact)
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;
378 void setup_action_movetoedge_south(ObAction **a, ObUserAction uact)
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;
385 void setup_action_movetoedge_east(ObAction **a, ObUserAction uact)
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;
392 void setup_action_movetoedge_west(ObAction **a, ObUserAction uact)
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;
399 void setup_action_growtoedge_north(ObAction **a, ObUserAction uact)
401 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
402 (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
405 void setup_action_growtoedge_south(ObAction **a, ObUserAction uact)
407 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
408 (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
411 void setup_action_growtoedge_east(ObAction **a, ObUserAction uact)
413 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
414 (*a)->data.diraction.direction = OB_DIRECTION_EAST;
417 void setup_action_growtoedge_west(ObAction **a, ObUserAction uact)
419 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
420 (*a)->data.diraction.direction = OB_DIRECTION_WEST;
423 void setup_action_top_layer(ObAction **a, ObUserAction uact)
425 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
426 (*a)->data.layer.layer = 1;
429 void setup_action_normal_layer(ObAction **a, ObUserAction uact)
431 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
432 (*a)->data.layer.layer = 0;
435 void setup_action_bottom_layer(ObAction **a, ObUserAction uact)
437 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
438 (*a)->data.layer.layer = -1;
441 void setup_action_move(ObAction **a, ObUserAction uact)
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;
451 void setup_action_resize(ObAction **a, ObUserAction uact)
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;
461 void setup_action_addremove_desktop_current(ObAction **a, ObUserAction uact)
463 (*a)->data.addremovedesktop.current = TRUE;
466 void setup_action_addremove_desktop_last(ObAction **a, ObUserAction uact)
468 (*a)->data.addremovedesktop.current = FALSE;
471 void setup_action_focus(ObAction **a, ObUserAction uact)
473 (*a)->data.any.client_action = OB_CLIENT_ACTION_OPTIONAL;
476 void setup_client_action(ObAction **a, ObUserAction uact)
478 (*a)->data.any.client_action = OB_CLIENT_ACTION_ALWAYS;
481 ActionString actionstrings[] =
484 "directionalfocusnorth",
485 action_directional_focus,
486 setup_action_directional_focus_north
489 "directionalfocuseast",
490 action_directional_focus,
491 setup_action_directional_focus_east
494 "directionalfocussouth",
495 action_directional_focus,
496 setup_action_directional_focus_south
499 "directionalfocuswest",
500 action_directional_focus,
501 setup_action_directional_focus_west
504 "directionalfocusnortheast",
505 action_directional_focus,
506 setup_action_directional_focus_northeast
509 "directionalfocussoutheast",
510 action_directional_focus,
511 setup_action_directional_focus_southeast
514 "directionalfocussouthwest",
515 action_directional_focus,
516 setup_action_directional_focus_southwest
519 "directionalfocusnorthwest",
520 action_directional_focus,
521 setup_action_directional_focus_northwest
545 action_focus_order_to_bottom,
600 action_toggle_omnipresent,
605 action_move_relative_horz,
610 action_move_relative_vert,
615 action_move_to_center,
619 "resizerelativehorz",
620 action_resize_relative_horz,
624 "resizerelativevert",
625 action_resize_relative_vert,
630 action_move_relative,
635 action_resize_relative,
640 action_maximize_full,
645 action_unmaximize_full,
649 "togglemaximizefull",
650 action_toggle_maximize_full,
655 action_maximize_horz,
660 action_unmaximize_horz,
664 "togglemaximizehorz",
665 action_toggle_maximize_horz,
670 action_maximize_vert,
675 action_unmaximize_vert,
679 "togglemaximizevert",
680 action_toggle_maximize_vert,
685 action_toggle_fullscreen,
690 action_send_to_desktop,
691 setup_action_send_to_desktop
695 action_send_to_desktop_dir,
696 setup_action_send_to_desktop_next
699 "sendtodesktopprevious",
700 action_send_to_desktop_dir,
701 setup_action_send_to_desktop_prev
704 "sendtodesktopright",
705 action_send_to_desktop_dir,
706 setup_action_send_to_desktop_right
710 action_send_to_desktop_dir,
711 setup_action_send_to_desktop_left
715 action_send_to_desktop_dir,
716 setup_action_send_to_desktop_up
720 action_send_to_desktop_dir,
721 setup_action_send_to_desktop_down
731 setup_action_desktop_next
736 setup_action_desktop_prev
741 setup_action_desktop_right
746 setup_action_desktop_left
751 setup_action_desktop_up
756 setup_action_desktop_down
760 action_toggle_decorations,
774 "toggledockautohide",
775 action_toggle_dockautohide,
780 action_toggle_show_desktop,
790 action_unshow_desktop,
815 action_send_to_layer,
816 setup_action_top_layer
821 setup_action_top_layer
825 action_send_to_layer,
826 setup_action_normal_layer
830 action_send_to_layer,
831 setup_action_bottom_layer
834 "togglealwaysonbottom",
836 setup_action_bottom_layer
840 action_cycle_windows,
841 setup_action_cycle_windows_next
845 action_cycle_windows,
846 setup_action_cycle_windows_previous
851 setup_action_movefromedge_north
856 setup_action_movefromedge_south
861 setup_action_movefromedge_west
866 setup_action_movefromedge_east
871 setup_action_movetoedge_north
876 setup_action_movetoedge_south
881 setup_action_movetoedge_west
886 setup_action_movetoedge_east
891 setup_action_growtoedge_north
896 setup_action_growtoedge_south
901 setup_action_growtoedge_west
906 setup_action_growtoedge_east
916 setup_action_addremove_desktop_last
920 action_remove_desktop,
921 setup_action_addremove_desktop_last
926 setup_action_addremove_desktop_current
929 "removedesktopcurrent",
930 action_remove_desktop,
931 setup_action_addremove_desktop_current
940 /* only key bindings can be interactive. thus saith the xor.
941 because of how the mouse is grabbed, mouse events dont even get
942 read during interactive events, so no dice! >:) */
943 #define INTERACTIVE_LIMIT(a, uact) \
944 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
945 a->data.any.interactive = FALSE;
947 ObAction *action_from_string(const gchar *name, ObUserAction uact)
950 gboolean exist = FALSE;
953 for (i = 0; actionstrings[i].name; i++)
954 if (!g_ascii_strcasecmp(name, actionstrings[i].name)) {
956 a = action_new(actionstrings[i].func);
957 if (actionstrings[i].setup)
958 actionstrings[i].setup(&a, uact);
960 INTERACTIVE_LIMIT(a, uact);
964 g_message(_("Invalid action '%s' requested. No such action exists."),
967 g_message(_("Invalid use of action '%s'. Action will be ignored."),
972 ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
976 ObAction *act = NULL;
979 if (parse_attr_string("name", node, &actname)) {
980 if ((act = action_from_string(actname, uact))) {
981 } else if (act->func == action_move_relative_horz ||
982 act->func == action_move_relative_vert ||
983 act->func == action_resize_relative_horz ||
984 act->func == action_resize_relative_vert) {
985 if ((n = parse_find_node("delta", node->xmlChildrenNode)))
986 act->data.relative.deltax = parse_int(doc, n);
987 } else if (act->func == action_move_relative) {
988 if ((n = parse_find_node("x", node->xmlChildrenNode)))
989 act->data.relative.deltax = parse_int(doc, n);
990 if ((n = parse_find_node("y", node->xmlChildrenNode)))
991 act->data.relative.deltay = parse_int(doc, n);
992 } else if (act->func == action_resize_relative) {
993 if ((n = parse_find_node("left", node->xmlChildrenNode)))
994 act->data.relative.deltaxl = parse_int(doc, n);
995 if ((n = parse_find_node("up", node->xmlChildrenNode)))
996 act->data.relative.deltayu = parse_int(doc, n);
997 if ((n = parse_find_node("right", node->xmlChildrenNode)))
998 act->data.relative.deltax = parse_int(doc, n);
999 if ((n = parse_find_node("down", node->xmlChildrenNode)))
1000 act->data.relative.deltay = parse_int(doc, n);
1001 } else if (act->func == action_desktop) {
1002 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
1003 act->data.desktop.desk = parse_int(doc, n);
1004 if (act->data.desktop.desk > 0) act->data.desktop.desk--;
1006 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
1007 act->data.desktop.inter.any.interactive =
1010 } else if (act->func == action_send_to_desktop) {
1011 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
1012 act->data.sendto.desk = parse_int(doc, n);
1013 if (act->data.sendto.desk > 0) act->data.sendto.desk--;
1014 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
1015 act->data.sendto.follow = parse_bool(doc, n);
1016 } else if (act->func == action_desktop_dir) {
1017 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
1018 act->data.desktopdir.wrap = parse_bool(doc, n);
1019 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
1020 act->data.desktopdir.inter.any.interactive =
1022 } else if (act->func == action_send_to_desktop_dir) {
1023 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
1024 act->data.sendtodir.wrap = parse_bool(doc, n);
1025 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
1026 act->data.sendtodir.follow = parse_bool(doc, n);
1027 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
1028 act->data.sendtodir.inter.any.interactive =
1030 } else if (act->func == action_activate) {
1031 if ((n = parse_find_node("here", node->xmlChildrenNode)))
1032 act->data.activate.here = parse_bool(doc, n);
1033 } else if (act->func == action_cycle_windows) {
1034 if ((n = parse_find_node("linear", node->xmlChildrenNode)))
1035 act->data.cycle.linear = parse_bool(doc, n);
1036 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
1037 act->data.cycle.dialog = parse_bool(doc, n);
1038 if ((n = parse_find_node("panels", node->xmlChildrenNode)))
1039 act->data.cycle.dock_windows = parse_bool(doc, n);
1040 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
1041 act->data.cycle.desktop_windows = parse_bool(doc, n);
1042 if ((n = parse_find_node("allDesktops",
1043 node->xmlChildrenNode)))
1044 act->data.cycle.all_desktops = parse_bool(doc, n);
1045 } else if (act->func == action_directional_focus) {
1046 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
1047 act->data.interdiraction.dialog = parse_bool(doc, n);
1048 if ((n = parse_find_node("panels", node->xmlChildrenNode)))
1049 act->data.interdiraction.dock_windows = parse_bool(doc, n);
1050 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
1051 act->data.interdiraction.desktop_windows =
1053 } else if (act->func == action_resize) {
1054 if ((n = parse_find_node("edge", node->xmlChildrenNode))) {
1055 gchar *s = parse_string(doc, n);
1056 if (!g_ascii_strcasecmp(s, "top"))
1057 act->data.moveresize.corner =
1058 prop_atoms.net_wm_moveresize_size_top;
1059 else if (!g_ascii_strcasecmp(s, "bottom"))
1060 act->data.moveresize.corner =
1061 prop_atoms.net_wm_moveresize_size_bottom;
1062 else if (!g_ascii_strcasecmp(s, "left"))
1063 act->data.moveresize.corner =
1064 prop_atoms.net_wm_moveresize_size_left;
1065 else if (!g_ascii_strcasecmp(s, "right"))
1066 act->data.moveresize.corner =
1067 prop_atoms.net_wm_moveresize_size_right;
1068 else if (!g_ascii_strcasecmp(s, "topleft"))
1069 act->data.moveresize.corner =
1070 prop_atoms.net_wm_moveresize_size_topleft;
1071 else if (!g_ascii_strcasecmp(s, "topright"))
1072 act->data.moveresize.corner =
1073 prop_atoms.net_wm_moveresize_size_topright;
1074 else if (!g_ascii_strcasecmp(s, "bottomleft"))
1075 act->data.moveresize.corner =
1076 prop_atoms.net_wm_moveresize_size_bottomleft;
1077 else if (!g_ascii_strcasecmp(s, "bottomright"))
1078 act->data.moveresize.corner =
1079 prop_atoms.net_wm_moveresize_size_bottomright;
1082 } else if (act->func == action_raise ||
1083 act->func == action_lower ||
1084 act->func == action_raiselower ||
1085 act->func == action_shadelower ||
1086 act->func == action_unshaderaise) {
1088 INTERACTIVE_LIMIT(act, uact);
1095 void action_run_list(GSList *acts, ObClient *c, ObFrameContext context,
1096 guint state, guint button, gint x, gint y, Time time,
1097 gboolean cancel, gboolean done)
1106 screen_pointer_pos(&x, &y);
1108 for (it = acts; it; it = g_slist_next(it)) {
1111 if (!(a->data.any.client_action == OB_CLIENT_ACTION_ALWAYS && !c)) {
1112 a->data.any.c = a->data.any.client_action ? c : NULL;
1113 a->data.any.context = context;
1117 a->data.any.button = button;
1119 a->data.any.time = time;
1121 if (a->data.any.interactive) {
1122 a->data.inter.cancel = cancel;
1123 a->data.inter.final = done;
1124 if (!(cancel || done))
1125 if (!keyboard_interactive_grab(state, a->data.any.c, a))
1129 /* XXX UGLY HACK race with motion event starting a move and the
1130 button release gettnig processed first. answer: don't queue
1131 moveresize starts. UGLY HACK XXX
1133 XXX ALSO don't queue showmenu events, because on button press
1134 events we need to know if a mouse grab is going to take place,
1135 and set the button to 0, so that later motion events don't think
1136 that a drag is going on. since showmenu grabs the pointer..
1138 if (a->data.any.interactive || a->func == action_move ||
1139 a->func == action_resize || a->func == action_showmenu)
1141 /* interactive actions are not queued */
1143 } else if (a->func == action_focus ||
1144 a->func == action_activate ||
1145 a->func == action_showmenu)
1147 /* XXX MORE UGLY HACK
1148 actions from clicks on client windows are NOT queued.
1149 this solves the mysterious click-and-drag-doesnt-work
1150 problem. it was because the window gets focused and stuff
1151 after the button event has already been passed through. i
1152 dont really know why it should care but it does and it makes
1155 however this very bogus ! !
1156 we want to send the button press to the window BEFORE
1157 we do the action because the action might move the windows
1158 (eg change desktops) and then the button press ends up on
1159 the completely wrong window !
1160 so, this is just for that bug, and it will only NOT queue it
1161 if it is a focusing action that can be used with the mouse
1164 also with the menus, there is a race going on. if the
1165 desktop wants to pop up a menu, and we do too, we send them
1166 the button before we pop up the menu, so they pop up their
1167 menu first. but not always. if we pop up our menu before
1168 sending them the button press, then the result is
1171 XXX further more. focus actions are not queued at all,
1172 because if you bind focus->showmenu, the menu will get
1173 hidden to do the focusing
1177 ob_main_loop_queue_action(ob_main_loop, a);
1182 void action_run_string(const gchar *name, struct _ObClient *c, Time time)
1187 a = action_from_string(name, OB_USER_ACTION_NONE);
1190 l = g_slist_append(NULL, a);
1192 action_run(l, c, 0, time);
1195 void action_activate(union ActionData *data)
1197 if (data->client.any.c) {
1198 if (!data->any.button || client_mouse_focusable(data->client.any.c) ||
1199 (data->any.context != OB_FRAME_CONTEXT_CLIENT &&
1200 data->any.context != OB_FRAME_CONTEXT_FRAME))
1202 /* if using focus_delay, stop the timer now so that focus doesn't
1204 event_halt_focus_delay();
1206 client_activate(data->activate.any.c, data->activate.here, TRUE);
1209 /* focus action on something other than a client, make keybindings
1210 work for this openbox instance, but don't focus any specific client
1216 void action_focus(union ActionData *data)
1218 if (data->client.any.c) {
1219 if (!data->any.button || client_mouse_focusable(data->client.any.c) ||
1220 (data->any.context != OB_FRAME_CONTEXT_CLIENT &&
1221 data->any.context != OB_FRAME_CONTEXT_FRAME))
1223 /* if using focus_delay, stop the timer now so that focus doesn't
1225 event_halt_focus_delay();
1227 client_focus(data->client.any.c);
1230 /* focus action on something other than a client, make keybindings
1231 work for this openbox instance, but don't focus any specific client
1237 void action_unfocus (union ActionData *data)
1239 if (data->client.any.c == focus_client)
1240 focus_fallback(FALSE, FALSE, TRUE);
1243 void action_iconify(union ActionData *data)
1245 client_action_start(data);
1246 client_iconify(data->client.any.c, TRUE, TRUE, FALSE);
1247 client_action_end(data, config_focus_under_mouse);
1250 void action_focus_order_to_bottom(union ActionData *data)
1252 focus_order_to_bottom(data->client.any.c);
1255 void action_raiselower(union ActionData *data)
1257 ObClient *c = data->client.any.c;
1259 client_action_start(data);
1260 stacking_restack_request(c, NULL, Opposite);
1261 client_action_end(data, config_focus_under_mouse);
1264 void action_raise(union ActionData *data)
1266 client_action_start(data);
1267 stacking_raise(CLIENT_AS_WINDOW(data->client.any.c));
1268 client_action_end(data, config_focus_under_mouse);
1271 void action_unshaderaise(union ActionData *data)
1273 if (data->client.any.c->shaded)
1274 action_unshade(data);
1279 void action_shadelower(union ActionData *data)
1281 if (data->client.any.c->shaded)
1287 void action_lower(union ActionData *data)
1289 client_action_start(data);
1290 stacking_lower(CLIENT_AS_WINDOW(data->client.any.c));
1291 client_action_end(data, config_focus_under_mouse);
1294 void action_close(union ActionData *data)
1296 client_close(data->client.any.c);
1299 void action_kill(union ActionData *data)
1301 client_kill(data->client.any.c);
1304 void action_shade(union ActionData *data)
1306 client_action_start(data);
1307 client_shade(data->client.any.c, TRUE);
1308 client_action_end(data, config_focus_under_mouse);
1311 void action_unshade(union ActionData *data)
1313 client_action_start(data);
1314 client_shade(data->client.any.c, FALSE);
1315 client_action_end(data, config_focus_under_mouse);
1318 void action_toggle_shade(union ActionData *data)
1320 client_action_start(data);
1321 client_shade(data->client.any.c, !data->client.any.c->shaded);
1322 client_action_end(data, config_focus_under_mouse);
1325 void action_toggle_omnipresent(union ActionData *data)
1327 client_set_desktop(data->client.any.c,
1328 data->client.any.c->desktop == DESKTOP_ALL ?
1329 screen_desktop : DESKTOP_ALL, FALSE, TRUE);
1332 void action_move_relative_horz(union ActionData *data)
1334 ObClient *c = data->relative.any.c;
1335 client_action_start(data);
1336 client_move(c, c->area.x + data->relative.deltax, c->area.y);
1337 client_action_end(data, FALSE);
1340 void action_move_relative_vert(union ActionData *data)
1342 ObClient *c = data->relative.any.c;
1343 client_action_start(data);
1344 client_move(c, c->area.x, c->area.y + data->relative.deltax);
1345 client_action_end(data, FALSE);
1348 void action_move_to_center(union ActionData *data)
1350 ObClient *c = data->client.any.c;
1352 area = screen_area(c->desktop, client_monitor(c), NULL);
1353 client_action_start(data);
1354 client_move(c, area->x + area->width / 2 - c->area.width / 2,
1355 area->y + area->height / 2 - c->area.height / 2);
1356 client_action_end(data, FALSE);
1360 void action_resize_relative_horz(union ActionData *data)
1362 ObClient *c = data->relative.any.c;
1363 client_action_start(data);
1365 c->area.width + data->relative.deltax * c->size_inc.width,
1367 client_action_end(data, FALSE);
1370 void action_resize_relative_vert(union ActionData *data)
1372 ObClient *c = data->relative.any.c;
1374 client_action_start(data);
1375 client_resize(c, c->area.width, c->area.height +
1376 data->relative.deltax * c->size_inc.height);
1377 client_action_end(data, FALSE);
1381 void action_move_relative(union ActionData *data)
1383 ObClient *c = data->relative.any.c;
1384 client_action_start(data);
1385 client_move(c, c->area.x + data->relative.deltax, c->area.y +
1386 data->relative.deltay);
1387 client_action_end(data, FALSE);
1390 void action_resize_relative(union ActionData *data)
1392 ObClient *c = data->relative.any.c;
1393 gint x, y, ow, xoff, nw, oh, yoff, nh, lw, lh;
1395 client_action_start(data);
1400 xoff = -data->relative.deltaxl * c->size_inc.width;
1401 nw = ow + data->relative.deltax * c->size_inc.width
1402 + data->relative.deltaxl * c->size_inc.width;
1403 oh = c->area.height;
1404 yoff = -data->relative.deltayu * c->size_inc.height;
1405 nh = oh + data->relative.deltay * c->size_inc.height
1406 + data->relative.deltayu * c->size_inc.height;
1408 g_print("deltax %d %d x %d ow %d xoff %d nw %d\n",
1409 data->relative.deltax,
1410 data->relative.deltaxl,
1413 client_try_configure(c, &x, &y, &nw, &nh, &lw, &lh, TRUE);
1414 xoff = xoff == 0 ? 0 : (xoff < 0 ? MAX(xoff, ow-nw) : MIN(xoff, ow-nw));
1415 yoff = yoff == 0 ? 0 : (yoff < 0 ? MAX(yoff, oh-nh) : MIN(yoff, oh-nh));
1416 client_move_resize(c, x + xoff, y + yoff, nw, nh);
1417 client_action_end(data, FALSE);
1420 void action_maximize_full(union ActionData *data)
1422 client_action_start(data);
1423 client_maximize(data->client.any.c, TRUE, 0);
1424 client_action_end(data, config_focus_under_mouse);
1427 void action_unmaximize_full(union ActionData *data)
1429 client_action_start(data);
1430 client_maximize(data->client.any.c, FALSE, 0);
1431 client_action_end(data, config_focus_under_mouse);
1434 void action_toggle_maximize_full(union ActionData *data)
1436 client_action_start(data);
1437 client_maximize(data->client.any.c,
1438 !(data->client.any.c->max_horz ||
1439 data->client.any.c->max_vert),
1441 client_action_end(data, config_focus_under_mouse);
1444 void action_maximize_horz(union ActionData *data)
1446 client_action_start(data);
1447 client_maximize(data->client.any.c, TRUE, 1);
1448 client_action_end(data, config_focus_under_mouse);
1451 void action_unmaximize_horz(union ActionData *data)
1453 client_action_start(data);
1454 client_maximize(data->client.any.c, FALSE, 1);
1455 client_action_end(data, config_focus_under_mouse);
1458 void action_toggle_maximize_horz(union ActionData *data)
1460 client_action_start(data);
1461 client_maximize(data->client.any.c,
1462 !data->client.any.c->max_horz, 1);
1463 client_action_end(data, config_focus_under_mouse);
1466 void action_maximize_vert(union ActionData *data)
1468 client_action_start(data);
1469 client_maximize(data->client.any.c, TRUE, 2);
1470 client_action_end(data, config_focus_under_mouse);
1473 void action_unmaximize_vert(union ActionData *data)
1475 client_action_start(data);
1476 client_maximize(data->client.any.c, FALSE, 2);
1477 client_action_end(data, config_focus_under_mouse);
1480 void action_toggle_maximize_vert(union ActionData *data)
1482 client_action_start(data);
1483 client_maximize(data->client.any.c,
1484 !data->client.any.c->max_vert, 2);
1485 client_action_end(data, config_focus_under_mouse);
1488 void action_toggle_fullscreen(union ActionData *data)
1490 client_action_start(data);
1491 client_fullscreen(data->client.any.c, !(data->client.any.c->fullscreen));
1492 client_action_end(data, config_focus_under_mouse);
1495 void action_send_to_desktop(union ActionData *data)
1497 ObClient *c = data->sendto.any.c;
1499 if (!client_normal(c)) return;
1501 if (data->sendto.desk < screen_num_desktops ||
1502 data->sendto.desk == DESKTOP_ALL) {
1503 client_set_desktop(c, data->sendto.desk, data->sendto.follow, FALSE);
1504 if (data->sendto.follow && data->sendto.desk != screen_desktop)
1505 screen_set_desktop(data->sendto.desk, TRUE);
1509 void action_desktop(union ActionData *data)
1511 /* XXX add the interactive/dialog option back again once the dialog
1512 has been made to not use grabs */
1513 if (data->desktop.desk < screen_num_desktops ||
1514 data->desktop.desk == DESKTOP_ALL)
1516 screen_set_desktop(data->desktop.desk, TRUE);
1517 if (data->inter.any.interactive)
1518 screen_desktop_popup(data->desktop.desk, TRUE);
1522 void action_desktop_dir(union ActionData *data)
1526 d = screen_cycle_desktop(data->desktopdir.dir,
1527 data->desktopdir.wrap,
1528 data->desktopdir.linear,
1529 data->desktopdir.inter.any.interactive,
1530 data->desktopdir.inter.final,
1531 data->desktopdir.inter.cancel);
1532 /* only move the desktop when the action is complete. if we switch
1533 desktops during the interactive action, focus will move but with
1534 NotifyWhileGrabbed and applications don't like that. */
1535 if (!data->sendtodir.inter.any.interactive ||
1536 (data->sendtodir.inter.final && !data->sendtodir.inter.cancel))
1538 if (d != screen_desktop)
1539 screen_set_desktop(d, TRUE);
1543 void action_send_to_desktop_dir(union ActionData *data)
1545 ObClient *c = data->sendtodir.inter.any.c;
1548 if (!client_normal(c)) return;
1550 d = screen_cycle_desktop(data->sendtodir.dir, data->sendtodir.wrap,
1551 data->sendtodir.linear,
1552 data->sendtodir.inter.any.interactive,
1553 data->sendtodir.inter.final,
1554 data->sendtodir.inter.cancel);
1555 /* only move the desktop when the action is complete. if we switch
1556 desktops during the interactive action, focus will move but with
1557 NotifyWhileGrabbed and applications don't like that. */
1558 if (!data->sendtodir.inter.any.interactive ||
1559 (data->sendtodir.inter.final && !data->sendtodir.inter.cancel))
1561 client_set_desktop(c, d, data->sendtodir.follow, FALSE);
1562 if (data->sendtodir.follow && d != screen_desktop)
1563 screen_set_desktop(d, TRUE);
1567 void action_desktop_last(union ActionData *data)
1569 if (screen_last_desktop < screen_num_desktops)
1570 screen_set_desktop(screen_last_desktop, TRUE);
1573 void action_toggle_decorations(union ActionData *data)
1575 ObClient *c = data->client.any.c;
1577 client_action_start(data);
1578 client_set_undecorated(c, !c->undecorated);
1579 client_action_end(data, FALSE);
1582 static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch,
1585 /* let's make x and y client relative instead of screen relative */
1587 y = ch - (y - cy); /* y is inverted, 0 is at the bottom of the window */
1590 #define A -4*X + 7*ch/3
1591 #define B 4*X -15*ch/9
1592 #define C -X/4 + 2*ch/3
1593 #define D X/4 + 5*ch/12
1594 #define E X/4 + ch/3
1595 #define F -X/4 + 7*ch/12
1596 #define G 4*X - 4*ch/3
1597 #define H -4*X + 8*ch/3
1598 #define a (y > 5*ch/9)
1599 #define b (x < 4*cw/9)
1600 #define c (x > 5*cw/9)
1601 #define d (y < 4*ch/9)
1604 Each of these defines (except X which is just there for fun), represents
1605 the equation of a line. The lines they represent are shown in the diagram
1606 below. Checking y against these lines, we are able to choose a region
1607 of the window as shown.
1609 +---------------------A-------|-------|-------B---------------------+
1616 | northwest | A north B | northeast |
1619 C---------------------+----A--+-------+--B----+---------------------D
1620 |CCCCCCC | A B | DDDDDDD|
1621 | CCCCCCCC | A | | B | DDDDDDDD |
1622 | CCCCCCC A B DDDDDDD |
1623 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
1625 | west | b move c | east | ad
1627 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
1628 | EEEEEEE G H FFFFFFF |
1629 | EEEEEEEE | G | | H | FFFFFFFF |
1630 |EEEEEEE | G H | FFFFFFF|
1631 E---------------------+----G--+-------+--H----+---------------------F
1634 | southwest | G south H | southeast |
1641 +---------------------G-------|-------|-------H---------------------+
1645 /* for shaded windows, you can only resize west/east and move */
1647 return prop_atoms.net_wm_moveresize_size_left;
1649 return prop_atoms.net_wm_moveresize_size_right;
1650 return prop_atoms.net_wm_moveresize_move;
1653 if (y < A && y >= C)
1654 return prop_atoms.net_wm_moveresize_size_topleft;
1655 else if (y >= A && y >= B && a)
1656 return prop_atoms.net_wm_moveresize_size_top;
1657 else if (y < B && y >= D)
1658 return prop_atoms.net_wm_moveresize_size_topright;
1659 else if (y < C && y >= E && b)
1660 return prop_atoms.net_wm_moveresize_size_left;
1661 else if (y < D && y >= F && c)
1662 return prop_atoms.net_wm_moveresize_size_right;
1663 else if (y < E && y >= G)
1664 return prop_atoms.net_wm_moveresize_size_bottomleft;
1665 else if (y < G && y < H && d)
1666 return prop_atoms.net_wm_moveresize_size_bottom;
1667 else if (y >= H && y < F)
1668 return prop_atoms.net_wm_moveresize_size_bottomright;
1670 return prop_atoms.net_wm_moveresize_move;
1687 void action_move(union ActionData *data)
1689 ObClient *c = data->moveresize.any.c;
1692 if (data->moveresize.keyboard)
1693 corner = prop_atoms.net_wm_moveresize_move_keyboard;
1695 corner = prop_atoms.net_wm_moveresize_move;
1697 moveresize_start(c, data->any.x, data->any.y, data->any.button, corner);
1700 void action_resize(union ActionData *data)
1702 ObClient *c = data->moveresize.any.c;
1705 if (data->moveresize.keyboard)
1706 corner = prop_atoms.net_wm_moveresize_size_keyboard;
1707 else if (data->moveresize.corner)
1708 corner = data->moveresize.corner; /* it was specified in the binding */
1710 corner = pick_corner(data->any.x, data->any.y,
1711 c->frame->area.x, c->frame->area.y,
1712 /* use the client size because the frame
1713 can be differently sized (shaded
1714 windows) and we want this based on the
1716 c->area.width + c->frame->size.left +
1717 c->frame->size.right,
1718 c->area.height + c->frame->size.top +
1719 c->frame->size.bottom, c->shaded);
1721 moveresize_start(c, data->any.x, data->any.y, data->any.button, corner);
1724 void action_reconfigure(union ActionData *data)
1729 void action_restart(union ActionData *data)
1731 ob_restart_other(data->execute.path);
1734 void action_exit(union ActionData *data)
1739 void action_cycle_windows(union ActionData *data)
1741 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1743 event_halt_focus_delay();
1745 focus_cycle(data->cycle.forward,
1746 data->cycle.all_desktops,
1747 data->cycle.dock_windows,
1748 data->cycle.desktop_windows,
1749 data->cycle.linear, data->any.interactive,
1751 data->cycle.inter.final, data->cycle.inter.cancel);
1754 void action_directional_focus(union ActionData *data)
1756 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1758 event_halt_focus_delay();
1760 focus_directional_cycle(data->interdiraction.direction,
1761 data->interdiraction.dock_windows,
1762 data->interdiraction.desktop_windows,
1763 data->any.interactive,
1764 data->interdiraction.dialog,
1765 data->interdiraction.inter.final,
1766 data->interdiraction.inter.cancel);
1769 void action_movetoedge(union ActionData *data)
1772 ObClient *c = data->diraction.any.c;
1774 x = c->frame->area.x;
1775 y = c->frame->area.y;
1777 switch(data->diraction.direction) {
1778 case OB_DIRECTION_NORTH:
1779 y = client_directional_edge_search(c, OB_DIRECTION_NORTH,
1780 data->diraction.hang)
1781 - (data->diraction.hang ? c->frame->area.height : 0);
1783 case OB_DIRECTION_WEST:
1784 x = client_directional_edge_search(c, OB_DIRECTION_WEST,
1785 data->diraction.hang)
1786 - (data->diraction.hang ? c->frame->area.width : 0);
1788 case OB_DIRECTION_SOUTH:
1789 y = client_directional_edge_search(c, OB_DIRECTION_SOUTH,
1790 data->diraction.hang)
1791 - (data->diraction.hang ? 0 : c->frame->area.height);
1793 case OB_DIRECTION_EAST:
1794 x = client_directional_edge_search(c, OB_DIRECTION_EAST,
1795 data->diraction.hang)
1796 - (data->diraction.hang ? 0 : c->frame->area.width);
1799 g_assert_not_reached();
1801 frame_frame_gravity(c->frame, &x, &y, c->area.width, c->area.height);
1802 client_action_start(data);
1803 client_move(c, x, y);
1804 client_action_end(data, FALSE);
1807 void action_growtoedge(union ActionData *data)
1809 gint x, y, width, height, dest;
1810 ObClient *c = data->diraction.any.c;
1813 a = screen_area(c->desktop, SCREEN_AREA_ALL_MONITORS, &c->frame->area);
1814 x = c->frame->area.x;
1815 y = c->frame->area.y;
1816 /* get the unshaded frame's dimensions..if it is shaded */
1817 width = c->area.width + c->frame->size.left + c->frame->size.right;
1818 height = c->area.height + c->frame->size.top + c->frame->size.bottom;
1820 switch(data->diraction.direction) {
1821 case OB_DIRECTION_NORTH:
1822 if (c->shaded) break; /* don't allow vertical resize if shaded */
1824 dest = client_directional_edge_search(c, OB_DIRECTION_NORTH, FALSE);
1826 height = height / 2;
1828 height = c->frame->area.y + height - dest;
1832 case OB_DIRECTION_WEST:
1833 dest = client_directional_edge_search(c, OB_DIRECTION_WEST, FALSE);
1837 width = c->frame->area.x + width - dest;
1841 case OB_DIRECTION_SOUTH:
1842 if (c->shaded) break; /* don't allow vertical resize if shaded */
1844 dest = client_directional_edge_search(c, OB_DIRECTION_SOUTH, FALSE);
1845 if (a->y + a->height == y + c->frame->area.height) {
1846 height = c->frame->area.height / 2;
1847 y = a->y + a->height - height;
1849 height = dest - c->frame->area.y;
1850 y += (height - c->frame->area.height) % c->size_inc.height;
1851 height -= (height - c->frame->area.height) % c->size_inc.height;
1853 case OB_DIRECTION_EAST:
1854 dest = client_directional_edge_search(c, OB_DIRECTION_EAST, FALSE);
1855 if (a->x + a->width == x + c->frame->area.width) {
1856 width = c->frame->area.width / 2;
1857 x = a->x + a->width - width;
1859 width = dest - c->frame->area.x;
1860 x += (width - c->frame->area.width) % c->size_inc.width;
1861 width -= (width - c->frame->area.width) % c->size_inc.width;
1864 g_assert_not_reached();
1866 width -= c->frame->size.left + c->frame->size.right;
1867 height -= c->frame->size.top + c->frame->size.bottom;
1868 frame_frame_gravity(c->frame, &x, &y, width, height);
1869 client_action_start(data);
1870 client_move_resize(c, x, y, width, height);
1871 client_action_end(data, FALSE);
1875 void action_send_to_layer(union ActionData *data)
1877 client_set_layer(data->layer.any.c, data->layer.layer);
1880 void action_toggle_layer(union ActionData *data)
1882 ObClient *c = data->layer.any.c;
1884 client_action_start(data);
1885 if (data->layer.layer < 0)
1886 client_set_layer(c, c->below ? 0 : -1);
1887 else if (data->layer.layer > 0)
1888 client_set_layer(c, c->above ? 0 : 1);
1889 client_action_end(data, config_focus_under_mouse);
1892 void action_toggle_dockautohide(union ActionData *data)
1894 config_dock_hide = !config_dock_hide;
1898 void action_toggle_show_desktop(union ActionData *data)
1900 screen_show_desktop(!screen_showing_desktop, NULL);
1903 void action_show_desktop(union ActionData *data)
1905 screen_show_desktop(TRUE, NULL);
1908 void action_unshow_desktop(union ActionData *data)
1910 screen_show_desktop(FALSE, NULL);
1913 void action_break_chroot(union ActionData *data)
1915 /* break out of one chroot */
1916 keyboard_reset_chains(1);
1919 void action_add_desktop(union ActionData *data)
1921 client_action_start(data);
1922 screen_set_num_desktops(screen_num_desktops+1);
1924 /* move all the clients over */
1925 if (data->addremovedesktop.current) {
1928 for (it = client_list; it; it = g_list_next(it)) {
1929 ObClient *c = it->data;
1930 if (c->desktop != DESKTOP_ALL && c->desktop >= screen_desktop)
1931 client_set_desktop(c, c->desktop+1, FALSE, TRUE);
1935 client_action_end(data, config_focus_under_mouse);
1938 void action_remove_desktop(union ActionData *data)
1940 guint rmdesktop, movedesktop;
1941 GList *it, *stacking_copy;
1943 if (screen_num_desktops < 2) return;
1945 client_action_start(data);
1947 /* what desktop are we removing and moving to? */
1948 if (data->addremovedesktop.current)
1949 rmdesktop = screen_desktop;
1951 rmdesktop = screen_num_desktops - 1;
1952 if (rmdesktop < screen_num_desktops - 1)
1953 movedesktop = rmdesktop + 1;
1955 movedesktop = rmdesktop;
1957 /* make a copy of the list cuz we're changing it */
1958 stacking_copy = g_list_copy(stacking_list);
1959 for (it = g_list_last(stacking_copy); it; it = g_list_previous(it)) {
1960 if (WINDOW_IS_CLIENT(it->data)) {
1961 ObClient *c = it->data;
1962 guint d = c->desktop;
1963 if (d != DESKTOP_ALL && d >= movedesktop) {
1964 client_set_desktop(c, c->desktop - 1, TRUE, TRUE);
1965 ob_debug("moving window %s\n", c->title);
1967 /* raise all the windows that are on the current desktop which
1969 if ((screen_desktop == rmdesktop - 1 ||
1970 screen_desktop == rmdesktop) &&
1971 (d == DESKTOP_ALL || d == screen_desktop))
1973 stacking_raise(CLIENT_AS_WINDOW(c));
1974 ob_debug("raising window %s\n", c->title);
1979 /* act like we're changing desktops */
1980 if (screen_desktop < screen_num_desktops - 1) {
1981 gint d = screen_desktop;
1982 screen_desktop = screen_last_desktop;
1983 screen_set_desktop(d, TRUE);
1984 ob_debug("fake desktop change\n");
1987 screen_set_num_desktops(screen_num_desktops-1);
1989 client_action_end(data, config_focus_under_mouse);