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()) && c
!= data
->any
.c
)
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 */
1154 } else if (a
->func
== action_focus
||
1155 a
->func
== action_activate
||
1156 a
->func
== action_showmenu
)
1158 /* XXX MORE UGLY HACK
1159 actions from clicks on client windows are NOT queued.
1160 this solves the mysterious click-and-drag-doesnt-work
1161 problem. it was because the window gets focused and stuff
1162 after the button event has already been passed through. i
1163 dont really know why it should care but it does and it makes
1166 however this very bogus ! !
1167 we want to send the button press to the window BEFORE
1168 we do the action because the action might move the windows
1169 (eg change desktops) and then the button press ends up on
1170 the completely wrong window !
1171 so, this is just for that bug, and it will only NOT queue it
1172 if it is a focusing action that can be used with the mouse
1175 also with the menus, there is a race going on. if the
1176 desktop wants to pop up a menu, and we do too, we send them
1177 the button before we pop up the menu, so they pop up their
1178 menu first. but not always. if we pop up our menu before
1179 sending them the button press, then the result is
1182 XXX further more. focus actions are not queued at all,
1183 because if you bind focus->showmenu, the menu will get
1184 hidden to do the focusing
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 a keyboard grab going on then we need to cancel
1220 it so the application can grab things */
1221 event_cancel_all_key_grabs();
1223 if (!g_shell_parse_argv (cmd
, NULL
, &argv
, &e
)) {
1224 g_message(_("Failed to execute '%s': %s"),
1227 } else if (data
->execute
.startupnotify
) {
1230 program
= g_path_get_basename(argv
[0]);
1231 /* sets up the environment */
1232 sn_setup_spawn_environment(program
,
1234 data
->execute
.icon_name
,
1235 /* launch it on the current
1238 data
->execute
.any
.time
);
1239 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
|
1240 G_SPAWN_DO_NOT_REAP_CHILD
,
1241 NULL
, NULL
, NULL
, &e
)) {
1242 g_message(_("Failed to execute '%s': %s"),
1247 unsetenv("DESKTOP_STARTUP_ID");
1251 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
|
1252 G_SPAWN_DO_NOT_REAP_CHILD
,
1253 NULL
, NULL
, NULL
, &e
))
1255 g_message(_("Failed to execute '%s': %s"),
1263 g_message(_("Failed to convert the path '%s' from utf8"),
1264 data
->execute
.path
);
1269 void action_activate(union ActionData
*data
)
1271 if (data
->client
.any
.c
) {
1272 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1273 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1274 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1276 /* if using focus_delay, stop the timer now so that focus doesn't
1278 event_halt_focus_delay();
1280 client_activate(data
->activate
.any
.c
, data
->activate
.here
, TRUE
);
1283 /* focus action on something other than a client, make keybindings
1284 work for this openbox instance, but don't focus any specific client
1290 void action_focus(union ActionData
*data
)
1292 if (data
->client
.any
.c
) {
1293 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1294 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1295 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1297 /* if using focus_delay, stop the timer now so that focus doesn't
1299 event_halt_focus_delay();
1301 client_focus(data
->client
.any
.c
);
1304 /* focus action on something other than a client, make keybindings
1305 work for this openbox instance, but don't focus any specific client
1311 void action_unfocus (union ActionData
*data
)
1313 if (data
->client
.any
.c
== focus_client
)
1314 focus_fallback(FALSE
, FALSE
);
1317 void action_iconify(union ActionData
*data
)
1319 client_action_start(data
);
1320 client_iconify(data
->client
.any
.c
, TRUE
, TRUE
, FALSE
);
1321 client_action_end(data
);
1324 void action_focus_order_to_bottom(union ActionData
*data
)
1326 focus_order_to_bottom(data
->client
.any
.c
);
1329 void action_raiselower(union ActionData
*data
)
1331 ObClient
*c
= data
->client
.any
.c
;
1333 gboolean raise
= FALSE
;
1335 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
1336 if (WINDOW_IS_CLIENT(it
->data
)) {
1337 ObClient
*cit
= it
->data
;
1339 if (cit
== c
) break;
1340 if (client_normal(cit
) == client_normal(c
) &&
1341 cit
->layer
== c
->layer
&&
1342 cit
->frame
->visible
&&
1343 !client_search_transient(c
, cit
))
1345 if (RECT_INTERSECTS_RECT(cit
->frame
->area
, c
->frame
->area
)) {
1359 void action_raise(union ActionData
*data
)
1361 client_action_start(data
);
1362 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1363 client_action_end(data
);
1366 void action_unshaderaise(union ActionData
*data
)
1368 if (data
->client
.any
.c
->shaded
)
1369 action_unshade(data
);
1374 void action_shadelower(union ActionData
*data
)
1376 if (data
->client
.any
.c
->shaded
)
1382 void action_lower(union ActionData
*data
)
1384 client_action_start(data
);
1385 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1386 client_action_end(data
);
1389 void action_close(union ActionData
*data
)
1391 client_close(data
->client
.any
.c
);
1394 void action_kill(union ActionData
*data
)
1396 client_kill(data
->client
.any
.c
);
1399 void action_shade(union ActionData
*data
)
1401 client_action_start(data
);
1402 client_shade(data
->client
.any
.c
, TRUE
);
1403 client_action_end(data
);
1406 void action_unshade(union ActionData
*data
)
1408 client_action_start(data
);
1409 client_shade(data
->client
.any
.c
, FALSE
);
1410 client_action_end(data
);
1413 void action_toggle_shade(union ActionData
*data
)
1415 client_action_start(data
);
1416 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1417 client_action_end(data
);
1420 void action_toggle_omnipresent(union ActionData
*data
)
1422 client_set_desktop(data
->client
.any
.c
,
1423 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1424 screen_desktop
: DESKTOP_ALL
, FALSE
);
1427 void action_move_relative_horz(union ActionData
*data
)
1429 ObClient
*c
= data
->relative
.any
.c
;
1430 client_action_start(data
);
1431 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
);
1432 client_action_end(data
);
1435 void action_move_relative_vert(union ActionData
*data
)
1437 ObClient
*c
= data
->relative
.any
.c
;
1438 client_action_start(data
);
1439 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.deltax
);
1440 client_action_end(data
);
1443 void action_move_to_center(union ActionData
*data
)
1445 ObClient
*c
= data
->client
.any
.c
;
1447 area
= screen_area_monitor(c
->desktop
, 0);
1448 client_action_start(data
);
1449 client_move(c
, area
->width
/ 2 - c
->area
.width
/ 2,
1450 area
->height
/ 2 - c
->area
.height
/ 2);
1451 client_action_end(data
);
1454 void action_resize_relative_horz(union ActionData
*data
)
1456 ObClient
*c
= data
->relative
.any
.c
;
1457 client_action_start(data
);
1459 c
->area
.width
+ data
->relative
.deltax
* c
->size_inc
.width
,
1461 client_action_end(data
);
1464 void action_resize_relative_vert(union ActionData
*data
)
1466 ObClient
*c
= data
->relative
.any
.c
;
1468 client_action_start(data
);
1469 client_resize(c
, c
->area
.width
, c
->area
.height
+
1470 data
->relative
.deltax
* c
->size_inc
.height
);
1471 client_action_end(data
);
1475 void action_move_relative(union ActionData
*data
)
1477 ObClient
*c
= data
->relative
.any
.c
;
1478 client_action_start(data
);
1479 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
+
1480 data
->relative
.deltay
);
1481 client_action_end(data
);
1484 void action_resize_relative(union ActionData
*data
)
1486 ObClient
*c
= data
->relative
.any
.c
;
1487 gint x
, y
, ow
, w
, oh
, h
, lw
, lh
;
1489 client_action_start(data
);
1494 w
= ow
+ data
->relative
.deltax
* c
->size_inc
.width
1495 + data
->relative
.deltaxl
* c
->size_inc
.width
;
1496 oh
= c
->area
.height
;
1497 h
= oh
+ data
->relative
.deltay
* c
->size_inc
.height
1498 + data
->relative
.deltayu
* c
->size_inc
.height
;
1500 client_try_configure(c
, &x
, &y
, &w
, &h
, &lw
, &lh
, TRUE
);
1501 client_move_resize(c
, x
+ (ow
- w
), y
+ (oh
- h
), w
, h
);
1502 client_action_end(data
);
1505 void action_maximize_full(union ActionData
*data
)
1507 client_action_start(data
);
1508 client_maximize(data
->client
.any
.c
, TRUE
, 0);
1509 client_action_end(data
);
1512 void action_unmaximize_full(union ActionData
*data
)
1514 client_action_start(data
);
1515 client_maximize(data
->client
.any
.c
, FALSE
, 0);
1516 client_action_end(data
);
1519 void action_toggle_maximize_full(union ActionData
*data
)
1521 client_action_start(data
);
1522 client_maximize(data
->client
.any
.c
,
1523 !(data
->client
.any
.c
->max_horz
||
1524 data
->client
.any
.c
->max_vert
),
1526 client_action_end(data
);
1529 void action_maximize_horz(union ActionData
*data
)
1531 client_action_start(data
);
1532 client_maximize(data
->client
.any
.c
, TRUE
, 1);
1533 client_action_end(data
);
1536 void action_unmaximize_horz(union ActionData
*data
)
1538 client_action_start(data
);
1539 client_maximize(data
->client
.any
.c
, FALSE
, 1);
1540 client_action_end(data
);
1543 void action_toggle_maximize_horz(union ActionData
*data
)
1545 client_action_start(data
);
1546 client_maximize(data
->client
.any
.c
,
1547 !data
->client
.any
.c
->max_horz
, 1);
1548 client_action_end(data
);
1551 void action_maximize_vert(union ActionData
*data
)
1553 client_action_start(data
);
1554 client_maximize(data
->client
.any
.c
, TRUE
, 2);
1555 client_action_end(data
);
1558 void action_unmaximize_vert(union ActionData
*data
)
1560 client_action_start(data
);
1561 client_maximize(data
->client
.any
.c
, FALSE
, 2);
1562 client_action_end(data
);
1565 void action_toggle_maximize_vert(union ActionData
*data
)
1567 client_action_start(data
);
1568 client_maximize(data
->client
.any
.c
,
1569 !data
->client
.any
.c
->max_vert
, 2);
1570 client_action_end(data
);
1573 void action_toggle_fullscreen(union ActionData
*data
)
1575 client_action_start(data
);
1576 client_fullscreen(data
->client
.any
.c
, !(data
->client
.any
.c
->fullscreen
));
1577 client_action_end(data
);
1580 void action_send_to_desktop(union ActionData
*data
)
1582 ObClient
*c
= data
->sendto
.any
.c
;
1584 if (!client_normal(c
)) return;
1586 if (data
->sendto
.desk
< screen_num_desktops
||
1587 data
->sendto
.desk
== DESKTOP_ALL
) {
1588 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
);
1589 if (data
->sendto
.follow
&& data
->sendto
.desk
!= screen_desktop
)
1590 screen_set_desktop(data
->sendto
.desk
, TRUE
);
1594 void action_desktop(union ActionData
*data
)
1596 /* XXX add the interactive/dialog option back again once the dialog
1597 has been made to not use grabs */
1598 if (data
->desktop
.desk
< screen_num_desktops
||
1599 data
->desktop
.desk
== DESKTOP_ALL
)
1601 screen_set_desktop(data
->desktop
.desk
, TRUE
);
1602 if (data
->inter
.any
.interactive
)
1603 screen_desktop_popup(data
->desktop
.desk
, TRUE
);
1607 void action_desktop_dir(union ActionData
*data
)
1611 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1612 data
->desktopdir
.wrap
,
1613 data
->desktopdir
.linear
,
1614 data
->desktopdir
.inter
.any
.interactive
,
1615 data
->desktopdir
.inter
.final
,
1616 data
->desktopdir
.inter
.cancel
);
1617 /* only move the desktop when the action is complete. if we switch
1618 desktops during the interactive action, focus will move but with
1619 NotifyWhileGrabbed and applications don't like that. */
1620 if (!data
->sendtodir
.inter
.any
.interactive
||
1621 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1623 if (d
!= screen_desktop
)
1624 screen_set_desktop(d
, TRUE
);
1628 void action_send_to_desktop_dir(union ActionData
*data
)
1630 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1633 if (!client_normal(c
)) return;
1635 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1636 data
->sendtodir
.linear
,
1637 data
->sendtodir
.inter
.any
.interactive
,
1638 data
->sendtodir
.inter
.final
,
1639 data
->sendtodir
.inter
.cancel
);
1640 /* only move the desktop when the action is complete. if we switch
1641 desktops during the interactive action, focus will move but with
1642 NotifyWhileGrabbed and applications don't like that. */
1643 if (!data
->sendtodir
.inter
.any
.interactive
||
1644 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1646 client_set_desktop(c
, d
, data
->sendtodir
.follow
);
1647 if (data
->sendtodir
.follow
&& d
!= screen_desktop
)
1648 screen_set_desktop(d
, TRUE
);
1652 void action_desktop_last(union ActionData
*data
)
1654 screen_set_desktop(screen_last_desktop
, TRUE
);
1657 void action_toggle_decorations(union ActionData
*data
)
1659 ObClient
*c
= data
->client
.any
.c
;
1661 client_action_start(data
);
1662 client_set_undecorated(c
, !c
->undecorated
);
1663 client_action_end(data
);
1666 static guint32
pick_corner(gint x
, gint y
, gint cx
, gint cy
, gint cw
, gint ch
,
1669 /* let's make x and y client relative instead of screen relative */
1671 y
= ch
- (y
- cy
); /* y is inverted, 0 is at the bottom of the window */
1674 #define A -4*X + 7*ch/3
1675 #define B 4*X -15*ch/9
1676 #define C -X/4 + 2*ch/3
1677 #define D X/4 + 5*ch/12
1678 #define E X/4 + ch/3
1679 #define F -X/4 + 7*ch/12
1680 #define G 4*X - 4*ch/3
1681 #define H -4*X + 8*ch/3
1682 #define a (y > 5*ch/9)
1683 #define b (x < 4*cw/9)
1684 #define c (x > 5*cw/9)
1685 #define d (y < 4*ch/9)
1688 Each of these defines (except X which is just there for fun), represents
1689 the equation of a line. The lines they represent are shown in the diagram
1690 below. Checking y against these lines, we are able to choose a region
1691 of the window as shown.
1693 +---------------------A-------|-------|-------B---------------------+
1700 | northwest | A north B | northeast |
1703 C---------------------+----A--+-------+--B----+---------------------D
1704 |CCCCCCC | A B | DDDDDDD|
1705 | CCCCCCCC | A | | B | DDDDDDDD |
1706 | CCCCCCC A B DDDDDDD |
1707 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
1709 | west | b move c | east | ad
1711 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
1712 | EEEEEEE G H FFFFFFF |
1713 | EEEEEEEE | G | | H | FFFFFFFF |
1714 |EEEEEEE | G H | FFFFFFF|
1715 E---------------------+----G--+-------+--H----+---------------------F
1718 | southwest | G south H | southeast |
1725 +---------------------G-------|-------|-------H---------------------+
1729 /* for shaded windows, you can only resize west/east and move */
1731 return prop_atoms
.net_wm_moveresize_size_left
;
1733 return prop_atoms
.net_wm_moveresize_size_right
;
1734 return prop_atoms
.net_wm_moveresize_move
;
1737 if (y
< A
&& y
>= C
)
1738 return prop_atoms
.net_wm_moveresize_size_topleft
;
1739 else if (y
>= A
&& y
>= B
&& a
)
1740 return prop_atoms
.net_wm_moveresize_size_top
;
1741 else if (y
< B
&& y
>= D
)
1742 return prop_atoms
.net_wm_moveresize_size_topright
;
1743 else if (y
< C
&& y
>= E
&& b
)
1744 return prop_atoms
.net_wm_moveresize_size_left
;
1745 else if (y
< D
&& y
>= F
&& c
)
1746 return prop_atoms
.net_wm_moveresize_size_right
;
1747 else if (y
< E
&& y
>= G
)
1748 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1749 else if (y
< G
&& y
< H
&& d
)
1750 return prop_atoms
.net_wm_moveresize_size_bottom
;
1751 else if (y
>= H
&& y
< F
)
1752 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1754 return prop_atoms
.net_wm_moveresize_move
;
1771 void action_move(union ActionData
*data
)
1773 ObClient
*c
= data
->moveresize
.any
.c
;
1776 if (data
->moveresize
.keyboard
)
1777 corner
= prop_atoms
.net_wm_moveresize_move_keyboard
;
1779 corner
= prop_atoms
.net_wm_moveresize_move
;
1781 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1784 void action_resize(union ActionData
*data
)
1786 ObClient
*c
= data
->moveresize
.any
.c
;
1789 if (data
->moveresize
.keyboard
)
1790 corner
= prop_atoms
.net_wm_moveresize_size_keyboard
;
1791 else if (data
->moveresize
.corner
)
1792 corner
= data
->moveresize
.corner
; /* it was specified in the binding */
1794 corner
= pick_corner(data
->any
.x
, data
->any
.y
,
1795 c
->frame
->area
.x
, c
->frame
->area
.y
,
1796 /* use the client size because the frame
1797 can be differently sized (shaded
1798 windows) and we want this based on the
1800 c
->area
.width
+ c
->frame
->size
.left
+
1801 c
->frame
->size
.right
,
1802 c
->area
.height
+ c
->frame
->size
.top
+
1803 c
->frame
->size
.bottom
, c
->shaded
);
1805 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1808 void action_reconfigure(union ActionData
*data
)
1813 void action_restart(union ActionData
*data
)
1815 ob_restart_other(data
->execute
.path
);
1818 void action_exit(union ActionData
*data
)
1823 void action_showmenu(union ActionData
*data
)
1825 if (data
->showmenu
.name
) {
1826 menu_show(data
->showmenu
.name
, data
->any
.x
, data
->any
.y
,
1827 data
->any
.button
, data
->showmenu
.any
.c
);
1831 void action_cycle_windows(union ActionData
*data
)
1833 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1835 event_halt_focus_delay();
1837 focus_cycle(data
->cycle
.forward
,
1838 data
->cycle
.all_desktops
,
1839 data
->cycle
.dock_windows
,
1840 data
->cycle
.desktop_windows
,
1841 data
->cycle
.linear
, data
->any
.interactive
,
1843 data
->cycle
.inter
.final
, data
->cycle
.inter
.cancel
);
1846 void action_directional_focus(union ActionData
*data
)
1848 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1850 event_halt_focus_delay();
1852 focus_directional_cycle(data
->interdiraction
.direction
,
1853 data
->interdiraction
.dock_windows
,
1854 data
->interdiraction
.desktop_windows
,
1855 data
->any
.interactive
,
1856 data
->interdiraction
.dialog
,
1857 data
->interdiraction
.inter
.final
,
1858 data
->interdiraction
.inter
.cancel
);
1861 void action_movetoedge(union ActionData
*data
)
1864 ObClient
*c
= data
->diraction
.any
.c
;
1866 x
= c
->frame
->area
.x
;
1867 y
= c
->frame
->area
.y
;
1869 switch(data
->diraction
.direction
) {
1870 case OB_DIRECTION_NORTH
:
1871 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
,
1872 data
->diraction
.hang
)
1873 - (data
->diraction
.hang
? c
->frame
->area
.height
: 0);
1875 case OB_DIRECTION_WEST
:
1876 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
,
1877 data
->diraction
.hang
)
1878 - (data
->diraction
.hang
? c
->frame
->area
.width
: 0);
1880 case OB_DIRECTION_SOUTH
:
1881 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
,
1882 data
->diraction
.hang
)
1883 - (data
->diraction
.hang
? 0 : c
->frame
->area
.height
);
1885 case OB_DIRECTION_EAST
:
1886 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
,
1887 data
->diraction
.hang
)
1888 - (data
->diraction
.hang
? 0 : c
->frame
->area
.width
);
1891 g_assert_not_reached();
1893 frame_frame_gravity(c
->frame
, &x
, &y
, c
->area
.width
, c
->area
.height
);
1894 client_action_start(data
);
1895 client_move(c
, x
, y
);
1896 client_action_end(data
);
1899 void action_growtoedge(union ActionData
*data
)
1901 gint x
, y
, width
, height
, dest
;
1902 ObClient
*c
= data
->diraction
.any
.c
;
1905 a
= screen_area(c
->desktop
);
1906 x
= c
->frame
->area
.x
;
1907 y
= c
->frame
->area
.y
;
1908 /* get the unshaded frame's dimensions..if it is shaded */
1909 width
= c
->area
.width
+ c
->frame
->size
.left
+ c
->frame
->size
.right
;
1910 height
= c
->area
.height
+ c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1912 switch(data
->diraction
.direction
) {
1913 case OB_DIRECTION_NORTH
:
1914 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1916 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
, FALSE
);
1918 height
= height
/ 2;
1920 height
= c
->frame
->area
.y
+ height
- dest
;
1924 case OB_DIRECTION_WEST
:
1925 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
, FALSE
);
1929 width
= c
->frame
->area
.x
+ width
- dest
;
1933 case OB_DIRECTION_SOUTH
:
1934 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1936 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
, FALSE
);
1937 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1938 height
= c
->frame
->area
.height
/ 2;
1939 y
= a
->y
+ a
->height
- height
;
1941 height
= dest
- c
->frame
->area
.y
;
1942 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1943 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1945 case OB_DIRECTION_EAST
:
1946 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
, FALSE
);
1947 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1948 width
= c
->frame
->area
.width
/ 2;
1949 x
= a
->x
+ a
->width
- width
;
1951 width
= dest
- c
->frame
->area
.x
;
1952 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1953 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1956 g_assert_not_reached();
1958 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1959 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1960 frame_frame_gravity(c
->frame
, &x
, &y
, width
, height
);
1961 client_action_start(data
);
1962 client_move_resize(c
, x
, y
, width
, height
);
1963 client_action_end(data
);
1966 void action_send_to_layer(union ActionData
*data
)
1968 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1971 void action_toggle_layer(union ActionData
*data
)
1973 ObClient
*c
= data
->layer
.any
.c
;
1975 client_action_start(data
);
1976 if (data
->layer
.layer
< 0)
1977 client_set_layer(c
, c
->below
? 0 : -1);
1978 else if (data
->layer
.layer
> 0)
1979 client_set_layer(c
, c
->above
? 0 : 1);
1980 client_action_end(data
);
1983 void action_toggle_dockautohide(union ActionData
*data
)
1985 config_dock_hide
= !config_dock_hide
;
1989 void action_toggle_show_desktop(union ActionData
*data
)
1991 screen_show_desktop(!screen_showing_desktop
, NULL
);
1994 void action_show_desktop(union ActionData
*data
)
1996 screen_show_desktop(TRUE
, NULL
);
1999 void action_unshow_desktop(union ActionData
*data
)
2001 screen_show_desktop(FALSE
, NULL
);
2004 void action_break_chroot(union ActionData
*data
)
2006 /* break out of one chroot */
2007 keyboard_reset_chains(1);