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 /* usually this is sorta redundant, but with a press action
53 the enter event will come as a GrabNotify which is
54 ignored, so this will handle that case */
55 if ((c
= client_under_pointer()))
56 event_enter_client(c
);
64 void (*func
)(union ActionData
*);
65 void (*setup
)(ObAction
**, ObUserAction uact
);
68 static ObAction
*action_new(void (*func
)(union ActionData
*data
),
71 ObAction
*a
= g_new0(ObAction
, 1);
77 void action_free(ObAction
*a
)
79 if (a
== NULL
) return;
81 /* deal with pointers */
82 if (a
->func
== action_execute
|| a
->func
== action_restart
)
83 g_free(a
->data
.execute
.path
);
84 else if (a
->func
== action_showmenu
)
85 g_free(a
->data
.showmenu
.name
);
90 void setup_action_directional_focus_north(ObAction
**a
, ObUserAction uact
)
92 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
93 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTH
;
96 void setup_action_directional_focus_east(ObAction
**a
, ObUserAction uact
)
98 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
99 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_EAST
;
102 void setup_action_directional_focus_south(ObAction
**a
, ObUserAction uact
)
104 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
105 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTH
;
108 void setup_action_directional_focus_west(ObAction
**a
, ObUserAction uact
)
110 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
111 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_WEST
;
114 void setup_action_directional_focus_northeast(ObAction
**a
, ObUserAction uact
)
116 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
117 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHEAST
;
120 void setup_action_directional_focus_southeast(ObAction
**a
, ObUserAction uact
)
122 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
123 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHEAST
;
126 void setup_action_directional_focus_southwest(ObAction
**a
, ObUserAction uact
)
128 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
129 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHWEST
;
132 void setup_action_directional_focus_northwest(ObAction
**a
, ObUserAction uact
)
134 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
135 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHWEST
;
138 void setup_action_send_to_desktop(ObAction
**a
, ObUserAction uact
)
140 (*a
)->data
.sendto
.follow
= TRUE
;
143 void setup_action_send_to_desktop_prev(ObAction
**a
, ObUserAction uact
)
145 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
146 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
147 (*a
)->data
.sendtodir
.linear
= TRUE
;
148 (*a
)->data
.sendtodir
.wrap
= TRUE
;
149 (*a
)->data
.sendtodir
.follow
= TRUE
;
152 void setup_action_send_to_desktop_next(ObAction
**a
, ObUserAction uact
)
154 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
155 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
156 (*a
)->data
.sendtodir
.linear
= TRUE
;
157 (*a
)->data
.sendtodir
.wrap
= TRUE
;
158 (*a
)->data
.sendtodir
.follow
= TRUE
;
161 void setup_action_send_to_desktop_left(ObAction
**a
, ObUserAction uact
)
163 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
164 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
165 (*a
)->data
.sendtodir
.linear
= FALSE
;
166 (*a
)->data
.sendtodir
.wrap
= TRUE
;
167 (*a
)->data
.sendtodir
.follow
= TRUE
;
170 void setup_action_send_to_desktop_right(ObAction
**a
, ObUserAction uact
)
172 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
173 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
174 (*a
)->data
.sendtodir
.linear
= FALSE
;
175 (*a
)->data
.sendtodir
.wrap
= TRUE
;
176 (*a
)->data
.sendtodir
.follow
= TRUE
;
179 void setup_action_send_to_desktop_up(ObAction
**a
, ObUserAction uact
)
181 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
182 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_NORTH
;
183 (*a
)->data
.sendtodir
.linear
= FALSE
;
184 (*a
)->data
.sendtodir
.wrap
= TRUE
;
185 (*a
)->data
.sendtodir
.follow
= TRUE
;
188 void setup_action_send_to_desktop_down(ObAction
**a
, ObUserAction uact
)
190 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
191 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_SOUTH
;
192 (*a
)->data
.sendtodir
.linear
= FALSE
;
193 (*a
)->data
.sendtodir
.wrap
= TRUE
;
194 (*a
)->data
.sendtodir
.follow
= TRUE
;
197 void setup_action_desktop_prev(ObAction
**a
, ObUserAction uact
)
199 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
200 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
201 (*a
)->data
.desktopdir
.linear
= TRUE
;
202 (*a
)->data
.desktopdir
.wrap
= TRUE
;
205 void setup_action_desktop_next(ObAction
**a
, ObUserAction uact
)
207 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
208 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
209 (*a
)->data
.desktopdir
.linear
= TRUE
;
210 (*a
)->data
.desktopdir
.wrap
= TRUE
;
213 void setup_action_desktop_left(ObAction
**a
, ObUserAction uact
)
215 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
216 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
217 (*a
)->data
.desktopdir
.linear
= FALSE
;
218 (*a
)->data
.desktopdir
.wrap
= TRUE
;
221 void setup_action_desktop_right(ObAction
**a
, ObUserAction uact
)
223 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
224 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
225 (*a
)->data
.desktopdir
.linear
= FALSE
;
226 (*a
)->data
.desktopdir
.wrap
= TRUE
;
229 void setup_action_desktop_up(ObAction
**a
, ObUserAction uact
)
231 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
232 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_NORTH
;
233 (*a
)->data
.desktopdir
.linear
= FALSE
;
234 (*a
)->data
.desktopdir
.wrap
= TRUE
;
237 void setup_action_desktop_down(ObAction
**a
, ObUserAction uact
)
239 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
240 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_SOUTH
;
241 (*a
)->data
.desktopdir
.linear
= FALSE
;
242 (*a
)->data
.desktopdir
.wrap
= TRUE
;
245 void setup_action_cycle_windows_next(ObAction
**a
, ObUserAction uact
)
247 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
248 (*a
)->data
.cycle
.linear
= FALSE
;
249 (*a
)->data
.cycle
.forward
= TRUE
;
252 void setup_action_cycle_windows_previous(ObAction
**a
, ObUserAction uact
)
254 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
255 (*a
)->data
.cycle
.linear
= FALSE
;
256 (*a
)->data
.cycle
.forward
= FALSE
;
259 void setup_action_movetoedge_north(ObAction
**a
, ObUserAction uact
)
261 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
264 void setup_action_movetoedge_south(ObAction
**a
, ObUserAction uact
)
266 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
269 void setup_action_movetoedge_east(ObAction
**a
, ObUserAction uact
)
271 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
274 void setup_action_movetoedge_west(ObAction
**a
, ObUserAction uact
)
276 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
279 void setup_action_growtoedge_north(ObAction
**a
, ObUserAction uact
)
281 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
284 void setup_action_growtoedge_south(ObAction
**a
, ObUserAction uact
)
286 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
289 void setup_action_growtoedge_east(ObAction
**a
, ObUserAction uact
)
291 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
294 void setup_action_growtoedge_west(ObAction
**a
, ObUserAction uact
)
296 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
299 void setup_action_top_layer(ObAction
**a
, ObUserAction uact
)
301 (*a
)->data
.layer
.layer
= 1;
304 void setup_action_normal_layer(ObAction
**a
, ObUserAction uact
)
306 (*a
)->data
.layer
.layer
= 0;
309 void setup_action_bottom_layer(ObAction
**a
, ObUserAction uact
)
311 (*a
)->data
.layer
.layer
= -1;
314 void setup_action_move(ObAction
**a
, ObUserAction uact
)
316 (*a
)->data
.moveresize
.move
= TRUE
;
317 (*a
)->data
.moveresize
.keyboard
=
318 (uact
== OB_USER_ACTION_KEYBOARD_KEY
||
319 uact
== OB_USER_ACTION_MENU_SELECTION
);
322 void setup_action_resize(ObAction
**a
, ObUserAction uact
)
324 (*a
)->data
.moveresize
.move
= FALSE
;
325 (*a
)->data
.moveresize
.keyboard
=
326 (uact
== OB_USER_ACTION_KEYBOARD_KEY
||
327 uact
== OB_USER_ACTION_MENU_SELECTION
);
330 void setup_action_showmenu(ObAction
**a
, ObUserAction uact
)
332 /* you cannot call ShowMenu from inside a menu, cuz the menu code makes
333 assumptions that there is only one menu (and submenus) open at
335 if (uact
== OB_USER_ACTION_MENU_SELECTION
) {
341 ActionString actionstrings
[] =
349 "directionalfocusnorth",
350 action_directional_focus
,
351 setup_action_directional_focus_north
354 "directionalfocuseast",
355 action_directional_focus
,
356 setup_action_directional_focus_east
359 "directionalfocussouth",
360 action_directional_focus
,
361 setup_action_directional_focus_south
364 "directionalfocuswest",
365 action_directional_focus
,
366 setup_action_directional_focus_west
369 "directionalfocusnortheast",
370 action_directional_focus
,
371 setup_action_directional_focus_northeast
374 "directionalfocussoutheast",
375 action_directional_focus
,
376 setup_action_directional_focus_southeast
379 "directionalfocussouthwest",
380 action_directional_focus
,
381 setup_action_directional_focus_southwest
384 "directionalfocusnorthwest",
385 action_directional_focus
,
386 setup_action_directional_focus_northwest
460 action_toggle_omnipresent
,
465 action_move_relative_horz
,
470 action_move_relative_vert
,
474 "resizerelativehorz",
475 action_resize_relative_horz
,
479 "resizerelativevert",
480 action_resize_relative_vert
,
485 action_maximize_full
,
490 action_unmaximize_full
,
494 "togglemaximizefull",
495 action_toggle_maximize_full
,
500 action_maximize_horz
,
505 action_unmaximize_horz
,
509 "togglemaximizehorz",
510 action_toggle_maximize_horz
,
515 action_maximize_vert
,
520 action_unmaximize_vert
,
524 "togglemaximizevert",
525 action_toggle_maximize_vert
,
530 action_send_to_desktop
,
531 setup_action_send_to_desktop
535 action_send_to_desktop_dir
,
536 setup_action_send_to_desktop_next
539 "sendtodesktopprevious",
540 action_send_to_desktop_dir
,
541 setup_action_send_to_desktop_prev
544 "sendtodesktopright",
545 action_send_to_desktop_dir
,
546 setup_action_send_to_desktop_right
550 action_send_to_desktop_dir
,
551 setup_action_send_to_desktop_left
555 action_send_to_desktop_dir
,
556 setup_action_send_to_desktop_up
560 action_send_to_desktop_dir
,
561 setup_action_send_to_desktop_down
571 setup_action_desktop_next
576 setup_action_desktop_prev
581 setup_action_desktop_right
586 setup_action_desktop_left
591 setup_action_desktop_up
596 setup_action_desktop_down
600 action_toggle_decorations
,
615 action_toggle_show_desktop
,
625 action_unshow_desktop
,
651 setup_action_showmenu
655 action_send_to_layer
,
656 setup_action_top_layer
661 setup_action_top_layer
665 action_send_to_layer
,
666 setup_action_normal_layer
670 action_send_to_layer
,
671 setup_action_bottom_layer
674 "togglealwaysonbottom",
676 setup_action_bottom_layer
680 action_cycle_windows
,
681 setup_action_cycle_windows_next
685 action_cycle_windows
,
686 setup_action_cycle_windows_previous
691 setup_action_movetoedge_north
696 setup_action_movetoedge_south
701 setup_action_movetoedge_west
706 setup_action_movetoedge_east
711 setup_action_growtoedge_north
716 setup_action_growtoedge_south
721 setup_action_growtoedge_west
726 setup_action_growtoedge_east
735 ObAction
*action_from_string(const gchar
*name
, ObUserAction uact
)
738 gboolean exist
= FALSE
;
741 for (i
= 0; actionstrings
[i
].name
; i
++)
742 if (!g_ascii_strcasecmp(name
, actionstrings
[i
].name
)) {
744 a
= action_new(actionstrings
[i
].func
, uact
);
745 if (actionstrings
[i
].setup
)
746 actionstrings
[i
].setup(&a
, uact
);
747 /* only key bindings can be interactive. thus saith the xor. */
748 if (uact
!= OB_USER_ACTION_KEYBOARD_KEY
)
749 a
->data
.any
.interactive
= FALSE
;
753 g_warning("Invalid action '%s' requested. No such action exists.",
756 g_warning("Invalid use of action '%s'. Action will be ignored.", name
);
760 ObAction
*action_parse(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
764 ObAction
*act
= NULL
;
767 if (parse_attr_string("name", node
, &actname
)) {
768 if ((act
= action_from_string(actname
, uact
))) {
769 if (act
->func
== action_execute
|| act
->func
== action_restart
) {
770 if ((n
= parse_find_node("execute", node
->xmlChildrenNode
))) {
771 gchar
*s
= parse_string(doc
, n
);
772 act
->data
.execute
.path
= parse_expand_tilde(s
);
775 } else if (act
->func
== action_showmenu
) {
776 if ((n
= parse_find_node("menu", node
->xmlChildrenNode
)))
777 act
->data
.showmenu
.name
= parse_string(doc
, n
);
778 } else if (act
->func
== action_move_relative_horz
||
779 act
->func
== action_move_relative_vert
||
780 act
->func
== action_resize_relative_horz
||
781 act
->func
== action_resize_relative_vert
) {
782 if ((n
= parse_find_node("delta", node
->xmlChildrenNode
)))
783 act
->data
.relative
.delta
= parse_int(doc
, n
);
784 } else if (act
->func
== action_desktop
) {
785 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
786 act
->data
.desktop
.desk
= parse_int(doc
, n
);
787 if (act
->data
.desktop
.desk
> 0) act
->data
.desktop
.desk
--;
788 } else if (act
->func
== action_send_to_desktop
) {
789 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
790 act
->data
.sendto
.desk
= parse_int(doc
, n
);
791 if (act
->data
.sendto
.desk
> 0) act
->data
.sendto
.desk
--;
792 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
793 act
->data
.sendto
.follow
= parse_bool(doc
, n
);
794 } else if (act
->func
== action_desktop_dir
) {
795 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
796 act
->data
.desktopdir
.wrap
= parse_bool(doc
, n
);
797 } else if (act
->func
== action_send_to_desktop_dir
) {
798 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
799 act
->data
.sendtodir
.wrap
= parse_bool(doc
, n
);
800 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
801 act
->data
.sendtodir
.follow
= parse_bool(doc
, n
);
802 } else if (act
->func
== action_activate
) {
803 if ((n
= parse_find_node("here", node
->xmlChildrenNode
)))
804 act
->data
.activate
.here
= parse_bool(doc
, n
);
805 } else if (act
->func
== action_cycle_windows
) {
806 if ((n
= parse_find_node("linear", node
->xmlChildrenNode
)))
807 act
->data
.cycle
.linear
= parse_bool(doc
, n
);
815 void action_run_list(GSList
*acts
, ObClient
*c
, ObFrameContext context
,
816 guint state
, guint button
, gint x
, gint y
,
817 gboolean cancel
, gboolean done
)
821 gboolean inter
= FALSE
;
827 screen_pointer_pos(&x
, &y
);
829 if (grab_on_keyboard())
832 for (it
= acts
; it
; it
= g_slist_next(it
)) {
834 if (a
->data
.any
.interactive
) {
841 /* sometimes when we execute another app as an action,
842 it won't work right unless we XUngrabKeyboard first,
843 even though we grabbed the key/button Asychronously.
844 e.g. "gnome-panel-control --main-menu" */
845 XUngrabKeyboard(ob_display
, event_lasttime
);
848 for (it
= acts
; it
; it
= g_slist_next(it
)) {
852 a
->data
.any
.context
= context
;
856 a
->data
.any
.button
= button
;
858 if (a
->data
.any
.interactive
) {
859 a
->data
.inter
.cancel
= cancel
;
860 a
->data
.inter
.final
= done
;
861 if (!(cancel
|| done
))
862 keyboard_interactive_grab(state
, c
, a
);
869 void action_execute(union ActionData
*data
)
873 if (data
->execute
.path
) {
874 cmd
= g_filename_from_utf8(data
->execute
.path
, -1, NULL
, NULL
, NULL
);
876 if (!g_spawn_command_line_async(cmd
, &e
)) {
877 g_warning("failed to execute '%s': %s",
882 g_warning("failed to convert '%s' from utf8", data
->execute
.path
);
887 void action_activate(union ActionData
*data
)
889 if (data
->activate
.any
.c
)
890 client_activate(data
->activate
.any
.c
, data
->activate
.here
);
893 void action_focus(union ActionData
*data
)
895 if (data
->client
.any
.c
)
896 client_focus(data
->client
.any
.c
);
899 void action_unfocus (union ActionData
*data
)
901 if (data
->client
.any
.c
)
902 client_unfocus(data
->client
.any
.c
);
905 void action_iconify(union ActionData
*data
)
907 if (data
->client
.any
.c
)
908 client_iconify(data
->client
.any
.c
, TRUE
, TRUE
);
911 void action_raiselower(union ActionData
*data
)
913 ObClient
*c
= data
->client
.any
.c
;
915 gboolean raise
= FALSE
;
919 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
920 ObClient
*cit
= it
->data
;
923 if (client_normal(cit
) == client_normal(c
) &&
924 cit
->layer
== c
->layer
&&
927 if (RECT_INTERSECTS_RECT(cit
->frame
->area
, c
->frame
->area
)) {
935 client_action_start(data
);
936 stacking_raise(CLIENT_AS_WINDOW(c
));
937 client_action_end(data
);
939 client_action_start(data
);
940 stacking_lower(CLIENT_AS_WINDOW(c
));
941 client_action_end(data
);
945 void action_raise(union ActionData
*data
)
947 if (data
->client
.any
.c
) {
948 client_action_start(data
);
949 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
950 client_action_end(data
);
954 void action_unshaderaise(union ActionData
*data
)
956 if (data
->client
.any
.c
) {
957 if (data
->client
.any
.c
->shaded
) {
958 client_action_start(data
);
959 client_shade(data
->client
.any
.c
, FALSE
);
960 client_action_end(data
);
962 client_action_start(data
);
963 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
964 client_action_end(data
);
969 void action_shadelower(union ActionData
*data
)
971 if (data
->client
.any
.c
) {
972 if (data
->client
.any
.c
->shaded
)
973 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
975 client_action_start(data
);
976 client_shade(data
->client
.any
.c
, TRUE
);
977 client_action_end(data
);
982 void action_lower(union ActionData
*data
)
984 if (data
->client
.any
.c
) {
985 client_action_start(data
);
986 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
987 client_action_end(data
);
991 void action_close(union ActionData
*data
)
993 if (data
->client
.any
.c
)
994 client_close(data
->client
.any
.c
);
997 void action_kill(union ActionData
*data
)
999 if (data
->client
.any
.c
)
1000 client_kill(data
->client
.any
.c
);
1003 void action_shade(union ActionData
*data
)
1005 if (data
->client
.any
.c
) {
1006 client_action_start(data
);
1007 client_shade(data
->client
.any
.c
, TRUE
);
1008 client_action_end(data
);
1012 void action_unshade(union ActionData
*data
)
1014 if (data
->client
.any
.c
) {
1015 client_action_start(data
);
1016 client_shade(data
->client
.any
.c
, FALSE
);
1017 client_action_end(data
);
1021 void action_toggle_shade(union ActionData
*data
)
1023 if (data
->client
.any
.c
) {
1024 client_action_start(data
);
1025 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1026 client_action_end(data
);
1030 void action_toggle_omnipresent(union ActionData
*data
)
1032 if (data
->client
.any
.c
)
1033 client_set_desktop(data
->client
.any
.c
,
1034 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1035 screen_desktop
: DESKTOP_ALL
, FALSE
);
1038 void action_move_relative_horz(union ActionData
*data
)
1040 ObClient
*c
= data
->relative
.any
.c
;
1042 client_action_start(data
);
1043 client_move(c
, c
->area
.x
+ data
->relative
.delta
, c
->area
.y
);
1044 client_action_end(data
);
1048 void action_move_relative_vert(union ActionData
*data
)
1050 ObClient
*c
= data
->relative
.any
.c
;
1052 client_action_start(data
);
1053 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.delta
);
1054 client_action_end(data
);
1058 void action_resize_relative_horz(union ActionData
*data
)
1060 ObClient
*c
= data
->relative
.any
.c
;
1062 client_action_start(data
);
1064 c
->area
.width
+ data
->relative
.delta
* c
->size_inc
.width
,
1066 client_action_end(data
);
1070 void action_resize_relative_vert(union ActionData
*data
)
1072 ObClient
*c
= data
->relative
.any
.c
;
1073 if (c
&& !c
->shaded
) {
1074 client_action_start(data
);
1075 client_resize(c
, c
->area
.width
, c
->area
.height
+
1076 data
->relative
.delta
* c
->size_inc
.height
);
1077 client_action_end(data
);
1081 void action_maximize_full(union ActionData
*data
)
1083 if (data
->client
.any
.c
) {
1084 client_action_start(data
);
1085 client_maximize(data
->client
.any
.c
, TRUE
, 0, TRUE
);
1086 client_action_end(data
);
1090 void action_unmaximize_full(union ActionData
*data
)
1092 if (data
->client
.any
.c
) {
1093 client_action_start(data
);
1094 client_maximize(data
->client
.any
.c
, FALSE
, 0, TRUE
);
1095 client_action_end(data
);
1099 void action_toggle_maximize_full(union ActionData
*data
)
1101 if (data
->client
.any
.c
) {
1102 client_action_start(data
);
1103 client_maximize(data
->client
.any
.c
,
1104 !(data
->client
.any
.c
->max_horz
||
1105 data
->client
.any
.c
->max_vert
),
1107 client_action_end(data
);
1111 void action_maximize_horz(union ActionData
*data
)
1113 if (data
->client
.any
.c
) {
1114 client_action_start(data
);
1115 client_maximize(data
->client
.any
.c
, TRUE
, 1, TRUE
);
1116 client_action_end(data
);
1120 void action_unmaximize_horz(union ActionData
*data
)
1122 if (data
->client
.any
.c
) {
1123 client_action_start(data
);
1124 client_maximize(data
->client
.any
.c
, FALSE
, 1, TRUE
);
1125 client_action_end(data
);
1129 void action_toggle_maximize_horz(union ActionData
*data
)
1131 if (data
->client
.any
.c
) {
1132 client_action_start(data
);
1133 client_maximize(data
->client
.any
.c
,
1134 !data
->client
.any
.c
->max_horz
, 1, TRUE
);
1135 client_action_end(data
);
1139 void action_maximize_vert(union ActionData
*data
)
1141 if (data
->client
.any
.c
) {
1142 client_action_start(data
);
1143 client_maximize(data
->client
.any
.c
, TRUE
, 2, TRUE
);
1144 client_action_end(data
);
1148 void action_unmaximize_vert(union ActionData
*data
)
1150 if (data
->client
.any
.c
) {
1151 client_action_start(data
);
1152 client_maximize(data
->client
.any
.c
, FALSE
, 2, TRUE
);
1153 client_action_end(data
);
1157 void action_toggle_maximize_vert(union ActionData
*data
)
1159 if (data
->client
.any
.c
) {
1160 client_action_start(data
);
1161 client_maximize(data
->client
.any
.c
,
1162 !data
->client
.any
.c
->max_vert
, 2, TRUE
);
1163 client_action_end(data
);
1167 void action_send_to_desktop(union ActionData
*data
)
1169 ObClient
*c
= data
->sendto
.any
.c
;
1171 if (!c
|| !client_normal(c
)) return;
1173 if (data
->sendto
.desk
< screen_num_desktops
||
1174 data
->sendto
.desk
== DESKTOP_ALL
) {
1175 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
);
1176 if (data
->sendto
.follow
)
1177 screen_set_desktop(data
->sendto
.desk
);
1181 void action_desktop(union ActionData
*data
)
1183 if (data
->desktop
.desk
< screen_num_desktops
||
1184 data
->desktop
.desk
== DESKTOP_ALL
)
1185 screen_set_desktop(data
->desktop
.desk
);
1188 void action_desktop_dir(union ActionData
*data
)
1192 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1193 data
->desktopdir
.wrap
,
1194 data
->sendtodir
.linear
,
1195 data
->desktopdir
.inter
.any
.interactive
,
1196 data
->desktopdir
.inter
.final
,
1197 data
->desktopdir
.inter
.cancel
);
1198 screen_set_desktop(d
);
1201 void action_send_to_desktop_dir(union ActionData
*data
)
1203 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1206 if (!c
|| !client_normal(c
)) return;
1208 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1209 data
->sendtodir
.linear
,
1210 data
->sendtodir
.inter
.any
.interactive
,
1211 data
->sendtodir
.inter
.final
,
1212 data
->sendtodir
.inter
.cancel
);
1213 client_set_desktop(c
, d
, data
->sendtodir
.follow
);
1214 if (data
->sendtodir
.follow
)
1215 screen_set_desktop(d
);
1218 void action_desktop_last(union ActionData
*data
)
1220 screen_set_desktop(screen_last_desktop
);
1223 void action_toggle_decorations(union ActionData
*data
)
1225 ObClient
*c
= data
->client
.any
.c
;
1228 client_action_start(data
);
1229 c
->decorate
= !c
->decorate
;
1230 client_setup_decor_and_functions(c
);
1231 client_action_end(data
);
1235 static guint32
pick_corner(int x
, int y
, int cx
, int cy
, int cw
, int ch
)
1237 if (x
- cx
> cw
/ 2) {
1238 if (y
- cy
> ch
/ 2)
1239 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1241 return prop_atoms
.net_wm_moveresize_size_topright
;
1243 if (y
- cy
> ch
/ 2)
1244 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1246 return prop_atoms
.net_wm_moveresize_size_topleft
;
1250 void action_moveresize(union ActionData
*data
)
1252 ObClient
*c
= data
->moveresize
.any
.c
;
1255 if (!c
|| !client_normal(c
)) return;
1257 if (data
->moveresize
.keyboard
) {
1258 corner
= (data
->moveresize
.move
?
1259 prop_atoms
.net_wm_moveresize_move_keyboard
:
1260 prop_atoms
.net_wm_moveresize_size_keyboard
);
1262 corner
= (data
->moveresize
.move
?
1263 prop_atoms
.net_wm_moveresize_move
:
1264 pick_corner(data
->any
.x
, data
->any
.y
,
1265 c
->frame
->area
.x
, c
->frame
->area
.y
,
1266 /* use the client size because the frame
1267 can be differently sized (shaded
1268 windows) and we want this based on the
1270 c
->area
.width
+ c
->frame
->size
.left
+
1271 c
->frame
->size
.right
,
1272 c
->area
.height
+ c
->frame
->size
.top
+
1273 c
->frame
->size
.bottom
));
1276 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1279 void action_reconfigure(union ActionData
*data
)
1284 void action_restart(union ActionData
*data
)
1286 ob_restart_other(data
->execute
.path
);
1289 void action_exit(union ActionData
*data
)
1294 void action_showmenu(union ActionData
*data
)
1296 if (data
->showmenu
.name
) {
1297 menu_show(data
->showmenu
.name
, data
->any
.x
, data
->any
.y
,
1298 data
->showmenu
.any
.c
);
1302 void action_cycle_windows(union ActionData
*data
)
1304 focus_cycle(data
->cycle
.forward
, data
->cycle
.linear
,
1305 data
->cycle
.inter
.any
.interactive
,
1306 data
->cycle
.inter
.final
, data
->cycle
.inter
.cancel
);
1309 void action_directional_focus(union ActionData
*data
)
1311 focus_directional_cycle(data
->interdiraction
.direction
,
1312 data
->interdiraction
.inter
.any
.interactive
,
1313 data
->interdiraction
.inter
.final
,
1314 data
->interdiraction
.inter
.cancel
);
1317 void action_movetoedge(union ActionData
*data
)
1320 ObClient
*c
= data
->diraction
.any
.c
;
1324 x
= c
->frame
->area
.x
;
1325 y
= c
->frame
->area
.y
;
1327 switch(data
->diraction
.direction
) {
1328 case OB_DIRECTION_NORTH
:
1329 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
);
1331 case OB_DIRECTION_WEST
:
1332 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
);
1334 case OB_DIRECTION_SOUTH
:
1335 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
) -
1336 c
->frame
->area
.height
;
1338 case OB_DIRECTION_EAST
:
1339 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
) -
1340 c
->frame
->area
.width
;
1343 g_assert_not_reached();
1345 frame_frame_gravity(c
->frame
, &x
, &y
);
1346 client_action_start(data
);
1347 client_move(c
, x
, y
);
1348 client_action_end(data
);
1352 void action_growtoedge(union ActionData
*data
)
1354 int x
, y
, width
, height
, dest
;
1355 ObClient
*c
= data
->diraction
.any
.c
;
1361 a
= screen_area(c
->desktop
);
1362 x
= c
->frame
->area
.x
;
1363 y
= c
->frame
->area
.y
;
1364 width
= c
->frame
->area
.width
;
1365 height
= c
->frame
->area
.height
;
1367 switch(data
->diraction
.direction
) {
1368 case OB_DIRECTION_NORTH
:
1369 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
);
1371 height
= c
->frame
->area
.height
/ 2;
1373 height
= c
->frame
->area
.y
+ c
->frame
->area
.height
- dest
;
1377 case OB_DIRECTION_WEST
:
1378 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
);
1380 width
= c
->frame
->area
.width
/ 2;
1382 width
= c
->frame
->area
.x
+ c
->frame
->area
.width
- dest
;
1386 case OB_DIRECTION_SOUTH
:
1387 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
);
1388 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1389 height
= c
->frame
->area
.height
/ 2;
1390 y
= a
->y
+ a
->height
- height
;
1392 height
= dest
- c
->frame
->area
.y
;
1393 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1394 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1396 case OB_DIRECTION_EAST
:
1397 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
);
1398 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1399 width
= c
->frame
->area
.width
/ 2;
1400 x
= a
->x
+ a
->width
- width
;
1402 width
= dest
- c
->frame
->area
.x
;
1403 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1404 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1407 g_assert_not_reached();
1409 frame_frame_gravity(c
->frame
, &x
, &y
);
1410 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1411 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1412 client_action_start(data
);
1413 client_move_resize(c
, x
, y
, width
, height
);
1414 client_action_end(data
);
1417 void action_send_to_layer(union ActionData
*data
)
1419 if (data
->layer
.any
.c
)
1420 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1423 void action_toggle_layer(union ActionData
*data
)
1425 ObClient
*c
= data
->layer
.any
.c
;
1428 client_action_start(data
);
1429 if (data
->layer
.layer
< 0)
1430 client_set_layer(c
, c
->below
? 0 : -1);
1431 else if (data
->layer
.layer
> 0)
1432 client_set_layer(c
, c
->above
? 0 : 1);
1433 client_action_end(data
);
1437 void action_toggle_show_desktop(union ActionData
*data
)
1439 screen_show_desktop(!screen_showing_desktop
);
1442 void action_show_desktop(union ActionData
*data
)
1444 screen_show_desktop(TRUE
);
1447 void action_unshow_desktop(union ActionData
*data
)
1449 screen_show_desktop(FALSE
);