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
)
263 (*a
)->data
.desktop
.inter
.any
.interactive
= FALSE
;
266 void setup_action_desktop_prev(ObAction
**a
, ObUserAction uact
)
268 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
269 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
270 (*a
)->data
.desktopdir
.linear
= TRUE
;
271 (*a
)->data
.desktopdir
.wrap
= TRUE
;
274 void setup_action_desktop_next(ObAction
**a
, ObUserAction uact
)
276 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
277 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
278 (*a
)->data
.desktopdir
.linear
= TRUE
;
279 (*a
)->data
.desktopdir
.wrap
= TRUE
;
282 void setup_action_desktop_left(ObAction
**a
, ObUserAction uact
)
284 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
285 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
286 (*a
)->data
.desktopdir
.linear
= FALSE
;
287 (*a
)->data
.desktopdir
.wrap
= TRUE
;
290 void setup_action_desktop_right(ObAction
**a
, ObUserAction uact
)
292 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
293 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
294 (*a
)->data
.desktopdir
.linear
= FALSE
;
295 (*a
)->data
.desktopdir
.wrap
= TRUE
;
298 void setup_action_desktop_up(ObAction
**a
, ObUserAction uact
)
300 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
301 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_NORTH
;
302 (*a
)->data
.desktopdir
.linear
= FALSE
;
303 (*a
)->data
.desktopdir
.wrap
= TRUE
;
306 void setup_action_desktop_down(ObAction
**a
, ObUserAction uact
)
308 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
309 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_SOUTH
;
310 (*a
)->data
.desktopdir
.linear
= FALSE
;
311 (*a
)->data
.desktopdir
.wrap
= TRUE
;
314 void setup_action_cycle_windows_next(ObAction
**a
, ObUserAction uact
)
316 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
317 (*a
)->data
.cycle
.linear
= FALSE
;
318 (*a
)->data
.cycle
.forward
= TRUE
;
319 (*a
)->data
.cycle
.dialog
= TRUE
;
320 (*a
)->data
.cycle
.dock_windows
= FALSE
;
321 (*a
)->data
.cycle
.desktop_windows
= FALSE
;
322 (*a
)->data
.cycle
.all_desktops
= FALSE
;
325 void setup_action_cycle_windows_previous(ObAction
**a
, ObUserAction uact
)
327 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
328 (*a
)->data
.cycle
.linear
= FALSE
;
329 (*a
)->data
.cycle
.forward
= FALSE
;
330 (*a
)->data
.cycle
.dialog
= TRUE
;
331 (*a
)->data
.cycle
.dock_windows
= FALSE
;
332 (*a
)->data
.cycle
.desktop_windows
= FALSE
;
333 (*a
)->data
.cycle
.all_desktops
= FALSE
;
336 void setup_action_movefromedge_north(ObAction
**a
, ObUserAction uact
)
338 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
339 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
340 (*a
)->data
.diraction
.hang
= TRUE
;
343 void setup_action_movefromedge_south(ObAction
**a
, ObUserAction uact
)
345 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
346 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
347 (*a
)->data
.diraction
.hang
= TRUE
;
350 void setup_action_movefromedge_east(ObAction
**a
, ObUserAction uact
)
352 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
353 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
354 (*a
)->data
.diraction
.hang
= TRUE
;
357 void setup_action_movefromedge_west(ObAction
**a
, ObUserAction uact
)
359 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
360 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
361 (*a
)->data
.diraction
.hang
= TRUE
;
364 void setup_action_movetoedge_north(ObAction
**a
, ObUserAction uact
)
366 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
367 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
368 (*a
)->data
.diraction
.hang
= FALSE
;
371 void setup_action_movetoedge_south(ObAction
**a
, ObUserAction uact
)
373 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
374 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
375 (*a
)->data
.diraction
.hang
= FALSE
;
378 void setup_action_movetoedge_east(ObAction
**a
, ObUserAction uact
)
380 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
381 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
382 (*a
)->data
.diraction
.hang
= FALSE
;
385 void setup_action_movetoedge_west(ObAction
**a
, ObUserAction uact
)
387 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
388 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
389 (*a
)->data
.diraction
.hang
= FALSE
;
392 void setup_action_growtoedge_north(ObAction
**a
, ObUserAction uact
)
394 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
395 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
398 void setup_action_growtoedge_south(ObAction
**a
, ObUserAction uact
)
400 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
401 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
404 void setup_action_growtoedge_east(ObAction
**a
, ObUserAction uact
)
406 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
407 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
410 void setup_action_growtoedge_west(ObAction
**a
, ObUserAction uact
)
412 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
413 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
416 void setup_action_top_layer(ObAction
**a
, ObUserAction uact
)
418 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
419 (*a
)->data
.layer
.layer
= 1;
422 void setup_action_normal_layer(ObAction
**a
, ObUserAction uact
)
424 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
425 (*a
)->data
.layer
.layer
= 0;
428 void setup_action_bottom_layer(ObAction
**a
, ObUserAction uact
)
430 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
431 (*a
)->data
.layer
.layer
= -1;
434 void setup_action_move(ObAction
**a
, ObUserAction uact
)
436 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
437 (*a
)->data
.moveresize
.keyboard
=
438 (uact
== OB_USER_ACTION_NONE
||
439 uact
== OB_USER_ACTION_KEYBOARD_KEY
||
440 uact
== OB_USER_ACTION_MENU_SELECTION
);
441 (*a
)->data
.moveresize
.corner
= 0;
444 void setup_action_resize(ObAction
**a
, ObUserAction uact
)
446 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
447 (*a
)->data
.moveresize
.keyboard
=
448 (uact
== OB_USER_ACTION_NONE
||
449 uact
== OB_USER_ACTION_KEYBOARD_KEY
||
450 uact
== OB_USER_ACTION_MENU_SELECTION
);
451 (*a
)->data
.moveresize
.corner
= 0;
454 void setup_action_showmenu(ObAction
**a
, ObUserAction uact
)
456 (*a
)->data
.showmenu
.any
.client_action
= OB_CLIENT_ACTION_OPTIONAL
;
457 /* you cannot call ShowMenu from inside a menu, cuz the menu code makes
458 assumptions that there is only one menu (and submenus) open at
460 if (uact
== OB_USER_ACTION_MENU_SELECTION
) {
466 void setup_action_focus(ObAction
**a
, ObUserAction uact
)
468 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_OPTIONAL
;
471 void setup_client_action(ObAction
**a
, ObUserAction uact
)
473 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
476 ActionString actionstrings
[] =
489 "directionalfocusnorth",
490 action_directional_focus
,
491 setup_action_directional_focus_north
494 "directionalfocuseast",
495 action_directional_focus
,
496 setup_action_directional_focus_east
499 "directionalfocussouth",
500 action_directional_focus
,
501 setup_action_directional_focus_south
504 "directionalfocuswest",
505 action_directional_focus
,
506 setup_action_directional_focus_west
509 "directionalfocusnortheast",
510 action_directional_focus
,
511 setup_action_directional_focus_northeast
514 "directionalfocussoutheast",
515 action_directional_focus
,
516 setup_action_directional_focus_southeast
519 "directionalfocussouthwest",
520 action_directional_focus
,
521 setup_action_directional_focus_southwest
524 "directionalfocusnorthwest",
525 action_directional_focus
,
526 setup_action_directional_focus_northwest
550 action_focus_order_to_bottom
,
605 action_toggle_omnipresent
,
610 action_move_relative_horz
,
615 action_move_relative_vert
,
620 action_move_to_center
,
624 "resizerelativehorz",
625 action_resize_relative_horz
,
629 "resizerelativevert",
630 action_resize_relative_vert
,
635 action_move_relative
,
640 action_resize_relative
,
645 action_maximize_full
,
650 action_unmaximize_full
,
654 "togglemaximizefull",
655 action_toggle_maximize_full
,
660 action_maximize_horz
,
665 action_unmaximize_horz
,
669 "togglemaximizehorz",
670 action_toggle_maximize_horz
,
675 action_maximize_vert
,
680 action_unmaximize_vert
,
684 "togglemaximizevert",
685 action_toggle_maximize_vert
,
690 action_toggle_fullscreen
,
695 action_send_to_desktop
,
696 setup_action_send_to_desktop
700 action_send_to_desktop_dir
,
701 setup_action_send_to_desktop_next
704 "sendtodesktopprevious",
705 action_send_to_desktop_dir
,
706 setup_action_send_to_desktop_prev
709 "sendtodesktopright",
710 action_send_to_desktop_dir
,
711 setup_action_send_to_desktop_right
715 action_send_to_desktop_dir
,
716 setup_action_send_to_desktop_left
720 action_send_to_desktop_dir
,
721 setup_action_send_to_desktop_up
725 action_send_to_desktop_dir
,
726 setup_action_send_to_desktop_down
736 setup_action_desktop_next
741 setup_action_desktop_prev
746 setup_action_desktop_right
751 setup_action_desktop_left
756 setup_action_desktop_up
761 setup_action_desktop_down
765 action_toggle_decorations
,
779 "toggledockautohide",
780 action_toggle_dockautohide
,
785 action_toggle_show_desktop
,
795 action_unshow_desktop
,
821 setup_action_showmenu
825 action_send_to_layer
,
826 setup_action_top_layer
831 setup_action_top_layer
835 action_send_to_layer
,
836 setup_action_normal_layer
840 action_send_to_layer
,
841 setup_action_bottom_layer
844 "togglealwaysonbottom",
846 setup_action_bottom_layer
850 action_cycle_windows
,
851 setup_action_cycle_windows_next
855 action_cycle_windows
,
856 setup_action_cycle_windows_previous
861 setup_action_movefromedge_north
866 setup_action_movefromedge_south
871 setup_action_movefromedge_west
876 setup_action_movefromedge_east
881 setup_action_movetoedge_north
886 setup_action_movetoedge_south
891 setup_action_movetoedge_west
896 setup_action_movetoedge_east
901 setup_action_growtoedge_north
906 setup_action_growtoedge_south
911 setup_action_growtoedge_west
916 setup_action_growtoedge_east
930 /* only key bindings can be interactive. thus saith the xor.
931 because of how the mouse is grabbed, mouse events dont even get
932 read during interactive events, so no dice! >:) */
933 #define INTERACTIVE_LIMIT(a, uact) \
934 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
935 a->data.any.interactive = FALSE;
937 ObAction
*action_from_string(const gchar
*name
, ObUserAction uact
)
940 gboolean exist
= FALSE
;
943 for (i
= 0; actionstrings
[i
].name
; i
++)
944 if (!g_ascii_strcasecmp(name
, actionstrings
[i
].name
)) {
946 a
= action_new(actionstrings
[i
].func
);
947 if (actionstrings
[i
].setup
)
948 actionstrings
[i
].setup(&a
, uact
);
950 INTERACTIVE_LIMIT(a
, uact
);
954 g_message(_("Invalid action '%s' requested. No such action exists."),
957 g_message(_("Invalid use of action '%s'. Action will be ignored."),
962 ObAction
*action_parse(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
966 ObAction
*act
= NULL
;
969 if (parse_attr_string("name", node
, &actname
)) {
970 if ((act
= action_from_string(actname
, uact
))) {
971 if (act
->func
== action_execute
|| act
->func
== action_restart
) {
972 if ((n
= parse_find_node("execute", node
->xmlChildrenNode
))) {
973 gchar
*s
= parse_string(doc
, n
);
974 act
->data
.execute
.path
= parse_expand_tilde(s
);
977 if ((n
= parse_find_node("startupnotify", node
->xmlChildrenNode
))) {
979 if ((m
= parse_find_node("enabled", n
->xmlChildrenNode
)))
980 act
->data
.execute
.startupnotify
= parse_bool(doc
, m
);
981 if ((m
= parse_find_node("name", n
->xmlChildrenNode
)))
982 act
->data
.execute
.name
= parse_string(doc
, m
);
983 if ((m
= parse_find_node("icon", n
->xmlChildrenNode
)))
984 act
->data
.execute
.icon_name
= parse_string(doc
, m
);
986 } else if (act
->func
== action_debug
) {
987 if ((n
= parse_find_node("string", node
->xmlChildrenNode
)))
988 act
->data
.debug
.string
= parse_string(doc
, n
);
989 } else if (act
->func
== action_showmenu
) {
990 if ((n
= parse_find_node("menu", node
->xmlChildrenNode
)))
991 act
->data
.showmenu
.name
= parse_string(doc
, n
);
992 } else if (act
->func
== action_move_relative_horz
||
993 act
->func
== action_move_relative_vert
||
994 act
->func
== action_resize_relative_horz
||
995 act
->func
== action_resize_relative_vert
) {
996 if ((n
= parse_find_node("delta", node
->xmlChildrenNode
)))
997 act
->data
.relative
.deltax
= parse_int(doc
, n
);
998 } else if (act
->func
== action_move_relative
) {
999 if ((n
= parse_find_node("x", node
->xmlChildrenNode
)))
1000 act
->data
.relative
.deltax
= parse_int(doc
, n
);
1001 if ((n
= parse_find_node("y", node
->xmlChildrenNode
)))
1002 act
->data
.relative
.deltay
= parse_int(doc
, n
);
1003 } else if (act
->func
== action_resize_relative
) {
1004 if ((n
= parse_find_node("left", node
->xmlChildrenNode
)))
1005 act
->data
.relative
.deltaxl
= parse_int(doc
, n
);
1006 if ((n
= parse_find_node("up", node
->xmlChildrenNode
)))
1007 act
->data
.relative
.deltayu
= parse_int(doc
, n
);
1008 if ((n
= parse_find_node("right", node
->xmlChildrenNode
)))
1009 act
->data
.relative
.deltax
= parse_int(doc
, n
);
1010 if ((n
= parse_find_node("down", node
->xmlChildrenNode
)))
1011 act
->data
.relative
.deltay
= parse_int(doc
, n
);
1012 } else if (act
->func
== action_desktop
) {
1013 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1014 act
->data
.desktop
.desk
= parse_int(doc
, n
);
1015 if (act
->data
.desktop
.desk
> 0) act
->data
.desktop
.desk
--;
1016 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1017 act
->data
.desktop
.inter
.any
.interactive
=
1019 } else if (act
->func
== action_send_to_desktop
) {
1020 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1021 act
->data
.sendto
.desk
= parse_int(doc
, n
);
1022 if (act
->data
.sendto
.desk
> 0) act
->data
.sendto
.desk
--;
1023 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
1024 act
->data
.sendto
.follow
= parse_bool(doc
, n
);
1025 } else if (act
->func
== action_desktop_dir
) {
1026 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
1027 act
->data
.desktopdir
.wrap
= parse_bool(doc
, n
);
1028 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1029 act
->data
.desktopdir
.inter
.any
.interactive
=
1031 } else if (act
->func
== action_send_to_desktop_dir
) {
1032 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
1033 act
->data
.sendtodir
.wrap
= parse_bool(doc
, n
);
1034 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
1035 act
->data
.sendtodir
.follow
= parse_bool(doc
, n
);
1036 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1037 act
->data
.sendtodir
.inter
.any
.interactive
=
1039 } else if (act
->func
== action_activate
) {
1040 if ((n
= parse_find_node("here", node
->xmlChildrenNode
)))
1041 act
->data
.activate
.here
= parse_bool(doc
, n
);
1042 } else if (act
->func
== action_cycle_windows
) {
1043 if ((n
= parse_find_node("linear", node
->xmlChildrenNode
)))
1044 act
->data
.cycle
.linear
= parse_bool(doc
, n
);
1045 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1046 act
->data
.cycle
.dialog
= parse_bool(doc
, n
);
1047 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
1048 act
->data
.cycle
.dock_windows
= parse_bool(doc
, n
);
1049 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1050 act
->data
.cycle
.desktop_windows
= parse_bool(doc
, n
);
1051 if ((n
= parse_find_node("allDesktops",
1052 node
->xmlChildrenNode
)))
1053 act
->data
.cycle
.all_desktops
= parse_bool(doc
, n
);
1054 } else if (act
->func
== action_directional_focus
) {
1055 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1056 act
->data
.interdiraction
.dialog
= parse_bool(doc
, n
);
1057 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
1058 act
->data
.interdiraction
.dock_windows
= parse_bool(doc
, n
);
1059 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1060 act
->data
.interdiraction
.desktop_windows
=
1062 } else if (act
->func
== action_resize
) {
1063 if ((n
= parse_find_node("edge", node
->xmlChildrenNode
))) {
1064 gchar
*s
= parse_string(doc
, n
);
1065 if (!g_ascii_strcasecmp(s
, "top"))
1066 act
->data
.moveresize
.corner
=
1067 prop_atoms
.net_wm_moveresize_size_top
;
1068 else if (!g_ascii_strcasecmp(s
, "bottom"))
1069 act
->data
.moveresize
.corner
=
1070 prop_atoms
.net_wm_moveresize_size_bottom
;
1071 else if (!g_ascii_strcasecmp(s
, "left"))
1072 act
->data
.moveresize
.corner
=
1073 prop_atoms
.net_wm_moveresize_size_left
;
1074 else if (!g_ascii_strcasecmp(s
, "right"))
1075 act
->data
.moveresize
.corner
=
1076 prop_atoms
.net_wm_moveresize_size_right
;
1077 else if (!g_ascii_strcasecmp(s
, "topleft"))
1078 act
->data
.moveresize
.corner
=
1079 prop_atoms
.net_wm_moveresize_size_topleft
;
1080 else if (!g_ascii_strcasecmp(s
, "topright"))
1081 act
->data
.moveresize
.corner
=
1082 prop_atoms
.net_wm_moveresize_size_topright
;
1083 else if (!g_ascii_strcasecmp(s
, "bottomleft"))
1084 act
->data
.moveresize
.corner
=
1085 prop_atoms
.net_wm_moveresize_size_bottomleft
;
1086 else if (!g_ascii_strcasecmp(s
, "bottomright"))
1087 act
->data
.moveresize
.corner
=
1088 prop_atoms
.net_wm_moveresize_size_bottomright
;
1091 } else if (act
->func
== action_raise
||
1092 act
->func
== action_lower
||
1093 act
->func
== action_raiselower
||
1094 act
->func
== action_shadelower
||
1095 act
->func
== action_unshaderaise
) {
1097 INTERACTIVE_LIMIT(act
, uact
);
1104 void action_run_list(GSList
*acts
, ObClient
*c
, ObFrameContext context
,
1105 guint state
, guint button
, gint x
, gint y
, Time time
,
1106 gboolean cancel
, gboolean done
)
1115 screen_pointer_pos(&x
, &y
);
1117 for (it
= acts
; it
; it
= g_slist_next(it
)) {
1120 if (!(a
->data
.any
.client_action
== OB_CLIENT_ACTION_ALWAYS
&& !c
)) {
1121 a
->data
.any
.c
= a
->data
.any
.client_action
? c
: NULL
;
1122 a
->data
.any
.context
= context
;
1126 a
->data
.any
.button
= button
;
1128 a
->data
.any
.time
= time
;
1130 if (a
->data
.any
.interactive
) {
1131 a
->data
.inter
.cancel
= cancel
;
1132 a
->data
.inter
.final
= done
;
1133 if (!(cancel
|| done
))
1134 if (!keyboard_interactive_grab(state
, a
->data
.any
.c
, a
))
1138 /* XXX UGLY HACK race with motion event starting a move and the
1139 button release gettnig processed first. answer: don't queue
1140 moveresize starts. UGLY HACK XXX */
1141 if (a
->data
.any
.interactive
|| a
->func
== action_move
||
1142 a
->func
== action_resize
)
1144 /* interactive actions are not queued */
1147 (context
== OB_FRAME_CONTEXT_CLIENT
||
1148 (c
->type
== OB_CLIENT_TYPE_DESKTOP
&&
1149 context
== OB_FRAME_CONTEXT_DESKTOP
)) &&
1150 (a
->func
== action_focus
||
1151 a
->func
== action_activate
||
1152 a
->func
== action_showmenu
))
1154 /* XXX MORE UGLY HACK
1155 actions from clicks on client windows are NOT queued.
1156 this solves the mysterious click-and-drag-doesnt-work
1157 problem. it was because the window gets focused and stuff
1158 after the button event has already been passed through. i
1159 dont really know why it should care but it does and it makes
1162 however this very bogus ! !
1163 we want to send the button press to the window BEFORE
1164 we do the action because the action might move the windows
1165 (eg change desktops) and then the button press ends up on
1166 the completely wrong window !
1167 so, this is just for that bug, and it will only NOT queue it
1168 if it is a focusing action that can be used with the mouse
1171 also with the menus, there is a race going on. if the
1172 desktop wants to pop up a menu, and we do to, we send them
1173 the button before we pop up the menu, so they pop up their
1174 menu first. but not always. if we pop up our menu before
1175 sending them the button press, then the result is
1180 ob_main_loop_queue_action(ob_main_loop
, a
);
1185 void action_run_string(const gchar
*name
, struct _ObClient
*c
, Time time
)
1190 a
= action_from_string(name
, OB_USER_ACTION_NONE
);
1193 l
= g_slist_append(NULL
, a
);
1195 action_run(l
, c
, 0, time
);
1198 void action_debug(union ActionData
*data
)
1200 if (data
->debug
.string
)
1201 g_print("%s\n", data
->debug
.string
);
1204 void action_execute(union ActionData
*data
)
1207 gchar
*cmd
, **argv
= 0;
1208 if (data
->execute
.path
) {
1209 /* Ungrab the keyboard before running the action.
1211 If there is an interactive action going on, then cancel it to
1212 release the keyboard. If not, then call XUngrabKeyboard().
1214 We call XUngrabKeyboard because a key press causes a passive
1215 grab on the keyboard, and so if program we are executing wants to
1216 grab the keyboard, it will fail if the button is still held down
1219 Use the X function not out own, because we're not considering
1220 a grab to be in place at all so our function won't try ungrab
1223 if (keyboard_interactively_grabbed())
1224 keyboard_interactive_cancel();
1226 XUngrabKeyboard(ob_display
, data
->any
.time
);
1228 cmd
= g_filename_from_utf8(data
->execute
.path
, -1, NULL
, NULL
, NULL
);
1230 if (!g_shell_parse_argv (cmd
, NULL
, &argv
, &e
)) {
1231 g_message(_("Failed to execute '%s': %s"),
1234 } else if (data
->execute
.startupnotify
) {
1237 program
= g_path_get_basename(argv
[0]);
1238 /* sets up the environment */
1239 sn_setup_spawn_environment(program
,
1241 data
->execute
.icon_name
,
1242 /* launch it on the current
1245 data
->execute
.any
.time
);
1246 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
|
1247 G_SPAWN_DO_NOT_REAP_CHILD
,
1248 NULL
, NULL
, NULL
, &e
)) {
1249 g_message(_("Failed to execute '%s': %s"),
1254 unsetenv("DESKTOP_STARTUP_ID");
1258 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
|
1259 G_SPAWN_DO_NOT_REAP_CHILD
,
1260 NULL
, NULL
, NULL
, &e
))
1262 g_message(_("Failed to execute '%s': %s"),
1270 g_message(_("Failed to convert the path '%s' from utf8"),
1271 data
->execute
.path
);
1276 void action_activate(union ActionData
*data
)
1278 if (data
->client
.any
.c
) {
1279 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1280 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1281 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1283 /* if using focus_delay, stop the timer now so that focus doesn't
1285 event_halt_focus_delay();
1287 client_activate(data
->activate
.any
.c
, data
->activate
.here
, TRUE
);
1290 /* focus action on something other than a client, make keybindings
1291 work for this openbox instance, but don't focus any specific client
1297 void action_focus(union ActionData
*data
)
1299 if (data
->client
.any
.c
) {
1300 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1301 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1302 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1304 /* if using focus_delay, stop the timer now so that focus doesn't
1306 event_halt_focus_delay();
1308 client_focus(data
->client
.any
.c
);
1311 /* focus action on something other than a client, make keybindings
1312 work for this openbox instance, but don't focus any specific client
1318 void action_unfocus (union ActionData
*data
)
1320 if (data
->client
.any
.c
== focus_client
)
1321 focus_fallback(TRUE
);
1324 void action_iconify(union ActionData
*data
)
1326 client_action_start(data
);
1327 client_iconify(data
->client
.any
.c
, TRUE
, TRUE
, FALSE
);
1328 client_action_end(data
);
1331 void action_focus_order_to_bottom(union ActionData
*data
)
1333 focus_order_to_bottom(data
->client
.any
.c
);
1336 void action_raiselower(union ActionData
*data
)
1338 ObClient
*c
= data
->client
.any
.c
;
1340 gboolean raise
= FALSE
;
1342 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
1343 if (WINDOW_IS_CLIENT(it
->data
)) {
1344 ObClient
*cit
= it
->data
;
1346 if (cit
== c
) break;
1347 if (client_normal(cit
) == client_normal(c
) &&
1348 cit
->layer
== c
->layer
&&
1349 cit
->frame
->visible
&&
1350 !client_search_transient(c
, cit
))
1352 if (RECT_INTERSECTS_RECT(cit
->frame
->area
, c
->frame
->area
)) {
1366 void action_raise(union ActionData
*data
)
1368 client_action_start(data
);
1369 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1370 client_action_end(data
);
1373 void action_unshaderaise(union ActionData
*data
)
1375 if (data
->client
.any
.c
->shaded
)
1376 action_unshade(data
);
1381 void action_shadelower(union ActionData
*data
)
1383 if (data
->client
.any
.c
->shaded
)
1389 void action_lower(union ActionData
*data
)
1391 client_action_start(data
);
1392 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1393 client_action_end(data
);
1396 void action_close(union ActionData
*data
)
1398 client_close(data
->client
.any
.c
);
1401 void action_kill(union ActionData
*data
)
1403 client_kill(data
->client
.any
.c
);
1406 void action_shade(union ActionData
*data
)
1408 client_action_start(data
);
1409 client_shade(data
->client
.any
.c
, TRUE
);
1410 client_action_end(data
);
1413 void action_unshade(union ActionData
*data
)
1415 client_action_start(data
);
1416 client_shade(data
->client
.any
.c
, FALSE
);
1417 client_action_end(data
);
1420 void action_toggle_shade(union ActionData
*data
)
1422 client_action_start(data
);
1423 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1424 client_action_end(data
);
1427 void action_toggle_omnipresent(union ActionData
*data
)
1429 client_set_desktop(data
->client
.any
.c
,
1430 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1431 screen_desktop
: DESKTOP_ALL
, FALSE
);
1434 void action_move_relative_horz(union ActionData
*data
)
1436 ObClient
*c
= data
->relative
.any
.c
;
1437 client_action_start(data
);
1438 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
);
1439 client_action_end(data
);
1442 void action_move_relative_vert(union ActionData
*data
)
1444 ObClient
*c
= data
->relative
.any
.c
;
1445 client_action_start(data
);
1446 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.deltax
);
1447 client_action_end(data
);
1450 void action_move_to_center(union ActionData
*data
)
1452 ObClient
*c
= data
->client
.any
.c
;
1454 area
= screen_area_monitor(c
->desktop
, 0);
1455 client_action_start(data
);
1456 client_move(c
, area
->width
/ 2 - c
->area
.width
/ 2,
1457 area
->height
/ 2 - c
->area
.height
/ 2);
1458 client_action_end(data
);
1461 void action_resize_relative_horz(union ActionData
*data
)
1463 ObClient
*c
= data
->relative
.any
.c
;
1464 client_action_start(data
);
1466 c
->area
.width
+ data
->relative
.deltax
* c
->size_inc
.width
,
1468 client_action_end(data
);
1471 void action_resize_relative_vert(union ActionData
*data
)
1473 ObClient
*c
= data
->relative
.any
.c
;
1475 client_action_start(data
);
1476 client_resize(c
, c
->area
.width
, c
->area
.height
+
1477 data
->relative
.deltax
* c
->size_inc
.height
);
1478 client_action_end(data
);
1482 void action_move_relative(union ActionData
*data
)
1484 ObClient
*c
= data
->relative
.any
.c
;
1485 client_action_start(data
);
1486 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
+
1487 data
->relative
.deltay
);
1488 client_action_end(data
);
1491 void action_resize_relative(union ActionData
*data
)
1493 ObClient
*c
= data
->relative
.any
.c
;
1494 gint x
, y
, ow
, w
, oh
, h
, lw
, lh
;
1496 client_action_start(data
);
1501 w
= ow
+ data
->relative
.deltax
* c
->size_inc
.width
1502 + data
->relative
.deltaxl
* c
->size_inc
.width
;
1503 oh
= c
->area
.height
;
1504 h
= oh
+ data
->relative
.deltay
* c
->size_inc
.height
1505 + data
->relative
.deltayu
* c
->size_inc
.height
;
1507 client_try_configure(c
, &x
, &y
, &w
, &h
, &lw
, &lh
, TRUE
);
1508 client_move_resize(c
, x
+ (ow
- w
), y
+ (oh
- h
), w
, h
);
1509 client_action_end(data
);
1512 void action_maximize_full(union ActionData
*data
)
1514 client_action_start(data
);
1515 client_maximize(data
->client
.any
.c
, TRUE
, 0);
1516 client_action_end(data
);
1519 void action_unmaximize_full(union ActionData
*data
)
1521 client_action_start(data
);
1522 client_maximize(data
->client
.any
.c
, FALSE
, 0);
1523 client_action_end(data
);
1526 void action_toggle_maximize_full(union ActionData
*data
)
1528 client_action_start(data
);
1529 client_maximize(data
->client
.any
.c
,
1530 !(data
->client
.any
.c
->max_horz
||
1531 data
->client
.any
.c
->max_vert
),
1533 client_action_end(data
);
1536 void action_maximize_horz(union ActionData
*data
)
1538 client_action_start(data
);
1539 client_maximize(data
->client
.any
.c
, TRUE
, 1);
1540 client_action_end(data
);
1543 void action_unmaximize_horz(union ActionData
*data
)
1545 client_action_start(data
);
1546 client_maximize(data
->client
.any
.c
, FALSE
, 1);
1547 client_action_end(data
);
1550 void action_toggle_maximize_horz(union ActionData
*data
)
1552 client_action_start(data
);
1553 client_maximize(data
->client
.any
.c
,
1554 !data
->client
.any
.c
->max_horz
, 1);
1555 client_action_end(data
);
1558 void action_maximize_vert(union ActionData
*data
)
1560 client_action_start(data
);
1561 client_maximize(data
->client
.any
.c
, TRUE
, 2);
1562 client_action_end(data
);
1565 void action_unmaximize_vert(union ActionData
*data
)
1567 client_action_start(data
);
1568 client_maximize(data
->client
.any
.c
, FALSE
, 2);
1569 client_action_end(data
);
1572 void action_toggle_maximize_vert(union ActionData
*data
)
1574 client_action_start(data
);
1575 client_maximize(data
->client
.any
.c
,
1576 !data
->client
.any
.c
->max_vert
, 2);
1577 client_action_end(data
);
1580 void action_toggle_fullscreen(union ActionData
*data
)
1582 client_action_start(data
);
1583 client_fullscreen(data
->client
.any
.c
, !(data
->client
.any
.c
->fullscreen
));
1584 client_action_end(data
);
1587 void action_send_to_desktop(union ActionData
*data
)
1589 ObClient
*c
= data
->sendto
.any
.c
;
1591 if (!client_normal(c
)) return;
1593 if (data
->sendto
.desk
< screen_num_desktops
||
1594 data
->sendto
.desk
== DESKTOP_ALL
) {
1595 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
);
1596 if (data
->sendto
.follow
)
1597 screen_set_desktop(data
->sendto
.desk
, TRUE
);
1601 void action_desktop(union ActionData
*data
)
1603 if (!data
->inter
.any
.interactive
||
1604 (!data
->inter
.cancel
&& !data
->inter
.final
))
1606 if (data
->desktop
.desk
< screen_num_desktops
||
1607 data
->desktop
.desk
== DESKTOP_ALL
)
1609 screen_set_desktop(data
->desktop
.desk
, TRUE
);
1610 if (data
->inter
.any
.interactive
)
1611 screen_desktop_popup(data
->desktop
.desk
, TRUE
);
1614 screen_desktop_popup(0, FALSE
);
1617 void action_desktop_dir(union ActionData
*data
)
1621 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1622 data
->desktopdir
.wrap
,
1623 data
->desktopdir
.linear
,
1624 data
->desktopdir
.inter
.any
.interactive
,
1625 data
->desktopdir
.inter
.final
,
1626 data
->desktopdir
.inter
.cancel
);
1627 /* only move the desktop when the action is complete. if we switch
1628 desktops during the interactive action, focus will move but with
1629 NotifyWhileGrabbed and applications don't like that. */
1630 if (!data
->sendtodir
.inter
.any
.interactive
||
1631 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1633 if (d
!= screen_desktop
) screen_set_desktop(d
, TRUE
);
1637 void action_send_to_desktop_dir(union ActionData
*data
)
1639 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1642 if (!client_normal(c
)) return;
1644 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1645 data
->sendtodir
.linear
,
1646 data
->sendtodir
.inter
.any
.interactive
,
1647 data
->sendtodir
.inter
.final
,
1648 data
->sendtodir
.inter
.cancel
);
1649 /* only move the desktop when the action is complete. if we switch
1650 desktops during the interactive action, focus will move but with
1651 NotifyWhileGrabbed and applications don't like that. */
1652 if (!data
->sendtodir
.inter
.any
.interactive
||
1653 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1655 client_set_desktop(c
, d
, data
->sendtodir
.follow
);
1656 if (data
->sendtodir
.follow
&& d
!= screen_desktop
)
1657 screen_set_desktop(d
, TRUE
);
1661 void action_desktop_last(union ActionData
*data
)
1663 screen_set_desktop(screen_last_desktop
, TRUE
);
1666 void action_toggle_decorations(union ActionData
*data
)
1668 ObClient
*c
= data
->client
.any
.c
;
1670 client_action_start(data
);
1671 client_set_undecorated(c
, !c
->undecorated
);
1672 client_action_end(data
);
1675 static guint32
pick_corner(gint x
, gint y
, gint cx
, gint cy
, gint cw
, gint ch
,
1678 /* let's make x and y client relative instead of screen relative */
1680 y
= ch
- (y
- cy
); /* y is inverted, 0 is at the bottom of the window */
1683 #define A -4*X + 7*ch/3
1684 #define B 4*X -15*ch/9
1685 #define C -X/4 + 2*ch/3
1686 #define D X/4 + 5*ch/12
1687 #define E X/4 + ch/3
1688 #define F -X/4 + 7*ch/12
1689 #define G 4*X - 4*ch/3
1690 #define H -4*X + 8*ch/3
1691 #define a (y > 5*ch/9)
1692 #define b (x < 4*cw/9)
1693 #define c (x > 5*cw/9)
1694 #define d (y < 4*ch/9)
1697 Each of these defines (except X which is just there for fun), represents
1698 the equation of a line. The lines they represent are shown in the diagram
1699 below. Checking y against these lines, we are able to choose a region
1700 of the window as shown.
1702 +---------------------A-------|-------|-------B---------------------+
1709 | northwest | A north B | northeast |
1712 C---------------------+----A--+-------+--B----+---------------------D
1713 |CCCCCCC | A B | DDDDDDD|
1714 | CCCCCCCC | A | | B | DDDDDDDD |
1715 | CCCCCCC A B DDDDDDD |
1716 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
1718 | west | b move c | east | ad
1720 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
1721 | EEEEEEE G H FFFFFFF |
1722 | EEEEEEEE | G | | H | FFFFFFFF |
1723 |EEEEEEE | G H | FFFFFFF|
1724 E---------------------+----G--+-------+--H----+---------------------F
1727 | southwest | G south H | southeast |
1734 +---------------------G-------|-------|-------H---------------------+
1738 /* for shaded windows, you can only resize west/east and move */
1740 return prop_atoms
.net_wm_moveresize_size_left
;
1742 return prop_atoms
.net_wm_moveresize_size_right
;
1743 return prop_atoms
.net_wm_moveresize_move
;
1746 if (y
< A
&& y
>= C
)
1747 return prop_atoms
.net_wm_moveresize_size_topleft
;
1748 else if (y
>= A
&& y
>= B
&& a
)
1749 return prop_atoms
.net_wm_moveresize_size_top
;
1750 else if (y
< B
&& y
>= D
)
1751 return prop_atoms
.net_wm_moveresize_size_topright
;
1752 else if (y
< C
&& y
>= E
&& b
)
1753 return prop_atoms
.net_wm_moveresize_size_left
;
1754 else if (y
< D
&& y
>= F
&& c
)
1755 return prop_atoms
.net_wm_moveresize_size_right
;
1756 else if (y
< E
&& y
>= G
)
1757 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1758 else if (y
< G
&& y
< H
&& d
)
1759 return prop_atoms
.net_wm_moveresize_size_bottom
;
1760 else if (y
>= H
&& y
< F
)
1761 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1763 return prop_atoms
.net_wm_moveresize_move
;
1780 void action_move(union ActionData
*data
)
1782 ObClient
*c
= data
->moveresize
.any
.c
;
1785 if (data
->moveresize
.keyboard
)
1786 corner
= prop_atoms
.net_wm_moveresize_move_keyboard
;
1788 corner
= prop_atoms
.net_wm_moveresize_move
;
1790 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1793 void action_resize(union ActionData
*data
)
1795 ObClient
*c
= data
->moveresize
.any
.c
;
1798 if (data
->moveresize
.keyboard
)
1799 corner
= prop_atoms
.net_wm_moveresize_size_keyboard
;
1800 else if (data
->moveresize
.corner
)
1801 corner
= data
->moveresize
.corner
; /* it was specified in the binding */
1803 corner
= pick_corner(data
->any
.x
, data
->any
.y
,
1804 c
->frame
->area
.x
, c
->frame
->area
.y
,
1805 /* use the client size because the frame
1806 can be differently sized (shaded
1807 windows) and we want this based on the
1809 c
->area
.width
+ c
->frame
->size
.left
+
1810 c
->frame
->size
.right
,
1811 c
->area
.height
+ c
->frame
->size
.top
+
1812 c
->frame
->size
.bottom
, c
->shaded
);
1814 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1817 void action_reconfigure(union ActionData
*data
)
1822 void action_restart(union ActionData
*data
)
1824 ob_restart_other(data
->execute
.path
);
1827 void action_exit(union ActionData
*data
)
1832 void action_showmenu(union ActionData
*data
)
1834 if (data
->showmenu
.name
) {
1835 menu_show(data
->showmenu
.name
, data
->any
.x
, data
->any
.y
,
1836 data
->any
.button
, data
->showmenu
.any
.c
);
1840 void action_cycle_windows(union ActionData
*data
)
1842 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1844 event_halt_focus_delay();
1846 focus_cycle(data
->cycle
.forward
,
1847 data
->cycle
.all_desktops
,
1848 data
->cycle
.dock_windows
,
1849 data
->cycle
.desktop_windows
,
1850 data
->cycle
.linear
, data
->any
.interactive
,
1852 data
->cycle
.inter
.final
, data
->cycle
.inter
.cancel
);
1855 void action_directional_focus(union ActionData
*data
)
1857 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1859 event_halt_focus_delay();
1861 focus_directional_cycle(data
->interdiraction
.direction
,
1862 data
->interdiraction
.dock_windows
,
1863 data
->interdiraction
.desktop_windows
,
1864 data
->any
.interactive
,
1865 data
->interdiraction
.dialog
,
1866 data
->interdiraction
.inter
.final
,
1867 data
->interdiraction
.inter
.cancel
);
1870 void action_movetoedge(union ActionData
*data
)
1873 ObClient
*c
= data
->diraction
.any
.c
;
1875 x
= c
->frame
->area
.x
;
1876 y
= c
->frame
->area
.y
;
1878 switch(data
->diraction
.direction
) {
1879 case OB_DIRECTION_NORTH
:
1880 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
,
1881 data
->diraction
.hang
)
1882 - (data
->diraction
.hang
? c
->frame
->area
.height
: 0);
1884 case OB_DIRECTION_WEST
:
1885 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
,
1886 data
->diraction
.hang
)
1887 - (data
->diraction
.hang
? c
->frame
->area
.width
: 0);
1889 case OB_DIRECTION_SOUTH
:
1890 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
,
1891 data
->diraction
.hang
)
1892 - (data
->diraction
.hang
? 0 : c
->frame
->area
.height
);
1894 case OB_DIRECTION_EAST
:
1895 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
,
1896 data
->diraction
.hang
)
1897 - (data
->diraction
.hang
? 0 : c
->frame
->area
.width
);
1900 g_assert_not_reached();
1902 frame_frame_gravity(c
->frame
, &x
, &y
, c
->area
.width
, c
->area
.height
);
1903 client_action_start(data
);
1904 client_move(c
, x
, y
);
1905 client_action_end(data
);
1908 void action_growtoedge(union ActionData
*data
)
1910 gint x
, y
, width
, height
, dest
;
1911 ObClient
*c
= data
->diraction
.any
.c
;
1914 a
= screen_area(c
->desktop
);
1915 x
= c
->frame
->area
.x
;
1916 y
= c
->frame
->area
.y
;
1917 /* get the unshaded frame's dimensions..if it is shaded */
1918 width
= c
->area
.width
+ c
->frame
->size
.left
+ c
->frame
->size
.right
;
1919 height
= c
->area
.height
+ c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1921 switch(data
->diraction
.direction
) {
1922 case OB_DIRECTION_NORTH
:
1923 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1925 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
, FALSE
);
1927 height
= height
/ 2;
1929 height
= c
->frame
->area
.y
+ height
- dest
;
1933 case OB_DIRECTION_WEST
:
1934 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
, FALSE
);
1938 width
= c
->frame
->area
.x
+ width
- dest
;
1942 case OB_DIRECTION_SOUTH
:
1943 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1945 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
, FALSE
);
1946 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1947 height
= c
->frame
->area
.height
/ 2;
1948 y
= a
->y
+ a
->height
- height
;
1950 height
= dest
- c
->frame
->area
.y
;
1951 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1952 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1954 case OB_DIRECTION_EAST
:
1955 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
, FALSE
);
1956 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1957 width
= c
->frame
->area
.width
/ 2;
1958 x
= a
->x
+ a
->width
- width
;
1960 width
= dest
- c
->frame
->area
.x
;
1961 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1962 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1965 g_assert_not_reached();
1967 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1968 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1969 frame_frame_gravity(c
->frame
, &x
, &y
, width
, height
);
1970 client_action_start(data
);
1971 client_move_resize(c
, x
, y
, width
, height
);
1972 client_action_end(data
);
1975 void action_send_to_layer(union ActionData
*data
)
1977 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1980 void action_toggle_layer(union ActionData
*data
)
1982 ObClient
*c
= data
->layer
.any
.c
;
1984 client_action_start(data
);
1985 if (data
->layer
.layer
< 0)
1986 client_set_layer(c
, c
->below
? 0 : -1);
1987 else if (data
->layer
.layer
> 0)
1988 client_set_layer(c
, c
->above
? 0 : 1);
1989 client_action_end(data
);
1992 void action_toggle_dockautohide(union ActionData
*data
)
1994 config_dock_hide
= !config_dock_hide
;
1998 void action_toggle_show_desktop(union ActionData
*data
)
2000 screen_show_desktop(!screen_showing_desktop
, NULL
);
2003 void action_show_desktop(union ActionData
*data
)
2005 screen_show_desktop(TRUE
, NULL
);
2008 void action_unshow_desktop(union ActionData
*data
)
2010 screen_show_desktop(FALSE
, NULL
);
2013 void action_break_chroot(union ActionData
*data
)
2015 /* break out of one chroot */
2016 keyboard_reset_chains(1);