1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 action.c for the Openbox window manager
4 Copyright (c) 2003 Ben Jansens
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 See the COPYING file for a copy of the GNU General Public License.
22 #include "moveresize.h"
36 inline void client_action_start(union ActionData *data)
38 if (config_focus_follow)
39 if (data->any.context != OB_FRAME_CONTEXT_CLIENT && !data->any.button)
40 grab_pointer(TRUE, OB_CURSOR_NONE);
43 inline void client_action_end(union ActionData *data)
45 if (config_focus_follow)
46 if (data->any.context != OB_FRAME_CONTEXT_CLIENT) {
47 if (!data->any.button) {
48 grab_pointer(FALSE, OB_CURSOR_NONE);
52 if ((c = client_under_pointer()))
53 event_enter_client(c);
58 typedef struct ActionString {
60 void (*func)(union ActionData *);
61 void (*setup)(ObAction **, ObUserAction uact);
64 static ObAction *action_new(void (*func)(union ActionData *data),
67 ObAction *a = g_new0(ObAction, 1);
73 void action_free(ObAction *a)
75 if (a == NULL) return;
77 /* deal with pointers */
78 if (a->func == action_execute || a->func == action_restart)
79 g_free(a->data.execute.path);
80 else if (a->func == action_showmenu)
81 g_free(a->data.showmenu.name);
86 void setup_action_directional_focus_north(ObAction **a, ObUserAction uact)
88 (*a)->data.interdiraction.inter.any.interactive = TRUE;
89 (*a)->data.interdiraction.direction = OB_DIRECTION_NORTH;
92 void setup_action_directional_focus_east(ObAction **a, ObUserAction uact)
94 (*a)->data.interdiraction.inter.any.interactive = TRUE;
95 (*a)->data.interdiraction.direction = OB_DIRECTION_EAST;
98 void setup_action_directional_focus_south(ObAction **a, ObUserAction uact)
100 (*a)->data.interdiraction.inter.any.interactive = TRUE;
101 (*a)->data.interdiraction.direction = OB_DIRECTION_SOUTH;
104 void setup_action_directional_focus_west(ObAction **a, ObUserAction uact)
106 (*a)->data.interdiraction.inter.any.interactive = TRUE;
107 (*a)->data.interdiraction.direction = OB_DIRECTION_WEST;
110 void setup_action_directional_focus_northeast(ObAction **a, ObUserAction uact)
112 (*a)->data.interdiraction.inter.any.interactive = TRUE;
113 (*a)->data.interdiraction.direction = OB_DIRECTION_NORTHEAST;
116 void setup_action_directional_focus_southeast(ObAction **a, ObUserAction uact)
118 (*a)->data.interdiraction.inter.any.interactive = TRUE;
119 (*a)->data.interdiraction.direction = OB_DIRECTION_SOUTHEAST;
122 void setup_action_directional_focus_southwest(ObAction **a, ObUserAction uact)
124 (*a)->data.interdiraction.inter.any.interactive = TRUE;
125 (*a)->data.interdiraction.direction = OB_DIRECTION_SOUTHWEST;
128 void setup_action_directional_focus_northwest(ObAction **a, ObUserAction uact)
130 (*a)->data.interdiraction.inter.any.interactive = TRUE;
131 (*a)->data.interdiraction.direction = OB_DIRECTION_NORTHWEST;
134 void setup_action_send_to_desktop(ObAction **a, ObUserAction uact)
136 (*a)->data.sendto.follow = TRUE;
139 void setup_action_send_to_desktop_prev(ObAction **a, ObUserAction uact)
141 (*a)->data.sendtodir.inter.any.interactive = TRUE;
142 (*a)->data.sendtodir.dir = OB_DIRECTION_WEST;
143 (*a)->data.sendtodir.linear = TRUE;
144 (*a)->data.sendtodir.wrap = TRUE;
145 (*a)->data.sendtodir.follow = TRUE;
148 void setup_action_send_to_desktop_next(ObAction **a, ObUserAction uact)
150 (*a)->data.sendtodir.inter.any.interactive = TRUE;
151 (*a)->data.sendtodir.dir = OB_DIRECTION_EAST;
152 (*a)->data.sendtodir.linear = TRUE;
153 (*a)->data.sendtodir.wrap = TRUE;
154 (*a)->data.sendtodir.follow = TRUE;
157 void setup_action_send_to_desktop_left(ObAction **a, ObUserAction uact)
159 (*a)->data.sendtodir.inter.any.interactive = TRUE;
160 (*a)->data.sendtodir.dir = OB_DIRECTION_WEST;
161 (*a)->data.sendtodir.linear = FALSE;
162 (*a)->data.sendtodir.wrap = TRUE;
163 (*a)->data.sendtodir.follow = TRUE;
166 void setup_action_send_to_desktop_right(ObAction **a, ObUserAction uact)
168 (*a)->data.sendtodir.inter.any.interactive = TRUE;
169 (*a)->data.sendtodir.dir = OB_DIRECTION_EAST;
170 (*a)->data.sendtodir.linear = FALSE;
171 (*a)->data.sendtodir.wrap = TRUE;
172 (*a)->data.sendtodir.follow = TRUE;
175 void setup_action_send_to_desktop_up(ObAction **a, ObUserAction uact)
177 (*a)->data.sendtodir.inter.any.interactive = TRUE;
178 (*a)->data.sendtodir.dir = OB_DIRECTION_NORTH;
179 (*a)->data.sendtodir.linear = FALSE;
180 (*a)->data.sendtodir.wrap = TRUE;
181 (*a)->data.sendtodir.follow = TRUE;
184 void setup_action_send_to_desktop_down(ObAction **a, ObUserAction uact)
186 (*a)->data.sendtodir.inter.any.interactive = TRUE;
187 (*a)->data.sendtodir.dir = OB_DIRECTION_SOUTH;
188 (*a)->data.sendtodir.linear = FALSE;
189 (*a)->data.sendtodir.wrap = TRUE;
190 (*a)->data.sendtodir.follow = TRUE;
193 void setup_action_desktop_prev(ObAction **a, ObUserAction uact)
195 (*a)->data.desktopdir.inter.any.interactive = TRUE;
196 (*a)->data.desktopdir.dir = OB_DIRECTION_WEST;
197 (*a)->data.desktopdir.linear = TRUE;
198 (*a)->data.desktopdir.wrap = TRUE;
201 void setup_action_desktop_next(ObAction **a, ObUserAction uact)
203 (*a)->data.desktopdir.inter.any.interactive = TRUE;
204 (*a)->data.desktopdir.dir = OB_DIRECTION_EAST;
205 (*a)->data.desktopdir.linear = TRUE;
206 (*a)->data.desktopdir.wrap = TRUE;
209 void setup_action_desktop_left(ObAction **a, ObUserAction uact)
211 (*a)->data.desktopdir.inter.any.interactive = TRUE;
212 (*a)->data.desktopdir.dir = OB_DIRECTION_WEST;
213 (*a)->data.desktopdir.linear = FALSE;
214 (*a)->data.desktopdir.wrap = TRUE;
217 void setup_action_desktop_right(ObAction **a, ObUserAction uact)
219 (*a)->data.desktopdir.inter.any.interactive = TRUE;
220 (*a)->data.desktopdir.dir = OB_DIRECTION_EAST;
221 (*a)->data.desktopdir.linear = FALSE;
222 (*a)->data.desktopdir.wrap = TRUE;
225 void setup_action_desktop_up(ObAction **a, ObUserAction uact)
227 (*a)->data.desktopdir.inter.any.interactive = TRUE;
228 (*a)->data.desktopdir.dir = OB_DIRECTION_NORTH;
229 (*a)->data.desktopdir.linear = FALSE;
230 (*a)->data.desktopdir.wrap = TRUE;
233 void setup_action_desktop_down(ObAction **a, ObUserAction uact)
235 (*a)->data.desktopdir.inter.any.interactive = TRUE;
236 (*a)->data.desktopdir.dir = OB_DIRECTION_SOUTH;
237 (*a)->data.desktopdir.linear = FALSE;
238 (*a)->data.desktopdir.wrap = TRUE;
241 void setup_action_cycle_windows_next(ObAction **a, ObUserAction uact)
243 (*a)->data.cycle.inter.any.interactive = TRUE;
244 (*a)->data.cycle.linear = FALSE;
245 (*a)->data.cycle.forward = TRUE;
248 void setup_action_cycle_windows_previous(ObAction **a, ObUserAction uact)
250 (*a)->data.cycle.inter.any.interactive = TRUE;
251 (*a)->data.cycle.linear = FALSE;
252 (*a)->data.cycle.forward = FALSE;
255 void setup_action_movetoedge_north(ObAction **a, ObUserAction uact)
257 (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
260 void setup_action_movetoedge_south(ObAction **a, ObUserAction uact)
262 (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
265 void setup_action_movetoedge_east(ObAction **a, ObUserAction uact)
267 (*a)->data.diraction.direction = OB_DIRECTION_EAST;
270 void setup_action_movetoedge_west(ObAction **a, ObUserAction uact)
272 (*a)->data.diraction.direction = OB_DIRECTION_WEST;
275 void setup_action_growtoedge_north(ObAction **a, ObUserAction uact)
277 (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
280 void setup_action_growtoedge_south(ObAction **a, ObUserAction uact)
282 (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
285 void setup_action_growtoedge_east(ObAction **a, ObUserAction uact)
287 (*a)->data.diraction.direction = OB_DIRECTION_EAST;
290 void setup_action_growtoedge_west(ObAction **a, ObUserAction uact)
292 (*a)->data.diraction.direction = OB_DIRECTION_WEST;
295 void setup_action_top_layer(ObAction **a, ObUserAction uact)
297 (*a)->data.layer.layer = 1;
300 void setup_action_normal_layer(ObAction **a, ObUserAction uact)
302 (*a)->data.layer.layer = 0;
305 void setup_action_bottom_layer(ObAction **a, ObUserAction uact)
307 (*a)->data.layer.layer = -1;
310 void setup_action_move(ObAction **a, ObUserAction uact)
312 (*a)->data.moveresize.move = TRUE;
313 (*a)->data.moveresize.keyboard =
314 (uact == OB_USER_ACTION_KEYBOARD_KEY ||
315 uact == OB_USER_ACTION_MENU_SELECTION);
318 void setup_action_resize(ObAction **a, ObUserAction uact)
320 (*a)->data.moveresize.move = FALSE;
321 (*a)->data.moveresize.keyboard =
322 (uact == OB_USER_ACTION_KEYBOARD_KEY ||
323 uact == OB_USER_ACTION_MENU_SELECTION);
326 void setup_action_showmenu(ObAction **a, ObUserAction uact)
328 /* you cannot call ShowMenu from inside a menu, cuz the menu code makes
329 assumptions that there is only one menu (and submenus) open at
331 if (uact == OB_USER_ACTION_MENU_SELECTION) {
337 ActionString actionstrings[] =
345 "directionalfocusnorth",
346 action_directional_focus,
347 setup_action_directional_focus_north
350 "directionalfocuseast",
351 action_directional_focus,
352 setup_action_directional_focus_east
355 "directionalfocussouth",
356 action_directional_focus,
357 setup_action_directional_focus_south
360 "directionalfocuswest",
361 action_directional_focus,
362 setup_action_directional_focus_west
365 "directionalfocusnortheast",
366 action_directional_focus,
367 setup_action_directional_focus_northeast
370 "directionalfocussoutheast",
371 action_directional_focus,
372 setup_action_directional_focus_southeast
375 "directionalfocussouthwest",
376 action_directional_focus,
377 setup_action_directional_focus_southwest
380 "directionalfocusnorthwest",
381 action_directional_focus,
382 setup_action_directional_focus_northwest
456 action_toggle_omnipresent,
461 action_move_relative_horz,
466 action_move_relative_vert,
470 "resizerelativehorz",
471 action_resize_relative_horz,
475 "resizerelativevert",
476 action_resize_relative_vert,
481 action_maximize_full,
486 action_unmaximize_full,
490 "togglemaximizefull",
491 action_toggle_maximize_full,
496 action_maximize_horz,
501 action_unmaximize_horz,
505 "togglemaximizehorz",
506 action_toggle_maximize_horz,
511 action_maximize_vert,
516 action_unmaximize_vert,
520 "togglemaximizevert",
521 action_toggle_maximize_vert,
526 action_send_to_desktop,
527 setup_action_send_to_desktop
531 action_send_to_desktop_dir,
532 setup_action_send_to_desktop_next
535 "sendtodesktopprevious",
536 action_send_to_desktop_dir,
537 setup_action_send_to_desktop_prev
540 "sendtodesktopright",
541 action_send_to_desktop_dir,
542 setup_action_send_to_desktop_right
546 action_send_to_desktop_dir,
547 setup_action_send_to_desktop_left
551 action_send_to_desktop_dir,
552 setup_action_send_to_desktop_up
556 action_send_to_desktop_dir,
557 setup_action_send_to_desktop_down
567 setup_action_desktop_next
572 setup_action_desktop_prev
577 setup_action_desktop_right
582 setup_action_desktop_left
587 setup_action_desktop_up
592 setup_action_desktop_down
596 action_toggle_decorations,
611 action_toggle_show_desktop,
621 action_unshow_desktop,
647 setup_action_showmenu
651 action_send_to_layer,
652 setup_action_top_layer
657 setup_action_top_layer
661 action_send_to_layer,
662 setup_action_normal_layer
666 action_send_to_layer,
667 setup_action_bottom_layer
670 "togglealwaysonbottom",
672 setup_action_bottom_layer
676 action_cycle_windows,
677 setup_action_cycle_windows_next
681 action_cycle_windows,
682 setup_action_cycle_windows_previous
687 setup_action_movetoedge_north
692 setup_action_movetoedge_south
697 setup_action_movetoedge_west
702 setup_action_movetoedge_east
707 setup_action_growtoedge_north
712 setup_action_growtoedge_south
717 setup_action_growtoedge_west
722 setup_action_growtoedge_east
731 ObAction *action_from_string(const gchar *name, ObUserAction uact)
734 gboolean exist = FALSE;
737 for (i = 0; actionstrings[i].name; i++)
738 if (!g_ascii_strcasecmp(name, actionstrings[i].name)) {
740 a = action_new(actionstrings[i].func, uact);
741 if (actionstrings[i].setup)
742 actionstrings[i].setup(&a, uact);
743 /* only key bindings can be interactive. thus saith the xor. */
744 if (uact != OB_USER_ACTION_KEYBOARD_KEY)
745 a->data.any.interactive = FALSE;
749 g_warning("Invalid action '%s' requested. No such action exists.",
752 g_warning("Invalid use of action '%s'. Action will be ignored.", name);
756 ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
760 ObAction *act = NULL;
763 if (parse_attr_string("name", node, &actname)) {
764 if ((act = action_from_string(actname, uact))) {
765 if (act->func == action_execute || act->func == action_restart) {
766 if ((n = parse_find_node("execute", node->xmlChildrenNode))) {
767 gchar *s = parse_string(doc, n);
768 act->data.execute.path = parse_expand_tilde(s);
771 } else if (act->func == action_showmenu) {
772 if ((n = parse_find_node("menu", node->xmlChildrenNode)))
773 act->data.showmenu.name = parse_string(doc, n);
774 } else if (act->func == action_move_relative_horz ||
775 act->func == action_move_relative_vert ||
776 act->func == action_resize_relative_horz ||
777 act->func == action_resize_relative_vert) {
778 if ((n = parse_find_node("delta", node->xmlChildrenNode)))
779 act->data.relative.delta = parse_int(doc, n);
780 } else if (act->func == action_desktop) {
781 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
782 act->data.desktop.desk = parse_int(doc, n);
783 if (act->data.desktop.desk > 0) act->data.desktop.desk--;
784 } else if (act->func == action_send_to_desktop) {
785 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
786 act->data.sendto.desk = parse_int(doc, n);
787 if (act->data.sendto.desk > 0) act->data.sendto.desk--;
788 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
789 act->data.sendto.follow = parse_bool(doc, n);
790 } else if (act->func == action_desktop_dir) {
791 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
792 act->data.desktopdir.wrap = parse_bool(doc, n);
793 } else if (act->func == action_send_to_desktop_dir) {
794 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
795 act->data.sendtodir.wrap = parse_bool(doc, n);
796 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
797 act->data.sendtodir.follow = parse_bool(doc, n);
798 } else if (act->func == action_activate) {
799 if ((n = parse_find_node("here", node->xmlChildrenNode)))
800 act->data.activate.here = parse_bool(doc, n);
801 } else if (act->func == action_cycle_windows) {
802 if ((n = parse_find_node("linear", node->xmlChildrenNode)))
803 act->data.cycle.linear = parse_bool(doc, n);
811 void action_run_list(GSList *acts, ObClient *c, ObFrameContext context,
812 guint state, guint button, gint x, gint y,
813 gboolean cancel, gboolean done)
817 gboolean inter = FALSE;
823 screen_pointer_pos(&x, &y);
825 if (grab_on_keyboard())
828 for (it = acts; it; it = g_slist_next(it)) {
830 if (a->data.any.interactive) {
837 /* sometimes when we execute another app as an action,
838 it won't work right unless we XUngrabKeyboard first,
839 even though we grabbed the key/button Asychronously.
840 e.g. "gnome-panel-control --main-menu" */
841 XUngrabKeyboard(ob_display, event_lasttime);
844 for (it = acts; it; it = g_slist_next(it)) {
848 a->data.any.context = context;
852 a->data.any.button = button;
854 if (a->data.any.interactive) {
855 a->data.inter.cancel = cancel;
856 a->data.inter.final = done;
857 if (!(cancel || done))
858 keyboard_interactive_grab(state, c, a);
865 void action_execute(union ActionData *data)
869 if (data->execute.path) {
870 cmd = g_filename_from_utf8(data->execute.path, -1, NULL, NULL, NULL);
872 if (!g_spawn_command_line_async(cmd, &e)) {
873 g_warning("failed to execute '%s': %s",
878 g_warning("failed to convert '%s' from utf8", data->execute.path);
883 void action_activate(union ActionData *data)
885 if (data->activate.any.c)
886 client_activate(data->activate.any.c, data->activate.here);
889 void action_focus(union ActionData *data)
891 if (data->client.any.c)
892 client_focus(data->client.any.c);
895 void action_unfocus (union ActionData *data)
897 if (data->client.any.c)
898 client_unfocus(data->client.any.c);
901 void action_iconify(union ActionData *data)
903 if (data->client.any.c)
904 client_iconify(data->client.any.c, TRUE, TRUE);
907 void action_raiselower(union ActionData *data)
909 ObClient *c = data->client.any.c;
911 gboolean raise = FALSE;
915 for (it = stacking_list; it; it = g_list_next(it)) {
916 ObClient *cit = it->data;
919 if (client_normal(cit) == client_normal(c) &&
920 cit->layer == c->layer &&
923 if (RECT_INTERSECTS_RECT(cit->frame->area, c->frame->area)) {
931 client_action_start(data);
932 stacking_raise(CLIENT_AS_WINDOW(c));
933 client_action_end(data);
935 client_action_start(data);
936 stacking_lower(CLIENT_AS_WINDOW(c));
937 client_action_end(data);
941 void action_raise(union ActionData *data)
943 if (data->client.any.c) {
944 client_action_start(data);
945 stacking_raise(CLIENT_AS_WINDOW(data->client.any.c));
946 client_action_end(data);
950 void action_unshaderaise(union ActionData *data)
952 if (data->client.any.c) {
953 if (data->client.any.c->shaded) {
954 client_action_start(data);
955 client_shade(data->client.any.c, FALSE);
956 client_action_end(data);
958 client_action_start(data);
959 stacking_raise(CLIENT_AS_WINDOW(data->client.any.c));
960 client_action_end(data);
965 void action_shadelower(union ActionData *data)
967 if (data->client.any.c) {
968 if (data->client.any.c->shaded)
969 stacking_lower(CLIENT_AS_WINDOW(data->client.any.c));
971 client_action_start(data);
972 client_shade(data->client.any.c, TRUE);
973 client_action_end(data);
978 void action_lower(union ActionData *data)
980 if (data->client.any.c) {
981 client_action_start(data);
982 stacking_lower(CLIENT_AS_WINDOW(data->client.any.c));
983 client_action_end(data);
987 void action_close(union ActionData *data)
989 if (data->client.any.c)
990 client_close(data->client.any.c);
993 void action_kill(union ActionData *data)
995 if (data->client.any.c)
996 client_kill(data->client.any.c);
999 void action_shade(union ActionData *data)
1001 if (data->client.any.c) {
1002 client_action_start(data);
1003 client_shade(data->client.any.c, TRUE);
1004 client_action_end(data);
1008 void action_unshade(union ActionData *data)
1010 if (data->client.any.c) {
1011 client_action_start(data);
1012 client_shade(data->client.any.c, FALSE);
1013 client_action_end(data);
1017 void action_toggle_shade(union ActionData *data)
1019 if (data->client.any.c) {
1020 client_action_start(data);
1021 client_shade(data->client.any.c, !data->client.any.c->shaded);
1022 client_action_end(data);
1026 void action_toggle_omnipresent(union ActionData *data)
1028 if (data->client.any.c)
1029 client_set_desktop(data->client.any.c,
1030 data->client.any.c->desktop == DESKTOP_ALL ?
1031 screen_desktop : DESKTOP_ALL, FALSE);
1034 void action_move_relative_horz(union ActionData *data)
1036 ObClient *c = data->relative.any.c;
1038 client_action_start(data);
1039 client_move(c, c->area.x + data->relative.delta, c->area.y);
1040 client_action_end(data);
1044 void action_move_relative_vert(union ActionData *data)
1046 ObClient *c = data->relative.any.c;
1048 client_action_start(data);
1049 client_move(c, c->area.x, c->area.y + data->relative.delta);
1050 client_action_end(data);
1054 void action_resize_relative_horz(union ActionData *data)
1056 ObClient *c = data->relative.any.c;
1058 client_action_start(data);
1060 c->area.width + data->relative.delta * c->size_inc.width,
1062 client_action_end(data);
1066 void action_resize_relative_vert(union ActionData *data)
1068 ObClient *c = data->relative.any.c;
1069 if (c && !c->shaded) {
1070 client_action_start(data);
1071 client_resize(c, c->area.width, c->area.height +
1072 data->relative.delta * c->size_inc.height);
1073 client_action_end(data);
1077 void action_maximize_full(union ActionData *data)
1079 if (data->client.any.c) {
1080 client_action_start(data);
1081 client_maximize(data->client.any.c, TRUE, 0, TRUE);
1082 client_action_end(data);
1086 void action_unmaximize_full(union ActionData *data)
1088 if (data->client.any.c) {
1089 client_action_start(data);
1090 client_maximize(data->client.any.c, FALSE, 0, TRUE);
1091 client_action_end(data);
1095 void action_toggle_maximize_full(union ActionData *data)
1097 if (data->client.any.c) {
1098 client_action_start(data);
1099 client_maximize(data->client.any.c,
1100 !(data->client.any.c->max_horz ||
1101 data->client.any.c->max_vert),
1103 client_action_end(data);
1107 void action_maximize_horz(union ActionData *data)
1109 if (data->client.any.c) {
1110 client_action_start(data);
1111 client_maximize(data->client.any.c, TRUE, 1, TRUE);
1112 client_action_end(data);
1116 void action_unmaximize_horz(union ActionData *data)
1118 if (data->client.any.c) {
1119 client_action_start(data);
1120 client_maximize(data->client.any.c, FALSE, 1, TRUE);
1121 client_action_end(data);
1125 void action_toggle_maximize_horz(union ActionData *data)
1127 if (data->client.any.c) {
1128 client_action_start(data);
1129 client_maximize(data->client.any.c,
1130 !data->client.any.c->max_horz, 1, TRUE);
1131 client_action_end(data);
1135 void action_maximize_vert(union ActionData *data)
1137 if (data->client.any.c) {
1138 client_action_start(data);
1139 client_maximize(data->client.any.c, TRUE, 2, TRUE);
1140 client_action_end(data);
1144 void action_unmaximize_vert(union ActionData *data)
1146 if (data->client.any.c) {
1147 client_action_start(data);
1148 client_maximize(data->client.any.c, FALSE, 2, TRUE);
1149 client_action_end(data);
1153 void action_toggle_maximize_vert(union ActionData *data)
1155 if (data->client.any.c) {
1156 client_action_start(data);
1157 client_maximize(data->client.any.c,
1158 !data->client.any.c->max_vert, 2, TRUE);
1159 client_action_end(data);
1163 void action_send_to_desktop(union ActionData *data)
1165 ObClient *c = data->sendto.any.c;
1167 if (!c || !client_normal(c)) return;
1169 if (data->sendto.desk < screen_num_desktops ||
1170 data->sendto.desk == DESKTOP_ALL) {
1171 client_set_desktop(c, data->sendto.desk, data->sendto.follow);
1172 if (data->sendto.follow)
1173 screen_set_desktop(data->sendto.desk);
1177 void action_desktop(union ActionData *data)
1179 if (data->desktop.desk < screen_num_desktops ||
1180 data->desktop.desk == DESKTOP_ALL)
1181 screen_set_desktop(data->desktop.desk);
1184 void action_desktop_dir(union ActionData *data)
1188 d = screen_cycle_desktop(data->desktopdir.dir,
1189 data->desktopdir.wrap,
1190 data->sendtodir.linear,
1191 data->desktopdir.inter.any.interactive,
1192 data->desktopdir.inter.final,
1193 data->desktopdir.inter.cancel);
1194 screen_set_desktop(d);
1197 void action_send_to_desktop_dir(union ActionData *data)
1199 ObClient *c = data->sendtodir.inter.any.c;
1202 if (!c || !client_normal(c)) return;
1204 d = screen_cycle_desktop(data->sendtodir.dir, data->sendtodir.wrap,
1205 data->sendtodir.linear,
1206 data->sendtodir.inter.any.interactive,
1207 data->sendtodir.inter.final,
1208 data->sendtodir.inter.cancel);
1209 client_set_desktop(c, d, data->sendtodir.follow);
1210 if (data->sendtodir.follow)
1211 screen_set_desktop(d);
1214 void action_desktop_last(union ActionData *data)
1216 screen_set_desktop(screen_last_desktop);
1219 void action_toggle_decorations(union ActionData *data)
1221 ObClient *c = data->client.any.c;
1224 client_action_start(data);
1225 c->decorate = !c->decorate;
1226 client_setup_decor_and_functions(c);
1227 client_action_end(data);
1231 static guint32 pick_corner(int x, int y, int cx, int cy, int cw, int ch)
1233 if (x - cx > cw / 2) {
1234 if (y - cy > ch / 2)
1235 return prop_atoms.net_wm_moveresize_size_bottomright;
1237 return prop_atoms.net_wm_moveresize_size_topright;
1239 if (y - cy > ch / 2)
1240 return prop_atoms.net_wm_moveresize_size_bottomleft;
1242 return prop_atoms.net_wm_moveresize_size_topleft;
1246 void action_moveresize(union ActionData *data)
1248 ObClient *c = data->moveresize.any.c;
1251 if (!c || !client_normal(c)) return;
1253 if (data->moveresize.keyboard) {
1254 corner = (data->moveresize.move ?
1255 prop_atoms.net_wm_moveresize_move_keyboard :
1256 prop_atoms.net_wm_moveresize_size_keyboard);
1258 corner = (data->moveresize.move ?
1259 prop_atoms.net_wm_moveresize_move :
1260 pick_corner(data->any.x, data->any.y,
1261 c->frame->area.x, c->frame->area.y,
1262 /* use the client size because the frame
1263 can be differently sized (shaded
1264 windows) and we want this based on the
1266 c->area.width + c->frame->size.left +
1267 c->frame->size.right,
1268 c->area.height + c->frame->size.top +
1269 c->frame->size.bottom));
1272 moveresize_start(c, data->any.x, data->any.y, data->any.button, corner);
1275 void action_reconfigure(union ActionData *data)
1280 void action_restart(union ActionData *data)
1282 ob_restart_other(data->execute.path);
1285 void action_exit(union ActionData *data)
1290 void action_showmenu(union ActionData *data)
1292 if (data->showmenu.name) {
1293 menu_show(data->showmenu.name, data->any.x, data->any.y,
1294 data->showmenu.any.c);
1298 void action_cycle_windows(union ActionData *data)
1300 focus_cycle(data->cycle.forward, data->cycle.linear,
1301 data->cycle.inter.any.interactive,
1302 data->cycle.inter.final, data->cycle.inter.cancel);
1305 void action_directional_focus(union ActionData *data)
1307 focus_directional_cycle(data->interdiraction.direction,
1308 data->interdiraction.inter.any.interactive,
1309 data->interdiraction.inter.final,
1310 data->interdiraction.inter.cancel);
1313 void action_movetoedge(union ActionData *data)
1316 ObClient *c = data->diraction.any.c;
1320 x = c->frame->area.x;
1321 y = c->frame->area.y;
1323 switch(data->diraction.direction) {
1324 case OB_DIRECTION_NORTH:
1325 y = client_directional_edge_search(c, OB_DIRECTION_NORTH);
1327 case OB_DIRECTION_WEST:
1328 x = client_directional_edge_search(c, OB_DIRECTION_WEST);
1330 case OB_DIRECTION_SOUTH:
1331 y = client_directional_edge_search(c, OB_DIRECTION_SOUTH) -
1332 c->frame->area.height;
1334 case OB_DIRECTION_EAST:
1335 x = client_directional_edge_search(c, OB_DIRECTION_EAST) -
1336 c->frame->area.width;
1339 g_assert_not_reached();
1341 frame_frame_gravity(c->frame, &x, &y);
1342 client_action_start(data);
1343 client_move(c, x, y);
1344 client_action_end(data);
1348 void action_growtoedge(union ActionData *data)
1350 int x, y, width, height, dest;
1351 ObClient *c = data->diraction.any.c;
1357 a = screen_area(c->desktop);
1358 x = c->frame->area.x;
1359 y = c->frame->area.y;
1360 width = c->frame->area.width;
1361 height = c->frame->area.height;
1363 switch(data->diraction.direction) {
1364 case OB_DIRECTION_NORTH:
1365 dest = client_directional_edge_search(c, OB_DIRECTION_NORTH);
1367 height = c->frame->area.height / 2;
1369 height = c->frame->area.y + c->frame->area.height - dest;
1373 case OB_DIRECTION_WEST:
1374 dest = client_directional_edge_search(c, OB_DIRECTION_WEST);
1376 width = c->frame->area.width / 2;
1378 width = c->frame->area.x + c->frame->area.width - dest;
1382 case OB_DIRECTION_SOUTH:
1383 dest = client_directional_edge_search(c, OB_DIRECTION_SOUTH);
1384 if (a->y + a->height == y + c->frame->area.height) {
1385 height = c->frame->area.height / 2;
1386 y = a->y + a->height - height;
1388 height = dest - c->frame->area.y;
1389 y += (height - c->frame->area.height) % c->size_inc.height;
1390 height -= (height - c->frame->area.height) % c->size_inc.height;
1392 case OB_DIRECTION_EAST:
1393 dest = client_directional_edge_search(c, OB_DIRECTION_EAST);
1394 if (a->x + a->width == x + c->frame->area.width) {
1395 width = c->frame->area.width / 2;
1396 x = a->x + a->width - width;
1398 width = dest - c->frame->area.x;
1399 x += (width - c->frame->area.width) % c->size_inc.width;
1400 width -= (width - c->frame->area.width) % c->size_inc.width;
1403 g_assert_not_reached();
1405 frame_frame_gravity(c->frame, &x, &y);
1406 width -= c->frame->size.left + c->frame->size.right;
1407 height -= c->frame->size.top + c->frame->size.bottom;
1408 client_action_start(data);
1409 client_move_resize(c, x, y, width, height);
1410 client_action_end(data);
1413 void action_send_to_layer(union ActionData *data)
1415 if (data->layer.any.c)
1416 client_set_layer(data->layer.any.c, data->layer.layer);
1419 void action_toggle_layer(union ActionData *data)
1421 ObClient *c = data->layer.any.c;
1424 client_action_start(data);
1425 if (data->layer.layer < 0)
1426 client_set_layer(c, c->below ? 0 : -1);
1427 else if (data->layer.layer > 0)
1428 client_set_layer(c, c->above ? 0 : 1);
1429 client_action_end(data);
1433 void action_toggle_show_desktop(union ActionData *data)
1435 screen_show_desktop(!screen_showing_desktop);
1438 void action_show_desktop(union ActionData *data)
1440 screen_show_desktop(TRUE);
1443 void action_unshow_desktop(union ActionData *data)
1445 screen_show_desktop(FALSE);