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 #define ACT_START(d) \
37 ((d->any.context != OB_FRAME_CONTEXT_CLIENT && config_focus_follow) ? \
38 grab_pointer(TRUE, OB_CURSOR_NONE), 0 : 0)
41 ((d->any.context != OB_FRAME_CONTEXT_CLIENT && config_focus_follow) ? \
42 grab_pointer(FALSE, OB_CURSOR_NONE), \
43 (d->any.button ? focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS), 1 : 0) : \
46 typedef struct ActionString
{
48 void (*func
)(union ActionData
*);
49 void (*setup
)(ObAction
**, ObUserAction uact
);
52 static ObAction
*action_new(void (*func
)(union ActionData
*data
),
55 ObAction
*a
= g_new0(ObAction
, 1);
61 void action_free(ObAction
*a
)
63 if (a
== NULL
) return;
65 /* deal with pointers */
66 if (a
->func
== action_execute
|| a
->func
== action_restart
)
67 g_free(a
->data
.execute
.path
);
68 else if (a
->func
== action_showmenu
)
69 g_free(a
->data
.showmenu
.name
);
74 void setup_action_directional_focus_north(ObAction
**a
, ObUserAction uact
)
76 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
77 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTH
;
80 void setup_action_directional_focus_east(ObAction
**a
, ObUserAction uact
)
82 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
83 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_EAST
;
86 void setup_action_directional_focus_south(ObAction
**a
, ObUserAction uact
)
88 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
89 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTH
;
92 void setup_action_directional_focus_west(ObAction
**a
, ObUserAction uact
)
94 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
95 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_WEST
;
98 void setup_action_directional_focus_northeast(ObAction
**a
, ObUserAction uact
)
100 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
101 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHEAST
;
104 void setup_action_directional_focus_southeast(ObAction
**a
, ObUserAction uact
)
106 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
107 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHEAST
;
110 void setup_action_directional_focus_southwest(ObAction
**a
, ObUserAction uact
)
112 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
113 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHWEST
;
116 void setup_action_directional_focus_northwest(ObAction
**a
, ObUserAction uact
)
118 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
119 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHWEST
;
122 void setup_action_send_to_desktop(ObAction
**a
, ObUserAction uact
)
124 (*a
)->data
.sendto
.follow
= TRUE
;
127 void setup_action_send_to_desktop_prev(ObAction
**a
, ObUserAction uact
)
129 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
130 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
131 (*a
)->data
.sendtodir
.linear
= TRUE
;
132 (*a
)->data
.sendtodir
.wrap
= TRUE
;
133 (*a
)->data
.sendtodir
.follow
= TRUE
;
136 void setup_action_send_to_desktop_next(ObAction
**a
, ObUserAction uact
)
138 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
139 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
140 (*a
)->data
.sendtodir
.linear
= TRUE
;
141 (*a
)->data
.sendtodir
.wrap
= TRUE
;
142 (*a
)->data
.sendtodir
.follow
= TRUE
;
145 void setup_action_send_to_desktop_left(ObAction
**a
, ObUserAction uact
)
147 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
148 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
149 (*a
)->data
.sendtodir
.linear
= FALSE
;
150 (*a
)->data
.sendtodir
.wrap
= TRUE
;
151 (*a
)->data
.sendtodir
.follow
= TRUE
;
154 void setup_action_send_to_desktop_right(ObAction
**a
, ObUserAction uact
)
156 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
157 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
158 (*a
)->data
.sendtodir
.linear
= FALSE
;
159 (*a
)->data
.sendtodir
.wrap
= TRUE
;
160 (*a
)->data
.sendtodir
.follow
= TRUE
;
163 void setup_action_send_to_desktop_up(ObAction
**a
, ObUserAction uact
)
165 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
166 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_NORTH
;
167 (*a
)->data
.sendtodir
.linear
= FALSE
;
168 (*a
)->data
.sendtodir
.wrap
= TRUE
;
169 (*a
)->data
.sendtodir
.follow
= TRUE
;
172 void setup_action_send_to_desktop_down(ObAction
**a
, ObUserAction uact
)
174 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
175 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_SOUTH
;
176 (*a
)->data
.sendtodir
.linear
= FALSE
;
177 (*a
)->data
.sendtodir
.wrap
= TRUE
;
178 (*a
)->data
.sendtodir
.follow
= TRUE
;
181 void setup_action_desktop_prev(ObAction
**a
, ObUserAction uact
)
183 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
184 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
185 (*a
)->data
.desktopdir
.linear
= TRUE
;
186 (*a
)->data
.desktopdir
.wrap
= TRUE
;
189 void setup_action_desktop_next(ObAction
**a
, ObUserAction uact
)
191 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
192 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
193 (*a
)->data
.desktopdir
.linear
= TRUE
;
194 (*a
)->data
.desktopdir
.wrap
= TRUE
;
197 void setup_action_desktop_left(ObAction
**a
, ObUserAction uact
)
199 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
200 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
201 (*a
)->data
.desktopdir
.linear
= FALSE
;
202 (*a
)->data
.desktopdir
.wrap
= TRUE
;
205 void setup_action_desktop_right(ObAction
**a
, ObUserAction uact
)
207 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
208 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
209 (*a
)->data
.desktopdir
.linear
= FALSE
;
210 (*a
)->data
.desktopdir
.wrap
= TRUE
;
213 void setup_action_desktop_up(ObAction
**a
, ObUserAction uact
)
215 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
216 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_NORTH
;
217 (*a
)->data
.desktopdir
.linear
= FALSE
;
218 (*a
)->data
.desktopdir
.wrap
= TRUE
;
221 void setup_action_desktop_down(ObAction
**a
, ObUserAction uact
)
223 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
224 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_SOUTH
;
225 (*a
)->data
.desktopdir
.linear
= FALSE
;
226 (*a
)->data
.desktopdir
.wrap
= TRUE
;
229 void setup_action_cycle_windows_next(ObAction
**a
, ObUserAction uact
)
231 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
232 (*a
)->data
.cycle
.linear
= FALSE
;
233 (*a
)->data
.cycle
.forward
= TRUE
;
236 void setup_action_cycle_windows_previous(ObAction
**a
, ObUserAction uact
)
238 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
239 (*a
)->data
.cycle
.linear
= FALSE
;
240 (*a
)->data
.cycle
.forward
= FALSE
;
243 void setup_action_movetoedge_north(ObAction
**a
, ObUserAction uact
)
245 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
248 void setup_action_movetoedge_south(ObAction
**a
, ObUserAction uact
)
250 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
253 void setup_action_movetoedge_east(ObAction
**a
, ObUserAction uact
)
255 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
258 void setup_action_movetoedge_west(ObAction
**a
, ObUserAction uact
)
260 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
263 void setup_action_growtoedge_north(ObAction
**a
, ObUserAction uact
)
265 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
268 void setup_action_growtoedge_south(ObAction
**a
, ObUserAction uact
)
270 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
273 void setup_action_growtoedge_east(ObAction
**a
, ObUserAction uact
)
275 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
278 void setup_action_growtoedge_west(ObAction
**a
, ObUserAction uact
)
280 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
283 void setup_action_top_layer(ObAction
**a
, ObUserAction uact
)
285 (*a
)->data
.layer
.layer
= 1;
288 void setup_action_normal_layer(ObAction
**a
, ObUserAction uact
)
290 (*a
)->data
.layer
.layer
= 0;
293 void setup_action_bottom_layer(ObAction
**a
, ObUserAction uact
)
295 (*a
)->data
.layer
.layer
= -1;
298 void setup_action_move(ObAction
**a
, ObUserAction uact
)
300 (*a
)->data
.moveresize
.move
= TRUE
;
301 (*a
)->data
.moveresize
.keyboard
=
302 (uact
== OB_USER_ACTION_KEYBOARD_KEY
||
303 uact
== OB_USER_ACTION_MENU_SELECTION
);
306 void setup_action_resize(ObAction
**a
, ObUserAction uact
)
308 (*a
)->data
.moveresize
.move
= FALSE
;
309 (*a
)->data
.moveresize
.keyboard
=
310 (uact
== OB_USER_ACTION_KEYBOARD_KEY
||
311 uact
== OB_USER_ACTION_MENU_SELECTION
);
314 void setup_action_showmenu(ObAction
**a
, ObUserAction uact
)
316 /* you cannot call ShowMenu from inside a menu, cuz the menu code makes
317 assumptions that there is only one menu (and submenus) open at
319 if (uact
== OB_USER_ACTION_MENU_SELECTION
) {
325 ActionString actionstrings
[] =
333 "directionalfocusnorth",
334 action_directional_focus
,
335 setup_action_directional_focus_north
338 "directionalfocuseast",
339 action_directional_focus
,
340 setup_action_directional_focus_east
343 "directionalfocussouth",
344 action_directional_focus
,
345 setup_action_directional_focus_south
348 "directionalfocuswest",
349 action_directional_focus
,
350 setup_action_directional_focus_west
353 "directionalfocusnortheast",
354 action_directional_focus
,
355 setup_action_directional_focus_northeast
358 "directionalfocussoutheast",
359 action_directional_focus
,
360 setup_action_directional_focus_southeast
363 "directionalfocussouthwest",
364 action_directional_focus
,
365 setup_action_directional_focus_southwest
368 "directionalfocusnorthwest",
369 action_directional_focus
,
370 setup_action_directional_focus_northwest
444 action_toggle_omnipresent
,
449 action_move_relative_horz
,
454 action_move_relative_vert
,
458 "resizerelativehorz",
459 action_resize_relative_horz
,
463 "resizerelativevert",
464 action_resize_relative_vert
,
469 action_maximize_full
,
474 action_unmaximize_full
,
478 "togglemaximizefull",
479 action_toggle_maximize_full
,
484 action_maximize_horz
,
489 action_unmaximize_horz
,
493 "togglemaximizehorz",
494 action_toggle_maximize_horz
,
499 action_maximize_vert
,
504 action_unmaximize_vert
,
508 "togglemaximizevert",
509 action_toggle_maximize_vert
,
514 action_send_to_desktop
,
515 setup_action_send_to_desktop
519 action_send_to_desktop_dir
,
520 setup_action_send_to_desktop_next
523 "sendtodesktopprevious",
524 action_send_to_desktop_dir
,
525 setup_action_send_to_desktop_prev
528 "sendtodesktopright",
529 action_send_to_desktop_dir
,
530 setup_action_send_to_desktop_right
534 action_send_to_desktop_dir
,
535 setup_action_send_to_desktop_left
539 action_send_to_desktop_dir
,
540 setup_action_send_to_desktop_up
544 action_send_to_desktop_dir
,
545 setup_action_send_to_desktop_down
555 setup_action_desktop_next
560 setup_action_desktop_prev
565 setup_action_desktop_right
570 setup_action_desktop_left
575 setup_action_desktop_up
580 setup_action_desktop_down
584 action_toggle_decorations
,
599 action_toggle_show_desktop
,
609 action_unshow_desktop
,
635 setup_action_showmenu
639 action_send_to_layer
,
640 setup_action_top_layer
645 setup_action_top_layer
649 action_send_to_layer
,
650 setup_action_normal_layer
654 action_send_to_layer
,
655 setup_action_bottom_layer
658 "togglealwaysonbottom",
660 setup_action_bottom_layer
664 action_cycle_windows
,
665 setup_action_cycle_windows_next
669 action_cycle_windows
,
670 setup_action_cycle_windows_previous
675 setup_action_movetoedge_north
680 setup_action_movetoedge_south
685 setup_action_movetoedge_west
690 setup_action_movetoedge_east
695 setup_action_growtoedge_north
700 setup_action_growtoedge_south
705 setup_action_growtoedge_west
710 setup_action_growtoedge_east
719 ObAction
*action_from_string(const gchar
*name
, ObUserAction uact
)
722 gboolean exist
= FALSE
;
725 for (i
= 0; actionstrings
[i
].name
; i
++)
726 if (!g_ascii_strcasecmp(name
, actionstrings
[i
].name
)) {
728 a
= action_new(actionstrings
[i
].func
, uact
);
729 if (actionstrings
[i
].setup
)
730 actionstrings
[i
].setup(&a
, uact
);
731 /* only key bindings can be interactive. thus saith the xor. */
732 if (uact
!= OB_USER_ACTION_KEYBOARD_KEY
)
733 a
->data
.any
.interactive
= FALSE
;
737 g_warning("Invalid action '%s' requested. No such action exists.",
740 g_warning("Invalid use of action '%s'. Action will be ignored.", name
);
744 ObAction
*action_parse(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
748 ObAction
*act
= NULL
;
751 if (parse_attr_string("name", node
, &actname
)) {
752 if ((act
= action_from_string(actname
, uact
))) {
753 if (act
->func
== action_execute
|| act
->func
== action_restart
) {
754 if ((n
= parse_find_node("execute", node
->xmlChildrenNode
))) {
755 gchar
*s
= parse_string(doc
, n
);
756 act
->data
.execute
.path
= parse_expand_tilde(s
);
759 } else if (act
->func
== action_showmenu
) {
760 if ((n
= parse_find_node("menu", node
->xmlChildrenNode
)))
761 act
->data
.showmenu
.name
= parse_string(doc
, n
);
762 } else if (act
->func
== action_move_relative_horz
||
763 act
->func
== action_move_relative_vert
||
764 act
->func
== action_resize_relative_horz
||
765 act
->func
== action_resize_relative_vert
) {
766 if ((n
= parse_find_node("delta", node
->xmlChildrenNode
)))
767 act
->data
.relative
.delta
= parse_int(doc
, n
);
768 } else if (act
->func
== action_desktop
) {
769 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
770 act
->data
.desktop
.desk
= parse_int(doc
, n
);
771 if (act
->data
.desktop
.desk
> 0) act
->data
.desktop
.desk
--;
772 } else if (act
->func
== action_send_to_desktop
) {
773 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
774 act
->data
.sendto
.desk
= parse_int(doc
, n
);
775 if (act
->data
.sendto
.desk
> 0) act
->data
.sendto
.desk
--;
776 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
777 act
->data
.sendto
.follow
= parse_bool(doc
, n
);
778 } else if (act
->func
== action_desktop_dir
) {
779 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
780 act
->data
.desktopdir
.wrap
= parse_bool(doc
, n
);
781 } else if (act
->func
== action_send_to_desktop_dir
) {
782 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
783 act
->data
.sendtodir
.wrap
= parse_bool(doc
, n
);
784 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
785 act
->data
.sendtodir
.follow
= parse_bool(doc
, n
);
786 } else if (act
->func
== action_activate
) {
787 if ((n
= parse_find_node("here", node
->xmlChildrenNode
)))
788 act
->data
.activate
.here
= parse_bool(doc
, n
);
789 } else if (act
->func
== action_cycle_windows
) {
790 if ((n
= parse_find_node("linear", node
->xmlChildrenNode
)))
791 act
->data
.cycle
.linear
= parse_bool(doc
, n
);
799 void action_run_list(GSList
*acts
, ObClient
*c
, ObFrameContext context
,
800 guint state
, guint button
, gint x
, gint y
,
801 gboolean cancel
, gboolean done
)
805 gboolean inter
= FALSE
;
811 screen_pointer_pos(&x
, &y
);
813 if (grab_on_keyboard())
816 for (it
= acts
; it
; it
= g_slist_next(it
)) {
818 if (a
->data
.any
.interactive
) {
825 /* sometimes when we execute another app as an action,
826 it won't work right unless we XUngrabKeyboard first,
827 even though we grabbed the key/button Asychronously.
828 e.g. "gnome-panel-control --main-menu" */
829 XUngrabKeyboard(ob_display
, event_lasttime
);
832 for (it
= acts
; it
; it
= g_slist_next(it
)) {
836 a
->data
.any
.context
= context
;
840 a
->data
.any
.button
= button
;
842 if (a
->data
.any
.interactive
) {
843 a
->data
.inter
.cancel
= cancel
;
844 a
->data
.inter
.final
= done
;
845 if (!(cancel
|| done
))
846 keyboard_interactive_grab(state
, c
, a
);
853 void action_execute(union ActionData
*data
)
857 if (data
->execute
.path
) {
858 cmd
= g_filename_from_utf8(data
->execute
.path
, -1, NULL
, NULL
, NULL
);
860 if (!g_spawn_command_line_async(cmd
, &e
)) {
861 g_warning("failed to execute '%s': %s",
866 g_warning("failed to convert '%s' from utf8", data
->execute
.path
);
871 void action_activate(union ActionData
*data
)
873 if (data
->activate
.any
.c
)
874 client_activate(data
->activate
.any
.c
, data
->activate
.here
);
877 void action_focus(union ActionData
*data
)
879 if (data
->client
.any
.c
)
880 client_focus(data
->client
.any
.c
);
883 void action_unfocus (union ActionData
*data
)
885 if (data
->client
.any
.c
)
886 client_unfocus(data
->client
.any
.c
);
889 void action_iconify(union ActionData
*data
)
891 if (data
->client
.any
.c
)
892 client_iconify(data
->client
.any
.c
, TRUE
, TRUE
);
895 void action_raiselower(union ActionData
*data
)
897 ObClient
*c
= data
->client
.any
.c
;
899 gboolean raise
= FALSE
;
903 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
904 ObClient
*cit
= it
->data
;
907 if (client_normal(cit
) == client_normal(c
) &&
908 cit
->layer
== c
->layer
&&
911 if (RECT_INTERSECTS_RECT(cit
->frame
->area
, c
->frame
->area
)) {
920 stacking_raise(CLIENT_AS_WINDOW(c
));
924 stacking_lower(CLIENT_AS_WINDOW(c
));
929 void action_raise(union ActionData
*data
)
931 if (data
->client
.any
.c
) {
933 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
938 void action_unshaderaise(union ActionData
*data
)
940 if (data
->client
.any
.c
) {
941 if (data
->client
.any
.c
->shaded
) {
943 client_shade(data
->client
.any
.c
, FALSE
);
947 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
953 void action_shadelower(union ActionData
*data
)
955 if (data
->client
.any
.c
) {
956 if (data
->client
.any
.c
->shaded
)
957 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
960 client_shade(data
->client
.any
.c
, TRUE
);
966 void action_lower(union ActionData
*data
)
968 if (data
->client
.any
.c
) {
970 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
975 void action_close(union ActionData
*data
)
977 if (data
->client
.any
.c
)
978 client_close(data
->client
.any
.c
);
981 void action_kill(union ActionData
*data
)
983 if (data
->client
.any
.c
)
984 client_kill(data
->client
.any
.c
);
987 void action_shade(union ActionData
*data
)
989 if (data
->client
.any
.c
) {
991 client_shade(data
->client
.any
.c
, TRUE
);
996 void action_unshade(union ActionData
*data
)
998 if (data
->client
.any
.c
) {
1000 client_shade(data
->client
.any
.c
, FALSE
);
1005 void action_toggle_shade(union ActionData
*data
)
1007 if (data
->client
.any
.c
) {
1009 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1014 void action_toggle_omnipresent(union ActionData
*data
)
1016 if (data
->client
.any
.c
)
1017 client_set_desktop(data
->client
.any
.c
,
1018 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1019 screen_desktop
: DESKTOP_ALL
, FALSE
);
1022 void action_move_relative_horz(union ActionData
*data
)
1024 ObClient
*c
= data
->relative
.any
.c
;
1027 client_move(c
, c
->area
.x
+ data
->relative
.delta
, c
->area
.y
);
1032 void action_move_relative_vert(union ActionData
*data
)
1034 ObClient
*c
= data
->relative
.any
.c
;
1037 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.delta
);
1042 void action_resize_relative_horz(union ActionData
*data
)
1044 ObClient
*c
= data
->relative
.any
.c
;
1048 c
->area
.width
+ data
->relative
.delta
* c
->size_inc
.width
,
1054 void action_resize_relative_vert(union ActionData
*data
)
1056 ObClient
*c
= data
->relative
.any
.c
;
1057 if (c
&& !c
->shaded
) {
1059 client_resize(c
, c
->area
.width
, c
->area
.height
+
1060 data
->relative
.delta
* c
->size_inc
.height
);
1065 void action_maximize_full(union ActionData
*data
)
1067 if (data
->client
.any
.c
) {
1069 client_maximize(data
->client
.any
.c
, TRUE
, 0, TRUE
);
1074 void action_unmaximize_full(union ActionData
*data
)
1076 if (data
->client
.any
.c
) {
1078 client_maximize(data
->client
.any
.c
, FALSE
, 0, TRUE
);
1083 void action_toggle_maximize_full(union ActionData
*data
)
1085 if (data
->client
.any
.c
) {
1087 client_maximize(data
->client
.any
.c
,
1088 !(data
->client
.any
.c
->max_horz
||
1089 data
->client
.any
.c
->max_vert
),
1095 void action_maximize_horz(union ActionData
*data
)
1097 if (data
->client
.any
.c
) {
1099 client_maximize(data
->client
.any
.c
, TRUE
, 1, TRUE
);
1104 void action_unmaximize_horz(union ActionData
*data
)
1106 if (data
->client
.any
.c
) {
1108 client_maximize(data
->client
.any
.c
, FALSE
, 1, TRUE
);
1113 void action_toggle_maximize_horz(union ActionData
*data
)
1115 if (data
->client
.any
.c
) {
1117 client_maximize(data
->client
.any
.c
,
1118 !data
->client
.any
.c
->max_horz
, 1, TRUE
);
1123 void action_maximize_vert(union ActionData
*data
)
1125 if (data
->client
.any
.c
) {
1127 client_maximize(data
->client
.any
.c
, TRUE
, 2, TRUE
);
1132 void action_unmaximize_vert(union ActionData
*data
)
1134 if (data
->client
.any
.c
) {
1136 client_maximize(data
->client
.any
.c
, FALSE
, 2, TRUE
);
1141 void action_toggle_maximize_vert(union ActionData
*data
)
1143 if (data
->client
.any
.c
) {
1145 client_maximize(data
->client
.any
.c
,
1146 !data
->client
.any
.c
->max_vert
, 2, TRUE
);
1151 void action_send_to_desktop(union ActionData
*data
)
1153 ObClient
*c
= data
->sendto
.any
.c
;
1155 if (!c
|| !client_normal(c
)) return;
1157 if (data
->sendto
.desk
< screen_num_desktops
||
1158 data
->sendto
.desk
== DESKTOP_ALL
) {
1159 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
);
1160 if (data
->sendto
.follow
)
1161 screen_set_desktop(data
->sendto
.desk
);
1165 void action_desktop(union ActionData
*data
)
1167 if (data
->desktop
.desk
< screen_num_desktops
||
1168 data
->desktop
.desk
== DESKTOP_ALL
)
1169 screen_set_desktop(data
->desktop
.desk
);
1172 void action_desktop_dir(union ActionData
*data
)
1176 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1177 data
->desktopdir
.wrap
,
1178 data
->sendtodir
.linear
,
1179 data
->desktopdir
.inter
.any
.interactive
,
1180 data
->desktopdir
.inter
.final
,
1181 data
->desktopdir
.inter
.cancel
);
1182 screen_set_desktop(d
);
1185 void action_send_to_desktop_dir(union ActionData
*data
)
1187 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1190 if (!c
|| !client_normal(c
)) return;
1192 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1193 data
->sendtodir
.linear
,
1194 data
->sendtodir
.inter
.any
.interactive
,
1195 data
->sendtodir
.inter
.final
,
1196 data
->sendtodir
.inter
.cancel
);
1197 client_set_desktop(c
, d
, data
->sendtodir
.follow
);
1198 if (data
->sendtodir
.follow
)
1199 screen_set_desktop(d
);
1202 void action_desktop_last(union ActionData
*data
)
1204 screen_set_desktop(screen_last_desktop
);
1207 void action_toggle_decorations(union ActionData
*data
)
1209 ObClient
*c
= data
->client
.any
.c
;
1213 c
->decorate
= !c
->decorate
;
1214 client_setup_decor_and_functions(c
);
1219 static guint32
pick_corner(int x
, int y
, int cx
, int cy
, int cw
, int ch
)
1221 if (x
- cx
> cw
/ 2) {
1222 if (y
- cy
> ch
/ 2)
1223 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1225 return prop_atoms
.net_wm_moveresize_size_topright
;
1227 if (y
- cy
> ch
/ 2)
1228 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1230 return prop_atoms
.net_wm_moveresize_size_topleft
;
1234 void action_moveresize(union ActionData
*data
)
1236 ObClient
*c
= data
->moveresize
.any
.c
;
1239 if (!c
|| !client_normal(c
)) return;
1241 if (data
->moveresize
.keyboard
) {
1242 corner
= (data
->moveresize
.move
?
1243 prop_atoms
.net_wm_moveresize_move_keyboard
:
1244 prop_atoms
.net_wm_moveresize_size_keyboard
);
1246 corner
= (data
->moveresize
.move
?
1247 prop_atoms
.net_wm_moveresize_move
:
1248 pick_corner(data
->any
.x
, data
->any
.y
,
1249 c
->frame
->area
.x
, c
->frame
->area
.y
,
1250 /* use the client size because the frame
1251 can be differently sized (shaded
1252 windows) and we want this based on the
1254 c
->area
.width
+ c
->frame
->size
.left
+
1255 c
->frame
->size
.right
,
1256 c
->area
.height
+ c
->frame
->size
.top
+
1257 c
->frame
->size
.bottom
));
1260 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1263 void action_reconfigure(union ActionData
*data
)
1268 void action_restart(union ActionData
*data
)
1270 ob_restart_other(data
->execute
.path
);
1273 void action_exit(union ActionData
*data
)
1278 void action_showmenu(union ActionData
*data
)
1280 if (data
->showmenu
.name
) {
1281 menu_show(data
->showmenu
.name
, data
->any
.x
, data
->any
.y
,
1282 data
->showmenu
.any
.c
);
1286 void action_cycle_windows(union ActionData
*data
)
1288 focus_cycle(data
->cycle
.forward
, data
->cycle
.linear
,
1289 data
->cycle
.inter
.any
.interactive
,
1290 data
->cycle
.inter
.final
, data
->cycle
.inter
.cancel
);
1293 void action_directional_focus(union ActionData
*data
)
1295 focus_directional_cycle(data
->interdiraction
.direction
,
1296 data
->interdiraction
.inter
.any
.interactive
,
1297 data
->interdiraction
.inter
.final
,
1298 data
->interdiraction
.inter
.cancel
);
1301 void action_movetoedge(union ActionData
*data
)
1304 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
);
1331 client_move(c
, x
, y
);
1336 void action_growtoedge(union ActionData
*data
)
1338 int x
, y
, width
, height
, dest
;
1339 ObClient
*c
= data
->diraction
.any
.c
;
1345 a
= screen_area(c
->desktop
);
1346 x
= c
->frame
->area
.x
;
1347 y
= c
->frame
->area
.y
;
1348 width
= c
->frame
->area
.width
;
1349 height
= c
->frame
->area
.height
;
1351 switch(data
->diraction
.direction
) {
1352 case OB_DIRECTION_NORTH
:
1353 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
);
1355 height
= c
->frame
->area
.height
/ 2;
1357 height
= c
->frame
->area
.y
+ c
->frame
->area
.height
- dest
;
1361 case OB_DIRECTION_WEST
:
1362 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
);
1364 width
= c
->frame
->area
.width
/ 2;
1366 width
= c
->frame
->area
.x
+ c
->frame
->area
.width
- dest
;
1370 case OB_DIRECTION_SOUTH
:
1371 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
);
1372 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1373 height
= c
->frame
->area
.height
/ 2;
1374 y
= a
->y
+ a
->height
- height
;
1376 height
= dest
- c
->frame
->area
.y
;
1377 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1378 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1380 case OB_DIRECTION_EAST
:
1381 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
);
1382 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1383 width
= c
->frame
->area
.width
/ 2;
1384 x
= a
->x
+ a
->width
- width
;
1386 width
= dest
- c
->frame
->area
.x
;
1387 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1388 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1391 g_assert_not_reached();
1393 frame_frame_gravity(c
->frame
, &x
, &y
);
1394 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1395 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1397 client_move_resize(c
, x
, y
, width
, height
);
1401 void action_send_to_layer(union ActionData
*data
)
1403 if (data
->layer
.any
.c
)
1404 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1407 void action_toggle_layer(union ActionData
*data
)
1409 ObClient
*c
= data
->layer
.any
.c
;
1413 if (data
->layer
.layer
< 0)
1414 client_set_layer(c
, c
->below
? 0 : -1);
1415 else if (data
->layer
.layer
> 0)
1416 client_set_layer(c
, c
->above
? 0 : 1);
1421 void action_toggle_show_desktop(union ActionData
*data
)
1423 screen_show_desktop(!screen_showing_desktop
);
1426 void action_show_desktop(union ActionData
*data
)
1428 screen_show_desktop(TRUE
);
1431 void action_unshow_desktop(union ActionData
*data
)
1433 screen_show_desktop(FALSE
);