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,
795 action_send_to_layer,
796 setup_action_top_layer
801 setup_action_top_layer
805 action_send_to_layer,
806 setup_action_normal_layer
810 action_send_to_layer,
811 setup_action_bottom_layer
814 "togglealwaysonbottom",
816 setup_action_bottom_layer
820 action_cycle_windows,
821 setup_action_cycle_windows_next
825 action_cycle_windows,
826 setup_action_cycle_windows_previous
831 setup_action_movefromedge_north
836 setup_action_movefromedge_south
841 setup_action_movefromedge_west
846 setup_action_movefromedge_east
851 setup_action_movetoedge_north
856 setup_action_movetoedge_south
861 setup_action_movetoedge_west
866 setup_action_movetoedge_east
871 setup_action_growtoedge_north
876 setup_action_growtoedge_south
881 setup_action_growtoedge_west
886 setup_action_growtoedge_east
896 setup_action_addremove_desktop_last
900 action_remove_desktop,
901 setup_action_addremove_desktop_last
906 setup_action_addremove_desktop_current
909 "removedesktopcurrent",
910 action_remove_desktop,
911 setup_action_addremove_desktop_current
920 /* only key bindings can be interactive. thus saith the xor.
921 because of how the mouse is grabbed, mouse events dont even get
922 read during interactive events, so no dice! >:) */
923 #define INTERACTIVE_LIMIT(a, uact) \
924 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
925 a->data.any.interactive = FALSE;
927 ObAction *action_from_string(const gchar *name, ObUserAction uact)
930 gboolean exist = FALSE;
933 for (i = 0; actionstrings[i].name; i++)
934 if (!g_ascii_strcasecmp(name, actionstrings[i].name)) {
936 a = action_new(actionstrings[i].func);
937 if (actionstrings[i].setup)
938 actionstrings[i].setup(&a, uact);
940 INTERACTIVE_LIMIT(a, uact);
944 g_message(_("Invalid action '%s' requested. No such action exists."),
947 g_message(_("Invalid use of action '%s'. Action will be ignored."),
952 ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
956 ObAction *act = NULL;
959 if (parse_attr_string("name", node, &actname)) {
960 if ((act = action_from_string(actname, uact))) {
961 } else if (act->func == action_move_relative_horz ||
962 act->func == action_move_relative_vert ||
963 act->func == action_resize_relative_horz ||
964 act->func == action_resize_relative_vert) {
965 if ((n = parse_find_node("delta", node->xmlChildrenNode)))
966 act->data.relative.deltax = parse_int(doc, n);
967 } else if (act->func == action_move_relative) {
968 if ((n = parse_find_node("x", node->xmlChildrenNode)))
969 act->data.relative.deltax = parse_int(doc, n);
970 if ((n = parse_find_node("y", node->xmlChildrenNode)))
971 act->data.relative.deltay = parse_int(doc, n);
972 } else if (act->func == action_resize_relative) {
973 if ((n = parse_find_node("left", node->xmlChildrenNode)))
974 act->data.relative.deltaxl = parse_int(doc, n);
975 if ((n = parse_find_node("up", node->xmlChildrenNode)))
976 act->data.relative.deltayu = parse_int(doc, n);
977 if ((n = parse_find_node("right", node->xmlChildrenNode)))
978 act->data.relative.deltax = parse_int(doc, n);
979 if ((n = parse_find_node("down", node->xmlChildrenNode)))
980 act->data.relative.deltay = parse_int(doc, n);
981 } else if (act->func == action_desktop) {
982 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
983 act->data.desktop.desk = parse_int(doc, n);
984 if (act->data.desktop.desk > 0) act->data.desktop.desk--;
986 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
987 act->data.desktop.inter.any.interactive =
990 } else if (act->func == action_send_to_desktop) {
991 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
992 act->data.sendto.desk = parse_int(doc, n);
993 if (act->data.sendto.desk > 0) act->data.sendto.desk--;
994 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
995 act->data.sendto.follow = parse_bool(doc, n);
996 } else if (act->func == action_desktop_dir) {
997 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
998 act->data.desktopdir.wrap = parse_bool(doc, n);
999 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
1000 act->data.desktopdir.inter.any.interactive =
1002 } else if (act->func == action_send_to_desktop_dir) {
1003 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
1004 act->data.sendtodir.wrap = parse_bool(doc, n);
1005 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
1006 act->data.sendtodir.follow = parse_bool(doc, n);
1007 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
1008 act->data.sendtodir.inter.any.interactive =
1010 } else if (act->func == action_activate) {
1011 if ((n = parse_find_node("here", node->xmlChildrenNode)))
1012 act->data.activate.here = parse_bool(doc, n);
1013 } else if (act->func == action_cycle_windows) {
1014 if ((n = parse_find_node("linear", node->xmlChildrenNode)))
1015 act->data.cycle.linear = parse_bool(doc, n);
1016 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
1017 act->data.cycle.dialog = parse_bool(doc, n);
1018 if ((n = parse_find_node("panels", node->xmlChildrenNode)))
1019 act->data.cycle.dock_windows = parse_bool(doc, n);
1020 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
1021 act->data.cycle.desktop_windows = parse_bool(doc, n);
1022 if ((n = parse_find_node("allDesktops",
1023 node->xmlChildrenNode)))
1024 act->data.cycle.all_desktops = parse_bool(doc, n);
1025 } else if (act->func == action_directional_focus) {
1026 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
1027 act->data.interdiraction.dialog = parse_bool(doc, n);
1028 if ((n = parse_find_node("panels", node->xmlChildrenNode)))
1029 act->data.interdiraction.dock_windows = parse_bool(doc, n);
1030 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
1031 act->data.interdiraction.desktop_windows =
1033 } else if (act->func == action_resize) {
1034 if ((n = parse_find_node("edge", node->xmlChildrenNode))) {
1035 gchar *s = parse_string(doc, n);
1036 if (!g_ascii_strcasecmp(s, "top"))
1037 act->data.moveresize.corner =
1038 prop_atoms.net_wm_moveresize_size_top;
1039 else if (!g_ascii_strcasecmp(s, "bottom"))
1040 act->data.moveresize.corner =
1041 prop_atoms.net_wm_moveresize_size_bottom;
1042 else if (!g_ascii_strcasecmp(s, "left"))
1043 act->data.moveresize.corner =
1044 prop_atoms.net_wm_moveresize_size_left;
1045 else if (!g_ascii_strcasecmp(s, "right"))
1046 act->data.moveresize.corner =
1047 prop_atoms.net_wm_moveresize_size_right;
1048 else if (!g_ascii_strcasecmp(s, "topleft"))
1049 act->data.moveresize.corner =
1050 prop_atoms.net_wm_moveresize_size_topleft;
1051 else if (!g_ascii_strcasecmp(s, "topright"))
1052 act->data.moveresize.corner =
1053 prop_atoms.net_wm_moveresize_size_topright;
1054 else if (!g_ascii_strcasecmp(s, "bottomleft"))
1055 act->data.moveresize.corner =
1056 prop_atoms.net_wm_moveresize_size_bottomleft;
1057 else if (!g_ascii_strcasecmp(s, "bottomright"))
1058 act->data.moveresize.corner =
1059 prop_atoms.net_wm_moveresize_size_bottomright;
1062 } else if (act->func == action_raise ||
1063 act->func == action_lower ||
1064 act->func == action_raiselower ||
1065 act->func == action_shadelower ||
1066 act->func == action_unshaderaise) {
1068 INTERACTIVE_LIMIT(act, uact);
1075 void action_run_list(GSList *acts, ObClient *c, ObFrameContext context,
1076 guint state, guint button, gint x, gint y, Time time,
1077 gboolean cancel, gboolean done)
1086 screen_pointer_pos(&x, &y);
1088 for (it = acts; it; it = g_slist_next(it)) {
1091 if (!(a->data.any.client_action == OB_CLIENT_ACTION_ALWAYS && !c)) {
1092 a->data.any.c = a->data.any.client_action ? c : NULL;
1093 a->data.any.context = context;
1097 a->data.any.button = button;
1099 a->data.any.time = time;
1101 if (a->data.any.interactive) {
1102 a->data.inter.cancel = cancel;
1103 a->data.inter.final = done;
1104 if (!(cancel || done))
1105 if (!keyboard_interactive_grab(state, a->data.any.c, a))
1109 /* XXX UGLY HACK race with motion event starting a move and the
1110 button release gettnig processed first. answer: don't queue
1111 moveresize starts. UGLY HACK XXX
1113 XXX ALSO don't queue showmenu events, because on button press
1114 events we need to know if a mouse grab is going to take place,
1115 and set the button to 0, so that later motion events don't think
1116 that a drag is going on. since showmenu grabs the pointer..
1118 if (a->data.any.interactive || a->func == action_move ||
1119 a->func == action_resize || a->func == action_showmenu)
1121 /* interactive actions are not queued */
1123 } else if (a->func == action_focus ||
1124 a->func == action_activate ||
1125 a->func == action_showmenu)
1127 /* XXX MORE UGLY HACK
1128 actions from clicks on client windows are NOT queued.
1129 this solves the mysterious click-and-drag-doesnt-work
1130 problem. it was because the window gets focused and stuff
1131 after the button event has already been passed through. i
1132 dont really know why it should care but it does and it makes
1135 however this very bogus ! !
1136 we want to send the button press to the window BEFORE
1137 we do the action because the action might move the windows
1138 (eg change desktops) and then the button press ends up on
1139 the completely wrong window !
1140 so, this is just for that bug, and it will only NOT queue it
1141 if it is a focusing action that can be used with the mouse
1144 also with the menus, there is a race going on. if the
1145 desktop wants to pop up a menu, and we do too, we send them
1146 the button before we pop up the menu, so they pop up their
1147 menu first. but not always. if we pop up our menu before
1148 sending them the button press, then the result is
1151 XXX further more. focus actions are not queued at all,
1152 because if you bind focus->showmenu, the menu will get
1153 hidden to do the focusing
1157 ob_main_loop_queue_action(ob_main_loop, a);
1162 void action_run_string(const gchar *name, struct _ObClient *c, Time time)
1167 a = action_from_string(name, OB_USER_ACTION_NONE);
1170 l = g_slist_append(NULL, a);
1172 action_run(l, c, 0, time);
1175 void action_activate(union ActionData *data)
1177 if (data->client.any.c) {
1178 if (!data->any.button || client_mouse_focusable(data->client.any.c) ||
1179 (data->any.context != OB_FRAME_CONTEXT_CLIENT &&
1180 data->any.context != OB_FRAME_CONTEXT_FRAME))
1182 /* if using focus_delay, stop the timer now so that focus doesn't
1184 event_halt_focus_delay();
1186 client_activate(data->activate.any.c, data->activate.here, TRUE);
1189 /* focus action on something other than a client, make keybindings
1190 work for this openbox instance, but don't focus any specific client
1196 void action_focus(union ActionData *data)
1198 if (data->client.any.c) {
1199 if (!data->any.button || client_mouse_focusable(data->client.any.c) ||
1200 (data->any.context != OB_FRAME_CONTEXT_CLIENT &&
1201 data->any.context != OB_FRAME_CONTEXT_FRAME))
1203 /* if using focus_delay, stop the timer now so that focus doesn't
1205 event_halt_focus_delay();
1207 client_focus(data->client.any.c);
1210 /* focus action on something other than a client, make keybindings
1211 work for this openbox instance, but don't focus any specific client
1217 void action_unfocus (union ActionData *data)
1219 if (data->client.any.c == focus_client)
1220 focus_fallback(FALSE, FALSE, TRUE);
1223 void action_iconify(union ActionData *data)
1225 client_action_start(data);
1226 client_iconify(data->client.any.c, TRUE, TRUE, FALSE);
1227 client_action_end(data, config_focus_under_mouse);
1230 void action_focus_order_to_bottom(union ActionData *data)
1232 focus_order_to_bottom(data->client.any.c);
1235 void action_raiselower(union ActionData *data)
1237 ObClient *c = data->client.any.c;
1239 client_action_start(data);
1240 stacking_restack_request(c, NULL, Opposite);
1241 client_action_end(data, config_focus_under_mouse);
1244 void action_raise(union ActionData *data)
1246 client_action_start(data);
1247 stacking_raise(CLIENT_AS_WINDOW(data->client.any.c));
1248 client_action_end(data, config_focus_under_mouse);
1251 void action_unshaderaise(union ActionData *data)
1253 if (data->client.any.c->shaded)
1254 action_unshade(data);
1259 void action_shadelower(union ActionData *data)
1261 if (data->client.any.c->shaded)
1267 void action_lower(union ActionData *data)
1269 client_action_start(data);
1270 stacking_lower(CLIENT_AS_WINDOW(data->client.any.c));
1271 client_action_end(data, config_focus_under_mouse);
1274 void action_close(union ActionData *data)
1276 client_close(data->client.any.c);
1279 void action_kill(union ActionData *data)
1281 client_kill(data->client.any.c);
1284 void action_shade(union ActionData *data)
1286 client_action_start(data);
1287 client_shade(data->client.any.c, TRUE);
1288 client_action_end(data, config_focus_under_mouse);
1291 void action_unshade(union ActionData *data)
1293 client_action_start(data);
1294 client_shade(data->client.any.c, FALSE);
1295 client_action_end(data, config_focus_under_mouse);
1298 void action_toggle_shade(union ActionData *data)
1300 client_action_start(data);
1301 client_shade(data->client.any.c, !data->client.any.c->shaded);
1302 client_action_end(data, config_focus_under_mouse);
1305 void action_toggle_omnipresent(union ActionData *data)
1307 client_set_desktop(data->client.any.c,
1308 data->client.any.c->desktop == DESKTOP_ALL ?
1309 screen_desktop : DESKTOP_ALL, FALSE, TRUE);
1312 void action_move_relative_horz(union ActionData *data)
1314 ObClient *c = data->relative.any.c;
1315 client_action_start(data);
1316 client_move(c, c->area.x + data->relative.deltax, c->area.y);
1317 client_action_end(data, FALSE);
1320 void action_move_relative_vert(union ActionData *data)
1322 ObClient *c = data->relative.any.c;
1323 client_action_start(data);
1324 client_move(c, c->area.x, c->area.y + data->relative.deltax);
1325 client_action_end(data, FALSE);
1328 void action_move_to_center(union ActionData *data)
1330 ObClient *c = data->client.any.c;
1332 area = screen_area(c->desktop, client_monitor(c), NULL);
1333 client_action_start(data);
1334 client_move(c, area->x + area->width / 2 - c->area.width / 2,
1335 area->y + area->height / 2 - c->area.height / 2);
1336 client_action_end(data, FALSE);
1340 void action_resize_relative_horz(union ActionData *data)
1342 ObClient *c = data->relative.any.c;
1343 client_action_start(data);
1345 c->area.width + data->relative.deltax * c->size_inc.width,
1347 client_action_end(data, FALSE);
1350 void action_resize_relative_vert(union ActionData *data)
1352 ObClient *c = data->relative.any.c;
1354 client_action_start(data);
1355 client_resize(c, c->area.width, c->area.height +
1356 data->relative.deltax * c->size_inc.height);
1357 client_action_end(data, FALSE);
1361 void action_move_relative(union ActionData *data)
1363 ObClient *c = data->relative.any.c;
1364 client_action_start(data);
1365 client_move(c, c->area.x + data->relative.deltax, c->area.y +
1366 data->relative.deltay);
1367 client_action_end(data, FALSE);
1370 void action_resize_relative(union ActionData *data)
1372 ObClient *c = data->relative.any.c;
1373 gint x, y, ow, xoff, nw, oh, yoff, nh, lw, lh;
1375 client_action_start(data);
1380 xoff = -data->relative.deltaxl * c->size_inc.width;
1381 nw = ow + data->relative.deltax * c->size_inc.width
1382 + data->relative.deltaxl * c->size_inc.width;
1383 oh = c->area.height;
1384 yoff = -data->relative.deltayu * c->size_inc.height;
1385 nh = oh + data->relative.deltay * c->size_inc.height
1386 + data->relative.deltayu * c->size_inc.height;
1388 g_print("deltax %d %d x %d ow %d xoff %d nw %d\n",
1389 data->relative.deltax,
1390 data->relative.deltaxl,
1393 client_try_configure(c, &x, &y, &nw, &nh, &lw, &lh, TRUE);
1394 xoff = xoff == 0 ? 0 : (xoff < 0 ? MAX(xoff, ow-nw) : MIN(xoff, ow-nw));
1395 yoff = yoff == 0 ? 0 : (yoff < 0 ? MAX(yoff, oh-nh) : MIN(yoff, oh-nh));
1396 client_move_resize(c, x + xoff, y + yoff, nw, nh);
1397 client_action_end(data, FALSE);
1400 void action_maximize_full(union ActionData *data)
1402 client_action_start(data);
1403 client_maximize(data->client.any.c, TRUE, 0);
1404 client_action_end(data, config_focus_under_mouse);
1407 void action_unmaximize_full(union ActionData *data)
1409 client_action_start(data);
1410 client_maximize(data->client.any.c, FALSE, 0);
1411 client_action_end(data, config_focus_under_mouse);
1414 void action_toggle_maximize_full(union ActionData *data)
1416 client_action_start(data);
1417 client_maximize(data->client.any.c,
1418 !(data->client.any.c->max_horz ||
1419 data->client.any.c->max_vert),
1421 client_action_end(data, config_focus_under_mouse);
1424 void action_maximize_horz(union ActionData *data)
1426 client_action_start(data);
1427 client_maximize(data->client.any.c, TRUE, 1);
1428 client_action_end(data, config_focus_under_mouse);
1431 void action_unmaximize_horz(union ActionData *data)
1433 client_action_start(data);
1434 client_maximize(data->client.any.c, FALSE, 1);
1435 client_action_end(data, config_focus_under_mouse);
1438 void action_toggle_maximize_horz(union ActionData *data)
1440 client_action_start(data);
1441 client_maximize(data->client.any.c,
1442 !data->client.any.c->max_horz, 1);
1443 client_action_end(data, config_focus_under_mouse);
1446 void action_maximize_vert(union ActionData *data)
1448 client_action_start(data);
1449 client_maximize(data->client.any.c, TRUE, 2);
1450 client_action_end(data, config_focus_under_mouse);
1453 void action_unmaximize_vert(union ActionData *data)
1455 client_action_start(data);
1456 client_maximize(data->client.any.c, FALSE, 2);
1457 client_action_end(data, config_focus_under_mouse);
1460 void action_toggle_maximize_vert(union ActionData *data)
1462 client_action_start(data);
1463 client_maximize(data->client.any.c,
1464 !data->client.any.c->max_vert, 2);
1465 client_action_end(data, config_focus_under_mouse);
1468 void action_toggle_fullscreen(union ActionData *data)
1470 client_action_start(data);
1471 client_fullscreen(data->client.any.c, !(data->client.any.c->fullscreen));
1472 client_action_end(data, config_focus_under_mouse);
1475 void action_send_to_desktop(union ActionData *data)
1477 ObClient *c = data->sendto.any.c;
1479 if (!client_normal(c)) return;
1481 if (data->sendto.desk < screen_num_desktops ||
1482 data->sendto.desk == DESKTOP_ALL) {
1483 client_set_desktop(c, data->sendto.desk, data->sendto.follow, FALSE);
1484 if (data->sendto.follow && data->sendto.desk != screen_desktop)
1485 screen_set_desktop(data->sendto.desk, TRUE);
1489 void action_desktop(union ActionData *data)
1491 /* XXX add the interactive/dialog option back again once the dialog
1492 has been made to not use grabs */
1493 if (data->desktop.desk < screen_num_desktops ||
1494 data->desktop.desk == DESKTOP_ALL)
1496 screen_set_desktop(data->desktop.desk, TRUE);
1497 if (data->inter.any.interactive)
1498 screen_desktop_popup(data->desktop.desk, TRUE);
1502 void action_desktop_dir(union ActionData *data)
1506 d = screen_cycle_desktop(data->desktopdir.dir,
1507 data->desktopdir.wrap,
1508 data->desktopdir.linear,
1509 data->desktopdir.inter.any.interactive,
1510 data->desktopdir.inter.final,
1511 data->desktopdir.inter.cancel);
1512 /* only move the desktop when the action is complete. if we switch
1513 desktops during the interactive action, focus will move but with
1514 NotifyWhileGrabbed and applications don't like that. */
1515 if (!data->sendtodir.inter.any.interactive ||
1516 (data->sendtodir.inter.final && !data->sendtodir.inter.cancel))
1518 if (d != screen_desktop)
1519 screen_set_desktop(d, TRUE);
1523 void action_send_to_desktop_dir(union ActionData *data)
1525 ObClient *c = data->sendtodir.inter.any.c;
1528 if (!client_normal(c)) return;
1530 d = screen_cycle_desktop(data->sendtodir.dir, data->sendtodir.wrap,
1531 data->sendtodir.linear,
1532 data->sendtodir.inter.any.interactive,
1533 data->sendtodir.inter.final,
1534 data->sendtodir.inter.cancel);
1535 /* only move the desktop when the action is complete. if we switch
1536 desktops during the interactive action, focus will move but with
1537 NotifyWhileGrabbed and applications don't like that. */
1538 if (!data->sendtodir.inter.any.interactive ||
1539 (data->sendtodir.inter.final && !data->sendtodir.inter.cancel))
1541 client_set_desktop(c, d, data->sendtodir.follow, FALSE);
1542 if (data->sendtodir.follow && d != screen_desktop)
1543 screen_set_desktop(d, TRUE);
1547 void action_desktop_last(union ActionData *data)
1549 if (screen_last_desktop < screen_num_desktops)
1550 screen_set_desktop(screen_last_desktop, TRUE);
1553 void action_toggle_decorations(union ActionData *data)
1555 ObClient *c = data->client.any.c;
1557 client_action_start(data);
1558 client_set_undecorated(c, !c->undecorated);
1559 client_action_end(data, FALSE);
1562 static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch,
1565 /* let's make x and y client relative instead of screen relative */
1567 y = ch - (y - cy); /* y is inverted, 0 is at the bottom of the window */
1570 #define A -4*X + 7*ch/3
1571 #define B 4*X -15*ch/9
1572 #define C -X/4 + 2*ch/3
1573 #define D X/4 + 5*ch/12
1574 #define E X/4 + ch/3
1575 #define F -X/4 + 7*ch/12
1576 #define G 4*X - 4*ch/3
1577 #define H -4*X + 8*ch/3
1578 #define a (y > 5*ch/9)
1579 #define b (x < 4*cw/9)
1580 #define c (x > 5*cw/9)
1581 #define d (y < 4*ch/9)
1584 Each of these defines (except X which is just there for fun), represents
1585 the equation of a line. The lines they represent are shown in the diagram
1586 below. Checking y against these lines, we are able to choose a region
1587 of the window as shown.
1589 +---------------------A-------|-------|-------B---------------------+
1596 | northwest | A north B | northeast |
1599 C---------------------+----A--+-------+--B----+---------------------D
1600 |CCCCCCC | A B | DDDDDDD|
1601 | CCCCCCCC | A | | B | DDDDDDDD |
1602 | CCCCCCC A B DDDDDDD |
1603 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
1605 | west | b move c | east | ad
1607 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
1608 | EEEEEEE G H FFFFFFF |
1609 | EEEEEEEE | G | | H | FFFFFFFF |
1610 |EEEEEEE | G H | FFFFFFF|
1611 E---------------------+----G--+-------+--H----+---------------------F
1614 | southwest | G south H | southeast |
1621 +---------------------G-------|-------|-------H---------------------+
1625 /* for shaded windows, you can only resize west/east and move */
1627 return prop_atoms.net_wm_moveresize_size_left;
1629 return prop_atoms.net_wm_moveresize_size_right;
1630 return prop_atoms.net_wm_moveresize_move;
1633 if (y < A && y >= C)
1634 return prop_atoms.net_wm_moveresize_size_topleft;
1635 else if (y >= A && y >= B && a)
1636 return prop_atoms.net_wm_moveresize_size_top;
1637 else if (y < B && y >= D)
1638 return prop_atoms.net_wm_moveresize_size_topright;
1639 else if (y < C && y >= E && b)
1640 return prop_atoms.net_wm_moveresize_size_left;
1641 else if (y < D && y >= F && c)
1642 return prop_atoms.net_wm_moveresize_size_right;
1643 else if (y < E && y >= G)
1644 return prop_atoms.net_wm_moveresize_size_bottomleft;
1645 else if (y < G && y < H && d)
1646 return prop_atoms.net_wm_moveresize_size_bottom;
1647 else if (y >= H && y < F)
1648 return prop_atoms.net_wm_moveresize_size_bottomright;
1650 return prop_atoms.net_wm_moveresize_move;
1667 void action_move(union ActionData *data)
1669 ObClient *c = data->moveresize.any.c;
1672 if (data->moveresize.keyboard)
1673 corner = prop_atoms.net_wm_moveresize_move_keyboard;
1675 corner = prop_atoms.net_wm_moveresize_move;
1677 moveresize_start(c, data->any.x, data->any.y, data->any.button, corner);
1680 void action_resize(union ActionData *data)
1682 ObClient *c = data->moveresize.any.c;
1685 if (data->moveresize.keyboard)
1686 corner = prop_atoms.net_wm_moveresize_size_keyboard;
1687 else if (data->moveresize.corner)
1688 corner = data->moveresize.corner; /* it was specified in the binding */
1690 corner = pick_corner(data->any.x, data->any.y,
1691 c->frame->area.x, c->frame->area.y,
1692 /* use the client size because the frame
1693 can be differently sized (shaded
1694 windows) and we want this based on the
1696 c->area.width + c->frame->size.left +
1697 c->frame->size.right,
1698 c->area.height + c->frame->size.top +
1699 c->frame->size.bottom, c->shaded);
1701 moveresize_start(c, data->any.x, data->any.y, data->any.button, corner);
1704 void action_restart(union ActionData *data)
1706 ob_restart_other(data->execute.path);
1709 void action_exit(union ActionData *data)
1713 void action_cycle_windows(union ActionData *data)
1715 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1717 event_halt_focus_delay();
1719 focus_cycle(data->cycle.forward,
1720 data->cycle.all_desktops,
1721 data->cycle.dock_windows,
1722 data->cycle.desktop_windows,
1723 data->cycle.linear, data->any.interactive,
1725 data->cycle.inter.final, data->cycle.inter.cancel);
1728 void action_directional_focus(union ActionData *data)
1730 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1732 event_halt_focus_delay();
1734 focus_directional_cycle(data->interdiraction.direction,
1735 data->interdiraction.dock_windows,
1736 data->interdiraction.desktop_windows,
1737 data->any.interactive,
1738 data->interdiraction.dialog,
1739 data->interdiraction.inter.final,
1740 data->interdiraction.inter.cancel);
1743 void action_movetoedge(union ActionData *data)
1746 ObClient *c = data->diraction.any.c;
1748 x = c->frame->area.x;
1749 y = c->frame->area.y;
1751 switch(data->diraction.direction) {
1752 case OB_DIRECTION_NORTH:
1753 y = client_directional_edge_search(c, OB_DIRECTION_NORTH,
1754 data->diraction.hang)
1755 - (data->diraction.hang ? c->frame->area.height : 0);
1757 case OB_DIRECTION_WEST:
1758 x = client_directional_edge_search(c, OB_DIRECTION_WEST,
1759 data->diraction.hang)
1760 - (data->diraction.hang ? c->frame->area.width : 0);
1762 case OB_DIRECTION_SOUTH:
1763 y = client_directional_edge_search(c, OB_DIRECTION_SOUTH,
1764 data->diraction.hang)
1765 - (data->diraction.hang ? 0 : c->frame->area.height);
1767 case OB_DIRECTION_EAST:
1768 x = client_directional_edge_search(c, OB_DIRECTION_EAST,
1769 data->diraction.hang)
1770 - (data->diraction.hang ? 0 : c->frame->area.width);
1773 g_assert_not_reached();
1775 frame_frame_gravity(c->frame, &x, &y, c->area.width, c->area.height);
1776 client_action_start(data);
1777 client_move(c, x, y);
1778 client_action_end(data, FALSE);
1781 void action_growtoedge(union ActionData *data)
1783 gint x, y, width, height, dest;
1784 ObClient *c = data->diraction.any.c;
1787 a = screen_area(c->desktop, SCREEN_AREA_ALL_MONITORS, &c->frame->area);
1788 x = c->frame->area.x;
1789 y = c->frame->area.y;
1790 /* get the unshaded frame's dimensions..if it is shaded */
1791 width = c->area.width + c->frame->size.left + c->frame->size.right;
1792 height = c->area.height + c->frame->size.top + c->frame->size.bottom;
1794 switch(data->diraction.direction) {
1795 case OB_DIRECTION_NORTH:
1796 if (c->shaded) break; /* don't allow vertical resize if shaded */
1798 dest = client_directional_edge_search(c, OB_DIRECTION_NORTH, FALSE);
1800 height = height / 2;
1802 height = c->frame->area.y + height - dest;
1806 case OB_DIRECTION_WEST:
1807 dest = client_directional_edge_search(c, OB_DIRECTION_WEST, FALSE);
1811 width = c->frame->area.x + width - dest;
1815 case OB_DIRECTION_SOUTH:
1816 if (c->shaded) break; /* don't allow vertical resize if shaded */
1818 dest = client_directional_edge_search(c, OB_DIRECTION_SOUTH, FALSE);
1819 if (a->y + a->height == y + c->frame->area.height) {
1820 height = c->frame->area.height / 2;
1821 y = a->y + a->height - height;
1823 height = dest - c->frame->area.y;
1824 y += (height - c->frame->area.height) % c->size_inc.height;
1825 height -= (height - c->frame->area.height) % c->size_inc.height;
1827 case OB_DIRECTION_EAST:
1828 dest = client_directional_edge_search(c, OB_DIRECTION_EAST, FALSE);
1829 if (a->x + a->width == x + c->frame->area.width) {
1830 width = c->frame->area.width / 2;
1831 x = a->x + a->width - width;
1833 width = dest - c->frame->area.x;
1834 x += (width - c->frame->area.width) % c->size_inc.width;
1835 width -= (width - c->frame->area.width) % c->size_inc.width;
1838 g_assert_not_reached();
1840 width -= c->frame->size.left + c->frame->size.right;
1841 height -= c->frame->size.top + c->frame->size.bottom;
1842 frame_frame_gravity(c->frame, &x, &y, width, height);
1843 client_action_start(data);
1844 client_move_resize(c, x, y, width, height);
1845 client_action_end(data, FALSE);
1849 void action_send_to_layer(union ActionData *data)
1851 client_set_layer(data->layer.any.c, data->layer.layer);
1854 void action_toggle_layer(union ActionData *data)
1856 ObClient *c = data->layer.any.c;
1858 client_action_start(data);
1859 if (data->layer.layer < 0)
1860 client_set_layer(c, c->below ? 0 : -1);
1861 else if (data->layer.layer > 0)
1862 client_set_layer(c, c->above ? 0 : 1);
1863 client_action_end(data, config_focus_under_mouse);
1866 void action_toggle_dockautohide(union ActionData *data)
1868 config_dock_hide = !config_dock_hide;
1872 void action_break_chroot(union ActionData *data)
1874 /* break out of one chroot */
1875 keyboard_reset_chains(1);
1878 void action_add_desktop(union ActionData *data)
1880 client_action_start(data);
1881 screen_set_num_desktops(screen_num_desktops+1);
1883 /* move all the clients over */
1884 if (data->addremovedesktop.current) {
1887 for (it = client_list; it; it = g_list_next(it)) {
1888 ObClient *c = it->data;
1889 if (c->desktop != DESKTOP_ALL && c->desktop >= screen_desktop)
1890 client_set_desktop(c, c->desktop+1, FALSE, TRUE);
1894 client_action_end(data, config_focus_under_mouse);
1897 void action_remove_desktop(union ActionData *data)
1899 guint rmdesktop, movedesktop;
1900 GList *it, *stacking_copy;
1902 if (screen_num_desktops < 2) return;
1904 client_action_start(data);
1906 /* what desktop are we removing and moving to? */
1907 if (data->addremovedesktop.current)
1908 rmdesktop = screen_desktop;
1910 rmdesktop = screen_num_desktops - 1;
1911 if (rmdesktop < screen_num_desktops - 1)
1912 movedesktop = rmdesktop + 1;
1914 movedesktop = rmdesktop;
1916 /* make a copy of the list cuz we're changing it */
1917 stacking_copy = g_list_copy(stacking_list);
1918 for (it = g_list_last(stacking_copy); it; it = g_list_previous(it)) {
1919 if (WINDOW_IS_CLIENT(it->data)) {
1920 ObClient *c = it->data;
1921 guint d = c->desktop;
1922 if (d != DESKTOP_ALL && d >= movedesktop) {
1923 client_set_desktop(c, c->desktop - 1, TRUE, TRUE);
1924 ob_debug("moving window %s\n", c->title);
1926 /* raise all the windows that are on the current desktop which
1928 if ((screen_desktop == rmdesktop - 1 ||
1929 screen_desktop == rmdesktop) &&
1930 (d == DESKTOP_ALL || d == screen_desktop))
1932 stacking_raise(CLIENT_AS_WINDOW(c));
1933 ob_debug("raising window %s\n", c->title);
1938 /* act like we're changing desktops */
1939 if (screen_desktop < screen_num_desktops - 1) {
1940 gint d = screen_desktop;
1941 screen_desktop = screen_last_desktop;
1942 screen_set_desktop(d, TRUE);
1943 ob_debug("fake desktop change\n");
1946 screen_set_num_desktops(screen_num_desktops-1);
1948 client_action_end(data, config_focus_under_mouse);