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
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
141 (*a
)->data
.sendto
.follow
= TRUE
;
144 void setup_action_send_to_desktop_prev(ObAction
**a
, ObUserAction uact
)
146 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
147 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
148 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
149 (*a
)->data
.sendtodir
.linear
= TRUE
;
150 (*a
)->data
.sendtodir
.wrap
= TRUE
;
151 (*a
)->data
.sendtodir
.follow
= TRUE
;
154 void setup_action_send_to_desktop_next(ObAction
**a
, ObUserAction uact
)
156 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
157 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
158 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
159 (*a
)->data
.sendtodir
.linear
= TRUE
;
160 (*a
)->data
.sendtodir
.wrap
= TRUE
;
161 (*a
)->data
.sendtodir
.follow
= TRUE
;
164 void setup_action_send_to_desktop_left(ObAction
**a
, ObUserAction uact
)
166 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
167 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
168 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
169 (*a
)->data
.sendtodir
.linear
= FALSE
;
170 (*a
)->data
.sendtodir
.wrap
= TRUE
;
171 (*a
)->data
.sendtodir
.follow
= TRUE
;
174 void setup_action_send_to_desktop_right(ObAction
**a
, ObUserAction uact
)
176 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
177 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
178 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
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_up(ObAction
**a
, ObUserAction uact
)
186 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
187 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
188 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_NORTH
;
189 (*a
)->data
.sendtodir
.linear
= FALSE
;
190 (*a
)->data
.sendtodir
.wrap
= TRUE
;
191 (*a
)->data
.sendtodir
.follow
= TRUE
;
194 void setup_action_send_to_desktop_down(ObAction
**a
, ObUserAction uact
)
196 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
197 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
198 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_SOUTH
;
199 (*a
)->data
.sendtodir
.linear
= FALSE
;
200 (*a
)->data
.sendtodir
.wrap
= TRUE
;
201 (*a
)->data
.sendtodir
.follow
= TRUE
;
204 void setup_action_desktop_prev(ObAction
**a
, ObUserAction uact
)
206 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
207 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
208 (*a
)->data
.desktopdir
.linear
= TRUE
;
209 (*a
)->data
.desktopdir
.wrap
= TRUE
;
212 void setup_action_desktop_next(ObAction
**a
, ObUserAction uact
)
214 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
215 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
216 (*a
)->data
.desktopdir
.linear
= TRUE
;
217 (*a
)->data
.desktopdir
.wrap
= TRUE
;
220 void setup_action_desktop_left(ObAction
**a
, ObUserAction uact
)
222 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
223 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
224 (*a
)->data
.desktopdir
.linear
= FALSE
;
225 (*a
)->data
.desktopdir
.wrap
= TRUE
;
228 void setup_action_desktop_right(ObAction
**a
, ObUserAction uact
)
230 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
231 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
232 (*a
)->data
.desktopdir
.linear
= FALSE
;
233 (*a
)->data
.desktopdir
.wrap
= TRUE
;
236 void setup_action_desktop_up(ObAction
**a
, ObUserAction uact
)
238 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
239 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_NORTH
;
240 (*a
)->data
.desktopdir
.linear
= FALSE
;
241 (*a
)->data
.desktopdir
.wrap
= TRUE
;
244 void setup_action_desktop_down(ObAction
**a
, ObUserAction uact
)
246 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
247 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_SOUTH
;
248 (*a
)->data
.desktopdir
.linear
= FALSE
;
249 (*a
)->data
.desktopdir
.wrap
= TRUE
;
252 void setup_action_cycle_windows_next(ObAction
**a
, ObUserAction uact
)
254 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
255 (*a
)->data
.cycle
.linear
= FALSE
;
256 (*a
)->data
.cycle
.forward
= TRUE
;
259 void setup_action_cycle_windows_previous(ObAction
**a
, ObUserAction uact
)
261 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
262 (*a
)->data
.cycle
.linear
= FALSE
;
263 (*a
)->data
.cycle
.forward
= FALSE
;
266 void setup_action_movetoedge_north(ObAction
**a
, ObUserAction uact
)
268 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
269 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
272 void setup_action_movetoedge_south(ObAction
**a
, ObUserAction uact
)
274 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
275 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
278 void setup_action_movetoedge_east(ObAction
**a
, ObUserAction uact
)
280 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
281 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
284 void setup_action_movetoedge_west(ObAction
**a
, ObUserAction uact
)
286 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
287 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
290 void setup_action_growtoedge_north(ObAction
**a
, ObUserAction uact
)
292 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
293 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
296 void setup_action_growtoedge_south(ObAction
**a
, ObUserAction uact
)
298 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
299 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
302 void setup_action_growtoedge_east(ObAction
**a
, ObUserAction uact
)
304 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
305 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
308 void setup_action_growtoedge_west(ObAction
**a
, ObUserAction uact
)
310 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
311 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
314 void setup_action_top_layer(ObAction
**a
, ObUserAction uact
)
316 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
317 (*a
)->data
.layer
.layer
= 1;
320 void setup_action_normal_layer(ObAction
**a
, ObUserAction uact
)
322 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
323 (*a
)->data
.layer
.layer
= 0;
326 void setup_action_bottom_layer(ObAction
**a
, ObUserAction uact
)
328 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
329 (*a
)->data
.layer
.layer
= -1;
332 void setup_action_move(ObAction
**a
, ObUserAction uact
)
334 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
335 (*a
)->data
.moveresize
.move
= TRUE
;
336 (*a
)->data
.moveresize
.keyboard
=
337 (uact
== OB_USER_ACTION_KEYBOARD_KEY
||
338 uact
== OB_USER_ACTION_MENU_SELECTION
);
341 void setup_action_resize(ObAction
**a
, ObUserAction uact
)
343 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
344 (*a
)->data
.moveresize
.move
= FALSE
;
345 (*a
)->data
.moveresize
.keyboard
=
346 (uact
== OB_USER_ACTION_KEYBOARD_KEY
||
347 uact
== OB_USER_ACTION_MENU_SELECTION
);
350 void setup_action_showmenu(ObAction
**a
, ObUserAction uact
)
352 (*a
)->data
.showmenu
.any
.client_action
= OB_CLIENT_ACTION_OPTIONAL
;
353 /* you cannot call ShowMenu from inside a menu, cuz the menu code makes
354 assumptions that there is only one menu (and submenus) open at
356 if (uact
== OB_USER_ACTION_MENU_SELECTION
) {
362 void setup_client_action(ObAction
**a
, ObUserAction uact
)
364 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
367 ActionString actionstrings
[] =
375 "directionalfocusnorth",
376 action_directional_focus
,
377 setup_action_directional_focus_north
380 "directionalfocuseast",
381 action_directional_focus
,
382 setup_action_directional_focus_east
385 "directionalfocussouth",
386 action_directional_focus
,
387 setup_action_directional_focus_south
390 "directionalfocuswest",
391 action_directional_focus
,
392 setup_action_directional_focus_west
395 "directionalfocusnortheast",
396 action_directional_focus
,
397 setup_action_directional_focus_northeast
400 "directionalfocussoutheast",
401 action_directional_focus
,
402 setup_action_directional_focus_southeast
405 "directionalfocussouthwest",
406 action_directional_focus
,
407 setup_action_directional_focus_southwest
410 "directionalfocusnorthwest",
411 action_directional_focus
,
412 setup_action_directional_focus_northwest
486 action_toggle_omnipresent
,
491 action_move_relative_horz
,
496 action_move_relative_vert
,
500 "resizerelativehorz",
501 action_resize_relative_horz
,
505 "resizerelativevert",
506 action_resize_relative_vert
,
511 action_maximize_full
,
516 action_unmaximize_full
,
520 "togglemaximizefull",
521 action_toggle_maximize_full
,
526 action_maximize_horz
,
531 action_unmaximize_horz
,
535 "togglemaximizehorz",
536 action_toggle_maximize_horz
,
541 action_maximize_vert
,
546 action_unmaximize_vert
,
550 "togglemaximizevert",
551 action_toggle_maximize_vert
,
556 action_send_to_desktop
,
557 setup_action_send_to_desktop
561 action_send_to_desktop_dir
,
562 setup_action_send_to_desktop_next
565 "sendtodesktopprevious",
566 action_send_to_desktop_dir
,
567 setup_action_send_to_desktop_prev
570 "sendtodesktopright",
571 action_send_to_desktop_dir
,
572 setup_action_send_to_desktop_right
576 action_send_to_desktop_dir
,
577 setup_action_send_to_desktop_left
581 action_send_to_desktop_dir
,
582 setup_action_send_to_desktop_up
586 action_send_to_desktop_dir
,
587 setup_action_send_to_desktop_down
597 setup_action_desktop_next
602 setup_action_desktop_prev
607 setup_action_desktop_right
612 setup_action_desktop_left
617 setup_action_desktop_up
622 setup_action_desktop_down
626 action_toggle_decorations
,
641 action_toggle_show_desktop
,
651 action_unshow_desktop
,
677 setup_action_showmenu
681 action_send_to_layer
,
682 setup_action_top_layer
687 setup_action_top_layer
691 action_send_to_layer
,
692 setup_action_normal_layer
696 action_send_to_layer
,
697 setup_action_bottom_layer
700 "togglealwaysonbottom",
702 setup_action_bottom_layer
706 action_cycle_windows
,
707 setup_action_cycle_windows_next
711 action_cycle_windows
,
712 setup_action_cycle_windows_previous
717 setup_action_movetoedge_north
722 setup_action_movetoedge_south
727 setup_action_movetoedge_west
732 setup_action_movetoedge_east
737 setup_action_growtoedge_north
742 setup_action_growtoedge_south
747 setup_action_growtoedge_west
752 setup_action_growtoedge_east
761 ObAction
*action_from_string(const gchar
*name
, ObUserAction uact
)
764 gboolean exist
= FALSE
;
767 for (i
= 0; actionstrings
[i
].name
; i
++)
768 if (!g_ascii_strcasecmp(name
, actionstrings
[i
].name
)) {
770 a
= action_new(actionstrings
[i
].func
, uact
);
771 if (actionstrings
[i
].setup
)
772 actionstrings
[i
].setup(&a
, uact
);
773 /* only key bindings can be interactive. thus saith the xor. */
774 if (uact
!= OB_USER_ACTION_KEYBOARD_KEY
)
775 a
->data
.any
.interactive
= FALSE
;
779 g_warning("Invalid action '%s' requested. No such action exists.",
782 g_warning("Invalid use of action '%s'. Action will be ignored.", name
);
786 ObAction
*action_parse(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
790 ObAction
*act
= NULL
;
793 if (parse_attr_string("name", node
, &actname
)) {
794 if ((act
= action_from_string(actname
, uact
))) {
795 if (act
->func
== action_execute
|| act
->func
== action_restart
) {
796 if ((n
= parse_find_node("execute", node
->xmlChildrenNode
))) {
797 gchar
*s
= parse_string(doc
, n
);
798 act
->data
.execute
.path
= parse_expand_tilde(s
);
801 } else if (act
->func
== action_showmenu
) {
802 if ((n
= parse_find_node("menu", node
->xmlChildrenNode
)))
803 act
->data
.showmenu
.name
= parse_string(doc
, n
);
804 } else if (act
->func
== action_move_relative_horz
||
805 act
->func
== action_move_relative_vert
||
806 act
->func
== action_resize_relative_horz
||
807 act
->func
== action_resize_relative_vert
) {
808 if ((n
= parse_find_node("delta", node
->xmlChildrenNode
)))
809 act
->data
.relative
.delta
= parse_int(doc
, n
);
810 } else if (act
->func
== action_desktop
) {
811 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
812 act
->data
.desktop
.desk
= parse_int(doc
, n
);
813 if (act
->data
.desktop
.desk
> 0) act
->data
.desktop
.desk
--;
814 } else if (act
->func
== action_send_to_desktop
) {
815 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
816 act
->data
.sendto
.desk
= parse_int(doc
, n
);
817 if (act
->data
.sendto
.desk
> 0) act
->data
.sendto
.desk
--;
818 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
819 act
->data
.sendto
.follow
= parse_bool(doc
, n
);
820 } else if (act
->func
== action_desktop_dir
) {
821 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
822 act
->data
.desktopdir
.wrap
= parse_bool(doc
, n
);
823 } else if (act
->func
== action_send_to_desktop_dir
) {
824 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
825 act
->data
.sendtodir
.wrap
= parse_bool(doc
, n
);
826 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
827 act
->data
.sendtodir
.follow
= parse_bool(doc
, n
);
828 } else if (act
->func
== action_activate
) {
829 if ((n
= parse_find_node("here", node
->xmlChildrenNode
)))
830 act
->data
.activate
.here
= parse_bool(doc
, n
);
831 } else if (act
->func
== action_cycle_windows
) {
832 if ((n
= parse_find_node("linear", node
->xmlChildrenNode
)))
833 act
->data
.cycle
.linear
= parse_bool(doc
, n
);
841 void action_run_list(GSList
*acts
, ObClient
*c
, ObFrameContext context
,
842 guint state
, guint button
, gint x
, gint y
,
843 gboolean cancel
, gboolean done
)
847 gboolean inter
= FALSE
;
853 screen_pointer_pos(&x
, &y
);
855 if (grab_on_keyboard())
858 for (it
= acts
; it
; it
= g_slist_next(it
)) {
860 if (a
->data
.any
.interactive
) {
867 /* sometimes when we execute another app as an action,
868 it won't work right unless we XUngrabKeyboard first,
869 even though we grabbed the key/button Asychronously.
870 e.g. "gnome-panel-control --main-menu" */
871 XUngrabKeyboard(ob_display
, event_lasttime
);
874 for (it
= acts
; it
; it
= g_slist_next(it
)) {
877 if (!(a
->data
.any
.client_action
== OB_CLIENT_ACTION_ALWAYS
&& !c
)) {
878 a
->data
.any
.c
= a
->data
.any
.client_action
? c
: NULL
;
879 a
->data
.any
.context
= context
;
883 a
->data
.any
.button
= button
;
885 if (a
->data
.any
.interactive
) {
886 a
->data
.inter
.cancel
= cancel
;
887 a
->data
.inter
.final
= done
;
888 if (!(cancel
|| done
))
889 keyboard_interactive_grab(state
, a
->data
.any
.c
, a
);
897 void action_execute(union ActionData
*data
)
901 if (data
->execute
.path
) {
902 cmd
= g_filename_from_utf8(data
->execute
.path
, -1, NULL
, NULL
, NULL
);
904 if (!g_spawn_command_line_async(cmd
, &e
)) {
905 g_warning("failed to execute '%s': %s",
910 g_warning("failed to convert '%s' from utf8", data
->execute
.path
);
915 void action_activate(union ActionData
*data
)
917 client_activate(data
->activate
.any
.c
, data
->activate
.here
);
920 void action_focus(union ActionData
*data
)
922 client_focus(data
->client
.any
.c
);
925 void action_unfocus (union ActionData
*data
)
927 client_unfocus(data
->client
.any
.c
);
930 void action_iconify(union ActionData
*data
)
932 client_iconify(data
->client
.any
.c
, TRUE
, TRUE
);
935 void action_raiselower(union ActionData
*data
)
937 ObClient
*c
= data
->client
.any
.c
;
939 gboolean raise
= FALSE
;
941 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
942 ObClient
*cit
= it
->data
;
945 if (client_normal(cit
) == client_normal(c
) &&
946 cit
->layer
== c
->layer
&&
949 if (RECT_INTERSECTS_RECT(cit
->frame
->area
, c
->frame
->area
)) {
957 client_action_start(data
);
958 stacking_raise(CLIENT_AS_WINDOW(c
));
959 client_action_end(data
);
961 client_action_start(data
);
962 stacking_lower(CLIENT_AS_WINDOW(c
));
963 client_action_end(data
);
967 void action_raise(union ActionData
*data
)
969 client_action_start(data
);
970 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
971 client_action_end(data
);
974 void action_unshaderaise(union ActionData
*data
)
976 if (data
->client
.any
.c
->shaded
) {
977 client_action_start(data
);
978 client_shade(data
->client
.any
.c
, FALSE
);
979 client_action_end(data
);
981 client_action_start(data
);
982 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
983 client_action_end(data
);
987 void action_shadelower(union ActionData
*data
)
989 if (data
->client
.any
.c
->shaded
)
990 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
992 client_action_start(data
);
993 client_shade(data
->client
.any
.c
, TRUE
);
994 client_action_end(data
);
998 void action_lower(union ActionData
*data
)
1000 client_action_start(data
);
1001 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1002 client_action_end(data
);
1005 void action_close(union ActionData
*data
)
1007 client_close(data
->client
.any
.c
);
1010 void action_kill(union ActionData
*data
)
1012 client_kill(data
->client
.any
.c
);
1015 void action_shade(union ActionData
*data
)
1017 client_action_start(data
);
1018 client_shade(data
->client
.any
.c
, TRUE
);
1019 client_action_end(data
);
1022 void action_unshade(union ActionData
*data
)
1024 client_action_start(data
);
1025 client_shade(data
->client
.any
.c
, FALSE
);
1026 client_action_end(data
);
1029 void action_toggle_shade(union ActionData
*data
)
1031 client_action_start(data
);
1032 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1033 client_action_end(data
);
1036 void action_toggle_omnipresent(union ActionData
*data
)
1038 client_set_desktop(data
->client
.any
.c
,
1039 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1040 screen_desktop
: DESKTOP_ALL
, FALSE
);
1043 void action_move_relative_horz(union ActionData
*data
)
1045 ObClient
*c
= data
->relative
.any
.c
;
1046 client_action_start(data
);
1047 client_move(c
, c
->area
.x
+ data
->relative
.delta
, c
->area
.y
);
1048 client_action_end(data
);
1051 void action_move_relative_vert(union ActionData
*data
)
1053 ObClient
*c
= data
->relative
.any
.c
;
1054 client_action_start(data
);
1055 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.delta
);
1056 client_action_end(data
);
1059 void action_resize_relative_horz(union ActionData
*data
)
1061 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
);
1069 void action_resize_relative_vert(union ActionData
*data
)
1071 ObClient
*c
= data
->relative
.any
.c
;
1073 client_action_start(data
);
1074 client_resize(c
, c
->area
.width
, c
->area
.height
+
1075 data
->relative
.delta
* c
->size_inc
.height
);
1076 client_action_end(data
);
1080 void action_maximize_full(union ActionData
*data
)
1082 client_action_start(data
);
1083 client_maximize(data
->client
.any
.c
, TRUE
, 0, TRUE
);
1084 client_action_end(data
);
1087 void action_unmaximize_full(union ActionData
*data
)
1089 client_action_start(data
);
1090 client_maximize(data
->client
.any
.c
, FALSE
, 0, TRUE
);
1091 client_action_end(data
);
1094 void action_toggle_maximize_full(union ActionData
*data
)
1096 client_action_start(data
);
1097 client_maximize(data
->client
.any
.c
,
1098 !(data
->client
.any
.c
->max_horz
||
1099 data
->client
.any
.c
->max_vert
),
1101 client_action_end(data
);
1104 void action_maximize_horz(union ActionData
*data
)
1106 client_action_start(data
);
1107 client_maximize(data
->client
.any
.c
, TRUE
, 1, TRUE
);
1108 client_action_end(data
);
1111 void action_unmaximize_horz(union ActionData
*data
)
1113 client_action_start(data
);
1114 client_maximize(data
->client
.any
.c
, FALSE
, 1, TRUE
);
1115 client_action_end(data
);
1118 void action_toggle_maximize_horz(union ActionData
*data
)
1120 client_action_start(data
);
1121 client_maximize(data
->client
.any
.c
,
1122 !data
->client
.any
.c
->max_horz
, 1, TRUE
);
1123 client_action_end(data
);
1126 void action_maximize_vert(union ActionData
*data
)
1128 client_action_start(data
);
1129 client_maximize(data
->client
.any
.c
, TRUE
, 2, TRUE
);
1130 client_action_end(data
);
1133 void action_unmaximize_vert(union ActionData
*data
)
1135 client_action_start(data
);
1136 client_maximize(data
->client
.any
.c
, FALSE
, 2, TRUE
);
1137 client_action_end(data
);
1140 void action_toggle_maximize_vert(union ActionData
*data
)
1142 client_action_start(data
);
1143 client_maximize(data
->client
.any
.c
,
1144 !data
->client
.any
.c
->max_vert
, 2, TRUE
);
1145 client_action_end(data
);
1148 void action_send_to_desktop(union ActionData
*data
)
1150 ObClient
*c
= data
->sendto
.any
.c
;
1152 if (!client_normal(c
)) return;
1154 if (data
->sendto
.desk
< screen_num_desktops
||
1155 data
->sendto
.desk
== DESKTOP_ALL
) {
1156 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
);
1157 if (data
->sendto
.follow
)
1158 screen_set_desktop(data
->sendto
.desk
);
1162 void action_desktop(union ActionData
*data
)
1164 if (data
->desktop
.desk
< screen_num_desktops
||
1165 data
->desktop
.desk
== DESKTOP_ALL
)
1166 screen_set_desktop(data
->desktop
.desk
);
1169 void action_desktop_dir(union ActionData
*data
)
1173 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1174 data
->desktopdir
.wrap
,
1175 data
->sendtodir
.linear
,
1176 data
->desktopdir
.inter
.any
.interactive
,
1177 data
->desktopdir
.inter
.final
,
1178 data
->desktopdir
.inter
.cancel
);
1179 if (!data
->sendtodir
.inter
.any
.interactive
||
1180 !data
->sendtodir
.inter
.final
)
1182 screen_set_desktop(d
);
1186 void action_send_to_desktop_dir(union ActionData
*data
)
1188 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1191 if (!client_normal(c
)) return;
1193 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1194 data
->sendtodir
.linear
,
1195 data
->sendtodir
.inter
.any
.interactive
,
1196 data
->sendtodir
.inter
.final
,
1197 data
->sendtodir
.inter
.cancel
);
1198 if (!data
->sendtodir
.inter
.any
.interactive
||
1199 !data
->sendtodir
.inter
.final
)
1201 client_set_desktop(c
, d
, data
->sendtodir
.follow
);
1202 if (data
->sendtodir
.follow
)
1203 screen_set_desktop(d
);
1207 void action_desktop_last(union ActionData
*data
)
1209 screen_set_desktop(screen_last_desktop
);
1212 void action_toggle_decorations(union ActionData
*data
)
1214 ObClient
*c
= data
->client
.any
.c
;
1216 client_action_start(data
);
1217 client_set_undecorated(c
, !c
->undecorated
);
1218 client_action_end(data
);
1221 static guint32
pick_corner(int x
, int y
, int cx
, int cy
, int cw
, int ch
)
1223 if (x
- cx
> cw
/ 2) {
1224 if (y
- cy
> ch
/ 2)
1225 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1227 return prop_atoms
.net_wm_moveresize_size_topright
;
1229 if (y
- cy
> ch
/ 2)
1230 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1232 return prop_atoms
.net_wm_moveresize_size_topleft
;
1236 void action_moveresize(union ActionData
*data
)
1238 ObClient
*c
= data
->moveresize
.any
.c
;
1241 if (!client_normal(c
)) return;
1243 if (data
->moveresize
.keyboard
) {
1244 corner
= (data
->moveresize
.move
?
1245 prop_atoms
.net_wm_moveresize_move_keyboard
:
1246 prop_atoms
.net_wm_moveresize_size_keyboard
);
1248 corner
= (data
->moveresize
.move
?
1249 prop_atoms
.net_wm_moveresize_move
:
1250 pick_corner(data
->any
.x
, data
->any
.y
,
1251 c
->frame
->area
.x
, c
->frame
->area
.y
,
1252 /* use the client size because the frame
1253 can be differently sized (shaded
1254 windows) and we want this based on the
1256 c
->area
.width
+ c
->frame
->size
.left
+
1257 c
->frame
->size
.right
,
1258 c
->area
.height
+ c
->frame
->size
.top
+
1259 c
->frame
->size
.bottom
));
1262 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1265 void action_reconfigure(union ActionData
*data
)
1270 void action_restart(union ActionData
*data
)
1272 ob_restart_other(data
->execute
.path
);
1275 void action_exit(union ActionData
*data
)
1280 void action_showmenu(union ActionData
*data
)
1282 if (data
->showmenu
.name
) {
1283 menu_show(data
->showmenu
.name
, data
->any
.x
, data
->any
.y
,
1284 data
->showmenu
.any
.c
);
1288 void action_cycle_windows(union ActionData
*data
)
1290 focus_cycle(data
->cycle
.forward
, data
->cycle
.linear
,
1291 data
->cycle
.inter
.any
.interactive
,
1292 data
->cycle
.inter
.final
, data
->cycle
.inter
.cancel
);
1295 void action_directional_focus(union ActionData
*data
)
1297 focus_directional_cycle(data
->interdiraction
.direction
,
1298 data
->interdiraction
.inter
.any
.interactive
,
1299 data
->interdiraction
.inter
.final
,
1300 data
->interdiraction
.inter
.cancel
);
1303 void action_movetoedge(union ActionData
*data
)
1306 ObClient
*c
= data
->diraction
.any
.c
;
1308 x
= c
->frame
->area
.x
;
1309 y
= c
->frame
->area
.y
;
1311 switch(data
->diraction
.direction
) {
1312 case OB_DIRECTION_NORTH
:
1313 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
);
1315 case OB_DIRECTION_WEST
:
1316 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
);
1318 case OB_DIRECTION_SOUTH
:
1319 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
) -
1320 c
->frame
->area
.height
;
1322 case OB_DIRECTION_EAST
:
1323 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
) -
1324 c
->frame
->area
.width
;
1327 g_assert_not_reached();
1329 frame_frame_gravity(c
->frame
, &x
, &y
);
1330 client_action_start(data
);
1331 client_move(c
, x
, y
);
1332 client_action_end(data
);
1335 void action_growtoedge(union ActionData
*data
)
1337 int x
, y
, width
, height
, dest
;
1338 ObClient
*c
= data
->diraction
.any
.c
;
1341 a
= screen_area(c
->desktop
);
1342 x
= c
->frame
->area
.x
;
1343 y
= c
->frame
->area
.y
;
1344 width
= c
->frame
->area
.width
;
1345 height
= c
->frame
->area
.height
;
1347 switch(data
->diraction
.direction
) {
1348 case OB_DIRECTION_NORTH
:
1349 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
);
1351 height
= c
->frame
->area
.height
/ 2;
1353 height
= c
->frame
->area
.y
+ c
->frame
->area
.height
- dest
;
1357 case OB_DIRECTION_WEST
:
1358 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
);
1360 width
= c
->frame
->area
.width
/ 2;
1362 width
= c
->frame
->area
.x
+ c
->frame
->area
.width
- dest
;
1366 case OB_DIRECTION_SOUTH
:
1367 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
);
1368 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1369 height
= c
->frame
->area
.height
/ 2;
1370 y
= a
->y
+ a
->height
- height
;
1372 height
= dest
- c
->frame
->area
.y
;
1373 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1374 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1376 case OB_DIRECTION_EAST
:
1377 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
);
1378 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1379 width
= c
->frame
->area
.width
/ 2;
1380 x
= a
->x
+ a
->width
- width
;
1382 width
= dest
- c
->frame
->area
.x
;
1383 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1384 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1387 g_assert_not_reached();
1389 frame_frame_gravity(c
->frame
, &x
, &y
);
1390 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1391 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1392 client_action_start(data
);
1393 client_move_resize(c
, x
, y
, width
, height
);
1394 client_action_end(data
);
1397 void action_send_to_layer(union ActionData
*data
)
1399 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1402 void action_toggle_layer(union ActionData
*data
)
1404 ObClient
*c
= data
->layer
.any
.c
;
1406 client_action_start(data
);
1407 if (data
->layer
.layer
< 0)
1408 client_set_layer(c
, c
->below
? 0 : -1);
1409 else if (data
->layer
.layer
> 0)
1410 client_set_layer(c
, c
->above
? 0 : 1);
1411 client_action_end(data
);
1414 void action_toggle_show_desktop(union ActionData
*data
)
1416 screen_show_desktop(!screen_showing_desktop
);
1419 void action_show_desktop(union ActionData
*data
)
1421 screen_show_desktop(TRUE
);
1424 void action_unshow_desktop(union ActionData
*data
)
1426 screen_show_desktop(FALSE
);