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 Ben 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 "moveresize.h"
39 inline void client_action_start(union ActionData *data)
41 if (config_focus_follow)
42 if (data->any.context != OB_FRAME_CONTEXT_CLIENT && !data->any.button)
43 grab_pointer(TRUE, OB_CURSOR_NONE);
46 inline void client_action_end(union ActionData *data)
48 if (config_focus_follow)
49 if (data->any.context != OB_FRAME_CONTEXT_CLIENT) {
50 if (!data->any.button) {
51 grab_pointer(FALSE, OB_CURSOR_NONE);
55 /* usually this is sorta redundant, but with a press action
56 the enter event will come as a GrabNotify which is
57 ignored, so this will handle that case */
58 if ((c = client_under_pointer()))
59 event_enter_client(c);
67 void (*func)(union ActionData *);
68 void (*setup)(ObAction **, ObUserAction uact);
71 static ObAction *action_new(void (*func)(union ActionData *data))
73 ObAction *a = g_new0(ObAction, 1);
80 void action_ref(ObAction *a)
85 void action_unref(ObAction *a)
87 if (a == NULL) return;
89 if (--a->ref > 0) return;
91 /* deal with pointers */
92 if (a->func == action_execute || a->func == action_restart)
93 g_free(a->data.execute.path);
94 else if (a->func == action_showmenu)
95 g_free(a->data.showmenu.name);
100 ObAction* action_copy(const ObAction *src)
102 ObAction *a = action_new(src->func);
106 /* deal with pointers */
107 if (a->func == action_execute || a->func == action_restart)
108 a->data.execute.path = g_strdup(a->data.execute.path);
109 else if (a->func == action_showmenu)
110 a->data.showmenu.name = g_strdup(a->data.showmenu.name);
115 void setup_action_directional_focus_north(ObAction **a, ObUserAction uact)
117 (*a)->data.interdiraction.inter.any.interactive = TRUE;
118 (*a)->data.interdiraction.direction = OB_DIRECTION_NORTH;
119 (*a)->data.interdiraction.dialog = TRUE;
122 void setup_action_directional_focus_east(ObAction **a, ObUserAction uact)
124 (*a)->data.interdiraction.inter.any.interactive = TRUE;
125 (*a)->data.interdiraction.direction = OB_DIRECTION_EAST;
126 (*a)->data.interdiraction.dialog = TRUE;
129 void setup_action_directional_focus_south(ObAction **a, ObUserAction uact)
131 (*a)->data.interdiraction.inter.any.interactive = TRUE;
132 (*a)->data.interdiraction.direction = OB_DIRECTION_SOUTH;
133 (*a)->data.interdiraction.dialog = TRUE;
136 void setup_action_directional_focus_west(ObAction **a, ObUserAction uact)
138 (*a)->data.interdiraction.inter.any.interactive = TRUE;
139 (*a)->data.interdiraction.direction = OB_DIRECTION_WEST;
140 (*a)->data.interdiraction.dialog = TRUE;
143 void setup_action_directional_focus_northeast(ObAction **a, ObUserAction uact)
145 (*a)->data.interdiraction.inter.any.interactive = TRUE;
146 (*a)->data.interdiraction.direction = OB_DIRECTION_NORTHEAST;
147 (*a)->data.interdiraction.dialog = TRUE;
150 void setup_action_directional_focus_southeast(ObAction **a, ObUserAction uact)
152 (*a)->data.interdiraction.inter.any.interactive = TRUE;
153 (*a)->data.interdiraction.direction = OB_DIRECTION_SOUTHEAST;
154 (*a)->data.interdiraction.dialog = TRUE;
157 void setup_action_directional_focus_southwest(ObAction **a, ObUserAction uact)
159 (*a)->data.interdiraction.inter.any.interactive = TRUE;
160 (*a)->data.interdiraction.direction = OB_DIRECTION_SOUTHWEST;
161 (*a)->data.interdiraction.dialog = TRUE;
164 void setup_action_directional_focus_northwest(ObAction **a, ObUserAction uact)
166 (*a)->data.interdiraction.inter.any.interactive = TRUE;
167 (*a)->data.interdiraction.direction = OB_DIRECTION_NORTHWEST;
168 (*a)->data.interdiraction.dialog = TRUE;
171 void setup_action_send_to_desktop(ObAction **a, ObUserAction uact)
173 (*a)->data.sendto.any.client_action = OB_CLIENT_ACTION_ALWAYS;
174 (*a)->data.sendto.follow = TRUE;
177 void setup_action_send_to_desktop_prev(ObAction **a, ObUserAction uact)
179 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
180 (*a)->data.sendtodir.inter.any.interactive = TRUE;
181 (*a)->data.sendtodir.dir = OB_DIRECTION_WEST;
182 (*a)->data.sendtodir.linear = TRUE;
183 (*a)->data.sendtodir.wrap = TRUE;
184 (*a)->data.sendtodir.follow = TRUE;
187 void setup_action_send_to_desktop_next(ObAction **a, ObUserAction uact)
189 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
190 (*a)->data.sendtodir.inter.any.interactive = TRUE;
191 (*a)->data.sendtodir.dir = OB_DIRECTION_EAST;
192 (*a)->data.sendtodir.linear = TRUE;
193 (*a)->data.sendtodir.wrap = TRUE;
194 (*a)->data.sendtodir.follow = TRUE;
197 void setup_action_send_to_desktop_left(ObAction **a, ObUserAction uact)
199 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
200 (*a)->data.sendtodir.inter.any.interactive = TRUE;
201 (*a)->data.sendtodir.dir = OB_DIRECTION_WEST;
202 (*a)->data.sendtodir.linear = FALSE;
203 (*a)->data.sendtodir.wrap = TRUE;
204 (*a)->data.sendtodir.follow = TRUE;
207 void setup_action_send_to_desktop_right(ObAction **a, ObUserAction uact)
209 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
210 (*a)->data.sendtodir.inter.any.interactive = TRUE;
211 (*a)->data.sendtodir.dir = OB_DIRECTION_EAST;
212 (*a)->data.sendtodir.linear = FALSE;
213 (*a)->data.sendtodir.wrap = TRUE;
214 (*a)->data.sendtodir.follow = TRUE;
217 void setup_action_send_to_desktop_up(ObAction **a, ObUserAction uact)
219 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
220 (*a)->data.sendtodir.inter.any.interactive = TRUE;
221 (*a)->data.sendtodir.dir = OB_DIRECTION_NORTH;
222 (*a)->data.sendtodir.linear = FALSE;
223 (*a)->data.sendtodir.wrap = TRUE;
224 (*a)->data.sendtodir.follow = TRUE;
227 void setup_action_send_to_desktop_down(ObAction **a, ObUserAction uact)
229 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
230 (*a)->data.sendtodir.inter.any.interactive = TRUE;
231 (*a)->data.sendtodir.dir = OB_DIRECTION_SOUTH;
232 (*a)->data.sendtodir.linear = FALSE;
233 (*a)->data.sendtodir.wrap = TRUE;
234 (*a)->data.sendtodir.follow = TRUE;
237 void setup_action_desktop(ObAction **a, ObUserAction uact)
239 (*a)->data.desktop.inter.any.interactive = FALSE;
242 void setup_action_desktop_prev(ObAction **a, ObUserAction uact)
244 (*a)->data.desktopdir.inter.any.interactive = TRUE;
245 (*a)->data.desktopdir.dir = OB_DIRECTION_WEST;
246 (*a)->data.desktopdir.linear = TRUE;
247 (*a)->data.desktopdir.wrap = TRUE;
250 void setup_action_desktop_next(ObAction **a, ObUserAction uact)
252 (*a)->data.desktopdir.inter.any.interactive = TRUE;
253 (*a)->data.desktopdir.dir = OB_DIRECTION_EAST;
254 (*a)->data.desktopdir.linear = TRUE;
255 (*a)->data.desktopdir.wrap = TRUE;
258 void setup_action_desktop_left(ObAction **a, ObUserAction uact)
260 (*a)->data.desktopdir.inter.any.interactive = TRUE;
261 (*a)->data.desktopdir.dir = OB_DIRECTION_WEST;
262 (*a)->data.desktopdir.linear = FALSE;
263 (*a)->data.desktopdir.wrap = TRUE;
266 void setup_action_desktop_right(ObAction **a, ObUserAction uact)
268 (*a)->data.desktopdir.inter.any.interactive = TRUE;
269 (*a)->data.desktopdir.dir = OB_DIRECTION_EAST;
270 (*a)->data.desktopdir.linear = FALSE;
271 (*a)->data.desktopdir.wrap = TRUE;
274 void setup_action_desktop_up(ObAction **a, ObUserAction uact)
276 (*a)->data.desktopdir.inter.any.interactive = TRUE;
277 (*a)->data.desktopdir.dir = OB_DIRECTION_NORTH;
278 (*a)->data.desktopdir.linear = FALSE;
279 (*a)->data.desktopdir.wrap = TRUE;
282 void setup_action_desktop_down(ObAction **a, ObUserAction uact)
284 (*a)->data.desktopdir.inter.any.interactive = TRUE;
285 (*a)->data.desktopdir.dir = OB_DIRECTION_SOUTH;
286 (*a)->data.desktopdir.linear = FALSE;
287 (*a)->data.desktopdir.wrap = TRUE;
290 void setup_action_cycle_windows_next(ObAction **a, ObUserAction uact)
292 (*a)->data.cycle.inter.any.interactive = TRUE;
293 (*a)->data.cycle.linear = FALSE;
294 (*a)->data.cycle.forward = TRUE;
295 (*a)->data.cycle.dialog = TRUE;
298 void setup_action_cycle_windows_previous(ObAction **a, ObUserAction uact)
300 (*a)->data.cycle.inter.any.interactive = TRUE;
301 (*a)->data.cycle.linear = FALSE;
302 (*a)->data.cycle.forward = FALSE;
303 (*a)->data.cycle.dialog = TRUE;
306 void setup_action_movetoedge_north(ObAction **a, ObUserAction uact)
308 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
309 (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
312 void setup_action_movetoedge_south(ObAction **a, ObUserAction uact)
314 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
315 (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
318 void setup_action_movetoedge_east(ObAction **a, ObUserAction uact)
320 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
321 (*a)->data.diraction.direction = OB_DIRECTION_EAST;
324 void setup_action_movetoedge_west(ObAction **a, ObUserAction uact)
326 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
327 (*a)->data.diraction.direction = OB_DIRECTION_WEST;
330 void setup_action_growtoedge_north(ObAction **a, ObUserAction uact)
332 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
333 (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
336 void setup_action_growtoedge_south(ObAction **a, ObUserAction uact)
338 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
339 (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
342 void setup_action_growtoedge_east(ObAction **a, ObUserAction uact)
344 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
345 (*a)->data.diraction.direction = OB_DIRECTION_EAST;
348 void setup_action_growtoedge_west(ObAction **a, ObUserAction uact)
350 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
351 (*a)->data.diraction.direction = OB_DIRECTION_WEST;
354 void setup_action_top_layer(ObAction **a, ObUserAction uact)
356 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
357 (*a)->data.layer.layer = 1;
360 void setup_action_normal_layer(ObAction **a, ObUserAction uact)
362 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
363 (*a)->data.layer.layer = 0;
366 void setup_action_bottom_layer(ObAction **a, ObUserAction uact)
368 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
369 (*a)->data.layer.layer = -1;
372 void setup_action_move(ObAction **a, ObUserAction uact)
374 (*a)->data.moveresize.any.client_action = OB_CLIENT_ACTION_ALWAYS;
375 (*a)->data.moveresize.move = TRUE;
376 (*a)->data.moveresize.keyboard =
377 (uact == OB_USER_ACTION_NONE ||
378 uact == OB_USER_ACTION_KEYBOARD_KEY ||
379 uact == OB_USER_ACTION_MENU_SELECTION);
382 void setup_action_resize(ObAction **a, ObUserAction uact)
384 (*a)->data.moveresize.any.client_action = OB_CLIENT_ACTION_ALWAYS;
385 (*a)->data.moveresize.move = FALSE;
386 (*a)->data.moveresize.keyboard =
387 (uact == OB_USER_ACTION_NONE ||
388 uact == OB_USER_ACTION_KEYBOARD_KEY ||
389 uact == OB_USER_ACTION_MENU_SELECTION);
392 void setup_action_showmenu(ObAction **a, ObUserAction uact)
394 (*a)->data.showmenu.any.client_action = OB_CLIENT_ACTION_OPTIONAL;
395 /* you cannot call ShowMenu from inside a menu, cuz the menu code makes
396 assumptions that there is only one menu (and submenus) open at
398 if (uact == OB_USER_ACTION_MENU_SELECTION) {
404 void setup_client_action(ObAction **a, ObUserAction uact)
406 (*a)->data.any.client_action = OB_CLIENT_ACTION_ALWAYS;
409 ActionString actionstrings[] =
417 "directionalfocusnorth",
418 action_directional_focus,
419 setup_action_directional_focus_north
422 "directionalfocuseast",
423 action_directional_focus,
424 setup_action_directional_focus_east
427 "directionalfocussouth",
428 action_directional_focus,
429 setup_action_directional_focus_south
432 "directionalfocuswest",
433 action_directional_focus,
434 setup_action_directional_focus_west
437 "directionalfocusnortheast",
438 action_directional_focus,
439 setup_action_directional_focus_northeast
442 "directionalfocussoutheast",
443 action_directional_focus,
444 setup_action_directional_focus_southeast
447 "directionalfocussouthwest",
448 action_directional_focus,
449 setup_action_directional_focus_southwest
452 "directionalfocusnorthwest",
453 action_directional_focus,
454 setup_action_directional_focus_northwest
478 action_focus_order_to_bottom,
533 action_toggle_omnipresent,
538 action_move_relative_horz,
543 action_move_relative_vert,
548 action_move_to_center,
552 "resizerelativehorz",
553 action_resize_relative_horz,
557 "resizerelativevert",
558 action_resize_relative_vert,
563 action_move_relative,
568 action_resize_relative,
573 action_maximize_full,
578 action_unmaximize_full,
582 "togglemaximizefull",
583 action_toggle_maximize_full,
588 action_maximize_horz,
593 action_unmaximize_horz,
597 "togglemaximizehorz",
598 action_toggle_maximize_horz,
603 action_maximize_vert,
608 action_unmaximize_vert,
612 "togglemaximizevert",
613 action_toggle_maximize_vert,
618 action_toggle_fullscreen,
623 action_send_to_desktop,
624 setup_action_send_to_desktop
628 action_send_to_desktop_dir,
629 setup_action_send_to_desktop_next
632 "sendtodesktopprevious",
633 action_send_to_desktop_dir,
634 setup_action_send_to_desktop_prev
637 "sendtodesktopright",
638 action_send_to_desktop_dir,
639 setup_action_send_to_desktop_right
643 action_send_to_desktop_dir,
644 setup_action_send_to_desktop_left
648 action_send_to_desktop_dir,
649 setup_action_send_to_desktop_up
653 action_send_to_desktop_dir,
654 setup_action_send_to_desktop_down
664 setup_action_desktop_next
669 setup_action_desktop_prev
674 setup_action_desktop_right
679 setup_action_desktop_left
684 setup_action_desktop_up
689 setup_action_desktop_down
693 action_toggle_decorations,
707 "toggledockautohide",
708 action_toggle_dockautohide,
713 action_toggle_show_desktop,
723 action_unshow_desktop,
749 setup_action_showmenu
753 action_send_to_layer,
754 setup_action_top_layer
759 setup_action_top_layer
763 action_send_to_layer,
764 setup_action_normal_layer
768 action_send_to_layer,
769 setup_action_bottom_layer
772 "togglealwaysonbottom",
774 setup_action_bottom_layer
778 action_cycle_windows,
779 setup_action_cycle_windows_next
783 action_cycle_windows,
784 setup_action_cycle_windows_previous
789 setup_action_movetoedge_north
794 setup_action_movetoedge_south
799 setup_action_movetoedge_west
804 setup_action_movetoedge_east
809 setup_action_growtoedge_north
814 setup_action_growtoedge_south
819 setup_action_growtoedge_west
824 setup_action_growtoedge_east
833 /* only key bindings can be interactive. thus saith the xor.
834 because of how the mouse is grabbed, mouse events dont even get
835 read during interactive events, so no dice! >:) */
836 #define INTERACTIVE_LIMIT(a, uact) \
837 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
838 a->data.any.interactive = FALSE;
840 ObAction *action_from_string(const gchar *name, ObUserAction uact)
843 gboolean exist = FALSE;
846 for (i = 0; actionstrings[i].name; i++)
847 if (!g_ascii_strcasecmp(name, actionstrings[i].name)) {
849 a = action_new(actionstrings[i].func);
850 if (actionstrings[i].setup)
851 actionstrings[i].setup(&a, uact);
853 INTERACTIVE_LIMIT(a, uact);
857 g_warning("Invalid action '%s' requested. No such action exists.",
860 g_warning("Invalid use of action '%s'. Action will be ignored.", name);
864 ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
868 ObAction *act = NULL;
871 if (parse_attr_string("name", node, &actname)) {
872 if ((act = action_from_string(actname, uact))) {
873 if (act->func == action_execute || act->func == action_restart) {
874 if ((n = parse_find_node("execute", node->xmlChildrenNode))) {
875 gchar *s = parse_string(doc, n);
876 act->data.execute.path = parse_expand_tilde(s);
879 } else if (act->func == action_showmenu) {
880 if ((n = parse_find_node("menu", node->xmlChildrenNode)))
881 act->data.showmenu.name = parse_string(doc, n);
882 } else if (act->func == action_move_relative_horz ||
883 act->func == action_move_relative_vert ||
884 act->func == action_resize_relative_horz ||
885 act->func == action_resize_relative_vert) {
886 if ((n = parse_find_node("delta", node->xmlChildrenNode)))
887 act->data.relative.deltax = parse_int(doc, n);
888 } else if (act->func == action_move_relative) {
889 if ((n = parse_find_node("x", node->xmlChildrenNode)))
890 act->data.relative.deltax = parse_int(doc, n);
891 if ((n = parse_find_node("y", node->xmlChildrenNode)))
892 act->data.relative.deltay = parse_int(doc, n);
893 } else if (act->func == action_resize_relative) {
894 if ((n = parse_find_node("left", node->xmlChildrenNode)))
895 act->data.relative.deltaxl = parse_int(doc, n);
896 if ((n = parse_find_node("up", node->xmlChildrenNode)))
897 act->data.relative.deltayu = parse_int(doc, n);
898 if ((n = parse_find_node("right", node->xmlChildrenNode)))
899 act->data.relative.deltax = parse_int(doc, n);
900 if ((n = parse_find_node("down", node->xmlChildrenNode)))
901 act->data.relative.deltay = parse_int(doc, n);
902 } else if (act->func == action_desktop) {
903 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
904 act->data.desktop.desk = parse_int(doc, n);
905 if (act->data.desktop.desk > 0) act->data.desktop.desk--;
906 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
907 act->data.desktop.inter.any.interactive =
909 } else if (act->func == action_send_to_desktop) {
910 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
911 act->data.sendto.desk = parse_int(doc, n);
912 if (act->data.sendto.desk > 0) act->data.sendto.desk--;
913 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
914 act->data.sendto.follow = parse_bool(doc, n);
915 } else if (act->func == action_desktop_dir) {
916 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
917 act->data.desktopdir.wrap = parse_bool(doc, n);
918 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
919 act->data.desktopdir.inter.any.interactive =
921 } else if (act->func == action_send_to_desktop_dir) {
922 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
923 act->data.sendtodir.wrap = parse_bool(doc, n);
924 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
925 act->data.sendtodir.follow = parse_bool(doc, n);
926 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
927 act->data.sendtodir.inter.any.interactive =
929 } else if (act->func == action_activate) {
930 if ((n = parse_find_node("here", node->xmlChildrenNode)))
931 act->data.activate.here = parse_bool(doc, n);
932 } else if (act->func == action_cycle_windows) {
933 if ((n = parse_find_node("linear", node->xmlChildrenNode)))
934 act->data.cycle.linear = parse_bool(doc, n);
935 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
936 act->data.cycle.dialog = parse_bool(doc, n);
937 } else if (act->func == action_directional_focus) {
938 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
939 act->data.cycle.dialog = parse_bool(doc, n);
940 } else if (act->func == action_raise ||
941 act->func == action_lower ||
942 act->func == action_raiselower ||
943 act->func == action_shadelower ||
944 act->func == action_unshaderaise) {
945 if ((n = parse_find_node("group", node->xmlChildrenNode)))
946 act->data.stacking.group = parse_bool(doc, n);
948 INTERACTIVE_LIMIT(act, uact);
955 void action_run_list(GSList *acts, ObClient *c, ObFrameContext context,
956 guint state, guint button, gint x, gint y,
957 gboolean cancel, gboolean done)
961 gboolean inter = FALSE;
967 screen_pointer_pos(&x, &y);
969 if (grab_on_keyboard())
972 for (it = acts; it; it = g_slist_next(it)) {
974 if (a->data.any.interactive) {
981 /* sometimes when we execute another app as an action,
982 it won't work right unless we XUngrabKeyboard first,
983 even though we grabbed the key/button Asychronously.
984 e.g. "gnome-panel-control --main-menu" */
985 XUngrabKeyboard(ob_display, event_lasttime);
988 for (it = acts; it; it = g_slist_next(it)) {
991 if (!(a->data.any.client_action == OB_CLIENT_ACTION_ALWAYS && !c)) {
992 a->data.any.c = a->data.any.client_action ? c : NULL;
993 a->data.any.context = context;
997 a->data.any.button = button;
999 if (a->data.any.interactive) {
1000 a->data.inter.cancel = cancel;
1001 a->data.inter.final = done;
1002 if (!(cancel || done))
1003 if (!keyboard_interactive_grab(state, a->data.any.c, a))
1007 /* XXX UGLY HACK race with motion event starting a move and the
1008 button release gettnig processed first. answer: don't queue
1009 moveresize starts. UGLY HACK XXX */
1010 if (a->data.any.interactive || a->func == action_moveresize) {
1011 /* interactive actions are not queued */
1014 ob_main_loop_queue_action(ob_main_loop, a);
1019 void action_run_string(const gchar *name, struct _ObClient *c)
1024 a = action_from_string(name, OB_USER_ACTION_NONE);
1027 l = g_slist_append(NULL, a);
1029 action_run(l, c, 0);
1032 void action_execute(union ActionData *data)
1035 gchar *cmd, **argv = 0;
1036 if (data->execute.path) {
1037 cmd = g_filename_from_utf8(data->execute.path, -1, NULL, NULL, NULL);
1039 if (!g_shell_parse_argv (cmd, NULL, &argv, &e)) {
1040 g_warning("failed to execute '%s': %s",
1044 if (!g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH |
1045 G_SPAWN_DO_NOT_REAP_CHILD,
1046 NULL, NULL, NULL, &e)) {
1047 g_warning("failed to execute '%s': %s",
1055 g_warning("failed to convert '%s' from utf8", data->execute.path);
1060 void action_activate(union ActionData *data)
1062 client_activate(data->activate.any.c, data->activate.here);
1065 void action_focus(union ActionData *data)
1067 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1069 event_halt_focus_delay();
1071 client_focus(data->client.any.c);
1074 void action_unfocus (union ActionData *data)
1076 if (data->client.any.c == focus_client);
1077 focus_fallback(OB_FOCUS_FALLBACK_UNFOCUSING);
1080 void action_iconify(union ActionData *data)
1082 client_action_start(data);
1083 client_iconify(data->client.any.c, TRUE, TRUE);
1084 client_action_end(data);
1087 void action_focus_order_to_bottom(union ActionData *data)
1089 focus_order_to_bottom(data->client.any.c);
1092 void action_raiselower(union ActionData *data)
1094 ObClient *c = data->client.any.c;
1096 gboolean raise = FALSE;
1098 for (it = stacking_list; it; it = g_list_next(it)) {
1099 if (WINDOW_IS_CLIENT(it->data)) {
1100 ObClient *cit = it->data;
1102 if (cit == c) break;
1103 if (client_normal(cit) == client_normal(c) &&
1104 cit->layer == c->layer &&
1105 cit->frame->visible &&
1106 !client_search_transient(c, cit))
1108 if (RECT_INTERSECTS_RECT(cit->frame->area, c->frame->area)) {
1122 void action_raise(union ActionData *data)
1124 client_action_start(data);
1125 stacking_raise(CLIENT_AS_WINDOW(data->client.any.c), data->stacking.group);
1126 client_action_end(data);
1129 void action_unshaderaise(union ActionData *data)
1131 if (data->client.any.c->shaded)
1132 action_unshade(data);
1137 void action_shadelower(union ActionData *data)
1139 if (data->client.any.c->shaded)
1145 void action_lower(union ActionData *data)
1147 client_action_start(data);
1148 stacking_lower(CLIENT_AS_WINDOW(data->client.any.c), data->stacking.group);
1149 client_action_end(data);
1152 void action_close(union ActionData *data)
1154 client_close(data->client.any.c);
1157 void action_kill(union ActionData *data)
1159 client_kill(data->client.any.c);
1162 void action_shade(union ActionData *data)
1164 client_action_start(data);
1165 client_shade(data->client.any.c, TRUE);
1166 client_action_end(data);
1169 void action_unshade(union ActionData *data)
1171 client_action_start(data);
1172 client_shade(data->client.any.c, FALSE);
1173 client_action_end(data);
1176 void action_toggle_shade(union ActionData *data)
1178 client_action_start(data);
1179 client_shade(data->client.any.c, !data->client.any.c->shaded);
1180 client_action_end(data);
1183 void action_toggle_omnipresent(union ActionData *data)
1185 client_set_desktop(data->client.any.c,
1186 data->client.any.c->desktop == DESKTOP_ALL ?
1187 screen_desktop : DESKTOP_ALL, FALSE);
1190 void action_move_relative_horz(union ActionData *data)
1192 ObClient *c = data->relative.any.c;
1193 client_action_start(data);
1194 client_move(c, c->area.x + data->relative.deltax, c->area.y);
1195 client_action_end(data);
1198 void action_move_relative_vert(union ActionData *data)
1200 ObClient *c = data->relative.any.c;
1201 client_action_start(data);
1202 client_move(c, c->area.x, c->area.y + data->relative.deltax);
1203 client_action_end(data);
1206 void action_move_to_center(union ActionData *data)
1208 ObClient *c = data->client.any.c;
1210 area = screen_area_monitor(c->desktop, 0);
1211 client_action_start(data);
1212 client_move(c, area->width / 2 - c->area.width / 2,
1213 area->height / 2 - c->area.height / 2);
1214 client_action_end(data);
1217 void action_resize_relative_horz(union ActionData *data)
1219 ObClient *c = data->relative.any.c;
1220 client_action_start(data);
1222 c->area.width + data->relative.deltax * c->size_inc.width,
1224 client_action_end(data);
1227 void action_resize_relative_vert(union ActionData *data)
1229 ObClient *c = data->relative.any.c;
1231 client_action_start(data);
1232 client_resize(c, c->area.width, c->area.height +
1233 data->relative.deltax * c->size_inc.height);
1234 client_action_end(data);
1238 void action_move_relative(union ActionData *data)
1240 ObClient *c = data->relative.any.c;
1241 client_action_start(data);
1242 client_move(c, c->area.x + data->relative.deltax, c->area.y +
1243 data->relative.deltay);
1244 client_action_end(data);
1247 void action_resize_relative(union ActionData *data)
1249 ObClient *c = data->relative.any.c;
1250 client_action_start(data);
1251 client_move_resize(c,
1252 c->area.x - data->relative.deltaxl * c->size_inc.width,
1253 c->area.y - data->relative.deltayu * c->size_inc.height,
1254 c->area.width + data->relative.deltax * c->size_inc.width
1255 + data->relative.deltaxl * c->size_inc.width,
1256 c->area.height + data->relative.deltay * c->size_inc.height
1257 + data->relative.deltayu * c->size_inc.height);
1258 client_action_end(data);
1261 void action_maximize_full(union ActionData *data)
1263 client_action_start(data);
1264 client_maximize(data->client.any.c, TRUE, 0, TRUE);
1265 client_action_end(data);
1268 void action_unmaximize_full(union ActionData *data)
1270 client_action_start(data);
1271 client_maximize(data->client.any.c, FALSE, 0, TRUE);
1272 client_action_end(data);
1275 void action_toggle_maximize_full(union ActionData *data)
1277 client_action_start(data);
1278 client_maximize(data->client.any.c,
1279 !(data->client.any.c->max_horz ||
1280 data->client.any.c->max_vert),
1282 client_action_end(data);
1285 void action_maximize_horz(union ActionData *data)
1287 client_action_start(data);
1288 client_maximize(data->client.any.c, TRUE, 1, TRUE);
1289 client_action_end(data);
1292 void action_unmaximize_horz(union ActionData *data)
1294 client_action_start(data);
1295 client_maximize(data->client.any.c, FALSE, 1, TRUE);
1296 client_action_end(data);
1299 void action_toggle_maximize_horz(union ActionData *data)
1301 client_action_start(data);
1302 client_maximize(data->client.any.c,
1303 !data->client.any.c->max_horz, 1, TRUE);
1304 client_action_end(data);
1307 void action_maximize_vert(union ActionData *data)
1309 client_action_start(data);
1310 client_maximize(data->client.any.c, TRUE, 2, TRUE);
1311 client_action_end(data);
1314 void action_unmaximize_vert(union ActionData *data)
1316 client_action_start(data);
1317 client_maximize(data->client.any.c, FALSE, 2, TRUE);
1318 client_action_end(data);
1321 void action_toggle_maximize_vert(union ActionData *data)
1323 client_action_start(data);
1324 client_maximize(data->client.any.c,
1325 !data->client.any.c->max_vert, 2, TRUE);
1326 client_action_end(data);
1329 void action_toggle_fullscreen(union ActionData *data)
1331 client_action_start(data);
1332 client_fullscreen(data->client.any.c,
1333 !(data->client.any.c->fullscreen), TRUE);
1334 client_action_end(data);
1337 void action_send_to_desktop(union ActionData *data)
1339 ObClient *c = data->sendto.any.c;
1341 if (!client_normal(c)) return;
1343 if (data->sendto.desk < screen_num_desktops ||
1344 data->sendto.desk == DESKTOP_ALL) {
1345 client_set_desktop(c, data->sendto.desk, data->sendto.follow);
1346 if (data->sendto.follow)
1347 screen_set_desktop(data->sendto.desk);
1351 void action_desktop(union ActionData *data)
1353 static guint first = (unsigned) -1;
1355 if (data->inter.any.interactive && first == (unsigned) -1)
1356 first = screen_desktop;
1358 if (!data->inter.any.interactive ||
1359 (!data->inter.cancel && !data->inter.final))
1361 if (data->desktop.desk < screen_num_desktops ||
1362 data->desktop.desk == DESKTOP_ALL)
1364 screen_set_desktop(data->desktop.desk);
1365 if (data->inter.any.interactive)
1366 screen_desktop_popup(data->desktop.desk, TRUE);
1368 } else if (data->inter.cancel) {
1369 screen_set_desktop(first);
1372 if (!data->inter.any.interactive || data->inter.final) {
1373 screen_desktop_popup(0, FALSE);
1374 first = (unsigned) -1;
1378 void action_desktop_dir(union ActionData *data)
1382 d = screen_cycle_desktop(data->desktopdir.dir,
1383 data->desktopdir.wrap,
1384 data->desktopdir.linear,
1385 data->desktopdir.inter.any.interactive,
1386 data->desktopdir.inter.final,
1387 data->desktopdir.inter.cancel);
1388 if (!data->sendtodir.inter.any.interactive ||
1389 !data->sendtodir.inter.final ||
1390 data->sendtodir.inter.cancel)
1392 screen_set_desktop(d);
1396 void action_send_to_desktop_dir(union ActionData *data)
1398 ObClient *c = data->sendtodir.inter.any.c;
1401 if (!client_normal(c)) return;
1403 d = screen_cycle_desktop(data->sendtodir.dir, data->sendtodir.wrap,
1404 data->sendtodir.linear,
1405 data->sendtodir.inter.any.interactive,
1406 data->sendtodir.inter.final,
1407 data->sendtodir.inter.cancel);
1408 if (!data->sendtodir.inter.any.interactive ||
1409 !data->sendtodir.inter.final ||
1410 data->sendtodir.inter.cancel)
1412 client_set_desktop(c, d, data->sendtodir.follow);
1413 if (data->sendtodir.follow)
1414 screen_set_desktop(d);
1418 void action_desktop_last(union ActionData *data)
1420 screen_set_desktop(screen_last_desktop);
1423 void action_toggle_decorations(union ActionData *data)
1425 ObClient *c = data->client.any.c;
1427 client_action_start(data);
1428 client_set_undecorated(c, !c->undecorated);
1429 client_action_end(data);
1432 static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch)
1434 if (config_resize_four_corners) {
1435 if (x - cx > cw / 2) {
1436 if (y - cy > ch / 2)
1437 return prop_atoms.net_wm_moveresize_size_bottomright;
1439 return prop_atoms.net_wm_moveresize_size_topright;
1441 if (y - cy > ch / 2)
1442 return prop_atoms.net_wm_moveresize_size_bottomleft;
1444 return prop_atoms.net_wm_moveresize_size_topleft;
1447 if (x - cx > cw * 2 / 3) {
1448 if (y - cy > ch * 2 / 3)
1449 return prop_atoms.net_wm_moveresize_size_bottomright;
1450 else if (y - cy < ch / 3)
1451 return prop_atoms.net_wm_moveresize_size_topright;
1453 return prop_atoms.net_wm_moveresize_size_right;
1454 } else if (x - cx < cw / 3) {
1455 if (y - cy > ch * 2 / 3)
1456 return prop_atoms.net_wm_moveresize_size_bottomleft;
1457 else if (y - cy < ch / 3)
1458 return prop_atoms.net_wm_moveresize_size_topleft;
1460 return prop_atoms.net_wm_moveresize_size_left;
1462 if (y - cy > ch * 2 / 3)
1463 return prop_atoms.net_wm_moveresize_size_bottom;
1464 else if (y - cy < ch / 3)
1465 return prop_atoms.net_wm_moveresize_size_top;
1467 return prop_atoms.net_wm_moveresize_move;
1471 void action_moveresize(union ActionData *data)
1473 ObClient *c = data->moveresize.any.c;
1476 if (!client_normal(c)) return;
1478 if (data->moveresize.keyboard) {
1479 corner = (data->moveresize.move ?
1480 prop_atoms.net_wm_moveresize_move_keyboard :
1481 prop_atoms.net_wm_moveresize_size_keyboard);
1483 corner = (data->moveresize.move ?
1484 prop_atoms.net_wm_moveresize_move :
1485 pick_corner(data->any.x, data->any.y,
1486 c->frame->area.x, c->frame->area.y,
1487 /* use the client size because the frame
1488 can be differently sized (shaded
1489 windows) and we want this based on the
1491 c->area.width + c->frame->size.left +
1492 c->frame->size.right,
1493 c->area.height + c->frame->size.top +
1494 c->frame->size.bottom));
1497 moveresize_start(c, data->any.x, data->any.y, data->any.button, corner);
1500 void action_reconfigure(union ActionData *data)
1505 void action_restart(union ActionData *data)
1507 ob_restart_other(data->execute.path);
1510 void action_exit(union ActionData *data)
1515 void action_showmenu(union ActionData *data)
1517 if (data->showmenu.name) {
1518 menu_show(data->showmenu.name, data->any.x, data->any.y,
1519 data->showmenu.any.c);
1523 void action_cycle_windows(union ActionData *data)
1525 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1527 event_halt_focus_delay();
1529 focus_cycle(data->cycle.forward, data->cycle.linear, data->any.interactive,
1531 data->cycle.inter.final, data->cycle.inter.cancel);
1534 void action_directional_focus(union ActionData *data)
1536 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1538 event_halt_focus_delay();
1540 focus_directional_cycle(data->interdiraction.direction,
1541 data->any.interactive,
1542 data->interdiraction.dialog,
1543 data->interdiraction.inter.final,
1544 data->interdiraction.inter.cancel);
1547 void action_movetoedge(union ActionData *data)
1550 ObClient *c = data->diraction.any.c;
1552 x = c->frame->area.x;
1553 y = c->frame->area.y;
1555 switch(data->diraction.direction) {
1556 case OB_DIRECTION_NORTH:
1557 y = client_directional_edge_search(c, OB_DIRECTION_NORTH);
1559 case OB_DIRECTION_WEST:
1560 x = client_directional_edge_search(c, OB_DIRECTION_WEST);
1562 case OB_DIRECTION_SOUTH:
1563 y = client_directional_edge_search(c, OB_DIRECTION_SOUTH) -
1564 c->frame->area.height;
1566 case OB_DIRECTION_EAST:
1567 x = client_directional_edge_search(c, OB_DIRECTION_EAST) -
1568 c->frame->area.width;
1571 g_assert_not_reached();
1573 frame_frame_gravity(c->frame, &x, &y);
1574 client_action_start(data);
1575 client_move(c, x, y);
1576 client_action_end(data);
1579 void action_growtoedge(union ActionData *data)
1581 gint x, y, width, height, dest;
1582 ObClient *c = data->diraction.any.c;
1585 //FIXME growtoedge resizes shaded windows to 0 height
1589 a = screen_area(c->desktop);
1590 x = c->frame->area.x;
1591 y = c->frame->area.y;
1592 width = c->frame->area.width;
1593 height = c->frame->area.height;
1595 switch(data->diraction.direction) {
1596 case OB_DIRECTION_NORTH:
1597 dest = client_directional_edge_search(c, OB_DIRECTION_NORTH);
1599 height = c->frame->area.height / 2;
1601 height = c->frame->area.y + c->frame->area.height - dest;
1605 case OB_DIRECTION_WEST:
1606 dest = client_directional_edge_search(c, OB_DIRECTION_WEST);
1608 width = c->frame->area.width / 2;
1610 width = c->frame->area.x + c->frame->area.width - dest;
1614 case OB_DIRECTION_SOUTH:
1615 dest = client_directional_edge_search(c, OB_DIRECTION_SOUTH);
1616 if (a->y + a->height == y + c->frame->area.height) {
1617 height = c->frame->area.height / 2;
1618 y = a->y + a->height - height;
1620 height = dest - c->frame->area.y;
1621 y += (height - c->frame->area.height) % c->size_inc.height;
1622 height -= (height - c->frame->area.height) % c->size_inc.height;
1624 case OB_DIRECTION_EAST:
1625 dest = client_directional_edge_search(c, OB_DIRECTION_EAST);
1626 if (a->x + a->width == x + c->frame->area.width) {
1627 width = c->frame->area.width / 2;
1628 x = a->x + a->width - width;
1630 width = dest - c->frame->area.x;
1631 x += (width - c->frame->area.width) % c->size_inc.width;
1632 width -= (width - c->frame->area.width) % c->size_inc.width;
1635 g_assert_not_reached();
1637 frame_frame_gravity(c->frame, &x, &y);
1638 width -= c->frame->size.left + c->frame->size.right;
1639 height -= c->frame->size.top + c->frame->size.bottom;
1640 client_action_start(data);
1641 client_move_resize(c, x, y, width, height);
1642 client_action_end(data);
1645 void action_send_to_layer(union ActionData *data)
1647 client_set_layer(data->layer.any.c, data->layer.layer);
1650 void action_toggle_layer(union ActionData *data)
1652 ObClient *c = data->layer.any.c;
1654 client_action_start(data);
1655 if (data->layer.layer < 0)
1656 client_set_layer(c, c->below ? 0 : -1);
1657 else if (data->layer.layer > 0)
1658 client_set_layer(c, c->above ? 0 : 1);
1659 client_action_end(data);
1662 void action_toggle_dockautohide(union ActionData *data)
1664 config_dock_hide = !config_dock_hide;
1668 void action_toggle_show_desktop(union ActionData *data)
1670 screen_show_desktop(!screen_showing_desktop);
1673 void action_show_desktop(union ActionData *data)
1675 screen_show_desktop(TRUE);
1678 void action_unshow_desktop(union ActionData *data)
1680 screen_show_desktop(FALSE);