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 "focus_cycle.h"
24 #include "moveresize.h"
37 #include "startupnotify.h"
42 static void client_action_start(union ActionData
*data
)
46 static void client_action_end(union ActionData
*data
)
48 if (config_focus_follow
)
49 if (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
) {
50 if (!data
->any
.button
&& data
->any
.c
) {
51 event_ignore_all_queued_enters();
55 /* usually this is sorta redundant, but with a press action
56 that moves windows our from under the cursor, the enter
57 event will come as a GrabNotify which is ignored, so this
58 makes a fake enter event
60 if ((c
= client_under_pointer()))
61 event_enter_client(c
);
69 void (*func
)(union ActionData
*);
70 void (*setup
)(ObAction
**, ObUserAction uact
);
73 static ObAction
*action_new(void (*func
)(union ActionData
*data
))
75 ObAction
*a
= g_new0(ObAction
, 1);
82 void action_ref(ObAction
*a
)
87 void action_unref(ObAction
*a
)
89 if (a
== NULL
) return;
91 if (--a
->ref
> 0) return;
93 /* deal with pointers */
94 if (a
->func
== action_execute
|| a
->func
== action_restart
)
95 g_free(a
->data
.execute
.path
);
96 else if (a
->func
== action_debug
)
97 g_free(a
->data
.debug
.string
);
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_debug
)
114 a
->data
.debug
.string
= g_strdup(a
->data
.debug
.string
);
115 else if (a
->func
== action_showmenu
)
116 a
->data
.showmenu
.name
= g_strdup(a
->data
.showmenu
.name
);
121 void setup_action_directional_focus_north(ObAction
**a
, ObUserAction uact
)
123 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
124 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTH
;
125 (*a
)->data
.interdiraction
.dialog
= TRUE
;
126 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
127 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
130 void setup_action_directional_focus_east(ObAction
**a
, ObUserAction uact
)
132 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
133 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_EAST
;
134 (*a
)->data
.interdiraction
.dialog
= TRUE
;
135 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
136 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
139 void setup_action_directional_focus_south(ObAction
**a
, ObUserAction uact
)
141 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
142 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTH
;
143 (*a
)->data
.interdiraction
.dialog
= TRUE
;
144 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
145 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
148 void setup_action_directional_focus_west(ObAction
**a
, ObUserAction uact
)
150 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
151 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_WEST
;
152 (*a
)->data
.interdiraction
.dialog
= TRUE
;
153 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
154 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
157 void setup_action_directional_focus_northeast(ObAction
**a
, ObUserAction uact
)
159 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
160 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHEAST
;
161 (*a
)->data
.interdiraction
.dialog
= TRUE
;
162 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
163 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
166 void setup_action_directional_focus_southeast(ObAction
**a
, ObUserAction uact
)
168 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
169 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHEAST
;
170 (*a
)->data
.interdiraction
.dialog
= TRUE
;
171 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
172 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
175 void setup_action_directional_focus_southwest(ObAction
**a
, ObUserAction uact
)
177 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
178 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHWEST
;
179 (*a
)->data
.interdiraction
.dialog
= TRUE
;
180 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
181 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
184 void setup_action_directional_focus_northwest(ObAction
**a
, ObUserAction uact
)
186 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
187 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHWEST
;
188 (*a
)->data
.interdiraction
.dialog
= TRUE
;
189 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
190 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
193 void setup_action_send_to_desktop(ObAction
**a
, ObUserAction uact
)
195 (*a
)->data
.sendto
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
196 (*a
)->data
.sendto
.follow
= TRUE
;
199 void setup_action_send_to_desktop_prev(ObAction
**a
, ObUserAction uact
)
201 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
202 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
203 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
204 (*a
)->data
.sendtodir
.linear
= TRUE
;
205 (*a
)->data
.sendtodir
.wrap
= TRUE
;
206 (*a
)->data
.sendtodir
.follow
= TRUE
;
209 void setup_action_send_to_desktop_next(ObAction
**a
, ObUserAction uact
)
211 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
212 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
213 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
214 (*a
)->data
.sendtodir
.linear
= TRUE
;
215 (*a
)->data
.sendtodir
.wrap
= TRUE
;
216 (*a
)->data
.sendtodir
.follow
= TRUE
;
219 void setup_action_send_to_desktop_left(ObAction
**a
, ObUserAction uact
)
221 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
222 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
223 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
224 (*a
)->data
.sendtodir
.linear
= FALSE
;
225 (*a
)->data
.sendtodir
.wrap
= TRUE
;
226 (*a
)->data
.sendtodir
.follow
= TRUE
;
229 void setup_action_send_to_desktop_right(ObAction
**a
, ObUserAction uact
)
231 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
232 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
233 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
234 (*a
)->data
.sendtodir
.linear
= FALSE
;
235 (*a
)->data
.sendtodir
.wrap
= TRUE
;
236 (*a
)->data
.sendtodir
.follow
= TRUE
;
239 void setup_action_send_to_desktop_up(ObAction
**a
, ObUserAction uact
)
241 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
242 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
243 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_NORTH
;
244 (*a
)->data
.sendtodir
.linear
= FALSE
;
245 (*a
)->data
.sendtodir
.wrap
= TRUE
;
246 (*a
)->data
.sendtodir
.follow
= TRUE
;
249 void setup_action_send_to_desktop_down(ObAction
**a
, ObUserAction uact
)
251 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
252 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
253 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_SOUTH
;
254 (*a
)->data
.sendtodir
.linear
= FALSE
;
255 (*a
)->data
.sendtodir
.wrap
= TRUE
;
256 (*a
)->data
.sendtodir
.follow
= TRUE
;
259 void setup_action_desktop(ObAction
**a
, ObUserAction uact
)
262 (*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
--;
1017 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
1018 act->data.desktop.inter.any.interactive =
1021 } else if (act
->func
== action_send_to_desktop
) {
1022 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1023 act
->data
.sendto
.desk
= parse_int(doc
, n
);
1024 if (act
->data
.sendto
.desk
> 0) act
->data
.sendto
.desk
--;
1025 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
1026 act
->data
.sendto
.follow
= parse_bool(doc
, n
);
1027 } else if (act
->func
== action_desktop_dir
) {
1028 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
1029 act
->data
.desktopdir
.wrap
= parse_bool(doc
, n
);
1030 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1031 act
->data
.desktopdir
.inter
.any
.interactive
=
1033 } else if (act
->func
== action_send_to_desktop_dir
) {
1034 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
1035 act
->data
.sendtodir
.wrap
= parse_bool(doc
, n
);
1036 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
1037 act
->data
.sendtodir
.follow
= parse_bool(doc
, n
);
1038 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1039 act
->data
.sendtodir
.inter
.any
.interactive
=
1041 } else if (act
->func
== action_activate
) {
1042 if ((n
= parse_find_node("here", node
->xmlChildrenNode
)))
1043 act
->data
.activate
.here
= parse_bool(doc
, n
);
1044 } else if (act
->func
== action_cycle_windows
) {
1045 if ((n
= parse_find_node("linear", node
->xmlChildrenNode
)))
1046 act
->data
.cycle
.linear
= parse_bool(doc
, n
);
1047 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1048 act
->data
.cycle
.dialog
= parse_bool(doc
, n
);
1049 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
1050 act
->data
.cycle
.dock_windows
= parse_bool(doc
, n
);
1051 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1052 act
->data
.cycle
.desktop_windows
= parse_bool(doc
, n
);
1053 if ((n
= parse_find_node("allDesktops",
1054 node
->xmlChildrenNode
)))
1055 act
->data
.cycle
.all_desktops
= parse_bool(doc
, n
);
1056 } else if (act
->func
== action_directional_focus
) {
1057 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1058 act
->data
.interdiraction
.dialog
= parse_bool(doc
, n
);
1059 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
1060 act
->data
.interdiraction
.dock_windows
= parse_bool(doc
, n
);
1061 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1062 act
->data
.interdiraction
.desktop_windows
=
1064 } else if (act
->func
== action_resize
) {
1065 if ((n
= parse_find_node("edge", node
->xmlChildrenNode
))) {
1066 gchar
*s
= parse_string(doc
, n
);
1067 if (!g_ascii_strcasecmp(s
, "top"))
1068 act
->data
.moveresize
.corner
=
1069 prop_atoms
.net_wm_moveresize_size_top
;
1070 else if (!g_ascii_strcasecmp(s
, "bottom"))
1071 act
->data
.moveresize
.corner
=
1072 prop_atoms
.net_wm_moveresize_size_bottom
;
1073 else if (!g_ascii_strcasecmp(s
, "left"))
1074 act
->data
.moveresize
.corner
=
1075 prop_atoms
.net_wm_moveresize_size_left
;
1076 else if (!g_ascii_strcasecmp(s
, "right"))
1077 act
->data
.moveresize
.corner
=
1078 prop_atoms
.net_wm_moveresize_size_right
;
1079 else if (!g_ascii_strcasecmp(s
, "topleft"))
1080 act
->data
.moveresize
.corner
=
1081 prop_atoms
.net_wm_moveresize_size_topleft
;
1082 else if (!g_ascii_strcasecmp(s
, "topright"))
1083 act
->data
.moveresize
.corner
=
1084 prop_atoms
.net_wm_moveresize_size_topright
;
1085 else if (!g_ascii_strcasecmp(s
, "bottomleft"))
1086 act
->data
.moveresize
.corner
=
1087 prop_atoms
.net_wm_moveresize_size_bottomleft
;
1088 else if (!g_ascii_strcasecmp(s
, "bottomright"))
1089 act
->data
.moveresize
.corner
=
1090 prop_atoms
.net_wm_moveresize_size_bottomright
;
1093 } else if (act
->func
== action_raise
||
1094 act
->func
== action_lower
||
1095 act
->func
== action_raiselower
||
1096 act
->func
== action_shadelower
||
1097 act
->func
== action_unshaderaise
) {
1099 INTERACTIVE_LIMIT(act
, uact
);
1106 void action_run_list(GSList
*acts
, ObClient
*c
, ObFrameContext context
,
1107 guint state
, guint button
, gint x
, gint y
, Time time
,
1108 gboolean cancel
, gboolean done
)
1117 screen_pointer_pos(&x
, &y
);
1119 for (it
= acts
; it
; it
= g_slist_next(it
)) {
1122 if (!(a
->data
.any
.client_action
== OB_CLIENT_ACTION_ALWAYS
&& !c
)) {
1123 a
->data
.any
.c
= a
->data
.any
.client_action
? c
: NULL
;
1124 a
->data
.any
.context
= context
;
1128 a
->data
.any
.button
= button
;
1130 a
->data
.any
.time
= time
;
1132 if (a
->data
.any
.interactive
) {
1133 a
->data
.inter
.cancel
= cancel
;
1134 a
->data
.inter
.final
= done
;
1135 if (!(cancel
|| done
))
1136 if (!keyboard_interactive_grab(state
, a
->data
.any
.c
, a
))
1140 /* XXX UGLY HACK race with motion event starting a move and the
1141 button release gettnig processed first. answer: don't queue
1142 moveresize starts. UGLY HACK XXX
1144 XXX ALSO don't queue showmenu events, because on button press
1145 events we need to know if a mouse grab is going to take place,
1146 and set the button to 0, so that later motion events don't think
1147 that a drag is going on. since showmenu grabs the pointer..
1149 if (a
->data
.any
.interactive
|| a
->func
== action_move
||
1150 a
->func
== action_resize
|| a
->func
== action_showmenu
)
1152 /* interactive actions are not queued */
1155 (context
== OB_FRAME_CONTEXT_CLIENT
||
1156 (c
->type
== OB_CLIENT_TYPE_DESKTOP
&&
1157 context
== OB_FRAME_CONTEXT_DESKTOP
)) &&
1158 (a
->func
== action_focus
||
1159 a
->func
== action_activate
||
1160 a
->func
== action_showmenu
))
1162 /* XXX MORE UGLY HACK
1163 actions from clicks on client windows are NOT queued.
1164 this solves the mysterious click-and-drag-doesnt-work
1165 problem. it was because the window gets focused and stuff
1166 after the button event has already been passed through. i
1167 dont really know why it should care but it does and it makes
1170 however this very bogus ! !
1171 we want to send the button press to the window BEFORE
1172 we do the action because the action might move the windows
1173 (eg change desktops) and then the button press ends up on
1174 the completely wrong window !
1175 so, this is just for that bug, and it will only NOT queue it
1176 if it is a focusing action that can be used with the mouse
1179 also with the menus, there is a race going on. if the
1180 desktop wants to pop up a menu, and we do to, we send them
1181 the button before we pop up the menu, so they pop up their
1182 menu first. but not always. if we pop up our menu before
1183 sending them the button press, then the result is
1188 ob_main_loop_queue_action(ob_main_loop
, a
);
1193 void action_run_string(const gchar
*name
, struct _ObClient
*c
, Time time
)
1198 a
= action_from_string(name
, OB_USER_ACTION_NONE
);
1201 l
= g_slist_append(NULL
, a
);
1203 action_run(l
, c
, 0, time
);
1206 void action_debug(union ActionData
*data
)
1208 if (data
->debug
.string
)
1209 g_print("%s\n", data
->debug
.string
);
1212 void action_execute(union ActionData
*data
)
1215 gchar
*cmd
, **argv
= 0;
1216 if (data
->execute
.path
) {
1217 cmd
= g_filename_from_utf8(data
->execute
.path
, -1, NULL
, NULL
, NULL
);
1219 /* If there is an interactive action going on, then cancel it
1220 to release the keyboard, so that the run application
1221 can grab the keyboard if it wants to. */
1222 if (keyboard_interactively_grabbed())
1223 keyboard_interactive_cancel();
1225 if (!g_shell_parse_argv (cmd
, NULL
, &argv
, &e
)) {
1226 g_message(_("Failed to execute '%s': %s"),
1229 } else if (data
->execute
.startupnotify
) {
1232 program
= g_path_get_basename(argv
[0]);
1233 /* sets up the environment */
1234 sn_setup_spawn_environment(program
,
1236 data
->execute
.icon_name
,
1237 /* launch it on the current
1240 data
->execute
.any
.time
);
1241 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
|
1242 G_SPAWN_DO_NOT_REAP_CHILD
,
1243 NULL
, NULL
, NULL
, &e
)) {
1244 g_message(_("Failed to execute '%s': %s"),
1249 unsetenv("DESKTOP_STARTUP_ID");
1253 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
|
1254 G_SPAWN_DO_NOT_REAP_CHILD
,
1255 NULL
, NULL
, NULL
, &e
))
1257 g_message(_("Failed to execute '%s': %s"),
1265 g_message(_("Failed to convert the path '%s' from utf8"),
1266 data
->execute
.path
);
1271 void action_activate(union ActionData
*data
)
1273 if (data
->client
.any
.c
) {
1274 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1275 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1276 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1278 /* if using focus_delay, stop the timer now so that focus doesn't
1280 event_halt_focus_delay();
1282 client_activate(data
->activate
.any
.c
, data
->activate
.here
, TRUE
);
1285 /* focus action on something other than a client, make keybindings
1286 work for this openbox instance, but don't focus any specific client
1292 void action_focus(union ActionData
*data
)
1294 if (data
->client
.any
.c
) {
1295 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1296 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1297 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1299 /* if using focus_delay, stop the timer now so that focus doesn't
1301 event_halt_focus_delay();
1303 client_focus(data
->client
.any
.c
);
1306 /* focus action on something other than a client, make keybindings
1307 work for this openbox instance, but don't focus any specific client
1313 void action_unfocus (union ActionData
*data
)
1315 if (data
->client
.any
.c
== focus_client
)
1316 focus_fallback(FALSE
);
1319 void action_iconify(union ActionData
*data
)
1321 client_action_start(data
);
1322 client_iconify(data
->client
.any
.c
, TRUE
, TRUE
, FALSE
);
1323 client_action_end(data
);
1326 void action_focus_order_to_bottom(union ActionData
*data
)
1328 focus_order_to_bottom(data
->client
.any
.c
);
1331 void action_raiselower(union ActionData
*data
)
1333 ObClient
*c
= data
->client
.any
.c
;
1335 gboolean raise
= FALSE
;
1337 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
1338 if (WINDOW_IS_CLIENT(it
->data
)) {
1339 ObClient
*cit
= it
->data
;
1341 if (cit
== c
) break;
1342 if (client_normal(cit
) == client_normal(c
) &&
1343 cit
->layer
== c
->layer
&&
1344 cit
->frame
->visible
&&
1345 !client_search_transient(c
, cit
))
1347 if (RECT_INTERSECTS_RECT(cit
->frame
->area
, c
->frame
->area
)) {
1361 void action_raise(union ActionData
*data
)
1363 client_action_start(data
);
1364 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1365 client_action_end(data
);
1368 void action_unshaderaise(union ActionData
*data
)
1370 if (data
->client
.any
.c
->shaded
)
1371 action_unshade(data
);
1376 void action_shadelower(union ActionData
*data
)
1378 if (data
->client
.any
.c
->shaded
)
1384 void action_lower(union ActionData
*data
)
1386 client_action_start(data
);
1387 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1388 client_action_end(data
);
1391 void action_close(union ActionData
*data
)
1393 client_close(data
->client
.any
.c
);
1396 void action_kill(union ActionData
*data
)
1398 client_kill(data
->client
.any
.c
);
1401 void action_shade(union ActionData
*data
)
1403 client_action_start(data
);
1404 client_shade(data
->client
.any
.c
, TRUE
);
1405 client_action_end(data
);
1408 void action_unshade(union ActionData
*data
)
1410 client_action_start(data
);
1411 client_shade(data
->client
.any
.c
, FALSE
);
1412 client_action_end(data
);
1415 void action_toggle_shade(union ActionData
*data
)
1417 client_action_start(data
);
1418 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1419 client_action_end(data
);
1422 void action_toggle_omnipresent(union ActionData
*data
)
1424 client_set_desktop(data
->client
.any
.c
,
1425 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1426 screen_desktop
: DESKTOP_ALL
, FALSE
);
1429 void action_move_relative_horz(union ActionData
*data
)
1431 ObClient
*c
= data
->relative
.any
.c
;
1432 client_action_start(data
);
1433 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
);
1434 client_action_end(data
);
1437 void action_move_relative_vert(union ActionData
*data
)
1439 ObClient
*c
= data
->relative
.any
.c
;
1440 client_action_start(data
);
1441 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.deltax
);
1442 client_action_end(data
);
1445 void action_move_to_center(union ActionData
*data
)
1447 ObClient
*c
= data
->client
.any
.c
;
1449 area
= screen_area_monitor(c
->desktop
, 0);
1450 client_action_start(data
);
1451 client_move(c
, area
->width
/ 2 - c
->area
.width
/ 2,
1452 area
->height
/ 2 - c
->area
.height
/ 2);
1453 client_action_end(data
);
1456 void action_resize_relative_horz(union ActionData
*data
)
1458 ObClient
*c
= data
->relative
.any
.c
;
1459 client_action_start(data
);
1461 c
->area
.width
+ data
->relative
.deltax
* c
->size_inc
.width
,
1463 client_action_end(data
);
1466 void action_resize_relative_vert(union ActionData
*data
)
1468 ObClient
*c
= data
->relative
.any
.c
;
1470 client_action_start(data
);
1471 client_resize(c
, c
->area
.width
, c
->area
.height
+
1472 data
->relative
.deltax
* c
->size_inc
.height
);
1473 client_action_end(data
);
1477 void action_move_relative(union ActionData
*data
)
1479 ObClient
*c
= data
->relative
.any
.c
;
1480 client_action_start(data
);
1481 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
+
1482 data
->relative
.deltay
);
1483 client_action_end(data
);
1486 void action_resize_relative(union ActionData
*data
)
1488 ObClient
*c
= data
->relative
.any
.c
;
1489 gint x
, y
, ow
, w
, oh
, h
, lw
, lh
;
1491 client_action_start(data
);
1496 w
= ow
+ data
->relative
.deltax
* c
->size_inc
.width
1497 + data
->relative
.deltaxl
* c
->size_inc
.width
;
1498 oh
= c
->area
.height
;
1499 h
= oh
+ data
->relative
.deltay
* c
->size_inc
.height
1500 + data
->relative
.deltayu
* c
->size_inc
.height
;
1502 client_try_configure(c
, &x
, &y
, &w
, &h
, &lw
, &lh
, TRUE
);
1503 client_move_resize(c
, x
+ (ow
- w
), y
+ (oh
- h
), w
, h
);
1504 client_action_end(data
);
1507 void action_maximize_full(union ActionData
*data
)
1509 client_action_start(data
);
1510 client_maximize(data
->client
.any
.c
, TRUE
, 0);
1511 client_action_end(data
);
1514 void action_unmaximize_full(union ActionData
*data
)
1516 client_action_start(data
);
1517 client_maximize(data
->client
.any
.c
, FALSE
, 0);
1518 client_action_end(data
);
1521 void action_toggle_maximize_full(union ActionData
*data
)
1523 client_action_start(data
);
1524 client_maximize(data
->client
.any
.c
,
1525 !(data
->client
.any
.c
->max_horz
||
1526 data
->client
.any
.c
->max_vert
),
1528 client_action_end(data
);
1531 void action_maximize_horz(union ActionData
*data
)
1533 client_action_start(data
);
1534 client_maximize(data
->client
.any
.c
, TRUE
, 1);
1535 client_action_end(data
);
1538 void action_unmaximize_horz(union ActionData
*data
)
1540 client_action_start(data
);
1541 client_maximize(data
->client
.any
.c
, FALSE
, 1);
1542 client_action_end(data
);
1545 void action_toggle_maximize_horz(union ActionData
*data
)
1547 client_action_start(data
);
1548 client_maximize(data
->client
.any
.c
,
1549 !data
->client
.any
.c
->max_horz
, 1);
1550 client_action_end(data
);
1553 void action_maximize_vert(union ActionData
*data
)
1555 client_action_start(data
);
1556 client_maximize(data
->client
.any
.c
, TRUE
, 2);
1557 client_action_end(data
);
1560 void action_unmaximize_vert(union ActionData
*data
)
1562 client_action_start(data
);
1563 client_maximize(data
->client
.any
.c
, FALSE
, 2);
1564 client_action_end(data
);
1567 void action_toggle_maximize_vert(union ActionData
*data
)
1569 client_action_start(data
);
1570 client_maximize(data
->client
.any
.c
,
1571 !data
->client
.any
.c
->max_vert
, 2);
1572 client_action_end(data
);
1575 void action_toggle_fullscreen(union ActionData
*data
)
1577 client_action_start(data
);
1578 client_fullscreen(data
->client
.any
.c
, !(data
->client
.any
.c
->fullscreen
));
1579 client_action_end(data
);
1582 void action_send_to_desktop(union ActionData
*data
)
1584 ObClient
*c
= data
->sendto
.any
.c
;
1586 if (!client_normal(c
)) return;
1588 if (data
->sendto
.desk
< screen_num_desktops
||
1589 data
->sendto
.desk
== DESKTOP_ALL
) {
1590 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
);
1591 if (data
->sendto
.follow
)
1592 screen_set_desktop(data
->sendto
.desk
, TRUE
);
1596 void action_desktop(union ActionData
*data
)
1598 /* XXX add the interactive/dialog option back again once the dialog
1599 has been made to not use grabs */
1600 if (data
->desktop
.desk
< screen_num_desktops
||
1601 data
->desktop
.desk
== DESKTOP_ALL
)
1603 screen_set_desktop(data
->desktop
.desk
, TRUE
);
1604 if (data
->inter
.any
.interactive
)
1605 screen_desktop_popup(data
->desktop
.desk
, TRUE
);
1609 void action_desktop_dir(union ActionData
*data
)
1613 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1614 data
->desktopdir
.wrap
,
1615 data
->desktopdir
.linear
,
1616 data
->desktopdir
.inter
.any
.interactive
,
1617 data
->desktopdir
.inter
.final
,
1618 data
->desktopdir
.inter
.cancel
);
1619 /* only move the desktop when the action is complete. if we switch
1620 desktops during the interactive action, focus will move but with
1621 NotifyWhileGrabbed and applications don't like that. */
1622 if (!data
->sendtodir
.inter
.any
.interactive
||
1623 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1625 if (d
!= screen_desktop
) screen_set_desktop(d
, TRUE
);
1629 void action_send_to_desktop_dir(union ActionData
*data
)
1631 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1634 if (!client_normal(c
)) return;
1636 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1637 data
->sendtodir
.linear
,
1638 data
->sendtodir
.inter
.any
.interactive
,
1639 data
->sendtodir
.inter
.final
,
1640 data
->sendtodir
.inter
.cancel
);
1641 /* only move the desktop when the action is complete. if we switch
1642 desktops during the interactive action, focus will move but with
1643 NotifyWhileGrabbed and applications don't like that. */
1644 if (!data
->sendtodir
.inter
.any
.interactive
||
1645 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1647 client_set_desktop(c
, d
, data
->sendtodir
.follow
);
1648 if (data
->sendtodir
.follow
&& d
!= screen_desktop
)
1649 screen_set_desktop(d
, TRUE
);
1653 void action_desktop_last(union ActionData
*data
)
1655 screen_set_desktop(screen_last_desktop
, TRUE
);
1658 void action_toggle_decorations(union ActionData
*data
)
1660 ObClient
*c
= data
->client
.any
.c
;
1662 client_action_start(data
);
1663 client_set_undecorated(c
, !c
->undecorated
);
1664 client_action_end(data
);
1667 static guint32
pick_corner(gint x
, gint y
, gint cx
, gint cy
, gint cw
, gint ch
,
1670 /* let's make x and y client relative instead of screen relative */
1672 y
= ch
- (y
- cy
); /* y is inverted, 0 is at the bottom of the window */
1675 #define A -4*X + 7*ch/3
1676 #define B 4*X -15*ch/9
1677 #define C -X/4 + 2*ch/3
1678 #define D X/4 + 5*ch/12
1679 #define E X/4 + ch/3
1680 #define F -X/4 + 7*ch/12
1681 #define G 4*X - 4*ch/3
1682 #define H -4*X + 8*ch/3
1683 #define a (y > 5*ch/9)
1684 #define b (x < 4*cw/9)
1685 #define c (x > 5*cw/9)
1686 #define d (y < 4*ch/9)
1689 Each of these defines (except X which is just there for fun), represents
1690 the equation of a line. The lines they represent are shown in the diagram
1691 below. Checking y against these lines, we are able to choose a region
1692 of the window as shown.
1694 +---------------------A-------|-------|-------B---------------------+
1701 | northwest | A north B | northeast |
1704 C---------------------+----A--+-------+--B----+---------------------D
1705 |CCCCCCC | A B | DDDDDDD|
1706 | CCCCCCCC | A | | B | DDDDDDDD |
1707 | CCCCCCC A B DDDDDDD |
1708 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
1710 | west | b move c | east | ad
1712 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
1713 | EEEEEEE G H FFFFFFF |
1714 | EEEEEEEE | G | | H | FFFFFFFF |
1715 |EEEEEEE | G H | FFFFFFF|
1716 E---------------------+----G--+-------+--H----+---------------------F
1719 | southwest | G south H | southeast |
1726 +---------------------G-------|-------|-------H---------------------+
1730 /* for shaded windows, you can only resize west/east and move */
1732 return prop_atoms
.net_wm_moveresize_size_left
;
1734 return prop_atoms
.net_wm_moveresize_size_right
;
1735 return prop_atoms
.net_wm_moveresize_move
;
1738 if (y
< A
&& y
>= C
)
1739 return prop_atoms
.net_wm_moveresize_size_topleft
;
1740 else if (y
>= A
&& y
>= B
&& a
)
1741 return prop_atoms
.net_wm_moveresize_size_top
;
1742 else if (y
< B
&& y
>= D
)
1743 return prop_atoms
.net_wm_moveresize_size_topright
;
1744 else if (y
< C
&& y
>= E
&& b
)
1745 return prop_atoms
.net_wm_moveresize_size_left
;
1746 else if (y
< D
&& y
>= F
&& c
)
1747 return prop_atoms
.net_wm_moveresize_size_right
;
1748 else if (y
< E
&& y
>= G
)
1749 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1750 else if (y
< G
&& y
< H
&& d
)
1751 return prop_atoms
.net_wm_moveresize_size_bottom
;
1752 else if (y
>= H
&& y
< F
)
1753 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1755 return prop_atoms
.net_wm_moveresize_move
;
1772 void action_move(union ActionData
*data
)
1774 ObClient
*c
= data
->moveresize
.any
.c
;
1777 if (data
->moveresize
.keyboard
)
1778 corner
= prop_atoms
.net_wm_moveresize_move_keyboard
;
1780 corner
= prop_atoms
.net_wm_moveresize_move
;
1782 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1785 void action_resize(union ActionData
*data
)
1787 ObClient
*c
= data
->moveresize
.any
.c
;
1790 if (data
->moveresize
.keyboard
)
1791 corner
= prop_atoms
.net_wm_moveresize_size_keyboard
;
1792 else if (data
->moveresize
.corner
)
1793 corner
= data
->moveresize
.corner
; /* it was specified in the binding */
1795 corner
= pick_corner(data
->any
.x
, data
->any
.y
,
1796 c
->frame
->area
.x
, c
->frame
->area
.y
,
1797 /* use the client size because the frame
1798 can be differently sized (shaded
1799 windows) and we want this based on the
1801 c
->area
.width
+ c
->frame
->size
.left
+
1802 c
->frame
->size
.right
,
1803 c
->area
.height
+ c
->frame
->size
.top
+
1804 c
->frame
->size
.bottom
, c
->shaded
);
1806 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1809 void action_reconfigure(union ActionData
*data
)
1814 void action_restart(union ActionData
*data
)
1816 ob_restart_other(data
->execute
.path
);
1819 void action_exit(union ActionData
*data
)
1824 void action_showmenu(union ActionData
*data
)
1826 if (data
->showmenu
.name
) {
1827 menu_show(data
->showmenu
.name
, data
->any
.x
, data
->any
.y
,
1828 data
->any
.button
, data
->showmenu
.any
.c
);
1832 void action_cycle_windows(union ActionData
*data
)
1834 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1836 event_halt_focus_delay();
1838 focus_cycle(data
->cycle
.forward
,
1839 data
->cycle
.all_desktops
,
1840 data
->cycle
.dock_windows
,
1841 data
->cycle
.desktop_windows
,
1842 data
->cycle
.linear
, data
->any
.interactive
,
1844 data
->cycle
.inter
.final
, data
->cycle
.inter
.cancel
);
1847 void action_directional_focus(union ActionData
*data
)
1849 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1851 event_halt_focus_delay();
1853 focus_directional_cycle(data
->interdiraction
.direction
,
1854 data
->interdiraction
.dock_windows
,
1855 data
->interdiraction
.desktop_windows
,
1856 data
->any
.interactive
,
1857 data
->interdiraction
.dialog
,
1858 data
->interdiraction
.inter
.final
,
1859 data
->interdiraction
.inter
.cancel
);
1862 void action_movetoedge(union ActionData
*data
)
1865 ObClient
*c
= data
->diraction
.any
.c
;
1867 x
= c
->frame
->area
.x
;
1868 y
= c
->frame
->area
.y
;
1870 switch(data
->diraction
.direction
) {
1871 case OB_DIRECTION_NORTH
:
1872 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
,
1873 data
->diraction
.hang
)
1874 - (data
->diraction
.hang
? c
->frame
->area
.height
: 0);
1876 case OB_DIRECTION_WEST
:
1877 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
,
1878 data
->diraction
.hang
)
1879 - (data
->diraction
.hang
? c
->frame
->area
.width
: 0);
1881 case OB_DIRECTION_SOUTH
:
1882 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
,
1883 data
->diraction
.hang
)
1884 - (data
->diraction
.hang
? 0 : c
->frame
->area
.height
);
1886 case OB_DIRECTION_EAST
:
1887 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
,
1888 data
->diraction
.hang
)
1889 - (data
->diraction
.hang
? 0 : c
->frame
->area
.width
);
1892 g_assert_not_reached();
1894 frame_frame_gravity(c
->frame
, &x
, &y
, c
->area
.width
, c
->area
.height
);
1895 client_action_start(data
);
1896 client_move(c
, x
, y
);
1897 client_action_end(data
);
1900 void action_growtoedge(union ActionData
*data
)
1902 gint x
, y
, width
, height
, dest
;
1903 ObClient
*c
= data
->diraction
.any
.c
;
1906 a
= screen_area(c
->desktop
);
1907 x
= c
->frame
->area
.x
;
1908 y
= c
->frame
->area
.y
;
1909 /* get the unshaded frame's dimensions..if it is shaded */
1910 width
= c
->area
.width
+ c
->frame
->size
.left
+ c
->frame
->size
.right
;
1911 height
= c
->area
.height
+ c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1913 switch(data
->diraction
.direction
) {
1914 case OB_DIRECTION_NORTH
:
1915 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1917 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
, FALSE
);
1919 height
= height
/ 2;
1921 height
= c
->frame
->area
.y
+ height
- dest
;
1925 case OB_DIRECTION_WEST
:
1926 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
, FALSE
);
1930 width
= c
->frame
->area
.x
+ width
- dest
;
1934 case OB_DIRECTION_SOUTH
:
1935 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1937 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
, FALSE
);
1938 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1939 height
= c
->frame
->area
.height
/ 2;
1940 y
= a
->y
+ a
->height
- height
;
1942 height
= dest
- c
->frame
->area
.y
;
1943 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1944 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1946 case OB_DIRECTION_EAST
:
1947 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
, FALSE
);
1948 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1949 width
= c
->frame
->area
.width
/ 2;
1950 x
= a
->x
+ a
->width
- width
;
1952 width
= dest
- c
->frame
->area
.x
;
1953 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1954 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1957 g_assert_not_reached();
1959 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1960 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1961 frame_frame_gravity(c
->frame
, &x
, &y
, width
, height
);
1962 client_action_start(data
);
1963 client_move_resize(c
, x
, y
, width
, height
);
1964 client_action_end(data
);
1967 void action_send_to_layer(union ActionData
*data
)
1969 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1972 void action_toggle_layer(union ActionData
*data
)
1974 ObClient
*c
= data
->layer
.any
.c
;
1976 client_action_start(data
);
1977 if (data
->layer
.layer
< 0)
1978 client_set_layer(c
, c
->below
? 0 : -1);
1979 else if (data
->layer
.layer
> 0)
1980 client_set_layer(c
, c
->above
? 0 : 1);
1981 client_action_end(data
);
1984 void action_toggle_dockautohide(union ActionData
*data
)
1986 config_dock_hide
= !config_dock_hide
;
1990 void action_toggle_show_desktop(union ActionData
*data
)
1992 screen_show_desktop(!screen_showing_desktop
, NULL
);
1995 void action_show_desktop(union ActionData
*data
)
1997 screen_show_desktop(TRUE
, NULL
);
2000 void action_unshow_desktop(union ActionData
*data
)
2002 screen_show_desktop(FALSE
, NULL
);
2005 void action_break_chroot(union ActionData
*data
)
2007 /* break out of one chroot */
2008 keyboard_reset_chains(1);