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
))
70 ObAction
*a
= g_new0(ObAction
, 1);
77 void action_ref(ObAction
*a
)
82 void action_unref(ObAction
*a
)
84 if (a
== NULL
) return;
86 if (--a
->ref
> 0) return;
88 /* deal with pointers */
89 if (a
->func
== action_execute
|| a
->func
== action_restart
)
90 g_free(a
->data
.execute
.path
);
91 else if (a
->func
== action_showmenu
)
92 g_free(a
->data
.showmenu
.name
);
97 void setup_action_directional_focus_north(ObAction
**a
, ObUserAction uact
)
99 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
100 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTH
;
103 void setup_action_directional_focus_east(ObAction
**a
, ObUserAction uact
)
105 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
106 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_EAST
;
109 void setup_action_directional_focus_south(ObAction
**a
, ObUserAction uact
)
111 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
112 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTH
;
115 void setup_action_directional_focus_west(ObAction
**a
, ObUserAction uact
)
117 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
118 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_WEST
;
121 void setup_action_directional_focus_northeast(ObAction
**a
, ObUserAction uact
)
123 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
124 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHEAST
;
127 void setup_action_directional_focus_southeast(ObAction
**a
, ObUserAction uact
)
129 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
130 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHEAST
;
133 void setup_action_directional_focus_southwest(ObAction
**a
, ObUserAction uact
)
135 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
136 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHWEST
;
139 void setup_action_directional_focus_northwest(ObAction
**a
, ObUserAction uact
)
141 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
142 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHWEST
;
145 void setup_action_send_to_desktop(ObAction
**a
, ObUserAction uact
)
147 (*a
)->data
.sendto
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
148 (*a
)->data
.sendto
.follow
= TRUE
;
151 void setup_action_send_to_desktop_prev(ObAction
**a
, ObUserAction uact
)
153 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
154 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
155 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
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_next(ObAction
**a
, ObUserAction uact
)
163 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
164 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
165 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
166 (*a
)->data
.sendtodir
.linear
= TRUE
;
167 (*a
)->data
.sendtodir
.wrap
= TRUE
;
168 (*a
)->data
.sendtodir
.follow
= TRUE
;
171 void setup_action_send_to_desktop_left(ObAction
**a
, ObUserAction uact
)
173 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
174 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
175 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
176 (*a
)->data
.sendtodir
.linear
= FALSE
;
177 (*a
)->data
.sendtodir
.wrap
= TRUE
;
178 (*a
)->data
.sendtodir
.follow
= TRUE
;
181 void setup_action_send_to_desktop_right(ObAction
**a
, ObUserAction uact
)
183 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
184 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
185 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
186 (*a
)->data
.sendtodir
.linear
= FALSE
;
187 (*a
)->data
.sendtodir
.wrap
= TRUE
;
188 (*a
)->data
.sendtodir
.follow
= TRUE
;
191 void setup_action_send_to_desktop_up(ObAction
**a
, ObUserAction uact
)
193 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
194 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
195 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_NORTH
;
196 (*a
)->data
.sendtodir
.linear
= FALSE
;
197 (*a
)->data
.sendtodir
.wrap
= TRUE
;
198 (*a
)->data
.sendtodir
.follow
= TRUE
;
201 void setup_action_send_to_desktop_down(ObAction
**a
, ObUserAction uact
)
203 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
204 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
205 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_SOUTH
;
206 (*a
)->data
.sendtodir
.linear
= FALSE
;
207 (*a
)->data
.sendtodir
.wrap
= TRUE
;
208 (*a
)->data
.sendtodir
.follow
= TRUE
;
211 void setup_action_desktop(ObAction
**a
, ObUserAction uact
)
213 (*a
)->data
.desktop
.inter
.any
.interactive
= TRUE
;
216 void setup_action_desktop_prev(ObAction
**a
, ObUserAction uact
)
218 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
219 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
220 (*a
)->data
.desktopdir
.linear
= TRUE
;
221 (*a
)->data
.desktopdir
.wrap
= TRUE
;
224 void setup_action_desktop_next(ObAction
**a
, ObUserAction uact
)
226 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
227 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
228 (*a
)->data
.desktopdir
.linear
= TRUE
;
229 (*a
)->data
.desktopdir
.wrap
= TRUE
;
232 void setup_action_desktop_left(ObAction
**a
, ObUserAction uact
)
234 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
235 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
236 (*a
)->data
.desktopdir
.linear
= FALSE
;
237 (*a
)->data
.desktopdir
.wrap
= TRUE
;
240 void setup_action_desktop_right(ObAction
**a
, ObUserAction uact
)
242 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
243 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
244 (*a
)->data
.desktopdir
.linear
= FALSE
;
245 (*a
)->data
.desktopdir
.wrap
= TRUE
;
248 void setup_action_desktop_up(ObAction
**a
, ObUserAction uact
)
250 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
251 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_NORTH
;
252 (*a
)->data
.desktopdir
.linear
= FALSE
;
253 (*a
)->data
.desktopdir
.wrap
= TRUE
;
256 void setup_action_desktop_down(ObAction
**a
, ObUserAction uact
)
258 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
259 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_SOUTH
;
260 (*a
)->data
.desktopdir
.linear
= FALSE
;
261 (*a
)->data
.desktopdir
.wrap
= TRUE
;
264 void setup_action_cycle_windows_next(ObAction
**a
, ObUserAction uact
)
266 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
267 (*a
)->data
.cycle
.linear
= FALSE
;
268 (*a
)->data
.cycle
.forward
= TRUE
;
271 void setup_action_cycle_windows_previous(ObAction
**a
, ObUserAction uact
)
273 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
274 (*a
)->data
.cycle
.linear
= FALSE
;
275 (*a
)->data
.cycle
.forward
= FALSE
;
278 void setup_action_movetoedge_north(ObAction
**a
, ObUserAction uact
)
280 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
281 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
284 void setup_action_movetoedge_south(ObAction
**a
, ObUserAction uact
)
286 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
287 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
290 void setup_action_movetoedge_east(ObAction
**a
, ObUserAction uact
)
292 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
293 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
296 void setup_action_movetoedge_west(ObAction
**a
, ObUserAction uact
)
298 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
299 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
302 void setup_action_growtoedge_north(ObAction
**a
, ObUserAction uact
)
304 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
305 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
308 void setup_action_growtoedge_south(ObAction
**a
, ObUserAction uact
)
310 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
311 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
314 void setup_action_growtoedge_east(ObAction
**a
, ObUserAction uact
)
316 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
317 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
320 void setup_action_growtoedge_west(ObAction
**a
, ObUserAction uact
)
322 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
323 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
326 void setup_action_top_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_normal_layer(ObAction
**a
, ObUserAction uact
)
334 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
335 (*a
)->data
.layer
.layer
= 0;
338 void setup_action_bottom_layer(ObAction
**a
, ObUserAction uact
)
340 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
341 (*a
)->data
.layer
.layer
= -1;
344 void setup_action_move(ObAction
**a
, ObUserAction uact
)
346 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
347 (*a
)->data
.moveresize
.move
= TRUE
;
348 (*a
)->data
.moveresize
.keyboard
=
349 (uact
== OB_USER_ACTION_KEYBOARD_KEY
||
350 uact
== OB_USER_ACTION_MENU_SELECTION
);
353 void setup_action_resize(ObAction
**a
, ObUserAction uact
)
355 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
356 (*a
)->data
.moveresize
.move
= FALSE
;
357 (*a
)->data
.moveresize
.keyboard
=
358 (uact
== OB_USER_ACTION_KEYBOARD_KEY
||
359 uact
== OB_USER_ACTION_MENU_SELECTION
);
362 void setup_action_showmenu(ObAction
**a
, ObUserAction uact
)
364 (*a
)->data
.showmenu
.any
.client_action
= OB_CLIENT_ACTION_OPTIONAL
;
365 /* you cannot call ShowMenu from inside a menu, cuz the menu code makes
366 assumptions that there is only one menu (and submenus) open at
368 if (uact
== OB_USER_ACTION_MENU_SELECTION
) {
374 void setup_client_action(ObAction
**a
, ObUserAction uact
)
376 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
379 ActionString actionstrings
[] =
387 "directionalfocusnorth",
388 action_directional_focus
,
389 setup_action_directional_focus_north
392 "directionalfocuseast",
393 action_directional_focus
,
394 setup_action_directional_focus_east
397 "directionalfocussouth",
398 action_directional_focus
,
399 setup_action_directional_focus_south
402 "directionalfocuswest",
403 action_directional_focus
,
404 setup_action_directional_focus_west
407 "directionalfocusnortheast",
408 action_directional_focus
,
409 setup_action_directional_focus_northeast
412 "directionalfocussoutheast",
413 action_directional_focus
,
414 setup_action_directional_focus_southeast
417 "directionalfocussouthwest",
418 action_directional_focus
,
419 setup_action_directional_focus_southwest
422 "directionalfocusnorthwest",
423 action_directional_focus
,
424 setup_action_directional_focus_northwest
498 action_toggle_omnipresent
,
503 action_move_relative_horz
,
508 action_move_relative_vert
,
512 "resizerelativehorz",
513 action_resize_relative_horz
,
517 "resizerelativevert",
518 action_resize_relative_vert
,
523 action_maximize_full
,
528 action_unmaximize_full
,
532 "togglemaximizefull",
533 action_toggle_maximize_full
,
538 action_maximize_horz
,
543 action_unmaximize_horz
,
547 "togglemaximizehorz",
548 action_toggle_maximize_horz
,
553 action_maximize_vert
,
558 action_unmaximize_vert
,
562 "togglemaximizevert",
563 action_toggle_maximize_vert
,
568 action_send_to_desktop
,
569 setup_action_send_to_desktop
573 action_send_to_desktop_dir
,
574 setup_action_send_to_desktop_next
577 "sendtodesktopprevious",
578 action_send_to_desktop_dir
,
579 setup_action_send_to_desktop_prev
582 "sendtodesktopright",
583 action_send_to_desktop_dir
,
584 setup_action_send_to_desktop_right
588 action_send_to_desktop_dir
,
589 setup_action_send_to_desktop_left
593 action_send_to_desktop_dir
,
594 setup_action_send_to_desktop_up
598 action_send_to_desktop_dir
,
599 setup_action_send_to_desktop_down
609 setup_action_desktop_next
614 setup_action_desktop_prev
619 setup_action_desktop_right
624 setup_action_desktop_left
629 setup_action_desktop_up
634 setup_action_desktop_down
638 action_toggle_decorations
,
653 action_toggle_show_desktop
,
663 action_unshow_desktop
,
689 setup_action_showmenu
693 action_send_to_layer
,
694 setup_action_top_layer
699 setup_action_top_layer
703 action_send_to_layer
,
704 setup_action_normal_layer
708 action_send_to_layer
,
709 setup_action_bottom_layer
712 "togglealwaysonbottom",
714 setup_action_bottom_layer
718 action_cycle_windows
,
719 setup_action_cycle_windows_next
723 action_cycle_windows
,
724 setup_action_cycle_windows_previous
729 setup_action_movetoedge_north
734 setup_action_movetoedge_south
739 setup_action_movetoedge_west
744 setup_action_movetoedge_east
749 setup_action_growtoedge_north
754 setup_action_growtoedge_south
759 setup_action_growtoedge_west
764 setup_action_growtoedge_east
773 ObAction
*action_from_string(const gchar
*name
, ObUserAction uact
)
776 gboolean exist
= FALSE
;
779 for (i
= 0; actionstrings
[i
].name
; i
++)
780 if (!g_ascii_strcasecmp(name
, actionstrings
[i
].name
)) {
782 a
= action_new(actionstrings
[i
].func
);
783 if (actionstrings
[i
].setup
)
784 actionstrings
[i
].setup(&a
, uact
);
785 /* only key bindings can be interactive. thus saith the xor.
786 because of how the mouse is grabbed, mouse events dont even get
787 read during interactive events, so no dice! >:) */
788 if (uact
!= OB_USER_ACTION_KEYBOARD_KEY
)
789 a
->data
.any
.interactive
= FALSE
;
793 g_warning("Invalid action '%s' requested. No such action exists.",
796 g_warning("Invalid use of action '%s'. Action will be ignored.", name
);
800 ObAction
*action_parse(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
804 ObAction
*act
= NULL
;
807 if (parse_attr_string("name", node
, &actname
)) {
808 if ((act
= action_from_string(actname
, uact
))) {
809 if (act
->func
== action_execute
|| act
->func
== action_restart
) {
810 if ((n
= parse_find_node("execute", node
->xmlChildrenNode
))) {
811 gchar
*s
= parse_string(doc
, n
);
812 act
->data
.execute
.path
= parse_expand_tilde(s
);
815 } else if (act
->func
== action_showmenu
) {
816 if ((n
= parse_find_node("menu", node
->xmlChildrenNode
)))
817 act
->data
.showmenu
.name
= parse_string(doc
, n
);
818 } else if (act
->func
== action_move_relative_horz
||
819 act
->func
== action_move_relative_vert
||
820 act
->func
== action_resize_relative_horz
||
821 act
->func
== action_resize_relative_vert
) {
822 if ((n
= parse_find_node("delta", node
->xmlChildrenNode
)))
823 act
->data
.relative
.delta
= parse_int(doc
, n
);
824 } else if (act
->func
== action_desktop
) {
825 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
826 act
->data
.desktop
.desk
= parse_int(doc
, n
);
827 if (act
->data
.desktop
.desk
> 0) act
->data
.desktop
.desk
--;
828 } else if (act
->func
== action_send_to_desktop
) {
829 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
830 act
->data
.sendto
.desk
= parse_int(doc
, n
);
831 if (act
->data
.sendto
.desk
> 0) act
->data
.sendto
.desk
--;
832 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
833 act
->data
.sendto
.follow
= parse_bool(doc
, n
);
834 } else if (act
->func
== action_desktop_dir
) {
835 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
836 act
->data
.desktopdir
.wrap
= parse_bool(doc
, n
);
837 } else if (act
->func
== action_send_to_desktop_dir
) {
838 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
839 act
->data
.sendtodir
.wrap
= parse_bool(doc
, n
);
840 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
841 act
->data
.sendtodir
.follow
= parse_bool(doc
, n
);
842 } else if (act
->func
== action_activate
) {
843 if ((n
= parse_find_node("here", node
->xmlChildrenNode
)))
844 act
->data
.activate
.here
= parse_bool(doc
, n
);
845 } else if (act
->func
== action_cycle_windows
) {
846 if ((n
= parse_find_node("linear", node
->xmlChildrenNode
)))
847 act
->data
.cycle
.linear
= parse_bool(doc
, n
);
855 void action_run_list(GSList
*acts
, ObClient
*c
, ObFrameContext context
,
856 guint state
, guint button
, gint x
, gint y
,
857 gboolean cancel
, gboolean done
)
861 gboolean inter
= FALSE
;
867 screen_pointer_pos(&x
, &y
);
869 if (grab_on_keyboard())
872 for (it
= acts
; it
; it
= g_slist_next(it
)) {
874 if (a
->data
.any
.interactive
) {
881 /* sometimes when we execute another app as an action,
882 it won't work right unless we XUngrabKeyboard first,
883 even though we grabbed the key/button Asychronously.
884 e.g. "gnome-panel-control --main-menu" */
885 XUngrabKeyboard(ob_display
, event_lasttime
);
888 for (it
= acts
; it
; it
= g_slist_next(it
)) {
891 if (!(a
->data
.any
.client_action
== OB_CLIENT_ACTION_ALWAYS
&& !c
)) {
892 a
->data
.any
.c
= a
->data
.any
.client_action
? c
: NULL
;
893 a
->data
.any
.context
= context
;
897 a
->data
.any
.button
= button
;
899 if (a
->data
.any
.interactive
) {
900 a
->data
.inter
.cancel
= cancel
;
901 a
->data
.inter
.final
= done
;
902 if (!(cancel
|| done
))
903 keyboard_interactive_grab(state
, a
->data
.any
.c
, a
);
911 void action_execute(union ActionData
*data
)
915 if (data
->execute
.path
) {
916 cmd
= g_filename_from_utf8(data
->execute
.path
, -1, NULL
, NULL
, NULL
);
918 if (!g_spawn_command_line_async(cmd
, &e
)) {
919 g_warning("failed to execute '%s': %s",
924 g_warning("failed to convert '%s' from utf8", data
->execute
.path
);
929 void action_activate(union ActionData
*data
)
931 client_activate(data
->activate
.any
.c
, data
->activate
.here
);
934 void action_focus(union ActionData
*data
)
936 client_focus(data
->client
.any
.c
);
939 void action_unfocus (union ActionData
*data
)
941 client_unfocus(data
->client
.any
.c
);
944 void action_iconify(union ActionData
*data
)
946 client_iconify(data
->client
.any
.c
, TRUE
, TRUE
);
949 void action_raiselower(union ActionData
*data
)
951 ObClient
*c
= data
->client
.any
.c
;
953 gboolean raise
= FALSE
;
955 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
956 ObClient
*cit
= it
->data
;
959 if (client_normal(cit
) == client_normal(c
) &&
960 cit
->layer
== c
->layer
&&
961 cit
->frame
->visible
&&
962 !client_search_transient(c
, cit
))
964 if (RECT_INTERSECTS_RECT(cit
->frame
->area
, c
->frame
->area
)) {
972 client_action_start(data
);
973 stacking_raise(CLIENT_AS_WINDOW(c
));
974 client_action_end(data
);
976 client_action_start(data
);
977 stacking_lower(CLIENT_AS_WINDOW(c
));
978 client_action_end(data
);
982 void action_raise(union ActionData
*data
)
984 client_action_start(data
);
985 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
986 client_action_end(data
);
989 void action_unshaderaise(union ActionData
*data
)
991 if (data
->client
.any
.c
->shaded
) {
992 client_action_start(data
);
993 client_shade(data
->client
.any
.c
, FALSE
);
994 client_action_end(data
);
996 client_action_start(data
);
997 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
998 client_action_end(data
);
1002 void action_shadelower(union ActionData
*data
)
1004 if (data
->client
.any
.c
->shaded
)
1005 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1007 client_action_start(data
);
1008 client_shade(data
->client
.any
.c
, TRUE
);
1009 client_action_end(data
);
1013 void action_lower(union ActionData
*data
)
1015 client_action_start(data
);
1016 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1017 client_action_end(data
);
1020 void action_close(union ActionData
*data
)
1022 client_close(data
->client
.any
.c
);
1025 void action_kill(union ActionData
*data
)
1027 client_kill(data
->client
.any
.c
);
1030 void action_shade(union ActionData
*data
)
1032 client_action_start(data
);
1033 client_shade(data
->client
.any
.c
, TRUE
);
1034 client_action_end(data
);
1037 void action_unshade(union ActionData
*data
)
1039 client_action_start(data
);
1040 client_shade(data
->client
.any
.c
, FALSE
);
1041 client_action_end(data
);
1044 void action_toggle_shade(union ActionData
*data
)
1046 client_action_start(data
);
1047 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1048 client_action_end(data
);
1051 void action_toggle_omnipresent(union ActionData
*data
)
1053 client_set_desktop(data
->client
.any
.c
,
1054 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1055 screen_desktop
: DESKTOP_ALL
, FALSE
);
1058 void action_move_relative_horz(union ActionData
*data
)
1060 ObClient
*c
= data
->relative
.any
.c
;
1061 client_action_start(data
);
1062 client_move(c
, c
->area
.x
+ data
->relative
.delta
, c
->area
.y
);
1063 client_action_end(data
);
1066 void action_move_relative_vert(union ActionData
*data
)
1068 ObClient
*c
= data
->relative
.any
.c
;
1069 client_action_start(data
);
1070 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.delta
);
1071 client_action_end(data
);
1074 void action_resize_relative_horz(union ActionData
*data
)
1076 ObClient
*c
= data
->relative
.any
.c
;
1077 client_action_start(data
);
1079 c
->area
.width
+ data
->relative
.delta
* c
->size_inc
.width
,
1081 client_action_end(data
);
1084 void action_resize_relative_vert(union ActionData
*data
)
1086 ObClient
*c
= data
->relative
.any
.c
;
1088 client_action_start(data
);
1089 client_resize(c
, c
->area
.width
, c
->area
.height
+
1090 data
->relative
.delta
* c
->size_inc
.height
);
1091 client_action_end(data
);
1095 void action_maximize_full(union ActionData
*data
)
1097 client_action_start(data
);
1098 client_maximize(data
->client
.any
.c
, TRUE
, 0, TRUE
);
1099 client_action_end(data
);
1102 void action_unmaximize_full(union ActionData
*data
)
1104 client_action_start(data
);
1105 client_maximize(data
->client
.any
.c
, FALSE
, 0, TRUE
);
1106 client_action_end(data
);
1109 void action_toggle_maximize_full(union ActionData
*data
)
1111 client_action_start(data
);
1112 client_maximize(data
->client
.any
.c
,
1113 !(data
->client
.any
.c
->max_horz
||
1114 data
->client
.any
.c
->max_vert
),
1116 client_action_end(data
);
1119 void action_maximize_horz(union ActionData
*data
)
1121 client_action_start(data
);
1122 client_maximize(data
->client
.any
.c
, TRUE
, 1, TRUE
);
1123 client_action_end(data
);
1126 void action_unmaximize_horz(union ActionData
*data
)
1128 client_action_start(data
);
1129 client_maximize(data
->client
.any
.c
, FALSE
, 1, TRUE
);
1130 client_action_end(data
);
1133 void action_toggle_maximize_horz(union ActionData
*data
)
1135 client_action_start(data
);
1136 client_maximize(data
->client
.any
.c
,
1137 !data
->client
.any
.c
->max_horz
, 1, TRUE
);
1138 client_action_end(data
);
1141 void action_maximize_vert(union ActionData
*data
)
1143 client_action_start(data
);
1144 client_maximize(data
->client
.any
.c
, TRUE
, 2, TRUE
);
1145 client_action_end(data
);
1148 void action_unmaximize_vert(union ActionData
*data
)
1150 client_action_start(data
);
1151 client_maximize(data
->client
.any
.c
, FALSE
, 2, TRUE
);
1152 client_action_end(data
);
1155 void action_toggle_maximize_vert(union ActionData
*data
)
1157 client_action_start(data
);
1158 client_maximize(data
->client
.any
.c
,
1159 !data
->client
.any
.c
->max_vert
, 2, TRUE
);
1160 client_action_end(data
);
1163 void action_send_to_desktop(union ActionData
*data
)
1165 ObClient
*c
= data
->sendto
.any
.c
;
1167 if (!client_normal(c
)) return;
1169 if (data
->sendto
.desk
< screen_num_desktops
||
1170 data
->sendto
.desk
== DESKTOP_ALL
) {
1171 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
);
1172 if (data
->sendto
.follow
)
1173 screen_set_desktop(data
->sendto
.desk
);
1177 void action_desktop(union ActionData
*data
)
1179 static guint first
= (unsigned) -1;
1181 if (data
->inter
.any
.interactive
&& first
== (unsigned) -1)
1182 first
= screen_desktop
;
1184 if (!data
->inter
.any
.interactive
||
1185 (!data
->inter
.cancel
&& !data
->inter
.final
))
1187 if (data
->desktop
.desk
< screen_num_desktops
||
1188 data
->desktop
.desk
== DESKTOP_ALL
)
1190 screen_set_desktop(data
->desktop
.desk
);
1191 if (data
->inter
.any
.interactive
)
1192 screen_desktop_popup(data
->desktop
.desk
, TRUE
);
1194 } else if (data
->inter
.cancel
) {
1195 screen_set_desktop(first
);
1198 if (data
->inter
.any
.interactive
&& data
->inter
.final
) {
1199 screen_desktop_popup(0, FALSE
);
1200 first
= (unsigned) -1;
1204 void action_desktop_dir(union ActionData
*data
)
1208 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1209 data
->desktopdir
.wrap
,
1210 data
->sendtodir
.linear
,
1211 data
->desktopdir
.inter
.any
.interactive
,
1212 data
->desktopdir
.inter
.final
,
1213 data
->desktopdir
.inter
.cancel
);
1214 if (!data
->sendtodir
.inter
.any
.interactive
||
1215 !data
->sendtodir
.inter
.final
)
1217 screen_set_desktop(d
);
1221 void action_send_to_desktop_dir(union ActionData
*data
)
1223 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1226 if (!client_normal(c
)) return;
1228 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1229 data
->sendtodir
.linear
,
1230 data
->sendtodir
.inter
.any
.interactive
,
1231 data
->sendtodir
.inter
.final
,
1232 data
->sendtodir
.inter
.cancel
);
1233 if (!data
->sendtodir
.inter
.any
.interactive
||
1234 !data
->sendtodir
.inter
.final
)
1236 client_set_desktop(c
, d
, data
->sendtodir
.follow
);
1237 if (data
->sendtodir
.follow
)
1238 screen_set_desktop(d
);
1242 void action_desktop_last(union ActionData
*data
)
1244 screen_set_desktop(screen_last_desktop
);
1247 void action_toggle_decorations(union ActionData
*data
)
1249 ObClient
*c
= data
->client
.any
.c
;
1251 client_action_start(data
);
1252 client_set_undecorated(c
, !c
->undecorated
);
1253 client_action_end(data
);
1256 static guint32
pick_corner(int x
, int y
, int cx
, int cy
, int cw
, int ch
)
1258 if (x
- cx
> cw
/ 2) {
1259 if (y
- cy
> ch
/ 2)
1260 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1262 return prop_atoms
.net_wm_moveresize_size_topright
;
1264 if (y
- cy
> ch
/ 2)
1265 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1267 return prop_atoms
.net_wm_moveresize_size_topleft
;
1271 void action_moveresize(union ActionData
*data
)
1273 ObClient
*c
= data
->moveresize
.any
.c
;
1276 if (!client_normal(c
)) return;
1278 if (data
->moveresize
.keyboard
) {
1279 corner
= (data
->moveresize
.move
?
1280 prop_atoms
.net_wm_moveresize_move_keyboard
:
1281 prop_atoms
.net_wm_moveresize_size_keyboard
);
1283 corner
= (data
->moveresize
.move
?
1284 prop_atoms
.net_wm_moveresize_move
:
1285 pick_corner(data
->any
.x
, data
->any
.y
,
1286 c
->frame
->area
.x
, c
->frame
->area
.y
,
1287 /* use the client size because the frame
1288 can be differently sized (shaded
1289 windows) and we want this based on the
1291 c
->area
.width
+ c
->frame
->size
.left
+
1292 c
->frame
->size
.right
,
1293 c
->area
.height
+ c
->frame
->size
.top
+
1294 c
->frame
->size
.bottom
));
1297 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1300 void action_reconfigure(union ActionData
*data
)
1305 void action_restart(union ActionData
*data
)
1307 ob_restart_other(data
->execute
.path
);
1310 void action_exit(union ActionData
*data
)
1315 void action_showmenu(union ActionData
*data
)
1317 if (data
->showmenu
.name
) {
1318 menu_show(data
->showmenu
.name
, data
->any
.x
, data
->any
.y
,
1319 data
->showmenu
.any
.c
);
1323 void action_cycle_windows(union ActionData
*data
)
1325 focus_cycle(data
->cycle
.forward
, data
->cycle
.linear
,
1326 data
->cycle
.inter
.any
.interactive
,
1327 data
->cycle
.inter
.final
, data
->cycle
.inter
.cancel
);
1330 void action_directional_focus(union ActionData
*data
)
1332 focus_directional_cycle(data
->interdiraction
.direction
,
1333 data
->interdiraction
.inter
.any
.interactive
,
1334 data
->interdiraction
.inter
.final
,
1335 data
->interdiraction
.inter
.cancel
);
1338 void action_movetoedge(union ActionData
*data
)
1341 ObClient
*c
= data
->diraction
.any
.c
;
1343 x
= c
->frame
->area
.x
;
1344 y
= c
->frame
->area
.y
;
1346 switch(data
->diraction
.direction
) {
1347 case OB_DIRECTION_NORTH
:
1348 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
);
1350 case OB_DIRECTION_WEST
:
1351 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
);
1353 case OB_DIRECTION_SOUTH
:
1354 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
) -
1355 c
->frame
->area
.height
;
1357 case OB_DIRECTION_EAST
:
1358 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
) -
1359 c
->frame
->area
.width
;
1362 g_assert_not_reached();
1364 frame_frame_gravity(c
->frame
, &x
, &y
);
1365 client_action_start(data
);
1366 client_move(c
, x
, y
);
1367 client_action_end(data
);
1370 void action_growtoedge(union ActionData
*data
)
1372 int x
, y
, width
, height
, dest
;
1373 ObClient
*c
= data
->diraction
.any
.c
;
1376 a
= screen_area(c
->desktop
);
1377 x
= c
->frame
->area
.x
;
1378 y
= c
->frame
->area
.y
;
1379 width
= c
->frame
->area
.width
;
1380 height
= c
->frame
->area
.height
;
1382 switch(data
->diraction
.direction
) {
1383 case OB_DIRECTION_NORTH
:
1384 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
);
1386 height
= c
->frame
->area
.height
/ 2;
1388 height
= c
->frame
->area
.y
+ c
->frame
->area
.height
- dest
;
1392 case OB_DIRECTION_WEST
:
1393 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
);
1395 width
= c
->frame
->area
.width
/ 2;
1397 width
= c
->frame
->area
.x
+ c
->frame
->area
.width
- dest
;
1401 case OB_DIRECTION_SOUTH
:
1402 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
);
1403 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1404 height
= c
->frame
->area
.height
/ 2;
1405 y
= a
->y
+ a
->height
- height
;
1407 height
= dest
- c
->frame
->area
.y
;
1408 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1409 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1411 case OB_DIRECTION_EAST
:
1412 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
);
1413 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1414 width
= c
->frame
->area
.width
/ 2;
1415 x
= a
->x
+ a
->width
- width
;
1417 width
= dest
- c
->frame
->area
.x
;
1418 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1419 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1422 g_assert_not_reached();
1424 frame_frame_gravity(c
->frame
, &x
, &y
);
1425 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1426 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1427 client_action_start(data
);
1428 client_move_resize(c
, x
, y
, width
, height
);
1429 client_action_end(data
);
1432 void action_send_to_layer(union ActionData
*data
)
1434 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1437 void action_toggle_layer(union ActionData
*data
)
1439 ObClient
*c
= data
->layer
.any
.c
;
1441 client_action_start(data
);
1442 if (data
->layer
.layer
< 0)
1443 client_set_layer(c
, c
->below
? 0 : -1);
1444 else if (data
->layer
.layer
> 0)
1445 client_set_layer(c
, c
->above
? 0 : 1);
1446 client_action_end(data
);
1449 void action_toggle_show_desktop(union ActionData
*data
)
1451 screen_show_desktop(!screen_showing_desktop
);
1454 void action_show_desktop(union ActionData
*data
)
1456 screen_show_desktop(TRUE
);
1459 void action_unshow_desktop(union ActionData
*data
)
1461 screen_show_desktop(FALSE
);