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
&&
947 cit
->frame
->visible
&&
948 !client_search_transient(c
, cit
))
950 if (RECT_INTERSECTS_RECT(cit
->frame
->area
, c
->frame
->area
)) {
958 client_action_start(data
);
959 stacking_raise(CLIENT_AS_WINDOW(c
));
960 client_action_end(data
);
962 client_action_start(data
);
963 stacking_lower(CLIENT_AS_WINDOW(c
));
964 client_action_end(data
);
968 void action_raise(union ActionData
*data
)
970 client_action_start(data
);
971 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
972 client_action_end(data
);
975 void action_unshaderaise(union ActionData
*data
)
977 if (data
->client
.any
.c
->shaded
) {
978 client_action_start(data
);
979 client_shade(data
->client
.any
.c
, FALSE
);
980 client_action_end(data
);
982 client_action_start(data
);
983 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
984 client_action_end(data
);
988 void action_shadelower(union ActionData
*data
)
990 if (data
->client
.any
.c
->shaded
)
991 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
993 client_action_start(data
);
994 client_shade(data
->client
.any
.c
, TRUE
);
995 client_action_end(data
);
999 void action_lower(union ActionData
*data
)
1001 client_action_start(data
);
1002 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1003 client_action_end(data
);
1006 void action_close(union ActionData
*data
)
1008 client_close(data
->client
.any
.c
);
1011 void action_kill(union ActionData
*data
)
1013 client_kill(data
->client
.any
.c
);
1016 void action_shade(union ActionData
*data
)
1018 client_action_start(data
);
1019 client_shade(data
->client
.any
.c
, TRUE
);
1020 client_action_end(data
);
1023 void action_unshade(union ActionData
*data
)
1025 client_action_start(data
);
1026 client_shade(data
->client
.any
.c
, FALSE
);
1027 client_action_end(data
);
1030 void action_toggle_shade(union ActionData
*data
)
1032 client_action_start(data
);
1033 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1034 client_action_end(data
);
1037 void action_toggle_omnipresent(union ActionData
*data
)
1039 client_set_desktop(data
->client
.any
.c
,
1040 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1041 screen_desktop
: DESKTOP_ALL
, FALSE
);
1044 void action_move_relative_horz(union ActionData
*data
)
1046 ObClient
*c
= data
->relative
.any
.c
;
1047 client_action_start(data
);
1048 client_move(c
, c
->area
.x
+ data
->relative
.delta
, c
->area
.y
);
1049 client_action_end(data
);
1052 void action_move_relative_vert(union ActionData
*data
)
1054 ObClient
*c
= data
->relative
.any
.c
;
1055 client_action_start(data
);
1056 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.delta
);
1057 client_action_end(data
);
1060 void action_resize_relative_horz(union ActionData
*data
)
1062 ObClient
*c
= data
->relative
.any
.c
;
1063 client_action_start(data
);
1065 c
->area
.width
+ data
->relative
.delta
* c
->size_inc
.width
,
1067 client_action_end(data
);
1070 void action_resize_relative_vert(union ActionData
*data
)
1072 ObClient
*c
= data
->relative
.any
.c
;
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 client_action_start(data
);
1084 client_maximize(data
->client
.any
.c
, TRUE
, 0, TRUE
);
1085 client_action_end(data
);
1088 void action_unmaximize_full(union ActionData
*data
)
1090 client_action_start(data
);
1091 client_maximize(data
->client
.any
.c
, FALSE
, 0, TRUE
);
1092 client_action_end(data
);
1095 void action_toggle_maximize_full(union ActionData
*data
)
1097 client_action_start(data
);
1098 client_maximize(data
->client
.any
.c
,
1099 !(data
->client
.any
.c
->max_horz
||
1100 data
->client
.any
.c
->max_vert
),
1102 client_action_end(data
);
1105 void action_maximize_horz(union ActionData
*data
)
1107 client_action_start(data
);
1108 client_maximize(data
->client
.any
.c
, TRUE
, 1, TRUE
);
1109 client_action_end(data
);
1112 void action_unmaximize_horz(union ActionData
*data
)
1114 client_action_start(data
);
1115 client_maximize(data
->client
.any
.c
, FALSE
, 1, TRUE
);
1116 client_action_end(data
);
1119 void action_toggle_maximize_horz(union ActionData
*data
)
1121 client_action_start(data
);
1122 client_maximize(data
->client
.any
.c
,
1123 !data
->client
.any
.c
->max_horz
, 1, TRUE
);
1124 client_action_end(data
);
1127 void action_maximize_vert(union ActionData
*data
)
1129 client_action_start(data
);
1130 client_maximize(data
->client
.any
.c
, TRUE
, 2, TRUE
);
1131 client_action_end(data
);
1134 void action_unmaximize_vert(union ActionData
*data
)
1136 client_action_start(data
);
1137 client_maximize(data
->client
.any
.c
, FALSE
, 2, TRUE
);
1138 client_action_end(data
);
1141 void action_toggle_maximize_vert(union ActionData
*data
)
1143 client_action_start(data
);
1144 client_maximize(data
->client
.any
.c
,
1145 !data
->client
.any
.c
->max_vert
, 2, TRUE
);
1146 client_action_end(data
);
1149 void action_send_to_desktop(union ActionData
*data
)
1151 ObClient
*c
= data
->sendto
.any
.c
;
1153 if (!client_normal(c
)) return;
1155 if (data
->sendto
.desk
< screen_num_desktops
||
1156 data
->sendto
.desk
== DESKTOP_ALL
) {
1157 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
);
1158 if (data
->sendto
.follow
)
1159 screen_set_desktop(data
->sendto
.desk
);
1163 void action_desktop(union ActionData
*data
)
1165 if (data
->desktop
.desk
< screen_num_desktops
||
1166 data
->desktop
.desk
== DESKTOP_ALL
)
1167 screen_set_desktop(data
->desktop
.desk
);
1170 void action_desktop_dir(union ActionData
*data
)
1174 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1175 data
->desktopdir
.wrap
,
1176 data
->sendtodir
.linear
,
1177 data
->desktopdir
.inter
.any
.interactive
,
1178 data
->desktopdir
.inter
.final
,
1179 data
->desktopdir
.inter
.cancel
);
1180 if (!data
->sendtodir
.inter
.any
.interactive
||
1181 !data
->sendtodir
.inter
.final
)
1183 screen_set_desktop(d
);
1187 void action_send_to_desktop_dir(union ActionData
*data
)
1189 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1192 if (!client_normal(c
)) return;
1194 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1195 data
->sendtodir
.linear
,
1196 data
->sendtodir
.inter
.any
.interactive
,
1197 data
->sendtodir
.inter
.final
,
1198 data
->sendtodir
.inter
.cancel
);
1199 if (!data
->sendtodir
.inter
.any
.interactive
||
1200 !data
->sendtodir
.inter
.final
)
1202 client_set_desktop(c
, d
, data
->sendtodir
.follow
);
1203 if (data
->sendtodir
.follow
)
1204 screen_set_desktop(d
);
1208 void action_desktop_last(union ActionData
*data
)
1210 screen_set_desktop(screen_last_desktop
);
1213 void action_toggle_decorations(union ActionData
*data
)
1215 ObClient
*c
= data
->client
.any
.c
;
1217 client_action_start(data
);
1218 client_set_undecorated(c
, !c
->undecorated
);
1219 client_action_end(data
);
1222 static guint32
pick_corner(int x
, int y
, int cx
, int cy
, int cw
, int ch
)
1224 if (x
- cx
> cw
/ 2) {
1225 if (y
- cy
> ch
/ 2)
1226 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1228 return prop_atoms
.net_wm_moveresize_size_topright
;
1230 if (y
- cy
> ch
/ 2)
1231 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1233 return prop_atoms
.net_wm_moveresize_size_topleft
;
1237 void action_moveresize(union ActionData
*data
)
1239 ObClient
*c
= data
->moveresize
.any
.c
;
1242 if (!client_normal(c
)) return;
1244 if (data
->moveresize
.keyboard
) {
1245 corner
= (data
->moveresize
.move
?
1246 prop_atoms
.net_wm_moveresize_move_keyboard
:
1247 prop_atoms
.net_wm_moveresize_size_keyboard
);
1249 corner
= (data
->moveresize
.move
?
1250 prop_atoms
.net_wm_moveresize_move
:
1251 pick_corner(data
->any
.x
, data
->any
.y
,
1252 c
->frame
->area
.x
, c
->frame
->area
.y
,
1253 /* use the client size because the frame
1254 can be differently sized (shaded
1255 windows) and we want this based on the
1257 c
->area
.width
+ c
->frame
->size
.left
+
1258 c
->frame
->size
.right
,
1259 c
->area
.height
+ c
->frame
->size
.top
+
1260 c
->frame
->size
.bottom
));
1263 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1266 void action_reconfigure(union ActionData
*data
)
1271 void action_restart(union ActionData
*data
)
1273 ob_restart_other(data
->execute
.path
);
1276 void action_exit(union ActionData
*data
)
1281 void action_showmenu(union ActionData
*data
)
1283 if (data
->showmenu
.name
) {
1284 menu_show(data
->showmenu
.name
, data
->any
.x
, data
->any
.y
,
1285 data
->showmenu
.any
.c
);
1289 void action_cycle_windows(union ActionData
*data
)
1291 focus_cycle(data
->cycle
.forward
, data
->cycle
.linear
,
1292 data
->cycle
.inter
.any
.interactive
,
1293 data
->cycle
.inter
.final
, data
->cycle
.inter
.cancel
);
1296 void action_directional_focus(union ActionData
*data
)
1298 focus_directional_cycle(data
->interdiraction
.direction
,
1299 data
->interdiraction
.inter
.any
.interactive
,
1300 data
->interdiraction
.inter
.final
,
1301 data
->interdiraction
.inter
.cancel
);
1304 void action_movetoedge(union ActionData
*data
)
1307 ObClient
*c
= data
->diraction
.any
.c
;
1309 x
= c
->frame
->area
.x
;
1310 y
= c
->frame
->area
.y
;
1312 switch(data
->diraction
.direction
) {
1313 case OB_DIRECTION_NORTH
:
1314 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
);
1316 case OB_DIRECTION_WEST
:
1317 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
);
1319 case OB_DIRECTION_SOUTH
:
1320 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
) -
1321 c
->frame
->area
.height
;
1323 case OB_DIRECTION_EAST
:
1324 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
) -
1325 c
->frame
->area
.width
;
1328 g_assert_not_reached();
1330 frame_frame_gravity(c
->frame
, &x
, &y
);
1331 client_action_start(data
);
1332 client_move(c
, x
, y
);
1333 client_action_end(data
);
1336 void action_growtoedge(union ActionData
*data
)
1338 int x
, y
, width
, height
, dest
;
1339 ObClient
*c
= data
->diraction
.any
.c
;
1342 a
= screen_area(c
->desktop
);
1343 x
= c
->frame
->area
.x
;
1344 y
= c
->frame
->area
.y
;
1345 width
= c
->frame
->area
.width
;
1346 height
= c
->frame
->area
.height
;
1348 switch(data
->diraction
.direction
) {
1349 case OB_DIRECTION_NORTH
:
1350 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
);
1352 height
= c
->frame
->area
.height
/ 2;
1354 height
= c
->frame
->area
.y
+ c
->frame
->area
.height
- dest
;
1358 case OB_DIRECTION_WEST
:
1359 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
);
1361 width
= c
->frame
->area
.width
/ 2;
1363 width
= c
->frame
->area
.x
+ c
->frame
->area
.width
- dest
;
1367 case OB_DIRECTION_SOUTH
:
1368 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
);
1369 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1370 height
= c
->frame
->area
.height
/ 2;
1371 y
= a
->y
+ a
->height
- height
;
1373 height
= dest
- c
->frame
->area
.y
;
1374 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1375 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1377 case OB_DIRECTION_EAST
:
1378 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
);
1379 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1380 width
= c
->frame
->area
.width
/ 2;
1381 x
= a
->x
+ a
->width
- width
;
1383 width
= dest
- c
->frame
->area
.x
;
1384 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1385 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1388 g_assert_not_reached();
1390 frame_frame_gravity(c
->frame
, &x
, &y
);
1391 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1392 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1393 client_action_start(data
);
1394 client_move_resize(c
, x
, y
, width
, height
);
1395 client_action_end(data
);
1398 void action_send_to_layer(union ActionData
*data
)
1400 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1403 void action_toggle_layer(union ActionData
*data
)
1405 ObClient
*c
= data
->layer
.any
.c
;
1407 client_action_start(data
);
1408 if (data
->layer
.layer
< 0)
1409 client_set_layer(c
, c
->below
? 0 : -1);
1410 else if (data
->layer
.layer
> 0)
1411 client_set_layer(c
, c
->above
? 0 : 1);
1412 client_action_end(data
);
1415 void action_toggle_show_desktop(union ActionData
*data
)
1417 screen_show_desktop(!screen_showing_desktop
);
1420 void action_show_desktop(union ActionData
*data
)
1422 screen_show_desktop(TRUE
);
1425 void action_unshow_desktop(union ActionData
*data
)
1427 screen_show_desktop(FALSE
);