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"
37 inline void client_action_start(union ActionData
*data
)
39 if (config_focus_follow
)
40 if (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&& !data
->any
.button
)
41 grab_pointer(TRUE
, OB_CURSOR_NONE
);
44 inline void client_action_end(union ActionData
*data
)
46 if (config_focus_follow
)
47 if (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
) {
48 if (!data
->any
.button
) {
49 grab_pointer(FALSE
, OB_CURSOR_NONE
);
53 /* usually this is sorta redundant, but with a press action
54 the enter event will come as a GrabNotify which is
55 ignored, so this will handle that case */
56 if ((c
= client_under_pointer()))
57 event_enter_client(c
);
65 void (*func
)(union ActionData
*);
66 void (*setup
)(ObAction
**, ObUserAction uact
);
69 static ObAction
*action_new(void (*func
)(union ActionData
*data
))
71 ObAction
*a
= g_new0(ObAction
, 1);
78 void action_ref(ObAction
*a
)
83 void action_unref(ObAction
*a
)
85 if (a
== NULL
) return;
87 if (--a
->ref
> 0) return;
89 /* deal with pointers */
90 if (a
->func
== action_execute
|| a
->func
== action_restart
)
91 g_free(a
->data
.execute
.path
);
92 else if (a
->func
== action_showmenu
)
93 g_free(a
->data
.showmenu
.name
);
98 ObAction
* action_copy(const ObAction
*src
)
100 ObAction
*a
= action_new(src
->func
);
104 /* deal with pointers */
105 if (a
->func
== action_execute
|| a
->func
== action_restart
)
106 a
->data
.execute
.path
= g_strdup(a
->data
.execute
.path
);
107 else if (a
->func
== action_showmenu
)
108 a
->data
.showmenu
.name
= g_strdup(a
->data
.showmenu
.name
);
113 void setup_action_directional_focus_north(ObAction
**a
, ObUserAction uact
)
115 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
116 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTH
;
119 void setup_action_directional_focus_east(ObAction
**a
, ObUserAction uact
)
121 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
122 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_EAST
;
125 void setup_action_directional_focus_south(ObAction
**a
, ObUserAction uact
)
127 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
128 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTH
;
131 void setup_action_directional_focus_west(ObAction
**a
, ObUserAction uact
)
133 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
134 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_WEST
;
137 void setup_action_directional_focus_northeast(ObAction
**a
, ObUserAction uact
)
139 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
140 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHEAST
;
143 void setup_action_directional_focus_southeast(ObAction
**a
, ObUserAction uact
)
145 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
146 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHEAST
;
149 void setup_action_directional_focus_southwest(ObAction
**a
, ObUserAction uact
)
151 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
152 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHWEST
;
155 void setup_action_directional_focus_northwest(ObAction
**a
, ObUserAction uact
)
157 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
158 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHWEST
;
161 void setup_action_send_to_desktop(ObAction
**a
, ObUserAction uact
)
163 (*a
)->data
.sendto
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
164 (*a
)->data
.sendto
.follow
= TRUE
;
167 void setup_action_send_to_desktop_prev(ObAction
**a
, ObUserAction uact
)
169 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
170 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
171 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
172 (*a
)->data
.sendtodir
.linear
= TRUE
;
173 (*a
)->data
.sendtodir
.wrap
= TRUE
;
174 (*a
)->data
.sendtodir
.follow
= TRUE
;
177 void setup_action_send_to_desktop_next(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_EAST
;
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_left(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_WEST
;
192 (*a
)->data
.sendtodir
.linear
= FALSE
;
193 (*a
)->data
.sendtodir
.wrap
= TRUE
;
194 (*a
)->data
.sendtodir
.follow
= TRUE
;
197 void setup_action_send_to_desktop_right(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_EAST
;
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_up(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_NORTH
;
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_down(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_SOUTH
;
222 (*a
)->data
.sendtodir
.linear
= FALSE
;
223 (*a
)->data
.sendtodir
.wrap
= TRUE
;
224 (*a
)->data
.sendtodir
.follow
= TRUE
;
227 void setup_action_desktop(ObAction
**a
, ObUserAction uact
)
229 (*a
)->data
.desktop
.inter
.any
.interactive
= TRUE
;
232 void setup_action_desktop_prev(ObAction
**a
, ObUserAction uact
)
234 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
235 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
236 (*a
)->data
.desktopdir
.linear
= TRUE
;
237 (*a
)->data
.desktopdir
.wrap
= TRUE
;
240 void setup_action_desktop_next(ObAction
**a
, ObUserAction uact
)
242 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
243 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
244 (*a
)->data
.desktopdir
.linear
= TRUE
;
245 (*a
)->data
.desktopdir
.wrap
= TRUE
;
248 void setup_action_desktop_left(ObAction
**a
, ObUserAction uact
)
250 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
251 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
252 (*a
)->data
.desktopdir
.linear
= FALSE
;
253 (*a
)->data
.desktopdir
.wrap
= TRUE
;
256 void setup_action_desktop_right(ObAction
**a
, ObUserAction uact
)
258 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
259 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
260 (*a
)->data
.desktopdir
.linear
= FALSE
;
261 (*a
)->data
.desktopdir
.wrap
= TRUE
;
264 void setup_action_desktop_up(ObAction
**a
, ObUserAction uact
)
266 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
267 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_NORTH
;
268 (*a
)->data
.desktopdir
.linear
= FALSE
;
269 (*a
)->data
.desktopdir
.wrap
= TRUE
;
272 void setup_action_desktop_down(ObAction
**a
, ObUserAction uact
)
274 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
275 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_SOUTH
;
276 (*a
)->data
.desktopdir
.linear
= FALSE
;
277 (*a
)->data
.desktopdir
.wrap
= TRUE
;
280 void setup_action_cycle_windows_next(ObAction
**a
, ObUserAction uact
)
282 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
283 (*a
)->data
.cycle
.linear
= FALSE
;
284 (*a
)->data
.cycle
.forward
= TRUE
;
287 void setup_action_cycle_windows_previous(ObAction
**a
, ObUserAction uact
)
289 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
290 (*a
)->data
.cycle
.linear
= FALSE
;
291 (*a
)->data
.cycle
.forward
= FALSE
;
294 void setup_action_movetoedge_north(ObAction
**a
, ObUserAction uact
)
296 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
297 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
300 void setup_action_movetoedge_south(ObAction
**a
, ObUserAction uact
)
302 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
303 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
306 void setup_action_movetoedge_east(ObAction
**a
, ObUserAction uact
)
308 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
309 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
312 void setup_action_movetoedge_west(ObAction
**a
, ObUserAction uact
)
314 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
315 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
318 void setup_action_growtoedge_north(ObAction
**a
, ObUserAction uact
)
320 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
321 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
324 void setup_action_growtoedge_south(ObAction
**a
, ObUserAction uact
)
326 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
327 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
330 void setup_action_growtoedge_east(ObAction
**a
, ObUserAction uact
)
332 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
333 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
336 void setup_action_growtoedge_west(ObAction
**a
, ObUserAction uact
)
338 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
339 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
342 void setup_action_top_layer(ObAction
**a
, ObUserAction uact
)
344 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
345 (*a
)->data
.layer
.layer
= 1;
348 void setup_action_normal_layer(ObAction
**a
, ObUserAction uact
)
350 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
351 (*a
)->data
.layer
.layer
= 0;
354 void setup_action_bottom_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_move(ObAction
**a
, ObUserAction uact
)
362 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
363 (*a
)->data
.moveresize
.move
= TRUE
;
364 (*a
)->data
.moveresize
.keyboard
=
365 (uact
== OB_USER_ACTION_NONE
||
366 uact
== OB_USER_ACTION_KEYBOARD_KEY
||
367 uact
== OB_USER_ACTION_MENU_SELECTION
);
370 void setup_action_resize(ObAction
**a
, ObUserAction uact
)
372 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
373 (*a
)->data
.moveresize
.move
= FALSE
;
374 (*a
)->data
.moveresize
.keyboard
=
375 (uact
== OB_USER_ACTION_NONE
||
376 uact
== OB_USER_ACTION_KEYBOARD_KEY
||
377 uact
== OB_USER_ACTION_MENU_SELECTION
);
380 void setup_action_showmenu(ObAction
**a
, ObUserAction uact
)
382 (*a
)->data
.showmenu
.any
.client_action
= OB_CLIENT_ACTION_OPTIONAL
;
383 /* you cannot call ShowMenu from inside a menu, cuz the menu code makes
384 assumptions that there is only one menu (and submenus) open at
386 if (uact
== OB_USER_ACTION_MENU_SELECTION
) {
392 void setup_client_action(ObAction
**a
, ObUserAction uact
)
394 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
397 ActionString actionstrings
[] =
405 "directionalfocusnorth",
406 action_directional_focus
,
407 setup_action_directional_focus_north
410 "directionalfocuseast",
411 action_directional_focus
,
412 setup_action_directional_focus_east
415 "directionalfocussouth",
416 action_directional_focus
,
417 setup_action_directional_focus_south
420 "directionalfocuswest",
421 action_directional_focus
,
422 setup_action_directional_focus_west
425 "directionalfocusnortheast",
426 action_directional_focus
,
427 setup_action_directional_focus_northeast
430 "directionalfocussoutheast",
431 action_directional_focus
,
432 setup_action_directional_focus_southeast
435 "directionalfocussouthwest",
436 action_directional_focus
,
437 setup_action_directional_focus_southwest
440 "directionalfocusnorthwest",
441 action_directional_focus
,
442 setup_action_directional_focus_northwest
516 action_toggle_omnipresent
,
521 action_move_relative_horz
,
526 action_move_relative_vert
,
530 "resizerelativehorz",
531 action_resize_relative_horz
,
535 "resizerelativevert",
536 action_resize_relative_vert
,
541 action_maximize_full
,
546 action_unmaximize_full
,
550 "togglemaximizefull",
551 action_toggle_maximize_full
,
556 action_maximize_horz
,
561 action_unmaximize_horz
,
565 "togglemaximizehorz",
566 action_toggle_maximize_horz
,
571 action_maximize_vert
,
576 action_unmaximize_vert
,
580 "togglemaximizevert",
581 action_toggle_maximize_vert
,
586 action_send_to_desktop
,
587 setup_action_send_to_desktop
591 action_send_to_desktop_dir
,
592 setup_action_send_to_desktop_next
595 "sendtodesktopprevious",
596 action_send_to_desktop_dir
,
597 setup_action_send_to_desktop_prev
600 "sendtodesktopright",
601 action_send_to_desktop_dir
,
602 setup_action_send_to_desktop_right
606 action_send_to_desktop_dir
,
607 setup_action_send_to_desktop_left
611 action_send_to_desktop_dir
,
612 setup_action_send_to_desktop_up
616 action_send_to_desktop_dir
,
617 setup_action_send_to_desktop_down
627 setup_action_desktop_next
632 setup_action_desktop_prev
637 setup_action_desktop_right
642 setup_action_desktop_left
647 setup_action_desktop_up
652 setup_action_desktop_down
656 action_toggle_decorations
,
671 action_toggle_show_desktop
,
681 action_unshow_desktop
,
707 setup_action_showmenu
711 action_send_to_layer
,
712 setup_action_top_layer
717 setup_action_top_layer
721 action_send_to_layer
,
722 setup_action_normal_layer
726 action_send_to_layer
,
727 setup_action_bottom_layer
730 "togglealwaysonbottom",
732 setup_action_bottom_layer
736 action_cycle_windows
,
737 setup_action_cycle_windows_next
741 action_cycle_windows
,
742 setup_action_cycle_windows_previous
747 setup_action_movetoedge_north
752 setup_action_movetoedge_south
757 setup_action_movetoedge_west
762 setup_action_movetoedge_east
767 setup_action_growtoedge_north
772 setup_action_growtoedge_south
777 setup_action_growtoedge_west
782 setup_action_growtoedge_east
791 ObAction
*action_from_string(const gchar
*name
, ObUserAction uact
)
794 gboolean exist
= FALSE
;
797 for (i
= 0; actionstrings
[i
].name
; i
++)
798 if (!g_ascii_strcasecmp(name
, actionstrings
[i
].name
)) {
800 a
= action_new(actionstrings
[i
].func
);
801 if (actionstrings
[i
].setup
)
802 actionstrings
[i
].setup(&a
, uact
);
803 /* only key bindings can be interactive. thus saith the xor.
804 because of how the mouse is grabbed, mouse events dont even get
805 read during interactive events, so no dice! >:) */
806 if (uact
!= OB_USER_ACTION_KEYBOARD_KEY
)
807 a
->data
.any
.interactive
= FALSE
;
811 g_warning("Invalid action '%s' requested. No such action exists.",
814 g_warning("Invalid use of action '%s'. Action will be ignored.", name
);
818 ObAction
*action_parse(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
822 ObAction
*act
= NULL
;
825 if (parse_attr_string("name", node
, &actname
)) {
826 if ((act
= action_from_string(actname
, uact
))) {
827 if (act
->func
== action_execute
|| act
->func
== action_restart
) {
828 if ((n
= parse_find_node("execute", node
->xmlChildrenNode
))) {
829 gchar
*s
= parse_string(doc
, n
);
830 act
->data
.execute
.path
= parse_expand_tilde(s
);
833 } else if (act
->func
== action_showmenu
) {
834 if ((n
= parse_find_node("menu", node
->xmlChildrenNode
)))
835 act
->data
.showmenu
.name
= parse_string(doc
, n
);
836 } else if (act
->func
== action_move_relative_horz
||
837 act
->func
== action_move_relative_vert
||
838 act
->func
== action_resize_relative_horz
||
839 act
->func
== action_resize_relative_vert
) {
840 if ((n
= parse_find_node("delta", node
->xmlChildrenNode
)))
841 act
->data
.relative
.delta
= parse_int(doc
, n
);
842 } else if (act
->func
== action_desktop
) {
843 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
844 act
->data
.desktop
.desk
= parse_int(doc
, n
);
845 if (act
->data
.desktop
.desk
> 0) act
->data
.desktop
.desk
--;
846 } else if (act
->func
== action_send_to_desktop
) {
847 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
848 act
->data
.sendto
.desk
= parse_int(doc
, n
);
849 if (act
->data
.sendto
.desk
> 0) act
->data
.sendto
.desk
--;
850 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
851 act
->data
.sendto
.follow
= parse_bool(doc
, n
);
852 } else if (act
->func
== action_desktop_dir
) {
853 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
854 act
->data
.desktopdir
.wrap
= parse_bool(doc
, n
);
855 } else if (act
->func
== action_send_to_desktop_dir
) {
856 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
857 act
->data
.sendtodir
.wrap
= parse_bool(doc
, n
);
858 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
859 act
->data
.sendtodir
.follow
= parse_bool(doc
, n
);
860 } else if (act
->func
== action_activate
) {
861 if ((n
= parse_find_node("here", node
->xmlChildrenNode
)))
862 act
->data
.activate
.here
= parse_bool(doc
, n
);
863 } else if (act
->func
== action_cycle_windows
) {
864 if ((n
= parse_find_node("linear", node
->xmlChildrenNode
)))
865 act
->data
.cycle
.linear
= parse_bool(doc
, n
);
873 void action_run_list(GSList
*acts
, ObClient
*c
, ObFrameContext context
,
874 guint state
, guint button
, gint x
, gint y
,
875 gboolean cancel
, gboolean done
)
879 gboolean inter
= FALSE
;
885 screen_pointer_pos(&x
, &y
);
887 if (grab_on_keyboard())
890 for (it
= acts
; it
; it
= g_slist_next(it
)) {
892 if (a
->data
.any
.interactive
) {
899 /* sometimes when we execute another app as an action,
900 it won't work right unless we XUngrabKeyboard first,
901 even though we grabbed the key/button Asychronously.
902 e.g. "gnome-panel-control --main-menu" */
903 XUngrabKeyboard(ob_display
, event_lasttime
);
906 for (it
= acts
; it
; it
= g_slist_next(it
)) {
909 if (!(a
->data
.any
.client_action
== OB_CLIENT_ACTION_ALWAYS
&& !c
)) {
910 a
->data
.any
.c
= a
->data
.any
.client_action
? c
: NULL
;
911 a
->data
.any
.context
= context
;
915 a
->data
.any
.button
= button
;
917 if (a
->data
.any
.interactive
) {
918 a
->data
.inter
.cancel
= cancel
;
919 a
->data
.inter
.final
= done
;
920 if (!(cancel
|| done
))
921 keyboard_interactive_grab(state
, a
->data
.any
.c
, a
);
924 ob_main_loop_queue_action(ob_main_loop
, a
);
932 if (data
->execute
.path
) {
933 cmd
= g_filename_from_utf8(data
->execute
.path
, -1, NULL
, NULL
, NULL
);
935 if (!g_spawn_command_line_async(cmd
, &e
)) {
936 g_warning("failed to execute '%s': %s",
941 g_warning("failed to convert '%s' from utf8", data
->execute
.path
);
946 void action_activate(union ActionData
*data
)
948 client_activate(data
->activate
.any
.c
, data
->activate
.here
);
951 void action_focus(union ActionData
*data
)
953 client_focus(data
->client
.any
.c
);
956 void action_unfocus (union ActionData
*data
)
958 client_unfocus(data
->client
.any
.c
);
961 void action_iconify(union ActionData
*data
)
963 client_iconify(data
->client
.any
.c
, TRUE
, TRUE
);
966 void action_raiselower(union ActionData
*data
)
968 ObClient
*c
= data
->client
.any
.c
;
970 gboolean raise
= FALSE
;
972 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
973 ObClient
*cit
= it
->data
;
976 if (client_normal(cit
) == client_normal(c
) &&
977 cit
->layer
== c
->layer
&&
978 cit
->frame
->visible
&&
979 !client_search_transient(c
, cit
))
981 if (RECT_INTERSECTS_RECT(cit
->frame
->area
, c
->frame
->area
)) {
989 client_action_start(data
);
990 stacking_raise(CLIENT_AS_WINDOW(c
));
991 client_action_end(data
);
993 client_action_start(data
);
994 stacking_lower(CLIENT_AS_WINDOW(c
));
995 client_action_end(data
);
999 void action_raise(union ActionData
*data
)
1001 client_action_start(data
);
1002 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1003 client_action_end(data
);
1006 void action_unshaderaise(union ActionData
*data
)
1008 if (data
->client
.any
.c
->shaded
) {
1009 client_action_start(data
);
1010 client_shade(data
->client
.any
.c
, FALSE
);
1011 client_action_end(data
);
1013 client_action_start(data
);
1014 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1015 client_action_end(data
);
1019 void action_shadelower(union ActionData
*data
)
1021 if (data
->client
.any
.c
->shaded
)
1022 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1024 client_action_start(data
);
1025 client_shade(data
->client
.any
.c
, TRUE
);
1026 client_action_end(data
);
1030 void action_lower(union ActionData
*data
)
1032 client_action_start(data
);
1033 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1034 client_action_end(data
);
1037 void action_close(union ActionData
*data
)
1039 client_close(data
->client
.any
.c
);
1042 void action_kill(union ActionData
*data
)
1044 client_kill(data
->client
.any
.c
);
1047 void action_shade(union ActionData
*data
)
1049 client_action_start(data
);
1050 client_shade(data
->client
.any
.c
, TRUE
);
1051 client_action_end(data
);
1054 void action_unshade(union ActionData
*data
)
1056 client_action_start(data
);
1057 client_shade(data
->client
.any
.c
, FALSE
);
1058 client_action_end(data
);
1061 void action_toggle_shade(union ActionData
*data
)
1063 client_action_start(data
);
1064 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1065 client_action_end(data
);
1068 void action_toggle_omnipresent(union ActionData
*data
)
1070 client_set_desktop(data
->client
.any
.c
,
1071 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1072 screen_desktop
: DESKTOP_ALL
, FALSE
);
1075 void action_move_relative_horz(union ActionData
*data
)
1077 ObClient
*c
= data
->relative
.any
.c
;
1078 client_action_start(data
);
1079 client_move(c
, c
->area
.x
+ data
->relative
.delta
, c
->area
.y
);
1080 client_action_end(data
);
1083 void action_move_relative_vert(union ActionData
*data
)
1085 ObClient
*c
= data
->relative
.any
.c
;
1086 client_action_start(data
);
1087 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.delta
);
1088 client_action_end(data
);
1091 void action_resize_relative_horz(union ActionData
*data
)
1093 ObClient
*c
= data
->relative
.any
.c
;
1094 client_action_start(data
);
1096 c
->area
.width
+ data
->relative
.delta
* c
->size_inc
.width
,
1098 client_action_end(data
);
1101 void action_resize_relative_vert(union ActionData
*data
)
1103 ObClient
*c
= data
->relative
.any
.c
;
1105 client_action_start(data
);
1106 client_resize(c
, c
->area
.width
, c
->area
.height
+
1107 data
->relative
.delta
* c
->size_inc
.height
);
1108 client_action_end(data
);
1112 void action_maximize_full(union ActionData
*data
)
1114 client_action_start(data
);
1115 client_maximize(data
->client
.any
.c
, TRUE
, 0, TRUE
);
1116 client_action_end(data
);
1119 void action_unmaximize_full(union ActionData
*data
)
1121 client_action_start(data
);
1122 client_maximize(data
->client
.any
.c
, FALSE
, 0, TRUE
);
1123 client_action_end(data
);
1126 void action_toggle_maximize_full(union ActionData
*data
)
1128 client_action_start(data
);
1129 client_maximize(data
->client
.any
.c
,
1130 !(data
->client
.any
.c
->max_horz
||
1131 data
->client
.any
.c
->max_vert
),
1133 client_action_end(data
);
1136 void action_maximize_horz(union ActionData
*data
)
1138 client_action_start(data
);
1139 client_maximize(data
->client
.any
.c
, TRUE
, 1, TRUE
);
1140 client_action_end(data
);
1143 void action_unmaximize_horz(union ActionData
*data
)
1145 client_action_start(data
);
1146 client_maximize(data
->client
.any
.c
, FALSE
, 1, TRUE
);
1147 client_action_end(data
);
1150 void action_toggle_maximize_horz(union ActionData
*data
)
1152 client_action_start(data
);
1153 client_maximize(data
->client
.any
.c
,
1154 !data
->client
.any
.c
->max_horz
, 1, TRUE
);
1155 client_action_end(data
);
1158 void action_maximize_vert(union ActionData
*data
)
1160 client_action_start(data
);
1161 client_maximize(data
->client
.any
.c
, TRUE
, 2, TRUE
);
1162 client_action_end(data
);
1165 void action_unmaximize_vert(union ActionData
*data
)
1167 client_action_start(data
);
1168 client_maximize(data
->client
.any
.c
, FALSE
, 2, TRUE
);
1169 client_action_end(data
);
1172 void action_toggle_maximize_vert(union ActionData
*data
)
1174 client_action_start(data
);
1175 client_maximize(data
->client
.any
.c
,
1176 !data
->client
.any
.c
->max_vert
, 2, TRUE
);
1177 client_action_end(data
);
1180 void action_send_to_desktop(union ActionData
*data
)
1182 ObClient
*c
= data
->sendto
.any
.c
;
1184 if (!client_normal(c
)) return;
1186 if (data
->sendto
.desk
< screen_num_desktops
||
1187 data
->sendto
.desk
== DESKTOP_ALL
) {
1188 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
);
1189 if (data
->sendto
.follow
)
1190 screen_set_desktop(data
->sendto
.desk
);
1194 void action_desktop(union ActionData
*data
)
1196 static guint first
= (unsigned) -1;
1198 if (data
->inter
.any
.interactive
&& first
== (unsigned) -1)
1199 first
= screen_desktop
;
1201 if (!data
->inter
.any
.interactive
||
1202 (!data
->inter
.cancel
&& !data
->inter
.final
))
1204 if (data
->desktop
.desk
< screen_num_desktops
||
1205 data
->desktop
.desk
== DESKTOP_ALL
)
1207 screen_set_desktop(data
->desktop
.desk
);
1208 if (data
->inter
.any
.interactive
)
1209 screen_desktop_popup(data
->desktop
.desk
, TRUE
);
1211 } else if (data
->inter
.cancel
) {
1212 screen_set_desktop(first
);
1215 if (data
->inter
.any
.interactive
&& data
->inter
.final
) {
1216 screen_desktop_popup(0, FALSE
);
1217 first
= (unsigned) -1;
1221 void action_desktop_dir(union ActionData
*data
)
1225 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1226 data
->desktopdir
.wrap
,
1227 data
->sendtodir
.linear
,
1228 data
->desktopdir
.inter
.any
.interactive
,
1229 data
->desktopdir
.inter
.final
,
1230 data
->desktopdir
.inter
.cancel
);
1231 if (!data
->sendtodir
.inter
.any
.interactive
||
1232 !data
->sendtodir
.inter
.final
)
1234 screen_set_desktop(d
);
1238 void action_send_to_desktop_dir(union ActionData
*data
)
1240 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1243 if (!client_normal(c
)) return;
1245 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1246 data
->sendtodir
.linear
,
1247 data
->sendtodir
.inter
.any
.interactive
,
1248 data
->sendtodir
.inter
.final
,
1249 data
->sendtodir
.inter
.cancel
);
1250 if (!data
->sendtodir
.inter
.any
.interactive
||
1251 !data
->sendtodir
.inter
.final
)
1253 client_set_desktop(c
, d
, data
->sendtodir
.follow
);
1254 if (data
->sendtodir
.follow
)
1255 screen_set_desktop(d
);
1259 void action_desktop_last(union ActionData
*data
)
1261 screen_set_desktop(screen_last_desktop
);
1264 void action_toggle_decorations(union ActionData
*data
)
1266 ObClient
*c
= data
->client
.any
.c
;
1268 client_action_start(data
);
1269 client_set_undecorated(c
, !c
->undecorated
);
1270 client_action_end(data
);
1273 static guint32
pick_corner(int x
, int y
, int cx
, int cy
, int cw
, int ch
)
1275 if (x
- cx
> cw
/ 2) {
1276 if (y
- cy
> ch
/ 2)
1277 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1279 return prop_atoms
.net_wm_moveresize_size_topright
;
1281 if (y
- cy
> ch
/ 2)
1282 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1284 return prop_atoms
.net_wm_moveresize_size_topleft
;
1288 void action_moveresize(union ActionData
*data
)
1290 ObClient
*c
= data
->moveresize
.any
.c
;
1293 if (!client_normal(c
)) return;
1295 if (data
->moveresize
.keyboard
) {
1296 corner
= (data
->moveresize
.move
?
1297 prop_atoms
.net_wm_moveresize_move_keyboard
:
1298 prop_atoms
.net_wm_moveresize_size_keyboard
);
1300 corner
= (data
->moveresize
.move
?
1301 prop_atoms
.net_wm_moveresize_move
:
1302 pick_corner(data
->any
.x
, data
->any
.y
,
1303 c
->frame
->area
.x
, c
->frame
->area
.y
,
1304 /* use the client size because the frame
1305 can be differently sized (shaded
1306 windows) and we want this based on the
1308 c
->area
.width
+ c
->frame
->size
.left
+
1309 c
->frame
->size
.right
,
1310 c
->area
.height
+ c
->frame
->size
.top
+
1311 c
->frame
->size
.bottom
));
1314 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1317 void action_reconfigure(union ActionData
*data
)
1322 void action_restart(union ActionData
*data
)
1324 ob_restart_other(data
->execute
.path
);
1327 void action_exit(union ActionData
*data
)
1332 void action_showmenu(union ActionData
*data
)
1334 if (data
->showmenu
.name
) {
1335 menu_show(data
->showmenu
.name
, data
->any
.x
, data
->any
.y
,
1336 data
->showmenu
.any
.c
);
1340 void action_cycle_windows(union ActionData
*data
)
1342 focus_cycle(data
->cycle
.forward
, data
->cycle
.linear
,
1343 data
->cycle
.inter
.any
.interactive
,
1344 data
->cycle
.inter
.final
, data
->cycle
.inter
.cancel
);
1347 void action_directional_focus(union ActionData
*data
)
1349 focus_directional_cycle(data
->interdiraction
.direction
,
1350 data
->interdiraction
.inter
.any
.interactive
,
1351 data
->interdiraction
.inter
.final
,
1352 data
->interdiraction
.inter
.cancel
);
1355 void action_movetoedge(union ActionData
*data
)
1358 ObClient
*c
= data
->diraction
.any
.c
;
1360 x
= c
->frame
->area
.x
;
1361 y
= c
->frame
->area
.y
;
1363 switch(data
->diraction
.direction
) {
1364 case OB_DIRECTION_NORTH
:
1365 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
);
1367 case OB_DIRECTION_WEST
:
1368 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
);
1370 case OB_DIRECTION_SOUTH
:
1371 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
) -
1372 c
->frame
->area
.height
;
1374 case OB_DIRECTION_EAST
:
1375 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
) -
1376 c
->frame
->area
.width
;
1379 g_assert_not_reached();
1381 frame_frame_gravity(c
->frame
, &x
, &y
);
1382 client_action_start(data
);
1383 client_move(c
, x
, y
);
1384 client_action_end(data
);
1387 void action_growtoedge(union ActionData
*data
)
1389 int x
, y
, width
, height
, dest
;
1390 ObClient
*c
= data
->diraction
.any
.c
;
1393 a
= screen_area(c
->desktop
);
1394 x
= c
->frame
->area
.x
;
1395 y
= c
->frame
->area
.y
;
1396 width
= c
->frame
->area
.width
;
1397 height
= c
->frame
->area
.height
;
1399 switch(data
->diraction
.direction
) {
1400 case OB_DIRECTION_NORTH
:
1401 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
);
1403 height
= c
->frame
->area
.height
/ 2;
1405 height
= c
->frame
->area
.y
+ c
->frame
->area
.height
- dest
;
1409 case OB_DIRECTION_WEST
:
1410 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
);
1412 width
= c
->frame
->area
.width
/ 2;
1414 width
= c
->frame
->area
.x
+ c
->frame
->area
.width
- dest
;
1418 case OB_DIRECTION_SOUTH
:
1419 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
);
1420 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1421 height
= c
->frame
->area
.height
/ 2;
1422 y
= a
->y
+ a
->height
- height
;
1424 height
= dest
- c
->frame
->area
.y
;
1425 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1426 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1428 case OB_DIRECTION_EAST
:
1429 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
);
1430 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1431 width
= c
->frame
->area
.width
/ 2;
1432 x
= a
->x
+ a
->width
- width
;
1434 width
= dest
- c
->frame
->area
.x
;
1435 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1436 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1439 g_assert_not_reached();
1441 frame_frame_gravity(c
->frame
, &x
, &y
);
1442 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1443 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1444 client_action_start(data
);
1445 client_move_resize(c
, x
, y
, width
, height
);
1446 client_action_end(data
);
1449 void action_send_to_layer(union ActionData
*data
)
1451 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1454 void action_toggle_layer(union ActionData
*data
)
1456 ObClient
*c
= data
->layer
.any
.c
;
1458 client_action_start(data
);
1459 if (data
->layer
.layer
< 0)
1460 client_set_layer(c
, c
->below
? 0 : -1);
1461 else if (data
->layer
.layer
> 0)
1462 client_set_layer(c
, c
->above
? 0 : 1);
1463 client_action_end(data
);
1466 void action_toggle_show_desktop(union ActionData
*data
)
1468 screen_show_desktop(!screen_showing_desktop
);
1471 void action_show_desktop(union ActionData
*data
)
1473 screen_show_desktop(TRUE
);
1476 void action_unshow_desktop(union ActionData
*data
)
1478 screen_show_desktop(FALSE
);