1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 action.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 See the COPYING file for a copy of the GNU General Public License.
23 #include "moveresize.h"
36 #include "startupnotify.h"
41 inline void client_action_start(union ActionData
*data
)
43 if (config_focus_follow
)
44 if (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&& !data
->any
.button
)
45 grab_pointer(FALSE
, FALSE
, OB_CURSOR_NONE
);
48 inline void client_action_end(union ActionData
*data
)
50 if (config_focus_follow
)
51 if (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
) {
52 if (!data
->any
.button
) {
57 /* usually this is sorta redundant, but with a press action
58 that moves windows our from under the cursor, the enter
59 event will come as a GrabNotify which is ignored, so this
60 makes a fake enter event
62 if ((c
= client_under_pointer()))
63 event_enter_client(c
);
71 void (*func
)(union ActionData
*);
72 void (*setup
)(ObAction
**, ObUserAction uact
);
75 static ObAction
*action_new(void (*func
)(union ActionData
*data
))
77 ObAction
*a
= g_new0(ObAction
, 1);
84 void action_ref(ObAction
*a
)
89 void action_unref(ObAction
*a
)
91 if (a
== NULL
) return;
93 if (--a
->ref
> 0) return;
95 /* deal with pointers */
96 if (a
->func
== action_execute
|| a
->func
== action_restart
)
97 g_free(a
->data
.execute
.path
);
98 else if (a
->func
== action_debug
)
99 g_free(a
->data
.debug
.string
);
100 else if (a
->func
== action_showmenu
)
101 g_free(a
->data
.showmenu
.name
);
106 ObAction
* action_copy(const ObAction
*src
)
108 ObAction
*a
= action_new(src
->func
);
112 /* deal with pointers */
113 if (a
->func
== action_execute
|| a
->func
== action_restart
)
114 a
->data
.execute
.path
= g_strdup(a
->data
.execute
.path
);
115 else if (a
->func
== action_debug
)
116 a
->data
.debug
.string
= g_strdup(a
->data
.debug
.string
);
117 else if (a
->func
== action_showmenu
)
118 a
->data
.showmenu
.name
= g_strdup(a
->data
.showmenu
.name
);
123 void setup_action_directional_focus_north(ObAction
**a
, ObUserAction uact
)
125 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
126 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTH
;
127 (*a
)->data
.interdiraction
.dialog
= TRUE
;
128 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
129 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
132 void setup_action_directional_focus_east(ObAction
**a
, ObUserAction uact
)
134 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
135 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_EAST
;
136 (*a
)->data
.interdiraction
.dialog
= TRUE
;
137 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
138 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
141 void setup_action_directional_focus_south(ObAction
**a
, ObUserAction uact
)
143 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
144 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTH
;
145 (*a
)->data
.interdiraction
.dialog
= TRUE
;
146 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
147 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
150 void setup_action_directional_focus_west(ObAction
**a
, ObUserAction uact
)
152 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
153 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_WEST
;
154 (*a
)->data
.interdiraction
.dialog
= TRUE
;
155 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
156 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
159 void setup_action_directional_focus_northeast(ObAction
**a
, ObUserAction uact
)
161 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
162 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHEAST
;
163 (*a
)->data
.interdiraction
.dialog
= TRUE
;
164 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
165 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
168 void setup_action_directional_focus_southeast(ObAction
**a
, ObUserAction uact
)
170 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
171 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHEAST
;
172 (*a
)->data
.interdiraction
.dialog
= TRUE
;
173 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
174 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
177 void setup_action_directional_focus_southwest(ObAction
**a
, ObUserAction uact
)
179 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
180 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHWEST
;
181 (*a
)->data
.interdiraction
.dialog
= TRUE
;
182 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
183 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
186 void setup_action_directional_focus_northwest(ObAction
**a
, ObUserAction uact
)
188 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
189 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHWEST
;
190 (*a
)->data
.interdiraction
.dialog
= TRUE
;
191 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
192 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
195 void setup_action_send_to_desktop(ObAction
**a
, ObUserAction uact
)
197 (*a
)->data
.sendto
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
198 (*a
)->data
.sendto
.follow
= TRUE
;
201 void setup_action_send_to_desktop_prev(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_WEST
;
206 (*a
)->data
.sendtodir
.linear
= TRUE
;
207 (*a
)->data
.sendtodir
.wrap
= TRUE
;
208 (*a
)->data
.sendtodir
.follow
= TRUE
;
211 void setup_action_send_to_desktop_next(ObAction
**a
, ObUserAction uact
)
213 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
214 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
215 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
216 (*a
)->data
.sendtodir
.linear
= TRUE
;
217 (*a
)->data
.sendtodir
.wrap
= TRUE
;
218 (*a
)->data
.sendtodir
.follow
= TRUE
;
221 void setup_action_send_to_desktop_left(ObAction
**a
, ObUserAction uact
)
223 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
224 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
225 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
226 (*a
)->data
.sendtodir
.linear
= FALSE
;
227 (*a
)->data
.sendtodir
.wrap
= TRUE
;
228 (*a
)->data
.sendtodir
.follow
= TRUE
;
231 void setup_action_send_to_desktop_right(ObAction
**a
, ObUserAction uact
)
233 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
234 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
235 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
236 (*a
)->data
.sendtodir
.linear
= FALSE
;
237 (*a
)->data
.sendtodir
.wrap
= TRUE
;
238 (*a
)->data
.sendtodir
.follow
= TRUE
;
241 void setup_action_send_to_desktop_up(ObAction
**a
, ObUserAction uact
)
243 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
244 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
245 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_NORTH
;
246 (*a
)->data
.sendtodir
.linear
= FALSE
;
247 (*a
)->data
.sendtodir
.wrap
= TRUE
;
248 (*a
)->data
.sendtodir
.follow
= TRUE
;
251 void setup_action_send_to_desktop_down(ObAction
**a
, ObUserAction uact
)
253 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
254 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
255 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_SOUTH
;
256 (*a
)->data
.sendtodir
.linear
= FALSE
;
257 (*a
)->data
.sendtodir
.wrap
= TRUE
;
258 (*a
)->data
.sendtodir
.follow
= TRUE
;
261 void setup_action_desktop(ObAction
**a
, ObUserAction uact
)
264 (*a)->data.desktop.inter.any.interactive = FALSE;
268 void setup_action_desktop_prev(ObAction
**a
, ObUserAction uact
)
270 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
271 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
272 (*a
)->data
.desktopdir
.linear
= TRUE
;
273 (*a
)->data
.desktopdir
.wrap
= TRUE
;
276 void setup_action_desktop_next(ObAction
**a
, ObUserAction uact
)
278 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
279 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
280 (*a
)->data
.desktopdir
.linear
= TRUE
;
281 (*a
)->data
.desktopdir
.wrap
= TRUE
;
284 void setup_action_desktop_left(ObAction
**a
, ObUserAction uact
)
286 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
287 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
288 (*a
)->data
.desktopdir
.linear
= FALSE
;
289 (*a
)->data
.desktopdir
.wrap
= TRUE
;
292 void setup_action_desktop_right(ObAction
**a
, ObUserAction uact
)
294 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
295 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
296 (*a
)->data
.desktopdir
.linear
= FALSE
;
297 (*a
)->data
.desktopdir
.wrap
= TRUE
;
300 void setup_action_desktop_up(ObAction
**a
, ObUserAction uact
)
302 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
303 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_NORTH
;
304 (*a
)->data
.desktopdir
.linear
= FALSE
;
305 (*a
)->data
.desktopdir
.wrap
= TRUE
;
308 void setup_action_desktop_down(ObAction
**a
, ObUserAction uact
)
310 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
311 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_SOUTH
;
312 (*a
)->data
.desktopdir
.linear
= FALSE
;
313 (*a
)->data
.desktopdir
.wrap
= TRUE
;
316 void setup_action_cycle_windows_next(ObAction
**a
, ObUserAction uact
)
318 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
319 (*a
)->data
.cycle
.linear
= FALSE
;
320 (*a
)->data
.cycle
.forward
= TRUE
;
321 (*a
)->data
.cycle
.dialog
= TRUE
;
322 (*a
)->data
.cycle
.dock_windows
= FALSE
;
323 (*a
)->data
.cycle
.desktop_windows
= FALSE
;
324 (*a
)->data
.cycle
.all_desktops
= FALSE
;
327 void setup_action_cycle_windows_previous(ObAction
**a
, ObUserAction uact
)
329 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
330 (*a
)->data
.cycle
.linear
= FALSE
;
331 (*a
)->data
.cycle
.forward
= FALSE
;
332 (*a
)->data
.cycle
.dialog
= TRUE
;
333 (*a
)->data
.cycle
.dock_windows
= FALSE
;
334 (*a
)->data
.cycle
.desktop_windows
= FALSE
;
335 (*a
)->data
.cycle
.all_desktops
= FALSE
;
338 void setup_action_movefromedge_north(ObAction
**a
, ObUserAction uact
)
340 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
341 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
342 (*a
)->data
.diraction
.hang
= TRUE
;
345 void setup_action_movefromedge_south(ObAction
**a
, ObUserAction uact
)
347 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
348 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
349 (*a
)->data
.diraction
.hang
= TRUE
;
352 void setup_action_movefromedge_east(ObAction
**a
, ObUserAction uact
)
354 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
355 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
356 (*a
)->data
.diraction
.hang
= TRUE
;
359 void setup_action_movefromedge_west(ObAction
**a
, ObUserAction uact
)
361 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
362 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
363 (*a
)->data
.diraction
.hang
= TRUE
;
366 void setup_action_movetoedge_north(ObAction
**a
, ObUserAction uact
)
368 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
369 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
370 (*a
)->data
.diraction
.hang
= FALSE
;
373 void setup_action_movetoedge_south(ObAction
**a
, ObUserAction uact
)
375 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
376 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
377 (*a
)->data
.diraction
.hang
= FALSE
;
380 void setup_action_movetoedge_east(ObAction
**a
, ObUserAction uact
)
382 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
383 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
384 (*a
)->data
.diraction
.hang
= FALSE
;
387 void setup_action_movetoedge_west(ObAction
**a
, ObUserAction uact
)
389 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
390 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
391 (*a
)->data
.diraction
.hang
= FALSE
;
394 void setup_action_growtoedge_north(ObAction
**a
, ObUserAction uact
)
396 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
397 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
400 void setup_action_growtoedge_south(ObAction
**a
, ObUserAction uact
)
402 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
403 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
406 void setup_action_growtoedge_east(ObAction
**a
, ObUserAction uact
)
408 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
409 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
412 void setup_action_growtoedge_west(ObAction
**a
, ObUserAction uact
)
414 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
415 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
418 void setup_action_top_layer(ObAction
**a
, ObUserAction uact
)
420 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
421 (*a
)->data
.layer
.layer
= 1;
424 void setup_action_normal_layer(ObAction
**a
, ObUserAction uact
)
426 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
427 (*a
)->data
.layer
.layer
= 0;
430 void setup_action_bottom_layer(ObAction
**a
, ObUserAction uact
)
432 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
433 (*a
)->data
.layer
.layer
= -1;
436 void setup_action_move(ObAction
**a
, ObUserAction uact
)
438 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
439 (*a
)->data
.moveresize
.keyboard
=
440 (uact
== OB_USER_ACTION_NONE
||
441 uact
== OB_USER_ACTION_KEYBOARD_KEY
||
442 uact
== OB_USER_ACTION_MENU_SELECTION
);
443 (*a
)->data
.moveresize
.corner
= 0;
446 void setup_action_resize(ObAction
**a
, ObUserAction uact
)
448 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
449 (*a
)->data
.moveresize
.keyboard
=
450 (uact
== OB_USER_ACTION_NONE
||
451 uact
== OB_USER_ACTION_KEYBOARD_KEY
||
452 uact
== OB_USER_ACTION_MENU_SELECTION
);
453 (*a
)->data
.moveresize
.corner
= 0;
456 void setup_action_showmenu(ObAction
**a
, ObUserAction uact
)
458 (*a
)->data
.showmenu
.any
.client_action
= OB_CLIENT_ACTION_OPTIONAL
;
459 /* you cannot call ShowMenu from inside a menu, cuz the menu code makes
460 assumptions that there is only one menu (and submenus) open at
462 if (uact
== OB_USER_ACTION_MENU_SELECTION
) {
468 void setup_action_focus(ObAction
**a
, ObUserAction uact
)
470 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_OPTIONAL
;
473 void setup_client_action(ObAction
**a
, ObUserAction uact
)
475 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
478 ActionString actionstrings
[] =
491 "directionalfocusnorth",
492 action_directional_focus
,
493 setup_action_directional_focus_north
496 "directionalfocuseast",
497 action_directional_focus
,
498 setup_action_directional_focus_east
501 "directionalfocussouth",
502 action_directional_focus
,
503 setup_action_directional_focus_south
506 "directionalfocuswest",
507 action_directional_focus
,
508 setup_action_directional_focus_west
511 "directionalfocusnortheast",
512 action_directional_focus
,
513 setup_action_directional_focus_northeast
516 "directionalfocussoutheast",
517 action_directional_focus
,
518 setup_action_directional_focus_southeast
521 "directionalfocussouthwest",
522 action_directional_focus
,
523 setup_action_directional_focus_southwest
526 "directionalfocusnorthwest",
527 action_directional_focus
,
528 setup_action_directional_focus_northwest
552 action_focus_order_to_bottom
,
607 action_toggle_omnipresent
,
612 action_move_relative_horz
,
617 action_move_relative_vert
,
622 action_move_to_center
,
626 "resizerelativehorz",
627 action_resize_relative_horz
,
631 "resizerelativevert",
632 action_resize_relative_vert
,
637 action_move_relative
,
642 action_resize_relative
,
647 action_maximize_full
,
652 action_unmaximize_full
,
656 "togglemaximizefull",
657 action_toggle_maximize_full
,
662 action_maximize_horz
,
667 action_unmaximize_horz
,
671 "togglemaximizehorz",
672 action_toggle_maximize_horz
,
677 action_maximize_vert
,
682 action_unmaximize_vert
,
686 "togglemaximizevert",
687 action_toggle_maximize_vert
,
692 action_toggle_fullscreen
,
697 action_send_to_desktop
,
698 setup_action_send_to_desktop
702 action_send_to_desktop_dir
,
703 setup_action_send_to_desktop_next
706 "sendtodesktopprevious",
707 action_send_to_desktop_dir
,
708 setup_action_send_to_desktop_prev
711 "sendtodesktopright",
712 action_send_to_desktop_dir
,
713 setup_action_send_to_desktop_right
717 action_send_to_desktop_dir
,
718 setup_action_send_to_desktop_left
722 action_send_to_desktop_dir
,
723 setup_action_send_to_desktop_up
727 action_send_to_desktop_dir
,
728 setup_action_send_to_desktop_down
738 setup_action_desktop_next
743 setup_action_desktop_prev
748 setup_action_desktop_right
753 setup_action_desktop_left
758 setup_action_desktop_up
763 setup_action_desktop_down
767 action_toggle_decorations
,
781 "toggledockautohide",
782 action_toggle_dockautohide
,
787 action_toggle_show_desktop
,
797 action_unshow_desktop
,
823 setup_action_showmenu
827 action_send_to_layer
,
828 setup_action_top_layer
833 setup_action_top_layer
837 action_send_to_layer
,
838 setup_action_normal_layer
842 action_send_to_layer
,
843 setup_action_bottom_layer
846 "togglealwaysonbottom",
848 setup_action_bottom_layer
852 action_cycle_windows
,
853 setup_action_cycle_windows_next
857 action_cycle_windows
,
858 setup_action_cycle_windows_previous
863 setup_action_movefromedge_north
868 setup_action_movefromedge_south
873 setup_action_movefromedge_west
878 setup_action_movefromedge_east
883 setup_action_movetoedge_north
888 setup_action_movetoedge_south
893 setup_action_movetoedge_west
898 setup_action_movetoedge_east
903 setup_action_growtoedge_north
908 setup_action_growtoedge_south
913 setup_action_growtoedge_west
918 setup_action_growtoedge_east
932 /* only key bindings can be interactive. thus saith the xor.
933 because of how the mouse is grabbed, mouse events dont even get
934 read during interactive events, so no dice! >:) */
935 #define INTERACTIVE_LIMIT(a, uact) \
936 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
937 a->data.any.interactive = FALSE;
939 ObAction
*action_from_string(const gchar
*name
, ObUserAction uact
)
942 gboolean exist
= FALSE
;
945 for (i
= 0; actionstrings
[i
].name
; i
++)
946 if (!g_ascii_strcasecmp(name
, actionstrings
[i
].name
)) {
948 a
= action_new(actionstrings
[i
].func
);
949 if (actionstrings
[i
].setup
)
950 actionstrings
[i
].setup(&a
, uact
);
952 INTERACTIVE_LIMIT(a
, uact
);
956 g_message(_("Invalid action '%s' requested. No such action exists."),
959 g_message(_("Invalid use of action '%s'. Action will be ignored."),
964 ObAction
*action_parse(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
968 ObAction
*act
= NULL
;
971 if (parse_attr_string("name", node
, &actname
)) {
972 if ((act
= action_from_string(actname
, uact
))) {
973 if (act
->func
== action_execute
|| act
->func
== action_restart
) {
974 if ((n
= parse_find_node("execute", node
->xmlChildrenNode
))) {
975 gchar
*s
= parse_string(doc
, n
);
976 act
->data
.execute
.path
= parse_expand_tilde(s
);
979 if ((n
= parse_find_node("startupnotify", node
->xmlChildrenNode
))) {
981 if ((m
= parse_find_node("enabled", n
->xmlChildrenNode
)))
982 act
->data
.execute
.startupnotify
= parse_bool(doc
, m
);
983 if ((m
= parse_find_node("name", n
->xmlChildrenNode
)))
984 act
->data
.execute
.name
= parse_string(doc
, m
);
985 if ((m
= parse_find_node("icon", n
->xmlChildrenNode
)))
986 act
->data
.execute
.icon_name
= parse_string(doc
, m
);
988 } else if (act
->func
== action_debug
) {
989 if ((n
= parse_find_node("string", node
->xmlChildrenNode
)))
990 act
->data
.debug
.string
= parse_string(doc
, n
);
991 } else if (act
->func
== action_showmenu
) {
992 if ((n
= parse_find_node("menu", node
->xmlChildrenNode
)))
993 act
->data
.showmenu
.name
= parse_string(doc
, n
);
994 } else if (act
->func
== action_move_relative_horz
||
995 act
->func
== action_move_relative_vert
||
996 act
->func
== action_resize_relative_horz
||
997 act
->func
== action_resize_relative_vert
) {
998 if ((n
= parse_find_node("delta", node
->xmlChildrenNode
)))
999 act
->data
.relative
.deltax
= parse_int(doc
, n
);
1000 } else if (act
->func
== action_move_relative
) {
1001 if ((n
= parse_find_node("x", node
->xmlChildrenNode
)))
1002 act
->data
.relative
.deltax
= parse_int(doc
, n
);
1003 if ((n
= parse_find_node("y", node
->xmlChildrenNode
)))
1004 act
->data
.relative
.deltay
= parse_int(doc
, n
);
1005 } else if (act
->func
== action_resize_relative
) {
1006 if ((n
= parse_find_node("left", node
->xmlChildrenNode
)))
1007 act
->data
.relative
.deltaxl
= parse_int(doc
, n
);
1008 if ((n
= parse_find_node("up", node
->xmlChildrenNode
)))
1009 act
->data
.relative
.deltayu
= parse_int(doc
, n
);
1010 if ((n
= parse_find_node("right", node
->xmlChildrenNode
)))
1011 act
->data
.relative
.deltax
= parse_int(doc
, n
);
1012 if ((n
= parse_find_node("down", node
->xmlChildrenNode
)))
1013 act
->data
.relative
.deltay
= parse_int(doc
, n
);
1014 } else if (act
->func
== action_desktop
) {
1015 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1016 act
->data
.desktop
.desk
= parse_int(doc
, n
);
1017 if (act
->data
.desktop
.desk
> 0) act
->data
.desktop
.desk
--;
1019 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
1020 act->data.desktop.inter.any.interactive =
1023 } else if (act
->func
== action_send_to_desktop
) {
1024 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1025 act
->data
.sendto
.desk
= parse_int(doc
, n
);
1026 if (act
->data
.sendto
.desk
> 0) act
->data
.sendto
.desk
--;
1027 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
1028 act
->data
.sendto
.follow
= parse_bool(doc
, n
);
1029 } else if (act
->func
== action_desktop_dir
) {
1030 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
1031 act
->data
.desktopdir
.wrap
= parse_bool(doc
, n
);
1032 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1033 act
->data
.desktopdir
.inter
.any
.interactive
=
1035 } else if (act
->func
== action_send_to_desktop_dir
) {
1036 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
1037 act
->data
.sendtodir
.wrap
= parse_bool(doc
, n
);
1038 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
1039 act
->data
.sendtodir
.follow
= parse_bool(doc
, n
);
1040 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1041 act
->data
.sendtodir
.inter
.any
.interactive
=
1043 } else if (act
->func
== action_activate
) {
1044 if ((n
= parse_find_node("here", node
->xmlChildrenNode
)))
1045 act
->data
.activate
.here
= parse_bool(doc
, n
);
1046 } else if (act
->func
== action_cycle_windows
) {
1047 if ((n
= parse_find_node("linear", node
->xmlChildrenNode
)))
1048 act
->data
.cycle
.linear
= parse_bool(doc
, n
);
1049 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1050 act
->data
.cycle
.dialog
= parse_bool(doc
, n
);
1051 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
1052 act
->data
.cycle
.dock_windows
= parse_bool(doc
, n
);
1053 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1054 act
->data
.cycle
.desktop_windows
= parse_bool(doc
, n
);
1055 if ((n
= parse_find_node("allDesktops",
1056 node
->xmlChildrenNode
)))
1057 act
->data
.cycle
.all_desktops
= parse_bool(doc
, n
);
1058 } else if (act
->func
== action_directional_focus
) {
1059 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1060 act
->data
.interdiraction
.dialog
= parse_bool(doc
, n
);
1061 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
1062 act
->data
.interdiraction
.dock_windows
= parse_bool(doc
, n
);
1063 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1064 act
->data
.interdiraction
.desktop_windows
=
1066 } else if (act
->func
== action_resize
) {
1067 if ((n
= parse_find_node("edge", node
->xmlChildrenNode
))) {
1068 gchar
*s
= parse_string(doc
, n
);
1069 if (!g_ascii_strcasecmp(s
, "top"))
1070 act
->data
.moveresize
.corner
=
1071 prop_atoms
.net_wm_moveresize_size_top
;
1072 else if (!g_ascii_strcasecmp(s
, "bottom"))
1073 act
->data
.moveresize
.corner
=
1074 prop_atoms
.net_wm_moveresize_size_bottom
;
1075 else if (!g_ascii_strcasecmp(s
, "left"))
1076 act
->data
.moveresize
.corner
=
1077 prop_atoms
.net_wm_moveresize_size_left
;
1078 else if (!g_ascii_strcasecmp(s
, "right"))
1079 act
->data
.moveresize
.corner
=
1080 prop_atoms
.net_wm_moveresize_size_right
;
1081 else if (!g_ascii_strcasecmp(s
, "topleft"))
1082 act
->data
.moveresize
.corner
=
1083 prop_atoms
.net_wm_moveresize_size_topleft
;
1084 else if (!g_ascii_strcasecmp(s
, "topright"))
1085 act
->data
.moveresize
.corner
=
1086 prop_atoms
.net_wm_moveresize_size_topright
;
1087 else if (!g_ascii_strcasecmp(s
, "bottomleft"))
1088 act
->data
.moveresize
.corner
=
1089 prop_atoms
.net_wm_moveresize_size_bottomleft
;
1090 else if (!g_ascii_strcasecmp(s
, "bottomright"))
1091 act
->data
.moveresize
.corner
=
1092 prop_atoms
.net_wm_moveresize_size_bottomright
;
1095 } else if (act
->func
== action_raise
||
1096 act
->func
== action_lower
||
1097 act
->func
== action_raiselower
||
1098 act
->func
== action_shadelower
||
1099 act
->func
== action_unshaderaise
) {
1101 INTERACTIVE_LIMIT(act
, uact
);
1108 void action_run_list(GSList
*acts
, ObClient
*c
, ObFrameContext context
,
1109 guint state
, guint button
, gint x
, gint y
, Time time
,
1110 gboolean cancel
, gboolean done
)
1119 screen_pointer_pos(&x
, &y
);
1121 for (it
= acts
; it
; it
= g_slist_next(it
)) {
1124 if (!(a
->data
.any
.client_action
== OB_CLIENT_ACTION_ALWAYS
&& !c
)) {
1125 a
->data
.any
.c
= a
->data
.any
.client_action
? c
: NULL
;
1126 a
->data
.any
.context
= context
;
1130 a
->data
.any
.button
= button
;
1132 a
->data
.any
.time
= time
;
1134 if (a
->data
.any
.interactive
) {
1135 a
->data
.inter
.cancel
= cancel
;
1136 a
->data
.inter
.final
= done
;
1137 if (!(cancel
|| done
))
1138 if (!keyboard_interactive_grab(state
, a
->data
.any
.c
, a
))
1142 /* XXX UGLY HACK race with motion event starting a move and the
1143 button release gettnig processed first. answer: don't queue
1144 moveresize starts. UGLY HACK XXX */
1145 if (a
->data
.any
.interactive
|| a
->func
== action_move
||
1146 a
->func
== action_resize
)
1148 /* interactive actions are not queued */
1151 (context
== OB_FRAME_CONTEXT_CLIENT
||
1152 (c
->type
== OB_CLIENT_TYPE_DESKTOP
&&
1153 context
== OB_FRAME_CONTEXT_DESKTOP
)) &&
1154 (a
->func
== action_focus
||
1155 a
->func
== action_activate
||
1156 a
->func
== action_showmenu
))
1158 /* XXX MORE UGLY HACK
1159 actions from clicks on client windows are NOT queued.
1160 this solves the mysterious click-and-drag-doesnt-work
1161 problem. it was because the window gets focused and stuff
1162 after the button event has already been passed through. i
1163 dont really know why it should care but it does and it makes
1166 however this very bogus ! !
1167 we want to send the button press to the window BEFORE
1168 we do the action because the action might move the windows
1169 (eg change desktops) and then the button press ends up on
1170 the completely wrong window !
1171 so, this is just for that bug, and it will only NOT queue it
1172 if it is a focusing action that can be used with the mouse
1175 also with the menus, there is a race going on. if the
1176 desktop wants to pop up a menu, and we do to, we send them
1177 the button before we pop up the menu, so they pop up their
1178 menu first. but not always. if we pop up our menu before
1179 sending them the button press, then the result is
1184 ob_main_loop_queue_action(ob_main_loop
, a
);
1189 void action_run_string(const gchar
*name
, struct _ObClient
*c
, Time time
)
1194 a
= action_from_string(name
, OB_USER_ACTION_NONE
);
1197 l
= g_slist_append(NULL
, a
);
1199 action_run(l
, c
, 0, time
);
1202 void action_debug(union ActionData
*data
)
1204 if (data
->debug
.string
)
1205 g_print("%s\n", data
->debug
.string
);
1208 void action_execute(union ActionData
*data
)
1211 gchar
*cmd
, **argv
= 0;
1212 if (data
->execute
.path
) {
1213 /* Ungrab the keyboard before running the action.
1215 If there is an interactive action going on, then cancel it to
1216 release the keyboard. If not, then call XUngrabKeyboard().
1218 We call XUngrabKeyboard because a key press causes a passive
1219 grab on the keyboard, and so if program we are executing wants to
1220 grab the keyboard, it will fail if the button is still held down
1223 Use the X function not out own, because we're not considering
1224 a grab to be in place at all so our function won't try ungrab
1227 if (keyboard_interactively_grabbed())
1228 keyboard_interactive_cancel();
1230 XUngrabKeyboard(ob_display
, data
->any
.time
);
1232 cmd
= g_filename_from_utf8(data
->execute
.path
, -1, NULL
, NULL
, NULL
);
1234 if (!g_shell_parse_argv (cmd
, NULL
, &argv
, &e
)) {
1235 g_message(_("Failed to execute '%s': %s"),
1238 } else if (data
->execute
.startupnotify
) {
1241 program
= g_path_get_basename(argv
[0]);
1242 /* sets up the environment */
1243 sn_setup_spawn_environment(program
,
1245 data
->execute
.icon_name
,
1246 /* launch it on the current
1249 data
->execute
.any
.time
);
1250 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
|
1251 G_SPAWN_DO_NOT_REAP_CHILD
,
1252 NULL
, NULL
, NULL
, &e
)) {
1253 g_message(_("Failed to execute '%s': %s"),
1258 unsetenv("DESKTOP_STARTUP_ID");
1262 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
|
1263 G_SPAWN_DO_NOT_REAP_CHILD
,
1264 NULL
, NULL
, NULL
, &e
))
1266 g_message(_("Failed to execute '%s': %s"),
1274 g_message(_("Failed to convert the path '%s' from utf8"),
1275 data
->execute
.path
);
1280 void action_activate(union ActionData
*data
)
1282 if (data
->client
.any
.c
) {
1283 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1284 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1285 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1287 /* if using focus_delay, stop the timer now so that focus doesn't
1289 event_halt_focus_delay();
1291 client_activate(data
->activate
.any
.c
, data
->activate
.here
, TRUE
);
1294 /* focus action on something other than a client, make keybindings
1295 work for this openbox instance, but don't focus any specific client
1301 void action_focus(union ActionData
*data
)
1303 if (data
->client
.any
.c
) {
1304 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1305 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1306 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1308 /* if using focus_delay, stop the timer now so that focus doesn't
1310 event_halt_focus_delay();
1312 client_focus(data
->client
.any
.c
);
1315 /* focus action on something other than a client, make keybindings
1316 work for this openbox instance, but don't focus any specific client
1322 void action_unfocus (union ActionData
*data
)
1324 if (data
->client
.any
.c
== focus_client
)
1325 focus_fallback(TRUE
);
1328 void action_iconify(union ActionData
*data
)
1330 client_action_start(data
);
1331 client_iconify(data
->client
.any
.c
, TRUE
, TRUE
, FALSE
);
1332 client_action_end(data
);
1335 void action_focus_order_to_bottom(union ActionData
*data
)
1337 focus_order_to_bottom(data
->client
.any
.c
);
1340 void action_raiselower(union ActionData
*data
)
1342 ObClient
*c
= data
->client
.any
.c
;
1344 gboolean raise
= FALSE
;
1346 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
1347 if (WINDOW_IS_CLIENT(it
->data
)) {
1348 ObClient
*cit
= it
->data
;
1350 if (cit
== c
) break;
1351 if (client_normal(cit
) == client_normal(c
) &&
1352 cit
->layer
== c
->layer
&&
1353 cit
->frame
->visible
&&
1354 !client_search_transient(c
, cit
))
1356 if (RECT_INTERSECTS_RECT(cit
->frame
->area
, c
->frame
->area
)) {
1370 void action_raise(union ActionData
*data
)
1372 client_action_start(data
);
1373 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1374 client_action_end(data
);
1377 void action_unshaderaise(union ActionData
*data
)
1379 if (data
->client
.any
.c
->shaded
)
1380 action_unshade(data
);
1385 void action_shadelower(union ActionData
*data
)
1387 if (data
->client
.any
.c
->shaded
)
1393 void action_lower(union ActionData
*data
)
1395 client_action_start(data
);
1396 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1397 client_action_end(data
);
1400 void action_close(union ActionData
*data
)
1402 client_close(data
->client
.any
.c
);
1405 void action_kill(union ActionData
*data
)
1407 client_kill(data
->client
.any
.c
);
1410 void action_shade(union ActionData
*data
)
1412 client_action_start(data
);
1413 client_shade(data
->client
.any
.c
, TRUE
);
1414 client_action_end(data
);
1417 void action_unshade(union ActionData
*data
)
1419 client_action_start(data
);
1420 client_shade(data
->client
.any
.c
, FALSE
);
1421 client_action_end(data
);
1424 void action_toggle_shade(union ActionData
*data
)
1426 client_action_start(data
);
1427 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1428 client_action_end(data
);
1431 void action_toggle_omnipresent(union ActionData
*data
)
1433 client_set_desktop(data
->client
.any
.c
,
1434 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1435 screen_desktop
: DESKTOP_ALL
, FALSE
);
1438 void action_move_relative_horz(union ActionData
*data
)
1440 ObClient
*c
= data
->relative
.any
.c
;
1441 client_action_start(data
);
1442 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
);
1443 client_action_end(data
);
1446 void action_move_relative_vert(union ActionData
*data
)
1448 ObClient
*c
= data
->relative
.any
.c
;
1449 client_action_start(data
);
1450 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.deltax
);
1451 client_action_end(data
);
1454 void action_move_to_center(union ActionData
*data
)
1456 ObClient
*c
= data
->client
.any
.c
;
1458 area
= screen_area_monitor(c
->desktop
, 0);
1459 client_action_start(data
);
1460 client_move(c
, area
->width
/ 2 - c
->area
.width
/ 2,
1461 area
->height
/ 2 - c
->area
.height
/ 2);
1462 client_action_end(data
);
1465 void action_resize_relative_horz(union ActionData
*data
)
1467 ObClient
*c
= data
->relative
.any
.c
;
1468 client_action_start(data
);
1470 c
->area
.width
+ data
->relative
.deltax
* c
->size_inc
.width
,
1472 client_action_end(data
);
1475 void action_resize_relative_vert(union ActionData
*data
)
1477 ObClient
*c
= data
->relative
.any
.c
;
1479 client_action_start(data
);
1480 client_resize(c
, c
->area
.width
, c
->area
.height
+
1481 data
->relative
.deltax
* c
->size_inc
.height
);
1482 client_action_end(data
);
1486 void action_move_relative(union ActionData
*data
)
1488 ObClient
*c
= data
->relative
.any
.c
;
1489 client_action_start(data
);
1490 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
+
1491 data
->relative
.deltay
);
1492 client_action_end(data
);
1495 void action_resize_relative(union ActionData
*data
)
1497 ObClient
*c
= data
->relative
.any
.c
;
1498 gint x
, y
, ow
, w
, oh
, h
, lw
, lh
;
1500 client_action_start(data
);
1505 w
= ow
+ data
->relative
.deltax
* c
->size_inc
.width
1506 + data
->relative
.deltaxl
* c
->size_inc
.width
;
1507 oh
= c
->area
.height
;
1508 h
= oh
+ data
->relative
.deltay
* c
->size_inc
.height
1509 + data
->relative
.deltayu
* c
->size_inc
.height
;
1511 client_try_configure(c
, &x
, &y
, &w
, &h
, &lw
, &lh
, TRUE
);
1512 client_move_resize(c
, x
+ (ow
- w
), y
+ (oh
- h
), w
, h
);
1513 client_action_end(data
);
1516 void action_maximize_full(union ActionData
*data
)
1518 client_action_start(data
);
1519 client_maximize(data
->client
.any
.c
, TRUE
, 0);
1520 client_action_end(data
);
1523 void action_unmaximize_full(union ActionData
*data
)
1525 client_action_start(data
);
1526 client_maximize(data
->client
.any
.c
, FALSE
, 0);
1527 client_action_end(data
);
1530 void action_toggle_maximize_full(union ActionData
*data
)
1532 client_action_start(data
);
1533 client_maximize(data
->client
.any
.c
,
1534 !(data
->client
.any
.c
->max_horz
||
1535 data
->client
.any
.c
->max_vert
),
1537 client_action_end(data
);
1540 void action_maximize_horz(union ActionData
*data
)
1542 client_action_start(data
);
1543 client_maximize(data
->client
.any
.c
, TRUE
, 1);
1544 client_action_end(data
);
1547 void action_unmaximize_horz(union ActionData
*data
)
1549 client_action_start(data
);
1550 client_maximize(data
->client
.any
.c
, FALSE
, 1);
1551 client_action_end(data
);
1554 void action_toggle_maximize_horz(union ActionData
*data
)
1556 client_action_start(data
);
1557 client_maximize(data
->client
.any
.c
,
1558 !data
->client
.any
.c
->max_horz
, 1);
1559 client_action_end(data
);
1562 void action_maximize_vert(union ActionData
*data
)
1564 client_action_start(data
);
1565 client_maximize(data
->client
.any
.c
, TRUE
, 2);
1566 client_action_end(data
);
1569 void action_unmaximize_vert(union ActionData
*data
)
1571 client_action_start(data
);
1572 client_maximize(data
->client
.any
.c
, FALSE
, 2);
1573 client_action_end(data
);
1576 void action_toggle_maximize_vert(union ActionData
*data
)
1578 client_action_start(data
);
1579 client_maximize(data
->client
.any
.c
,
1580 !data
->client
.any
.c
->max_vert
, 2);
1581 client_action_end(data
);
1584 void action_toggle_fullscreen(union ActionData
*data
)
1586 client_action_start(data
);
1587 client_fullscreen(data
->client
.any
.c
, !(data
->client
.any
.c
->fullscreen
));
1588 client_action_end(data
);
1591 void action_send_to_desktop(union ActionData
*data
)
1593 ObClient
*c
= data
->sendto
.any
.c
;
1595 if (!client_normal(c
)) return;
1597 if (data
->sendto
.desk
< screen_num_desktops
||
1598 data
->sendto
.desk
== DESKTOP_ALL
) {
1599 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
);
1600 if (data
->sendto
.follow
)
1601 screen_set_desktop(data
->sendto
.desk
, TRUE
);
1605 void action_desktop(union ActionData
*data
)
1607 /* XXX add the interactive/dialog option back again once the dialog
1608 has been made to not use grabs */
1609 if (data
->desktop
.desk
< screen_num_desktops
||
1610 data
->desktop
.desk
== DESKTOP_ALL
)
1612 screen_set_desktop(data
->desktop
.desk
, TRUE
);
1613 if (data
->inter
.any
.interactive
)
1614 screen_desktop_popup(data
->desktop
.desk
, TRUE
);
1618 void action_desktop_dir(union ActionData
*data
)
1622 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1623 data
->desktopdir
.wrap
,
1624 data
->desktopdir
.linear
,
1625 data
->desktopdir
.inter
.any
.interactive
,
1626 data
->desktopdir
.inter
.final
,
1627 data
->desktopdir
.inter
.cancel
);
1628 /* only move the desktop when the action is complete. if we switch
1629 desktops during the interactive action, focus will move but with
1630 NotifyWhileGrabbed and applications don't like that. */
1631 if (!data
->sendtodir
.inter
.any
.interactive
||
1632 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1634 if (d
!= screen_desktop
) screen_set_desktop(d
, TRUE
);
1638 void action_send_to_desktop_dir(union ActionData
*data
)
1640 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1643 if (!client_normal(c
)) return;
1645 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1646 data
->sendtodir
.linear
,
1647 data
->sendtodir
.inter
.any
.interactive
,
1648 data
->sendtodir
.inter
.final
,
1649 data
->sendtodir
.inter
.cancel
);
1650 /* only move the desktop when the action is complete. if we switch
1651 desktops during the interactive action, focus will move but with
1652 NotifyWhileGrabbed and applications don't like that. */
1653 if (!data
->sendtodir
.inter
.any
.interactive
||
1654 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1656 client_set_desktop(c
, d
, data
->sendtodir
.follow
);
1657 if (data
->sendtodir
.follow
&& d
!= screen_desktop
)
1658 screen_set_desktop(d
, TRUE
);
1662 void action_desktop_last(union ActionData
*data
)
1664 screen_set_desktop(screen_last_desktop
, TRUE
);
1667 void action_toggle_decorations(union ActionData
*data
)
1669 ObClient
*c
= data
->client
.any
.c
;
1671 client_action_start(data
);
1672 client_set_undecorated(c
, !c
->undecorated
);
1673 client_action_end(data
);
1676 static guint32
pick_corner(gint x
, gint y
, gint cx
, gint cy
, gint cw
, gint ch
,
1679 /* let's make x and y client relative instead of screen relative */
1681 y
= ch
- (y
- cy
); /* y is inverted, 0 is at the bottom of the window */
1684 #define A -4*X + 7*ch/3
1685 #define B 4*X -15*ch/9
1686 #define C -X/4 + 2*ch/3
1687 #define D X/4 + 5*ch/12
1688 #define E X/4 + ch/3
1689 #define F -X/4 + 7*ch/12
1690 #define G 4*X - 4*ch/3
1691 #define H -4*X + 8*ch/3
1692 #define a (y > 5*ch/9)
1693 #define b (x < 4*cw/9)
1694 #define c (x > 5*cw/9)
1695 #define d (y < 4*ch/9)
1698 Each of these defines (except X which is just there for fun), represents
1699 the equation of a line. The lines they represent are shown in the diagram
1700 below. Checking y against these lines, we are able to choose a region
1701 of the window as shown.
1703 +---------------------A-------|-------|-------B---------------------+
1710 | northwest | A north B | northeast |
1713 C---------------------+----A--+-------+--B----+---------------------D
1714 |CCCCCCC | A B | DDDDDDD|
1715 | CCCCCCCC | A | | B | DDDDDDDD |
1716 | CCCCCCC A B DDDDDDD |
1717 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
1719 | west | b move c | east | ad
1721 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
1722 | EEEEEEE G H FFFFFFF |
1723 | EEEEEEEE | G | | H | FFFFFFFF |
1724 |EEEEEEE | G H | FFFFFFF|
1725 E---------------------+----G--+-------+--H----+---------------------F
1728 | southwest | G south H | southeast |
1735 +---------------------G-------|-------|-------H---------------------+
1739 /* for shaded windows, you can only resize west/east and move */
1741 return prop_atoms
.net_wm_moveresize_size_left
;
1743 return prop_atoms
.net_wm_moveresize_size_right
;
1744 return prop_atoms
.net_wm_moveresize_move
;
1747 if (y
< A
&& y
>= C
)
1748 return prop_atoms
.net_wm_moveresize_size_topleft
;
1749 else if (y
>= A
&& y
>= B
&& a
)
1750 return prop_atoms
.net_wm_moveresize_size_top
;
1751 else if (y
< B
&& y
>= D
)
1752 return prop_atoms
.net_wm_moveresize_size_topright
;
1753 else if (y
< C
&& y
>= E
&& b
)
1754 return prop_atoms
.net_wm_moveresize_size_left
;
1755 else if (y
< D
&& y
>= F
&& c
)
1756 return prop_atoms
.net_wm_moveresize_size_right
;
1757 else if (y
< E
&& y
>= G
)
1758 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1759 else if (y
< G
&& y
< H
&& d
)
1760 return prop_atoms
.net_wm_moveresize_size_bottom
;
1761 else if (y
>= H
&& y
< F
)
1762 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1764 return prop_atoms
.net_wm_moveresize_move
;
1781 void action_move(union ActionData
*data
)
1783 ObClient
*c
= data
->moveresize
.any
.c
;
1786 if (data
->moveresize
.keyboard
)
1787 corner
= prop_atoms
.net_wm_moveresize_move_keyboard
;
1789 corner
= prop_atoms
.net_wm_moveresize_move
;
1791 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1794 void action_resize(union ActionData
*data
)
1796 ObClient
*c
= data
->moveresize
.any
.c
;
1799 if (data
->moveresize
.keyboard
)
1800 corner
= prop_atoms
.net_wm_moveresize_size_keyboard
;
1801 else if (data
->moveresize
.corner
)
1802 corner
= data
->moveresize
.corner
; /* it was specified in the binding */
1804 corner
= pick_corner(data
->any
.x
, data
->any
.y
,
1805 c
->frame
->area
.x
, c
->frame
->area
.y
,
1806 /* use the client size because the frame
1807 can be differently sized (shaded
1808 windows) and we want this based on the
1810 c
->area
.width
+ c
->frame
->size
.left
+
1811 c
->frame
->size
.right
,
1812 c
->area
.height
+ c
->frame
->size
.top
+
1813 c
->frame
->size
.bottom
, c
->shaded
);
1815 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1818 void action_reconfigure(union ActionData
*data
)
1823 void action_restart(union ActionData
*data
)
1825 ob_restart_other(data
->execute
.path
);
1828 void action_exit(union ActionData
*data
)
1833 void action_showmenu(union ActionData
*data
)
1835 if (data
->showmenu
.name
) {
1836 menu_show(data
->showmenu
.name
, data
->any
.x
, data
->any
.y
,
1837 data
->any
.button
, data
->showmenu
.any
.c
);
1841 void action_cycle_windows(union ActionData
*data
)
1843 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1845 event_halt_focus_delay();
1847 focus_cycle(data
->cycle
.forward
,
1848 data
->cycle
.all_desktops
,
1849 data
->cycle
.dock_windows
,
1850 data
->cycle
.desktop_windows
,
1851 data
->cycle
.linear
, data
->any
.interactive
,
1853 data
->cycle
.inter
.final
, data
->cycle
.inter
.cancel
);
1856 void action_directional_focus(union ActionData
*data
)
1858 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1860 event_halt_focus_delay();
1862 focus_directional_cycle(data
->interdiraction
.direction
,
1863 data
->interdiraction
.dock_windows
,
1864 data
->interdiraction
.desktop_windows
,
1865 data
->any
.interactive
,
1866 data
->interdiraction
.dialog
,
1867 data
->interdiraction
.inter
.final
,
1868 data
->interdiraction
.inter
.cancel
);
1871 void action_movetoedge(union ActionData
*data
)
1874 ObClient
*c
= data
->diraction
.any
.c
;
1876 x
= c
->frame
->area
.x
;
1877 y
= c
->frame
->area
.y
;
1879 switch(data
->diraction
.direction
) {
1880 case OB_DIRECTION_NORTH
:
1881 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
,
1882 data
->diraction
.hang
)
1883 - (data
->diraction
.hang
? c
->frame
->area
.height
: 0);
1885 case OB_DIRECTION_WEST
:
1886 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
,
1887 data
->diraction
.hang
)
1888 - (data
->diraction
.hang
? c
->frame
->area
.width
: 0);
1890 case OB_DIRECTION_SOUTH
:
1891 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
,
1892 data
->diraction
.hang
)
1893 - (data
->diraction
.hang
? 0 : c
->frame
->area
.height
);
1895 case OB_DIRECTION_EAST
:
1896 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
,
1897 data
->diraction
.hang
)
1898 - (data
->diraction
.hang
? 0 : c
->frame
->area
.width
);
1901 g_assert_not_reached();
1903 frame_frame_gravity(c
->frame
, &x
, &y
, c
->area
.width
, c
->area
.height
);
1904 client_action_start(data
);
1905 client_move(c
, x
, y
);
1906 client_action_end(data
);
1909 void action_growtoedge(union ActionData
*data
)
1911 gint x
, y
, width
, height
, dest
;
1912 ObClient
*c
= data
->diraction
.any
.c
;
1915 a
= screen_area(c
->desktop
);
1916 x
= c
->frame
->area
.x
;
1917 y
= c
->frame
->area
.y
;
1918 /* get the unshaded frame's dimensions..if it is shaded */
1919 width
= c
->area
.width
+ c
->frame
->size
.left
+ c
->frame
->size
.right
;
1920 height
= c
->area
.height
+ c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1922 switch(data
->diraction
.direction
) {
1923 case OB_DIRECTION_NORTH
:
1924 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1926 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
, FALSE
);
1928 height
= height
/ 2;
1930 height
= c
->frame
->area
.y
+ height
- dest
;
1934 case OB_DIRECTION_WEST
:
1935 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
, FALSE
);
1939 width
= c
->frame
->area
.x
+ width
- dest
;
1943 case OB_DIRECTION_SOUTH
:
1944 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1946 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
, FALSE
);
1947 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1948 height
= c
->frame
->area
.height
/ 2;
1949 y
= a
->y
+ a
->height
- height
;
1951 height
= dest
- c
->frame
->area
.y
;
1952 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1953 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1955 case OB_DIRECTION_EAST
:
1956 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
, FALSE
);
1957 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1958 width
= c
->frame
->area
.width
/ 2;
1959 x
= a
->x
+ a
->width
- width
;
1961 width
= dest
- c
->frame
->area
.x
;
1962 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1963 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1966 g_assert_not_reached();
1968 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1969 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1970 frame_frame_gravity(c
->frame
, &x
, &y
, width
, height
);
1971 client_action_start(data
);
1972 client_move_resize(c
, x
, y
, width
, height
);
1973 client_action_end(data
);
1976 void action_send_to_layer(union ActionData
*data
)
1978 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1981 void action_toggle_layer(union ActionData
*data
)
1983 ObClient
*c
= data
->layer
.any
.c
;
1985 client_action_start(data
);
1986 if (data
->layer
.layer
< 0)
1987 client_set_layer(c
, c
->below
? 0 : -1);
1988 else if (data
->layer
.layer
> 0)
1989 client_set_layer(c
, c
->above
? 0 : 1);
1990 client_action_end(data
);
1993 void action_toggle_dockautohide(union ActionData
*data
)
1995 config_dock_hide
= !config_dock_hide
;
1999 void action_toggle_show_desktop(union ActionData
*data
)
2001 screen_show_desktop(!screen_showing_desktop
, NULL
);
2004 void action_show_desktop(union ActionData
*data
)
2006 screen_show_desktop(TRUE
, NULL
);
2009 void action_unshow_desktop(union ActionData
*data
)
2011 screen_show_desktop(FALSE
, NULL
);
2014 void action_break_chroot(union ActionData
*data
)
2016 /* break out of one chroot */
2017 keyboard_reset_chains(1);