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
);