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_showmenu
)
99 g_free(a
->data
.showmenu
.name
);
104 ObAction
* action_copy(const ObAction
*src
)
106 ObAction
*a
= action_new(src
->func
);
110 /* deal with pointers */
111 if (a
->func
== action_execute
|| a
->func
== action_restart
)
112 a
->data
.execute
.path
= g_strdup(a
->data
.execute
.path
);
113 else if (a
->func
== action_showmenu
)
114 a
->data
.showmenu
.name
= g_strdup(a
->data
.showmenu
.name
);
119 void setup_action_directional_focus_north(ObAction
**a
, ObUserAction uact
)
121 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
122 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTH
;
123 (*a
)->data
.interdiraction
.dialog
= TRUE
;
124 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
125 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
128 void setup_action_directional_focus_east(ObAction
**a
, ObUserAction uact
)
130 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
131 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_EAST
;
132 (*a
)->data
.interdiraction
.dialog
= TRUE
;
133 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
134 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
137 void setup_action_directional_focus_south(ObAction
**a
, ObUserAction uact
)
139 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
140 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTH
;
141 (*a
)->data
.interdiraction
.dialog
= TRUE
;
142 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
143 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
146 void setup_action_directional_focus_west(ObAction
**a
, ObUserAction uact
)
148 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
149 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_WEST
;
150 (*a
)->data
.interdiraction
.dialog
= TRUE
;
151 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
152 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
155 void setup_action_directional_focus_northeast(ObAction
**a
, ObUserAction uact
)
157 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
158 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHEAST
;
159 (*a
)->data
.interdiraction
.dialog
= TRUE
;
160 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
161 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
164 void setup_action_directional_focus_southeast(ObAction
**a
, ObUserAction uact
)
166 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
167 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHEAST
;
168 (*a
)->data
.interdiraction
.dialog
= TRUE
;
169 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
170 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
173 void setup_action_directional_focus_southwest(ObAction
**a
, ObUserAction uact
)
175 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
176 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHWEST
;
177 (*a
)->data
.interdiraction
.dialog
= TRUE
;
178 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
179 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
182 void setup_action_directional_focus_northwest(ObAction
**a
, ObUserAction uact
)
184 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
185 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHWEST
;
186 (*a
)->data
.interdiraction
.dialog
= TRUE
;
187 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
188 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
191 void setup_action_send_to_desktop(ObAction
**a
, ObUserAction uact
)
193 (*a
)->data
.sendto
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
194 (*a
)->data
.sendto
.follow
= TRUE
;
197 void setup_action_send_to_desktop_prev(ObAction
**a
, ObUserAction uact
)
199 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
200 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
201 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
202 (*a
)->data
.sendtodir
.linear
= TRUE
;
203 (*a
)->data
.sendtodir
.wrap
= TRUE
;
204 (*a
)->data
.sendtodir
.follow
= TRUE
;
207 void setup_action_send_to_desktop_next(ObAction
**a
, ObUserAction uact
)
209 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
210 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
211 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
212 (*a
)->data
.sendtodir
.linear
= TRUE
;
213 (*a
)->data
.sendtodir
.wrap
= TRUE
;
214 (*a
)->data
.sendtodir
.follow
= TRUE
;
217 void setup_action_send_to_desktop_left(ObAction
**a
, ObUserAction uact
)
219 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
220 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
221 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
222 (*a
)->data
.sendtodir
.linear
= FALSE
;
223 (*a
)->data
.sendtodir
.wrap
= TRUE
;
224 (*a
)->data
.sendtodir
.follow
= TRUE
;
227 void setup_action_send_to_desktop_right(ObAction
**a
, ObUserAction uact
)
229 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
230 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
231 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
232 (*a
)->data
.sendtodir
.linear
= FALSE
;
233 (*a
)->data
.sendtodir
.wrap
= TRUE
;
234 (*a
)->data
.sendtodir
.follow
= TRUE
;
237 void setup_action_send_to_desktop_up(ObAction
**a
, ObUserAction uact
)
239 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
240 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
241 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_NORTH
;
242 (*a
)->data
.sendtodir
.linear
= FALSE
;
243 (*a
)->data
.sendtodir
.wrap
= TRUE
;
244 (*a
)->data
.sendtodir
.follow
= TRUE
;
247 void setup_action_send_to_desktop_down(ObAction
**a
, ObUserAction uact
)
249 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
250 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
251 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_SOUTH
;
252 (*a
)->data
.sendtodir
.linear
= FALSE
;
253 (*a
)->data
.sendtodir
.wrap
= TRUE
;
254 (*a
)->data
.sendtodir
.follow
= TRUE
;
257 void setup_action_desktop(ObAction
**a
, ObUserAction uact
)
259 (*a
)->data
.desktop
.inter
.any
.interactive
= FALSE
;
262 void setup_action_desktop_prev(ObAction
**a
, ObUserAction uact
)
264 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
265 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
266 (*a
)->data
.desktopdir
.linear
= TRUE
;
267 (*a
)->data
.desktopdir
.wrap
= TRUE
;
270 void setup_action_desktop_next(ObAction
**a
, ObUserAction uact
)
272 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
273 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
274 (*a
)->data
.desktopdir
.linear
= TRUE
;
275 (*a
)->data
.desktopdir
.wrap
= TRUE
;
278 void setup_action_desktop_left(ObAction
**a
, ObUserAction uact
)
280 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
281 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
282 (*a
)->data
.desktopdir
.linear
= FALSE
;
283 (*a
)->data
.desktopdir
.wrap
= TRUE
;
286 void setup_action_desktop_right(ObAction
**a
, ObUserAction uact
)
288 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
289 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
290 (*a
)->data
.desktopdir
.linear
= FALSE
;
291 (*a
)->data
.desktopdir
.wrap
= TRUE
;
294 void setup_action_desktop_up(ObAction
**a
, ObUserAction uact
)
296 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
297 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_NORTH
;
298 (*a
)->data
.desktopdir
.linear
= FALSE
;
299 (*a
)->data
.desktopdir
.wrap
= TRUE
;
302 void setup_action_desktop_down(ObAction
**a
, ObUserAction uact
)
304 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
305 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_SOUTH
;
306 (*a
)->data
.desktopdir
.linear
= FALSE
;
307 (*a
)->data
.desktopdir
.wrap
= TRUE
;
310 void setup_action_cycle_windows_next(ObAction
**a
, ObUserAction uact
)
312 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
313 (*a
)->data
.cycle
.linear
= FALSE
;
314 (*a
)->data
.cycle
.forward
= TRUE
;
315 (*a
)->data
.cycle
.dialog
= TRUE
;
316 (*a
)->data
.cycle
.dock_windows
= FALSE
;
317 (*a
)->data
.cycle
.desktop_windows
= FALSE
;
318 (*a
)->data
.cycle
.all_desktops
= FALSE
;
321 void setup_action_cycle_windows_previous(ObAction
**a
, ObUserAction uact
)
323 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
324 (*a
)->data
.cycle
.linear
= FALSE
;
325 (*a
)->data
.cycle
.forward
= FALSE
;
326 (*a
)->data
.cycle
.dialog
= TRUE
;
327 (*a
)->data
.cycle
.dock_windows
= FALSE
;
328 (*a
)->data
.cycle
.desktop_windows
= FALSE
;
329 (*a
)->data
.cycle
.all_desktops
= FALSE
;
332 void setup_action_movefromedge_north(ObAction
**a
, ObUserAction uact
)
334 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
335 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
336 (*a
)->data
.diraction
.hang
= TRUE
;
339 void setup_action_movefromedge_south(ObAction
**a
, ObUserAction uact
)
341 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
342 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
343 (*a
)->data
.diraction
.hang
= TRUE
;
346 void setup_action_movefromedge_east(ObAction
**a
, ObUserAction uact
)
348 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
349 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
350 (*a
)->data
.diraction
.hang
= TRUE
;
353 void setup_action_movefromedge_west(ObAction
**a
, ObUserAction uact
)
355 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
356 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
357 (*a
)->data
.diraction
.hang
= TRUE
;
360 void setup_action_movetoedge_north(ObAction
**a
, ObUserAction uact
)
362 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
363 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
364 (*a
)->data
.diraction
.hang
= FALSE
;
367 void setup_action_movetoedge_south(ObAction
**a
, ObUserAction uact
)
369 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
370 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
371 (*a
)->data
.diraction
.hang
= FALSE
;
374 void setup_action_movetoedge_east(ObAction
**a
, ObUserAction uact
)
376 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
377 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
378 (*a
)->data
.diraction
.hang
= FALSE
;
381 void setup_action_movetoedge_west(ObAction
**a
, ObUserAction uact
)
383 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
384 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
385 (*a
)->data
.diraction
.hang
= FALSE
;
388 void setup_action_growtoedge_north(ObAction
**a
, ObUserAction uact
)
390 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
391 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
394 void setup_action_growtoedge_south(ObAction
**a
, ObUserAction uact
)
396 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
397 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
400 void setup_action_growtoedge_east(ObAction
**a
, ObUserAction uact
)
402 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
403 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
406 void setup_action_growtoedge_west(ObAction
**a
, ObUserAction uact
)
408 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
409 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
412 void setup_action_top_layer(ObAction
**a
, ObUserAction uact
)
414 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
415 (*a
)->data
.layer
.layer
= 1;
418 void setup_action_normal_layer(ObAction
**a
, ObUserAction uact
)
420 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
421 (*a
)->data
.layer
.layer
= 0;
424 void setup_action_bottom_layer(ObAction
**a
, ObUserAction uact
)
426 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
427 (*a
)->data
.layer
.layer
= -1;
430 void setup_action_move(ObAction
**a
, ObUserAction uact
)
432 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
433 (*a
)->data
.moveresize
.keyboard
=
434 (uact
== OB_USER_ACTION_NONE
||
435 uact
== OB_USER_ACTION_KEYBOARD_KEY
||
436 uact
== OB_USER_ACTION_MENU_SELECTION
);
437 (*a
)->data
.moveresize
.corner
= 0;
440 void setup_action_resize(ObAction
**a
, ObUserAction uact
)
442 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
443 (*a
)->data
.moveresize
.keyboard
=
444 (uact
== OB_USER_ACTION_NONE
||
445 uact
== OB_USER_ACTION_KEYBOARD_KEY
||
446 uact
== OB_USER_ACTION_MENU_SELECTION
);
447 (*a
)->data
.moveresize
.corner
= 0;
450 void setup_action_showmenu(ObAction
**a
, ObUserAction uact
)
452 (*a
)->data
.showmenu
.any
.client_action
= OB_CLIENT_ACTION_OPTIONAL
;
453 /* you cannot call ShowMenu from inside a menu, cuz the menu code makes
454 assumptions that there is only one menu (and submenus) open at
456 if (uact
== OB_USER_ACTION_MENU_SELECTION
) {
462 void setup_action_focus(ObAction
**a
, ObUserAction uact
)
464 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_OPTIONAL
;
467 void setup_client_action(ObAction
**a
, ObUserAction uact
)
469 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
472 ActionString actionstrings
[] =
480 "directionalfocusnorth",
481 action_directional_focus
,
482 setup_action_directional_focus_north
485 "directionalfocuseast",
486 action_directional_focus
,
487 setup_action_directional_focus_east
490 "directionalfocussouth",
491 action_directional_focus
,
492 setup_action_directional_focus_south
495 "directionalfocuswest",
496 action_directional_focus
,
497 setup_action_directional_focus_west
500 "directionalfocusnortheast",
501 action_directional_focus
,
502 setup_action_directional_focus_northeast
505 "directionalfocussoutheast",
506 action_directional_focus
,
507 setup_action_directional_focus_southeast
510 "directionalfocussouthwest",
511 action_directional_focus
,
512 setup_action_directional_focus_southwest
515 "directionalfocusnorthwest",
516 action_directional_focus
,
517 setup_action_directional_focus_northwest
541 action_focus_order_to_bottom
,
596 action_toggle_omnipresent
,
601 action_move_relative_horz
,
606 action_move_relative_vert
,
611 action_move_to_center
,
615 "resizerelativehorz",
616 action_resize_relative_horz
,
620 "resizerelativevert",
621 action_resize_relative_vert
,
626 action_move_relative
,
631 action_resize_relative
,
636 action_maximize_full
,
641 action_unmaximize_full
,
645 "togglemaximizefull",
646 action_toggle_maximize_full
,
651 action_maximize_horz
,
656 action_unmaximize_horz
,
660 "togglemaximizehorz",
661 action_toggle_maximize_horz
,
666 action_maximize_vert
,
671 action_unmaximize_vert
,
675 "togglemaximizevert",
676 action_toggle_maximize_vert
,
681 action_toggle_fullscreen
,
686 action_send_to_desktop
,
687 setup_action_send_to_desktop
691 action_send_to_desktop_dir
,
692 setup_action_send_to_desktop_next
695 "sendtodesktopprevious",
696 action_send_to_desktop_dir
,
697 setup_action_send_to_desktop_prev
700 "sendtodesktopright",
701 action_send_to_desktop_dir
,
702 setup_action_send_to_desktop_right
706 action_send_to_desktop_dir
,
707 setup_action_send_to_desktop_left
711 action_send_to_desktop_dir
,
712 setup_action_send_to_desktop_up
716 action_send_to_desktop_dir
,
717 setup_action_send_to_desktop_down
727 setup_action_desktop_next
732 setup_action_desktop_prev
737 setup_action_desktop_right
742 setup_action_desktop_left
747 setup_action_desktop_up
752 setup_action_desktop_down
756 action_toggle_decorations
,
770 "toggledockautohide",
771 action_toggle_dockautohide
,
776 action_toggle_show_desktop
,
786 action_unshow_desktop
,
812 setup_action_showmenu
816 action_send_to_layer
,
817 setup_action_top_layer
822 setup_action_top_layer
826 action_send_to_layer
,
827 setup_action_normal_layer
831 action_send_to_layer
,
832 setup_action_bottom_layer
835 "togglealwaysonbottom",
837 setup_action_bottom_layer
841 action_cycle_windows
,
842 setup_action_cycle_windows_next
846 action_cycle_windows
,
847 setup_action_cycle_windows_previous
852 setup_action_movefromedge_north
857 setup_action_movefromedge_south
862 setup_action_movefromedge_west
867 setup_action_movefromedge_east
872 setup_action_movetoedge_north
877 setup_action_movetoedge_south
882 setup_action_movetoedge_west
887 setup_action_movetoedge_east
892 setup_action_growtoedge_north
897 setup_action_growtoedge_south
902 setup_action_growtoedge_west
907 setup_action_growtoedge_east
921 /* only key bindings can be interactive. thus saith the xor.
922 because of how the mouse is grabbed, mouse events dont even get
923 read during interactive events, so no dice! >:) */
924 #define INTERACTIVE_LIMIT(a, uact) \
925 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
926 a->data.any.interactive = FALSE;
928 ObAction
*action_from_string(const gchar
*name
, ObUserAction uact
)
931 gboolean exist
= FALSE
;
934 for (i
= 0; actionstrings
[i
].name
; i
++)
935 if (!g_ascii_strcasecmp(name
, actionstrings
[i
].name
)) {
937 a
= action_new(actionstrings
[i
].func
);
938 if (actionstrings
[i
].setup
)
939 actionstrings
[i
].setup(&a
, uact
);
941 INTERACTIVE_LIMIT(a
, uact
);
945 g_message(_("Invalid action '%s' requested. No such action exists."),
948 g_message(_("Invalid use of action '%s'. Action will be ignored."),
953 ObAction
*action_parse(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
957 ObAction
*act
= NULL
;
960 if (parse_attr_string("name", node
, &actname
)) {
961 if ((act
= action_from_string(actname
, uact
))) {
962 if (act
->func
== action_execute
|| act
->func
== action_restart
) {
963 if ((n
= parse_find_node("execute", node
->xmlChildrenNode
))) {
964 gchar
*s
= parse_string(doc
, n
);
965 act
->data
.execute
.path
= parse_expand_tilde(s
);
968 if ((n
= parse_find_node("startupnotify", node
->xmlChildrenNode
))) {
970 if ((m
= parse_find_node("enabled", n
->xmlChildrenNode
)))
971 act
->data
.execute
.startupnotify
= parse_bool(doc
, m
);
972 if ((m
= parse_find_node("name", n
->xmlChildrenNode
)))
973 act
->data
.execute
.name
= parse_string(doc
, m
);
974 if ((m
= parse_find_node("icon", n
->xmlChildrenNode
)))
975 act
->data
.execute
.icon_name
= parse_string(doc
, m
);
977 } else if (act
->func
== action_showmenu
) {
978 if ((n
= parse_find_node("menu", node
->xmlChildrenNode
)))
979 act
->data
.showmenu
.name
= parse_string(doc
, n
);
980 } else if (act
->func
== action_move_relative_horz
||
981 act
->func
== action_move_relative_vert
||
982 act
->func
== action_resize_relative_horz
||
983 act
->func
== action_resize_relative_vert
) {
984 if ((n
= parse_find_node("delta", node
->xmlChildrenNode
)))
985 act
->data
.relative
.deltax
= parse_int(doc
, n
);
986 } else if (act
->func
== action_move_relative
) {
987 if ((n
= parse_find_node("x", node
->xmlChildrenNode
)))
988 act
->data
.relative
.deltax
= parse_int(doc
, n
);
989 if ((n
= parse_find_node("y", node
->xmlChildrenNode
)))
990 act
->data
.relative
.deltay
= parse_int(doc
, n
);
991 } else if (act
->func
== action_resize_relative
) {
992 if ((n
= parse_find_node("left", node
->xmlChildrenNode
)))
993 act
->data
.relative
.deltaxl
= parse_int(doc
, n
);
994 if ((n
= parse_find_node("up", node
->xmlChildrenNode
)))
995 act
->data
.relative
.deltayu
= parse_int(doc
, n
);
996 if ((n
= parse_find_node("right", node
->xmlChildrenNode
)))
997 act
->data
.relative
.deltax
= parse_int(doc
, n
);
998 if ((n
= parse_find_node("down", node
->xmlChildrenNode
)))
999 act
->data
.relative
.deltay
= parse_int(doc
, n
);
1000 } else if (act
->func
== action_desktop
) {
1001 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1002 act
->data
.desktop
.desk
= parse_int(doc
, n
);
1003 if (act
->data
.desktop
.desk
> 0) act
->data
.desktop
.desk
--;
1004 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1005 act
->data
.desktop
.inter
.any
.interactive
=
1007 } else if (act
->func
== action_send_to_desktop
) {
1008 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1009 act
->data
.sendto
.desk
= parse_int(doc
, n
);
1010 if (act
->data
.sendto
.desk
> 0) act
->data
.sendto
.desk
--;
1011 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
1012 act
->data
.sendto
.follow
= parse_bool(doc
, n
);
1013 } else if (act
->func
== action_desktop_dir
) {
1014 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
1015 act
->data
.desktopdir
.wrap
= parse_bool(doc
, n
);
1016 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1017 act
->data
.desktopdir
.inter
.any
.interactive
=
1019 } else if (act
->func
== action_send_to_desktop_dir
) {
1020 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
1021 act
->data
.sendtodir
.wrap
= parse_bool(doc
, n
);
1022 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
1023 act
->data
.sendtodir
.follow
= parse_bool(doc
, n
);
1024 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1025 act
->data
.sendtodir
.inter
.any
.interactive
=
1027 } else if (act
->func
== action_activate
) {
1028 if ((n
= parse_find_node("here", node
->xmlChildrenNode
)))
1029 act
->data
.activate
.here
= parse_bool(doc
, n
);
1030 } else if (act
->func
== action_cycle_windows
) {
1031 if ((n
= parse_find_node("linear", node
->xmlChildrenNode
)))
1032 act
->data
.cycle
.linear
= parse_bool(doc
, n
);
1033 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1034 act
->data
.cycle
.dialog
= parse_bool(doc
, n
);
1035 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
1036 act
->data
.cycle
.dock_windows
= parse_bool(doc
, n
);
1037 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1038 act
->data
.cycle
.desktop_windows
= parse_bool(doc
, n
);
1039 if ((n
= parse_find_node("allDesktops",
1040 node
->xmlChildrenNode
)))
1041 act
->data
.cycle
.all_desktops
= parse_bool(doc
, n
);
1042 } else if (act
->func
== action_directional_focus
) {
1043 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1044 act
->data
.interdiraction
.dialog
= parse_bool(doc
, n
);
1045 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
1046 act
->data
.interdiraction
.dock_windows
= parse_bool(doc
, n
);
1047 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1048 act
->data
.interdiraction
.desktop_windows
=
1050 } else if (act
->func
== action_resize
) {
1051 if ((n
= parse_find_node("edge", node
->xmlChildrenNode
))) {
1052 gchar
*s
= parse_string(doc
, n
);
1053 if (!g_ascii_strcasecmp(s
, "top"))
1054 act
->data
.moveresize
.corner
=
1055 prop_atoms
.net_wm_moveresize_size_top
;
1056 else if (!g_ascii_strcasecmp(s
, "bottom"))
1057 act
->data
.moveresize
.corner
=
1058 prop_atoms
.net_wm_moveresize_size_bottom
;
1059 else if (!g_ascii_strcasecmp(s
, "left"))
1060 act
->data
.moveresize
.corner
=
1061 prop_atoms
.net_wm_moveresize_size_left
;
1062 else if (!g_ascii_strcasecmp(s
, "right"))
1063 act
->data
.moveresize
.corner
=
1064 prop_atoms
.net_wm_moveresize_size_right
;
1065 else if (!g_ascii_strcasecmp(s
, "topleft"))
1066 act
->data
.moveresize
.corner
=
1067 prop_atoms
.net_wm_moveresize_size_topleft
;
1068 else if (!g_ascii_strcasecmp(s
, "topright"))
1069 act
->data
.moveresize
.corner
=
1070 prop_atoms
.net_wm_moveresize_size_topright
;
1071 else if (!g_ascii_strcasecmp(s
, "bottomleft"))
1072 act
->data
.moveresize
.corner
=
1073 prop_atoms
.net_wm_moveresize_size_bottomleft
;
1074 else if (!g_ascii_strcasecmp(s
, "bottomright"))
1075 act
->data
.moveresize
.corner
=
1076 prop_atoms
.net_wm_moveresize_size_bottomright
;
1079 } else if (act
->func
== action_raise
||
1080 act
->func
== action_lower
||
1081 act
->func
== action_raiselower
||
1082 act
->func
== action_shadelower
||
1083 act
->func
== action_unshaderaise
) {
1085 INTERACTIVE_LIMIT(act
, uact
);
1092 void action_run_list(GSList
*acts
, ObClient
*c
, ObFrameContext context
,
1093 guint state
, guint button
, gint x
, gint y
, Time time
,
1094 gboolean cancel
, gboolean done
)
1103 screen_pointer_pos(&x
, &y
);
1105 for (it
= acts
; it
; it
= g_slist_next(it
)) {
1108 if (!(a
->data
.any
.client_action
== OB_CLIENT_ACTION_ALWAYS
&& !c
)) {
1109 a
->data
.any
.c
= a
->data
.any
.client_action
? c
: NULL
;
1110 a
->data
.any
.context
= context
;
1114 a
->data
.any
.button
= button
;
1116 a
->data
.any
.time
= time
;
1118 if (a
->data
.any
.interactive
) {
1119 a
->data
.inter
.cancel
= cancel
;
1120 a
->data
.inter
.final
= done
;
1121 if (!(cancel
|| done
))
1122 if (!keyboard_interactive_grab(state
, a
->data
.any
.c
, a
))
1126 /* XXX UGLY HACK race with motion event starting a move and the
1127 button release gettnig processed first. answer: don't queue
1128 moveresize starts. UGLY HACK XXX */
1129 if (a
->data
.any
.interactive
|| a
->func
== action_move
||
1130 a
->func
== action_resize
)
1132 /* interactive actions are not queued */
1135 (context
== OB_FRAME_CONTEXT_CLIENT
||
1136 (c
->type
== OB_CLIENT_TYPE_DESKTOP
&&
1137 context
== OB_FRAME_CONTEXT_DESKTOP
)) &&
1138 (a
->func
== action_focus
||
1139 a
->func
== action_activate
||
1140 a
->func
== action_showmenu
))
1142 /* XXX MORE UGLY HACK
1143 actions from clicks on client windows are NOT queued.
1144 this solves the mysterious click-and-drag-doesnt-work
1145 problem. it was because the window gets focused and stuff
1146 after the button event has already been passed through. i
1147 dont really know why it should care but it does and it makes
1150 however this very bogus ! !
1151 we want to send the button press to the window BEFORE
1152 we do the action because the action might move the windows
1153 (eg change desktops) and then the button press ends up on
1154 the completely wrong window !
1155 so, this is just for that bug, and it will only NOT queue it
1156 if it is a focusing action that can be used with the mouse
1159 also with the menus, there is a race going on. if the
1160 desktop wants to pop up a menu, and we do to, we send them
1161 the button before we pop up the menu, so they pop up their
1162 menu first. but not always. if we pop up our menu before
1163 sending them the button press, then the result is
1168 ob_main_loop_queue_action(ob_main_loop
, a
);
1173 void action_run_string(const gchar
*name
, struct _ObClient
*c
, Time time
)
1178 a
= action_from_string(name
, OB_USER_ACTION_NONE
);
1181 l
= g_slist_append(NULL
, a
);
1183 action_run(l
, c
, 0, time
);
1186 void action_execute(union ActionData
*data
)
1189 gchar
*cmd
, **argv
= 0;
1190 if (data
->execute
.path
) {
1191 /* Ungrab the keyboard before running the action.
1193 If there is an interactive action going on, then cancel it to
1194 release the keyboard. If not, then call XUngrabKeyboard().
1196 We call XUngrabKeyboard because a key press causes a passive
1197 grab on the keyboard, and so if program we are executing wants to
1198 grab the keyboard, it will fail if the button is still held down
1201 Use the X function not out own, because we're not considering
1202 a grab to be in place at all so our function won't try ungrab
1205 if (keyboard_interactively_grabbed())
1206 keyboard_interactive_cancel();
1208 XUngrabKeyboard(ob_display
, data
->any
.time
);
1210 cmd
= g_filename_from_utf8(data
->execute
.path
, -1, NULL
, NULL
, NULL
);
1212 if (!g_shell_parse_argv (cmd
, NULL
, &argv
, &e
)) {
1213 g_message(_("Failed to execute '%s': %s"),
1216 } else if (data
->execute
.startupnotify
) {
1219 program
= g_path_get_basename(argv
[0]);
1220 /* sets up the environment */
1221 sn_setup_spawn_environment(program
,
1223 data
->execute
.icon_name
,
1224 /* launch it on the current
1227 data
->execute
.any
.time
);
1228 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
|
1229 G_SPAWN_DO_NOT_REAP_CHILD
,
1230 NULL
, NULL
, NULL
, &e
)) {
1231 g_message(_("Failed to execute '%s': %s"),
1236 unsetenv("DESKTOP_STARTUP_ID");
1240 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
|
1241 G_SPAWN_DO_NOT_REAP_CHILD
,
1242 NULL
, NULL
, NULL
, &e
))
1244 g_message(_("Failed to execute '%s': %s"),
1252 g_message(_("Failed to convert the path '%s' from utf8"),
1253 data
->execute
.path
);
1258 void action_activate(union ActionData
*data
)
1260 if (data
->client
.any
.c
) {
1261 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1262 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1263 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1265 /* if using focus_delay, stop the timer now so that focus doesn't
1267 event_halt_focus_delay();
1269 client_activate(data
->activate
.any
.c
, data
->activate
.here
, TRUE
);
1272 /* focus action on something other than a client, make keybindings
1273 work for this openbox instance, but don't focus any specific client
1279 void action_focus(union ActionData
*data
)
1281 if (data
->client
.any
.c
) {
1282 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1283 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1284 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1286 /* if using focus_delay, stop the timer now so that focus doesn't
1288 event_halt_focus_delay();
1290 client_focus(data
->client
.any
.c
);
1293 /* focus action on something other than a client, make keybindings
1294 work for this openbox instance, but don't focus any specific client
1300 void action_unfocus (union ActionData
*data
)
1302 if (data
->client
.any
.c
== focus_client
)
1303 focus_fallback(TRUE
);
1306 void action_iconify(union ActionData
*data
)
1308 client_action_start(data
);
1309 client_iconify(data
->client
.any
.c
, TRUE
, TRUE
, FALSE
);
1310 client_action_end(data
);
1313 void action_focus_order_to_bottom(union ActionData
*data
)
1315 focus_order_to_bottom(data
->client
.any
.c
);
1318 void action_raiselower(union ActionData
*data
)
1320 ObClient
*c
= data
->client
.any
.c
;
1322 gboolean raise
= FALSE
;
1324 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
1325 if (WINDOW_IS_CLIENT(it
->data
)) {
1326 ObClient
*cit
= it
->data
;
1328 if (cit
== c
) break;
1329 if (client_normal(cit
) == client_normal(c
) &&
1330 cit
->layer
== c
->layer
&&
1331 cit
->frame
->visible
&&
1332 !client_search_transient(c
, cit
))
1334 if (RECT_INTERSECTS_RECT(cit
->frame
->area
, c
->frame
->area
)) {
1348 void action_raise(union ActionData
*data
)
1350 client_action_start(data
);
1351 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1352 client_action_end(data
);
1355 void action_unshaderaise(union ActionData
*data
)
1357 if (data
->client
.any
.c
->shaded
)
1358 action_unshade(data
);
1363 void action_shadelower(union ActionData
*data
)
1365 if (data
->client
.any
.c
->shaded
)
1371 void action_lower(union ActionData
*data
)
1373 client_action_start(data
);
1374 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1375 client_action_end(data
);
1378 void action_close(union ActionData
*data
)
1380 client_close(data
->client
.any
.c
);
1383 void action_kill(union ActionData
*data
)
1385 client_kill(data
->client
.any
.c
);
1388 void action_shade(union ActionData
*data
)
1390 client_action_start(data
);
1391 client_shade(data
->client
.any
.c
, TRUE
);
1392 client_action_end(data
);
1395 void action_unshade(union ActionData
*data
)
1397 client_action_start(data
);
1398 client_shade(data
->client
.any
.c
, FALSE
);
1399 client_action_end(data
);
1402 void action_toggle_shade(union ActionData
*data
)
1404 client_action_start(data
);
1405 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1406 client_action_end(data
);
1409 void action_toggle_omnipresent(union ActionData
*data
)
1411 client_set_desktop(data
->client
.any
.c
,
1412 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1413 screen_desktop
: DESKTOP_ALL
, FALSE
);
1416 void action_move_relative_horz(union ActionData
*data
)
1418 ObClient
*c
= data
->relative
.any
.c
;
1419 client_action_start(data
);
1420 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
);
1421 client_action_end(data
);
1424 void action_move_relative_vert(union ActionData
*data
)
1426 ObClient
*c
= data
->relative
.any
.c
;
1427 client_action_start(data
);
1428 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.deltax
);
1429 client_action_end(data
);
1432 void action_move_to_center(union ActionData
*data
)
1434 ObClient
*c
= data
->client
.any
.c
;
1436 area
= screen_area_monitor(c
->desktop
, 0);
1437 client_action_start(data
);
1438 client_move(c
, area
->width
/ 2 - c
->area
.width
/ 2,
1439 area
->height
/ 2 - c
->area
.height
/ 2);
1440 client_action_end(data
);
1443 void action_resize_relative_horz(union ActionData
*data
)
1445 ObClient
*c
= data
->relative
.any
.c
;
1446 client_action_start(data
);
1448 c
->area
.width
+ data
->relative
.deltax
* c
->size_inc
.width
,
1450 client_action_end(data
);
1453 void action_resize_relative_vert(union ActionData
*data
)
1455 ObClient
*c
= data
->relative
.any
.c
;
1457 client_action_start(data
);
1458 client_resize(c
, c
->area
.width
, c
->area
.height
+
1459 data
->relative
.deltax
* c
->size_inc
.height
);
1460 client_action_end(data
);
1464 void action_move_relative(union ActionData
*data
)
1466 ObClient
*c
= data
->relative
.any
.c
;
1467 client_action_start(data
);
1468 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
+
1469 data
->relative
.deltay
);
1470 client_action_end(data
);
1473 void action_resize_relative(union ActionData
*data
)
1475 ObClient
*c
= data
->relative
.any
.c
;
1476 gint x
, y
, ow
, w
, oh
, h
, lw
, lh
;
1478 client_action_start(data
);
1483 w
= ow
+ data
->relative
.deltax
* c
->size_inc
.width
1484 + data
->relative
.deltaxl
* c
->size_inc
.width
;
1485 oh
= c
->area
.height
;
1486 h
= oh
+ data
->relative
.deltay
* c
->size_inc
.height
1487 + data
->relative
.deltayu
* c
->size_inc
.height
;
1489 client_try_configure(c
, &x
, &y
, &w
, &h
, &lw
, &lh
, TRUE
);
1490 client_move_resize(c
, x
+ (ow
- w
), y
+ (oh
- h
), w
, h
);
1491 client_action_end(data
);
1494 void action_maximize_full(union ActionData
*data
)
1496 client_action_start(data
);
1497 client_maximize(data
->client
.any
.c
, TRUE
, 0);
1498 client_action_end(data
);
1501 void action_unmaximize_full(union ActionData
*data
)
1503 client_action_start(data
);
1504 client_maximize(data
->client
.any
.c
, FALSE
, 0);
1505 client_action_end(data
);
1508 void action_toggle_maximize_full(union ActionData
*data
)
1510 client_action_start(data
);
1511 client_maximize(data
->client
.any
.c
,
1512 !(data
->client
.any
.c
->max_horz
||
1513 data
->client
.any
.c
->max_vert
),
1515 client_action_end(data
);
1518 void action_maximize_horz(union ActionData
*data
)
1520 client_action_start(data
);
1521 client_maximize(data
->client
.any
.c
, TRUE
, 1);
1522 client_action_end(data
);
1525 void action_unmaximize_horz(union ActionData
*data
)
1527 client_action_start(data
);
1528 client_maximize(data
->client
.any
.c
, FALSE
, 1);
1529 client_action_end(data
);
1532 void action_toggle_maximize_horz(union ActionData
*data
)
1534 client_action_start(data
);
1535 client_maximize(data
->client
.any
.c
,
1536 !data
->client
.any
.c
->max_horz
, 1);
1537 client_action_end(data
);
1540 void action_maximize_vert(union ActionData
*data
)
1542 client_action_start(data
);
1543 client_maximize(data
->client
.any
.c
, TRUE
, 2);
1544 client_action_end(data
);
1547 void action_unmaximize_vert(union ActionData
*data
)
1549 client_action_start(data
);
1550 client_maximize(data
->client
.any
.c
, FALSE
, 2);
1551 client_action_end(data
);
1554 void action_toggle_maximize_vert(union ActionData
*data
)
1556 client_action_start(data
);
1557 client_maximize(data
->client
.any
.c
,
1558 !data
->client
.any
.c
->max_vert
, 2);
1559 client_action_end(data
);
1562 void action_toggle_fullscreen(union ActionData
*data
)
1564 client_action_start(data
);
1565 client_fullscreen(data
->client
.any
.c
, !(data
->client
.any
.c
->fullscreen
));
1566 client_action_end(data
);
1569 void action_send_to_desktop(union ActionData
*data
)
1571 ObClient
*c
= data
->sendto
.any
.c
;
1573 if (!client_normal(c
)) return;
1575 if (data
->sendto
.desk
< screen_num_desktops
||
1576 data
->sendto
.desk
== DESKTOP_ALL
) {
1577 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
);
1578 if (data
->sendto
.follow
)
1579 screen_set_desktop(data
->sendto
.desk
, TRUE
);
1583 void action_desktop(union ActionData
*data
)
1585 if (!data
->inter
.any
.interactive
||
1586 (!data
->inter
.cancel
&& !data
->inter
.final
))
1588 if (data
->desktop
.desk
< screen_num_desktops
||
1589 data
->desktop
.desk
== DESKTOP_ALL
)
1591 screen_set_desktop(data
->desktop
.desk
, TRUE
);
1592 if (data
->inter
.any
.interactive
)
1593 screen_desktop_popup(data
->desktop
.desk
, TRUE
);
1596 screen_desktop_popup(0, FALSE
);
1599 void action_desktop_dir(union ActionData
*data
)
1603 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1604 data
->desktopdir
.wrap
,
1605 data
->desktopdir
.linear
,
1606 data
->desktopdir
.inter
.any
.interactive
,
1607 data
->desktopdir
.inter
.final
,
1608 data
->desktopdir
.inter
.cancel
);
1609 /* only move the desktop when the action is complete. if we switch
1610 desktops during the interactive action, focus will move but with
1611 NotifyWhileGrabbed and applications don't like that. */
1612 if (!data
->sendtodir
.inter
.any
.interactive
||
1613 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1615 if (d
!= screen_desktop
) screen_set_desktop(d
, TRUE
);
1619 void action_send_to_desktop_dir(union ActionData
*data
)
1621 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1624 if (!client_normal(c
)) return;
1626 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1627 data
->sendtodir
.linear
,
1628 data
->sendtodir
.inter
.any
.interactive
,
1629 data
->sendtodir
.inter
.final
,
1630 data
->sendtodir
.inter
.cancel
);
1631 /* only move the desktop when the action is complete. if we switch
1632 desktops during the interactive action, focus will move but with
1633 NotifyWhileGrabbed and applications don't like that. */
1634 if (!data
->sendtodir
.inter
.any
.interactive
||
1635 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1637 client_set_desktop(c
, d
, data
->sendtodir
.follow
);
1638 if (data
->sendtodir
.follow
&& d
!= screen_desktop
)
1639 screen_set_desktop(d
, TRUE
);
1643 void action_desktop_last(union ActionData
*data
)
1645 screen_set_desktop(screen_last_desktop
, TRUE
);
1648 void action_toggle_decorations(union ActionData
*data
)
1650 ObClient
*c
= data
->client
.any
.c
;
1652 client_action_start(data
);
1653 client_set_undecorated(c
, !c
->undecorated
);
1654 client_action_end(data
);
1657 static guint32
pick_corner(gint x
, gint y
, gint cx
, gint cy
, gint cw
, gint ch
,
1660 /* let's make x and y client relative instead of screen relative */
1662 y
= ch
- (y
- cy
); /* y is inverted, 0 is at the bottom of the window */
1665 #define A -4*X + 7*ch/3
1666 #define B 4*X -15*ch/9
1667 #define C -X/4 + 2*ch/3
1668 #define D X/4 + 5*ch/12
1669 #define E X/4 + ch/3
1670 #define F -X/4 + 7*ch/12
1671 #define G 4*X - 4*ch/3
1672 #define H -4*X + 8*ch/3
1673 #define a (y > 5*ch/9)
1674 #define b (x < 4*cw/9)
1675 #define c (x > 5*cw/9)
1676 #define d (y < 4*ch/9)
1679 Each of these defines (except X which is just there for fun), represents
1680 the equation of a line. The lines they represent are shown in the diagram
1681 below. Checking y against these lines, we are able to choose a region
1682 of the window as shown.
1684 +---------------------A-------|-------|-------B---------------------+
1691 | northwest | A north B | northeast |
1694 C---------------------+----A--+-------+--B----+---------------------D
1695 |CCCCCCC | A B | DDDDDDD|
1696 | CCCCCCCC | A | | B | DDDDDDDD |
1697 | CCCCCCC A B DDDDDDD |
1698 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
1700 | west | b move c | east | ad
1702 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
1703 | EEEEEEE G H FFFFFFF |
1704 | EEEEEEEE | G | | H | FFFFFFFF |
1705 |EEEEEEE | G H | FFFFFFF|
1706 E---------------------+----G--+-------+--H----+---------------------F
1709 | southwest | G south H | southeast |
1716 +---------------------G-------|-------|-------H---------------------+
1720 /* for shaded windows, you can only resize west/east and move */
1722 return prop_atoms
.net_wm_moveresize_size_left
;
1724 return prop_atoms
.net_wm_moveresize_size_right
;
1725 return prop_atoms
.net_wm_moveresize_move
;
1728 if (y
< A
&& y
>= C
)
1729 return prop_atoms
.net_wm_moveresize_size_topleft
;
1730 else if (y
>= A
&& y
>= B
&& a
)
1731 return prop_atoms
.net_wm_moveresize_size_top
;
1732 else if (y
< B
&& y
>= D
)
1733 return prop_atoms
.net_wm_moveresize_size_topright
;
1734 else if (y
< C
&& y
>= E
&& b
)
1735 return prop_atoms
.net_wm_moveresize_size_left
;
1736 else if (y
< D
&& y
>= F
&& c
)
1737 return prop_atoms
.net_wm_moveresize_size_right
;
1738 else if (y
< E
&& y
>= G
)
1739 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1740 else if (y
< G
&& y
< H
&& d
)
1741 return prop_atoms
.net_wm_moveresize_size_bottom
;
1742 else if (y
>= H
&& y
< F
)
1743 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1745 return prop_atoms
.net_wm_moveresize_move
;
1762 void action_move(union ActionData
*data
)
1764 ObClient
*c
= data
->moveresize
.any
.c
;
1767 if (data
->moveresize
.keyboard
)
1768 corner
= prop_atoms
.net_wm_moveresize_move_keyboard
;
1770 corner
= prop_atoms
.net_wm_moveresize_move
;
1772 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1775 void action_resize(union ActionData
*data
)
1777 ObClient
*c
= data
->moveresize
.any
.c
;
1780 if (data
->moveresize
.keyboard
)
1781 corner
= prop_atoms
.net_wm_moveresize_size_keyboard
;
1782 else if (data
->moveresize
.corner
)
1783 corner
= data
->moveresize
.corner
; /* it was specified in the binding */
1785 corner
= pick_corner(data
->any
.x
, data
->any
.y
,
1786 c
->frame
->area
.x
, c
->frame
->area
.y
,
1787 /* use the client size because the frame
1788 can be differently sized (shaded
1789 windows) and we want this based on the
1791 c
->area
.width
+ c
->frame
->size
.left
+
1792 c
->frame
->size
.right
,
1793 c
->area
.height
+ c
->frame
->size
.top
+
1794 c
->frame
->size
.bottom
, c
->shaded
);
1796 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1799 void action_reconfigure(union ActionData
*data
)
1804 void action_restart(union ActionData
*data
)
1806 ob_restart_other(data
->execute
.path
);
1809 void action_exit(union ActionData
*data
)
1814 void action_showmenu(union ActionData
*data
)
1816 if (data
->showmenu
.name
) {
1817 menu_show(data
->showmenu
.name
, data
->any
.x
, data
->any
.y
,
1818 data
->any
.button
, data
->showmenu
.any
.c
);
1822 void action_cycle_windows(union ActionData
*data
)
1824 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1826 event_halt_focus_delay();
1828 focus_cycle(data
->cycle
.forward
,
1829 data
->cycle
.all_desktops
,
1830 data
->cycle
.dock_windows
,
1831 data
->cycle
.desktop_windows
,
1832 data
->cycle
.linear
, data
->any
.interactive
,
1834 data
->cycle
.inter
.final
, data
->cycle
.inter
.cancel
);
1837 void action_directional_focus(union ActionData
*data
)
1839 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1841 event_halt_focus_delay();
1843 focus_directional_cycle(data
->interdiraction
.direction
,
1844 data
->interdiraction
.dock_windows
,
1845 data
->interdiraction
.desktop_windows
,
1846 data
->any
.interactive
,
1847 data
->interdiraction
.dialog
,
1848 data
->interdiraction
.inter
.final
,
1849 data
->interdiraction
.inter
.cancel
);
1852 void action_movetoedge(union ActionData
*data
)
1855 ObClient
*c
= data
->diraction
.any
.c
;
1857 x
= c
->frame
->area
.x
;
1858 y
= c
->frame
->area
.y
;
1860 switch(data
->diraction
.direction
) {
1861 case OB_DIRECTION_NORTH
:
1862 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
,
1863 data
->diraction
.hang
)
1864 - (data
->diraction
.hang
? c
->frame
->area
.height
: 0);
1866 case OB_DIRECTION_WEST
:
1867 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
,
1868 data
->diraction
.hang
)
1869 - (data
->diraction
.hang
? c
->frame
->area
.width
: 0);
1871 case OB_DIRECTION_SOUTH
:
1872 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
,
1873 data
->diraction
.hang
)
1874 - (data
->diraction
.hang
? 0 : c
->frame
->area
.height
);
1876 case OB_DIRECTION_EAST
:
1877 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
,
1878 data
->diraction
.hang
)
1879 - (data
->diraction
.hang
? 0 : c
->frame
->area
.width
);
1882 g_assert_not_reached();
1884 frame_frame_gravity(c
->frame
, &x
, &y
, c
->area
.width
, c
->area
.height
);
1885 client_action_start(data
);
1886 client_move(c
, x
, y
);
1887 client_action_end(data
);
1890 void action_growtoedge(union ActionData
*data
)
1892 gint x
, y
, width
, height
, dest
;
1893 ObClient
*c
= data
->diraction
.any
.c
;
1896 a
= screen_area(c
->desktop
);
1897 x
= c
->frame
->area
.x
;
1898 y
= c
->frame
->area
.y
;
1899 /* get the unshaded frame's dimensions..if it is shaded */
1900 width
= c
->area
.width
+ c
->frame
->size
.left
+ c
->frame
->size
.right
;
1901 height
= c
->area
.height
+ c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1903 switch(data
->diraction
.direction
) {
1904 case OB_DIRECTION_NORTH
:
1905 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1907 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
, FALSE
);
1909 height
= height
/ 2;
1911 height
= c
->frame
->area
.y
+ height
- dest
;
1915 case OB_DIRECTION_WEST
:
1916 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
, FALSE
);
1920 width
= c
->frame
->area
.x
+ width
- dest
;
1924 case OB_DIRECTION_SOUTH
:
1925 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1927 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
, FALSE
);
1928 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1929 height
= c
->frame
->area
.height
/ 2;
1930 y
= a
->y
+ a
->height
- height
;
1932 height
= dest
- c
->frame
->area
.y
;
1933 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1934 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1936 case OB_DIRECTION_EAST
:
1937 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
, FALSE
);
1938 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1939 width
= c
->frame
->area
.width
/ 2;
1940 x
= a
->x
+ a
->width
- width
;
1942 width
= dest
- c
->frame
->area
.x
;
1943 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1944 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1947 g_assert_not_reached();
1949 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1950 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1951 frame_frame_gravity(c
->frame
, &x
, &y
, width
, height
);
1952 client_action_start(data
);
1953 client_move_resize(c
, x
, y
, width
, height
);
1954 client_action_end(data
);
1957 void action_send_to_layer(union ActionData
*data
)
1959 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1962 void action_toggle_layer(union ActionData
*data
)
1964 ObClient
*c
= data
->layer
.any
.c
;
1966 client_action_start(data
);
1967 if (data
->layer
.layer
< 0)
1968 client_set_layer(c
, c
->below
? 0 : -1);
1969 else if (data
->layer
.layer
> 0)
1970 client_set_layer(c
, c
->above
? 0 : 1);
1971 client_action_end(data
);
1974 void action_toggle_dockautohide(union ActionData
*data
)
1976 config_dock_hide
= !config_dock_hide
;
1980 void action_toggle_show_desktop(union ActionData
*data
)
1982 screen_show_desktop(!screen_showing_desktop
, NULL
);
1985 void action_show_desktop(union ActionData
*data
)
1987 screen_show_desktop(TRUE
, NULL
);
1990 void action_unshow_desktop(union ActionData
*data
)
1992 screen_show_desktop(FALSE
, NULL
);
1995 void action_break_chroot(union ActionData
*data
)
1997 /* break out of one chroot */
1998 keyboard_reset_chains(1);