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 gulong ignore_start
= 0;
44 static void client_action_start(union ActionData
*data
)
46 ignore_start
= event_start_ignore_all_enters();
49 static void client_action_end(union ActionData
*data
, gboolean allow_enters
)
51 if (config_focus_follow
)
52 if (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
) {
53 if (!data
->any
.button
&& data
->any
.c
&& !allow_enters
) {
54 event_end_ignore_all_enters(ignore_start
);
58 /* usually this is sorta redundant, but with a press action
59 that moves windows our from under the cursor, the enter
60 event will come as a GrabNotify which is ignored, so this
61 makes a fake enter event
63 if ((c
= client_under_pointer()) && c
!= data
->any
.c
) {
64 ob_debug_type(OB_DEBUG_FOCUS
,
65 "Generating fake enter because we did a "
66 "mouse-event action");
67 event_enter_client(c
);
76 void (*func
)(union ActionData
*);
77 void (*setup
)(ObAction
**, ObUserAction uact
);
80 static ObAction
*action_new(void (*func
)(union ActionData
*data
))
82 ObAction
*a
= g_new0(ObAction
, 1);
89 void action_ref(ObAction
*a
)
94 void action_unref(ObAction
*a
)
96 if (a
== NULL
) return;
98 if (--a
->ref
> 0) return;
100 /* deal with pointers */
101 if (a
->func
== action_execute
|| a
->func
== action_restart
)
102 g_free(a
->data
.execute
.path
);
103 else if (a
->func
== action_debug
)
104 g_free(a
->data
.debug
.string
);
105 else if (a
->func
== action_showmenu
)
106 g_free(a
->data
.showmenu
.name
);
111 ObAction
* action_copy(const ObAction
*src
)
113 ObAction
*a
= action_new(src
->func
);
117 /* deal with pointers */
118 if (a
->func
== action_execute
|| a
->func
== action_restart
)
119 a
->data
.execute
.path
= g_strdup(a
->data
.execute
.path
);
120 else if (a
->func
== action_debug
)
121 a
->data
.debug
.string
= g_strdup(a
->data
.debug
.string
);
122 else if (a
->func
== action_showmenu
)
123 a
->data
.showmenu
.name
= g_strdup(a
->data
.showmenu
.name
);
128 void setup_action_directional_focus_north(ObAction
**a
, ObUserAction uact
)
130 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
131 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTH
;
132 (*a
)->data
.interdiraction
.dialog
= TRUE
;
133 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
134 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
137 void setup_action_directional_focus_east(ObAction
**a
, ObUserAction uact
)
139 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
140 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_EAST
;
141 (*a
)->data
.interdiraction
.dialog
= TRUE
;
142 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
143 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
146 void setup_action_directional_focus_south(ObAction
**a
, ObUserAction uact
)
148 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
149 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTH
;
150 (*a
)->data
.interdiraction
.dialog
= TRUE
;
151 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
152 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
155 void setup_action_directional_focus_west(ObAction
**a
, ObUserAction uact
)
157 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
158 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_WEST
;
159 (*a
)->data
.interdiraction
.dialog
= TRUE
;
160 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
161 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
164 void setup_action_directional_focus_northeast(ObAction
**a
, ObUserAction uact
)
166 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
167 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHEAST
;
168 (*a
)->data
.interdiraction
.dialog
= TRUE
;
169 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
170 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
173 void setup_action_directional_focus_southeast(ObAction
**a
, ObUserAction uact
)
175 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
176 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHEAST
;
177 (*a
)->data
.interdiraction
.dialog
= TRUE
;
178 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
179 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
182 void setup_action_directional_focus_southwest(ObAction
**a
, ObUserAction uact
)
184 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
185 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHWEST
;
186 (*a
)->data
.interdiraction
.dialog
= TRUE
;
187 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
188 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
191 void setup_action_directional_focus_northwest(ObAction
**a
, ObUserAction uact
)
193 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
194 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHWEST
;
195 (*a
)->data
.interdiraction
.dialog
= TRUE
;
196 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
197 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
200 void setup_action_send_to_desktop(ObAction
**a
, ObUserAction uact
)
202 (*a
)->data
.sendto
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
203 (*a
)->data
.sendto
.follow
= TRUE
;
206 void setup_action_send_to_desktop_prev(ObAction
**a
, ObUserAction uact
)
208 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
209 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
210 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
211 (*a
)->data
.sendtodir
.linear
= TRUE
;
212 (*a
)->data
.sendtodir
.wrap
= TRUE
;
213 (*a
)->data
.sendtodir
.follow
= TRUE
;
216 void setup_action_send_to_desktop_next(ObAction
**a
, ObUserAction uact
)
218 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
219 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
220 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
221 (*a
)->data
.sendtodir
.linear
= TRUE
;
222 (*a
)->data
.sendtodir
.wrap
= TRUE
;
223 (*a
)->data
.sendtodir
.follow
= TRUE
;
226 void setup_action_send_to_desktop_left(ObAction
**a
, ObUserAction uact
)
228 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
229 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
230 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
231 (*a
)->data
.sendtodir
.linear
= FALSE
;
232 (*a
)->data
.sendtodir
.wrap
= TRUE
;
233 (*a
)->data
.sendtodir
.follow
= TRUE
;
236 void setup_action_send_to_desktop_right(ObAction
**a
, ObUserAction uact
)
238 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
239 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
240 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
241 (*a
)->data
.sendtodir
.linear
= FALSE
;
242 (*a
)->data
.sendtodir
.wrap
= TRUE
;
243 (*a
)->data
.sendtodir
.follow
= TRUE
;
246 void setup_action_send_to_desktop_up(ObAction
**a
, ObUserAction uact
)
248 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
249 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
250 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_NORTH
;
251 (*a
)->data
.sendtodir
.linear
= FALSE
;
252 (*a
)->data
.sendtodir
.wrap
= TRUE
;
253 (*a
)->data
.sendtodir
.follow
= TRUE
;
256 void setup_action_send_to_desktop_down(ObAction
**a
, ObUserAction uact
)
258 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
259 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
260 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_SOUTH
;
261 (*a
)->data
.sendtodir
.linear
= FALSE
;
262 (*a
)->data
.sendtodir
.wrap
= TRUE
;
263 (*a
)->data
.sendtodir
.follow
= TRUE
;
266 void setup_action_desktop(ObAction
**a
, ObUserAction uact
)
269 (*a)->data.desktop.inter.any.interactive = FALSE;
273 void setup_action_desktop_prev(ObAction
**a
, ObUserAction uact
)
275 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
276 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
277 (*a
)->data
.desktopdir
.linear
= TRUE
;
278 (*a
)->data
.desktopdir
.wrap
= TRUE
;
281 void setup_action_desktop_next(ObAction
**a
, ObUserAction uact
)
283 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
284 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
285 (*a
)->data
.desktopdir
.linear
= TRUE
;
286 (*a
)->data
.desktopdir
.wrap
= TRUE
;
289 void setup_action_desktop_left(ObAction
**a
, ObUserAction uact
)
291 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
292 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
293 (*a
)->data
.desktopdir
.linear
= FALSE
;
294 (*a
)->data
.desktopdir
.wrap
= TRUE
;
297 void setup_action_desktop_right(ObAction
**a
, ObUserAction uact
)
299 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
300 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
301 (*a
)->data
.desktopdir
.linear
= FALSE
;
302 (*a
)->data
.desktopdir
.wrap
= TRUE
;
305 void setup_action_desktop_up(ObAction
**a
, ObUserAction uact
)
307 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
308 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_NORTH
;
309 (*a
)->data
.desktopdir
.linear
= FALSE
;
310 (*a
)->data
.desktopdir
.wrap
= TRUE
;
313 void setup_action_desktop_down(ObAction
**a
, ObUserAction uact
)
315 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
316 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_SOUTH
;
317 (*a
)->data
.desktopdir
.linear
= FALSE
;
318 (*a
)->data
.desktopdir
.wrap
= TRUE
;
321 void setup_action_cycle_windows_next(ObAction
**a
, ObUserAction uact
)
323 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
324 (*a
)->data
.cycle
.linear
= FALSE
;
325 (*a
)->data
.cycle
.forward
= TRUE
;
326 (*a
)->data
.cycle
.dialog
= TRUE
;
327 (*a
)->data
.cycle
.dock_windows
= FALSE
;
328 (*a
)->data
.cycle
.desktop_windows
= FALSE
;
329 (*a
)->data
.cycle
.all_desktops
= FALSE
;
332 void setup_action_cycle_windows_previous(ObAction
**a
, ObUserAction uact
)
334 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
335 (*a
)->data
.cycle
.linear
= FALSE
;
336 (*a
)->data
.cycle
.forward
= FALSE
;
337 (*a
)->data
.cycle
.dialog
= TRUE
;
338 (*a
)->data
.cycle
.dock_windows
= FALSE
;
339 (*a
)->data
.cycle
.desktop_windows
= FALSE
;
340 (*a
)->data
.cycle
.all_desktops
= FALSE
;
343 void setup_action_movefromedge_north(ObAction
**a
, ObUserAction uact
)
345 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
346 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
347 (*a
)->data
.diraction
.hang
= TRUE
;
350 void setup_action_movefromedge_south(ObAction
**a
, ObUserAction uact
)
352 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
353 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
354 (*a
)->data
.diraction
.hang
= TRUE
;
357 void setup_action_movefromedge_east(ObAction
**a
, ObUserAction uact
)
359 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
360 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
361 (*a
)->data
.diraction
.hang
= TRUE
;
364 void setup_action_movefromedge_west(ObAction
**a
, ObUserAction uact
)
366 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
367 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
368 (*a
)->data
.diraction
.hang
= TRUE
;
371 void setup_action_movetoedge_north(ObAction
**a
, ObUserAction uact
)
373 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
374 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
375 (*a
)->data
.diraction
.hang
= FALSE
;
378 void setup_action_movetoedge_south(ObAction
**a
, ObUserAction uact
)
380 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
381 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
382 (*a
)->data
.diraction
.hang
= FALSE
;
385 void setup_action_movetoedge_east(ObAction
**a
, ObUserAction uact
)
387 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
388 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
389 (*a
)->data
.diraction
.hang
= FALSE
;
392 void setup_action_movetoedge_west(ObAction
**a
, ObUserAction uact
)
394 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
395 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
396 (*a
)->data
.diraction
.hang
= FALSE
;
399 void setup_action_growtoedge_north(ObAction
**a
, ObUserAction uact
)
401 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
402 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
405 void setup_action_growtoedge_south(ObAction
**a
, ObUserAction uact
)
407 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
408 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
411 void setup_action_growtoedge_east(ObAction
**a
, ObUserAction uact
)
413 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
414 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
417 void setup_action_growtoedge_west(ObAction
**a
, ObUserAction uact
)
419 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
420 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
423 void setup_action_top_layer(ObAction
**a
, ObUserAction uact
)
425 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
426 (*a
)->data
.layer
.layer
= 1;
429 void setup_action_normal_layer(ObAction
**a
, ObUserAction uact
)
431 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
432 (*a
)->data
.layer
.layer
= 0;
435 void setup_action_bottom_layer(ObAction
**a
, ObUserAction uact
)
437 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
438 (*a
)->data
.layer
.layer
= -1;
441 void setup_action_move(ObAction
**a
, ObUserAction uact
)
443 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
444 (*a
)->data
.moveresize
.keyboard
=
445 (uact
== OB_USER_ACTION_NONE
||
446 uact
== OB_USER_ACTION_KEYBOARD_KEY
||
447 uact
== OB_USER_ACTION_MENU_SELECTION
);
448 (*a
)->data
.moveresize
.corner
= 0;
451 void setup_action_resize(ObAction
**a
, ObUserAction uact
)
453 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
454 (*a
)->data
.moveresize
.keyboard
=
455 (uact
== OB_USER_ACTION_NONE
||
456 uact
== OB_USER_ACTION_KEYBOARD_KEY
||
457 uact
== OB_USER_ACTION_MENU_SELECTION
);
458 (*a
)->data
.moveresize
.corner
= 0;
461 void setup_action_showmenu(ObAction
**a
, ObUserAction uact
)
463 (*a
)->data
.showmenu
.any
.client_action
= OB_CLIENT_ACTION_OPTIONAL
;
464 /* you cannot call ShowMenu from inside a menu, cuz the menu code makes
465 assumptions that there is only one menu (and submenus) open at
467 if (uact
== OB_USER_ACTION_MENU_SELECTION
) {
473 void setup_action_focus(ObAction
**a
, ObUserAction uact
)
475 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_OPTIONAL
;
478 void setup_client_action(ObAction
**a
, ObUserAction uact
)
480 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
483 ActionString actionstrings
[] =
496 "directionalfocusnorth",
497 action_directional_focus
,
498 setup_action_directional_focus_north
501 "directionalfocuseast",
502 action_directional_focus
,
503 setup_action_directional_focus_east
506 "directionalfocussouth",
507 action_directional_focus
,
508 setup_action_directional_focus_south
511 "directionalfocuswest",
512 action_directional_focus
,
513 setup_action_directional_focus_west
516 "directionalfocusnortheast",
517 action_directional_focus
,
518 setup_action_directional_focus_northeast
521 "directionalfocussoutheast",
522 action_directional_focus
,
523 setup_action_directional_focus_southeast
526 "directionalfocussouthwest",
527 action_directional_focus
,
528 setup_action_directional_focus_southwest
531 "directionalfocusnorthwest",
532 action_directional_focus
,
533 setup_action_directional_focus_northwest
557 action_focus_order_to_bottom
,
612 action_toggle_omnipresent
,
617 action_move_relative_horz
,
622 action_move_relative_vert
,
627 action_move_to_center
,
631 "resizerelativehorz",
632 action_resize_relative_horz
,
636 "resizerelativevert",
637 action_resize_relative_vert
,
642 action_move_relative
,
647 action_resize_relative
,
652 action_maximize_full
,
657 action_unmaximize_full
,
661 "togglemaximizefull",
662 action_toggle_maximize_full
,
667 action_maximize_horz
,
672 action_unmaximize_horz
,
676 "togglemaximizehorz",
677 action_toggle_maximize_horz
,
682 action_maximize_vert
,
687 action_unmaximize_vert
,
691 "togglemaximizevert",
692 action_toggle_maximize_vert
,
697 action_toggle_fullscreen
,
702 action_send_to_desktop
,
703 setup_action_send_to_desktop
707 action_send_to_desktop_dir
,
708 setup_action_send_to_desktop_next
711 "sendtodesktopprevious",
712 action_send_to_desktop_dir
,
713 setup_action_send_to_desktop_prev
716 "sendtodesktopright",
717 action_send_to_desktop_dir
,
718 setup_action_send_to_desktop_right
722 action_send_to_desktop_dir
,
723 setup_action_send_to_desktop_left
727 action_send_to_desktop_dir
,
728 setup_action_send_to_desktop_up
732 action_send_to_desktop_dir
,
733 setup_action_send_to_desktop_down
743 setup_action_desktop_next
748 setup_action_desktop_prev
753 setup_action_desktop_right
758 setup_action_desktop_left
763 setup_action_desktop_up
768 setup_action_desktop_down
772 action_toggle_decorations
,
786 "toggledockautohide",
787 action_toggle_dockautohide
,
792 action_toggle_show_desktop
,
802 action_unshow_desktop
,
828 setup_action_showmenu
832 action_send_to_layer
,
833 setup_action_top_layer
838 setup_action_top_layer
842 action_send_to_layer
,
843 setup_action_normal_layer
847 action_send_to_layer
,
848 setup_action_bottom_layer
851 "togglealwaysonbottom",
853 setup_action_bottom_layer
857 action_cycle_windows
,
858 setup_action_cycle_windows_next
862 action_cycle_windows
,
863 setup_action_cycle_windows_previous
868 setup_action_movefromedge_north
873 setup_action_movefromedge_south
878 setup_action_movefromedge_west
883 setup_action_movefromedge_east
888 setup_action_movetoedge_north
893 setup_action_movetoedge_south
898 setup_action_movetoedge_west
903 setup_action_movetoedge_east
908 setup_action_growtoedge_north
913 setup_action_growtoedge_south
918 setup_action_growtoedge_west
923 setup_action_growtoedge_east
937 /* only key bindings can be interactive. thus saith the xor.
938 because of how the mouse is grabbed, mouse events dont even get
939 read during interactive events, so no dice! >:) */
940 #define INTERACTIVE_LIMIT(a, uact) \
941 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
942 a->data.any.interactive = FALSE;
944 ObAction
*action_from_string(const gchar
*name
, ObUserAction uact
)
947 gboolean exist
= FALSE
;
950 for (i
= 0; actionstrings
[i
].name
; i
++)
951 if (!g_ascii_strcasecmp(name
, actionstrings
[i
].name
)) {
953 a
= action_new(actionstrings
[i
].func
);
954 if (actionstrings
[i
].setup
)
955 actionstrings
[i
].setup(&a
, uact
);
957 INTERACTIVE_LIMIT(a
, uact
);
961 g_message(_("Invalid action '%s' requested. No such action exists."),
964 g_message(_("Invalid use of action '%s'. Action will be ignored."),
969 ObAction
*action_parse(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
973 ObAction
*act
= NULL
;
976 if (parse_attr_string("name", node
, &actname
)) {
977 if ((act
= action_from_string(actname
, uact
))) {
978 if (act
->func
== action_execute
|| act
->func
== action_restart
) {
979 if ((n
= parse_find_node("execute", node
->xmlChildrenNode
))) {
980 gchar
*s
= parse_string(doc
, n
);
981 act
->data
.execute
.path
= parse_expand_tilde(s
);
984 if ((n
= parse_find_node("startupnotify", node
->xmlChildrenNode
))) {
986 if ((m
= parse_find_node("enabled", n
->xmlChildrenNode
)))
987 act
->data
.execute
.startupnotify
= parse_bool(doc
, m
);
988 if ((m
= parse_find_node("name", n
->xmlChildrenNode
)))
989 act
->data
.execute
.name
= parse_string(doc
, m
);
990 if ((m
= parse_find_node("icon", n
->xmlChildrenNode
)))
991 act
->data
.execute
.icon_name
= parse_string(doc
, m
);
993 } else if (act
->func
== action_debug
) {
994 if ((n
= parse_find_node("string", node
->xmlChildrenNode
)))
995 act
->data
.debug
.string
= parse_string(doc
, n
);
996 } else if (act
->func
== action_showmenu
) {
997 if ((n
= parse_find_node("menu", node
->xmlChildrenNode
)))
998 act
->data
.showmenu
.name
= parse_string(doc
, n
);
999 } else if (act
->func
== action_move_relative_horz
||
1000 act
->func
== action_move_relative_vert
||
1001 act
->func
== action_resize_relative_horz
||
1002 act
->func
== action_resize_relative_vert
) {
1003 if ((n
= parse_find_node("delta", node
->xmlChildrenNode
)))
1004 act
->data
.relative
.deltax
= parse_int(doc
, n
);
1005 } else if (act
->func
== action_move_relative
) {
1006 if ((n
= parse_find_node("x", node
->xmlChildrenNode
)))
1007 act
->data
.relative
.deltax
= parse_int(doc
, n
);
1008 if ((n
= parse_find_node("y", node
->xmlChildrenNode
)))
1009 act
->data
.relative
.deltay
= parse_int(doc
, n
);
1010 } else if (act
->func
== action_resize_relative
) {
1011 if ((n
= parse_find_node("left", node
->xmlChildrenNode
)))
1012 act
->data
.relative
.deltaxl
= parse_int(doc
, n
);
1013 if ((n
= parse_find_node("up", node
->xmlChildrenNode
)))
1014 act
->data
.relative
.deltayu
= parse_int(doc
, n
);
1015 if ((n
= parse_find_node("right", node
->xmlChildrenNode
)))
1016 act
->data
.relative
.deltax
= parse_int(doc
, n
);
1017 if ((n
= parse_find_node("down", node
->xmlChildrenNode
)))
1018 act
->data
.relative
.deltay
= parse_int(doc
, n
);
1019 } else if (act
->func
== action_desktop
) {
1020 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1021 act
->data
.desktop
.desk
= parse_int(doc
, n
);
1022 if (act
->data
.desktop
.desk
> 0) act
->data
.desktop
.desk
--;
1024 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
1025 act->data.desktop.inter.any.interactive =
1028 } else if (act
->func
== action_send_to_desktop
) {
1029 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1030 act
->data
.sendto
.desk
= parse_int(doc
, n
);
1031 if (act
->data
.sendto
.desk
> 0) act
->data
.sendto
.desk
--;
1032 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
1033 act
->data
.sendto
.follow
= parse_bool(doc
, n
);
1034 } else if (act
->func
== action_desktop_dir
) {
1035 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
1036 act
->data
.desktopdir
.wrap
= parse_bool(doc
, n
);
1037 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1038 act
->data
.desktopdir
.inter
.any
.interactive
=
1040 } else if (act
->func
== action_send_to_desktop_dir
) {
1041 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
1042 act
->data
.sendtodir
.wrap
= parse_bool(doc
, n
);
1043 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
1044 act
->data
.sendtodir
.follow
= parse_bool(doc
, n
);
1045 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1046 act
->data
.sendtodir
.inter
.any
.interactive
=
1048 } else if (act
->func
== action_activate
) {
1049 if ((n
= parse_find_node("here", node
->xmlChildrenNode
)))
1050 act
->data
.activate
.here
= parse_bool(doc
, n
);
1051 } else if (act
->func
== action_cycle_windows
) {
1052 if ((n
= parse_find_node("linear", node
->xmlChildrenNode
)))
1053 act
->data
.cycle
.linear
= parse_bool(doc
, n
);
1054 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1055 act
->data
.cycle
.dialog
= parse_bool(doc
, n
);
1056 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
1057 act
->data
.cycle
.dock_windows
= parse_bool(doc
, n
);
1058 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1059 act
->data
.cycle
.desktop_windows
= parse_bool(doc
, n
);
1060 if ((n
= parse_find_node("allDesktops",
1061 node
->xmlChildrenNode
)))
1062 act
->data
.cycle
.all_desktops
= parse_bool(doc
, n
);
1063 } else if (act
->func
== action_directional_focus
) {
1064 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1065 act
->data
.interdiraction
.dialog
= parse_bool(doc
, n
);
1066 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
1067 act
->data
.interdiraction
.dock_windows
= parse_bool(doc
, n
);
1068 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1069 act
->data
.interdiraction
.desktop_windows
=
1071 } else if (act
->func
== action_resize
) {
1072 if ((n
= parse_find_node("edge", node
->xmlChildrenNode
))) {
1073 gchar
*s
= parse_string(doc
, n
);
1074 if (!g_ascii_strcasecmp(s
, "top"))
1075 act
->data
.moveresize
.corner
=
1076 prop_atoms
.net_wm_moveresize_size_top
;
1077 else if (!g_ascii_strcasecmp(s
, "bottom"))
1078 act
->data
.moveresize
.corner
=
1079 prop_atoms
.net_wm_moveresize_size_bottom
;
1080 else if (!g_ascii_strcasecmp(s
, "left"))
1081 act
->data
.moveresize
.corner
=
1082 prop_atoms
.net_wm_moveresize_size_left
;
1083 else if (!g_ascii_strcasecmp(s
, "right"))
1084 act
->data
.moveresize
.corner
=
1085 prop_atoms
.net_wm_moveresize_size_right
;
1086 else if (!g_ascii_strcasecmp(s
, "topleft"))
1087 act
->data
.moveresize
.corner
=
1088 prop_atoms
.net_wm_moveresize_size_topleft
;
1089 else if (!g_ascii_strcasecmp(s
, "topright"))
1090 act
->data
.moveresize
.corner
=
1091 prop_atoms
.net_wm_moveresize_size_topright
;
1092 else if (!g_ascii_strcasecmp(s
, "bottomleft"))
1093 act
->data
.moveresize
.corner
=
1094 prop_atoms
.net_wm_moveresize_size_bottomleft
;
1095 else if (!g_ascii_strcasecmp(s
, "bottomright"))
1096 act
->data
.moveresize
.corner
=
1097 prop_atoms
.net_wm_moveresize_size_bottomright
;
1100 } else if (act
->func
== action_raise
||
1101 act
->func
== action_lower
||
1102 act
->func
== action_raiselower
||
1103 act
->func
== action_shadelower
||
1104 act
->func
== action_unshaderaise
) {
1106 INTERACTIVE_LIMIT(act
, uact
);
1113 void action_run_list(GSList
*acts
, ObClient
*c
, ObFrameContext context
,
1114 guint state
, guint button
, gint x
, gint y
, Time time
,
1115 gboolean cancel
, gboolean done
)
1124 screen_pointer_pos(&x
, &y
);
1126 for (it
= acts
; it
; it
= g_slist_next(it
)) {
1129 if (!(a
->data
.any
.client_action
== OB_CLIENT_ACTION_ALWAYS
&& !c
)) {
1130 a
->data
.any
.c
= a
->data
.any
.client_action
? c
: NULL
;
1131 a
->data
.any
.context
= context
;
1135 a
->data
.any
.button
= button
;
1137 a
->data
.any
.time
= time
;
1139 if (a
->data
.any
.interactive
) {
1140 a
->data
.inter
.cancel
= cancel
;
1141 a
->data
.inter
.final
= done
;
1142 if (!(cancel
|| done
))
1143 if (!keyboard_interactive_grab(state
, a
->data
.any
.c
, a
))
1147 /* XXX UGLY HACK race with motion event starting a move and the
1148 button release gettnig processed first. answer: don't queue
1149 moveresize starts. UGLY HACK XXX
1151 XXX ALSO don't queue showmenu events, because on button press
1152 events we need to know if a mouse grab is going to take place,
1153 and set the button to 0, so that later motion events don't think
1154 that a drag is going on. since showmenu grabs the pointer..
1156 if (a
->data
.any
.interactive
|| a
->func
== action_move
||
1157 a
->func
== action_resize
|| a
->func
== action_showmenu
)
1159 /* interactive actions are not queued */
1161 } else if (a
->func
== action_focus
||
1162 a
->func
== action_activate
||
1163 a
->func
== action_showmenu
)
1165 /* XXX MORE UGLY HACK
1166 actions from clicks on client windows are NOT queued.
1167 this solves the mysterious click-and-drag-doesnt-work
1168 problem. it was because the window gets focused and stuff
1169 after the button event has already been passed through. i
1170 dont really know why it should care but it does and it makes
1173 however this very bogus ! !
1174 we want to send the button press to the window BEFORE
1175 we do the action because the action might move the windows
1176 (eg change desktops) and then the button press ends up on
1177 the completely wrong window !
1178 so, this is just for that bug, and it will only NOT queue it
1179 if it is a focusing action that can be used with the mouse
1182 also with the menus, there is a race going on. if the
1183 desktop wants to pop up a menu, and we do too, we send them
1184 the button before we pop up the menu, so they pop up their
1185 menu first. but not always. if we pop up our menu before
1186 sending them the button press, then the result is
1189 XXX further more. focus actions are not queued at all,
1190 because if you bind focus->showmenu, the menu will get
1191 hidden to do the focusing
1195 ob_main_loop_queue_action(ob_main_loop
, a
);
1200 void action_run_string(const gchar
*name
, struct _ObClient
*c
, Time time
)
1205 a
= action_from_string(name
, OB_USER_ACTION_NONE
);
1208 l
= g_slist_append(NULL
, a
);
1210 action_run(l
, c
, 0, time
);
1213 void action_debug(union ActionData
*data
)
1215 if (data
->debug
.string
)
1216 g_print("%s\n", data
->debug
.string
);
1219 void action_execute(union ActionData
*data
)
1222 gchar
*cmd
, **argv
= 0;
1223 if (data
->execute
.path
) {
1224 cmd
= g_filename_from_utf8(data
->execute
.path
, -1, NULL
, NULL
, NULL
);
1226 /* If there is a keyboard grab going on then we need to cancel
1227 it so the application can grab things */
1228 event_cancel_all_key_grabs();
1230 if (!g_shell_parse_argv (cmd
, NULL
, &argv
, &e
)) {
1231 g_message(_("Failed to execute '%s': %s"),
1234 } else if (data
->execute
.startupnotify
) {
1237 program
= g_path_get_basename(argv
[0]);
1238 /* sets up the environment */
1239 sn_setup_spawn_environment(program
,
1241 data
->execute
.icon_name
,
1242 /* launch it on the current
1245 data
->execute
.any
.time
);
1246 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
|
1247 G_SPAWN_DO_NOT_REAP_CHILD
,
1248 NULL
, NULL
, NULL
, &e
)) {
1249 g_message(_("Failed to execute '%s': %s"),
1254 unsetenv("DESKTOP_STARTUP_ID");
1258 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
|
1259 G_SPAWN_DO_NOT_REAP_CHILD
,
1260 NULL
, NULL
, NULL
, &e
))
1262 g_message(_("Failed to execute '%s': %s"),
1270 g_message(_("Failed to convert the path '%s' from utf8"),
1271 data
->execute
.path
);
1276 void action_activate(union ActionData
*data
)
1278 if (data
->client
.any
.c
) {
1279 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1280 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1281 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1283 /* if using focus_delay, stop the timer now so that focus doesn't
1285 event_halt_focus_delay();
1287 client_activate(data
->activate
.any
.c
, data
->activate
.here
, TRUE
);
1290 /* focus action on something other than a client, make keybindings
1291 work for this openbox instance, but don't focus any specific client
1297 void action_focus(union ActionData
*data
)
1299 if (data
->client
.any
.c
) {
1300 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1301 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1302 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1304 /* if using focus_delay, stop the timer now so that focus doesn't
1306 event_halt_focus_delay();
1308 client_focus(data
->client
.any
.c
);
1311 /* focus action on something other than a client, make keybindings
1312 work for this openbox instance, but don't focus any specific client
1318 void action_unfocus (union ActionData
*data
)
1320 if (data
->client
.any
.c
== focus_client
)
1321 focus_fallback(FALSE
, FALSE
, TRUE
);
1324 void action_iconify(union ActionData
*data
)
1326 client_action_start(data
);
1327 client_iconify(data
->client
.any
.c
, TRUE
, TRUE
, FALSE
);
1328 client_action_end(data
, config_focus_under_mouse
);
1331 void action_focus_order_to_bottom(union ActionData
*data
)
1333 focus_order_to_bottom(data
->client
.any
.c
);
1336 void action_raiselower(union ActionData
*data
)
1338 ObClient
*c
= data
->client
.any
.c
;
1340 client_action_start(data
);
1341 stacking_restack_request(c
, NULL
, Opposite
, FALSE
);
1342 client_action_end(data
, config_focus_under_mouse
);
1345 void action_raise(union ActionData
*data
)
1347 client_action_start(data
);
1348 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1349 client_action_end(data
, config_focus_under_mouse
);
1352 void action_unshaderaise(union ActionData
*data
)
1354 if (data
->client
.any
.c
->shaded
)
1355 action_unshade(data
);
1360 void action_shadelower(union ActionData
*data
)
1362 if (data
->client
.any
.c
->shaded
)
1368 void action_lower(union ActionData
*data
)
1370 client_action_start(data
);
1371 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1372 client_action_end(data
, config_focus_under_mouse
);
1375 void action_close(union ActionData
*data
)
1377 client_close(data
->client
.any
.c
);
1380 void action_kill(union ActionData
*data
)
1382 client_kill(data
->client
.any
.c
);
1385 void action_shade(union ActionData
*data
)
1387 client_action_start(data
);
1388 client_shade(data
->client
.any
.c
, TRUE
);
1389 client_action_end(data
, config_focus_under_mouse
);
1392 void action_unshade(union ActionData
*data
)
1394 client_action_start(data
);
1395 client_shade(data
->client
.any
.c
, FALSE
);
1396 client_action_end(data
, config_focus_under_mouse
);
1399 void action_toggle_shade(union ActionData
*data
)
1401 client_action_start(data
);
1402 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1403 client_action_end(data
, config_focus_under_mouse
);
1406 void action_toggle_omnipresent(union ActionData
*data
)
1408 client_set_desktop(data
->client
.any
.c
,
1409 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1410 screen_desktop
: DESKTOP_ALL
, FALSE
);
1413 void action_move_relative_horz(union ActionData
*data
)
1415 ObClient
*c
= data
->relative
.any
.c
;
1416 client_action_start(data
);
1417 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
);
1418 client_action_end(data
, FALSE
);
1421 void action_move_relative_vert(union ActionData
*data
)
1423 ObClient
*c
= data
->relative
.any
.c
;
1424 client_action_start(data
);
1425 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.deltax
);
1426 client_action_end(data
, FALSE
);
1429 void action_move_to_center(union ActionData
*data
)
1431 ObClient
*c
= data
->client
.any
.c
;
1433 area
= screen_area_monitor(c
->desktop
, 0);
1434 client_action_start(data
);
1435 client_move(c
, area
->width
/ 2 - c
->area
.width
/ 2,
1436 area
->height
/ 2 - c
->area
.height
/ 2);
1437 client_action_end(data
, FALSE
);
1440 void action_resize_relative_horz(union ActionData
*data
)
1442 ObClient
*c
= data
->relative
.any
.c
;
1443 client_action_start(data
);
1445 c
->area
.width
+ data
->relative
.deltax
* c
->size_inc
.width
,
1447 client_action_end(data
, FALSE
);
1450 void action_resize_relative_vert(union ActionData
*data
)
1452 ObClient
*c
= data
->relative
.any
.c
;
1454 client_action_start(data
);
1455 client_resize(c
, c
->area
.width
, c
->area
.height
+
1456 data
->relative
.deltax
* c
->size_inc
.height
);
1457 client_action_end(data
, FALSE
);
1461 void action_move_relative(union ActionData
*data
)
1463 ObClient
*c
= data
->relative
.any
.c
;
1464 client_action_start(data
);
1465 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
+
1466 data
->relative
.deltay
);
1467 client_action_end(data
, FALSE
);
1470 void action_resize_relative(union ActionData
*data
)
1472 ObClient
*c
= data
->relative
.any
.c
;
1473 gint x
, y
, ow
, xoff
, nw
, oh
, yoff
, nh
, lw
, lh
;
1475 client_action_start(data
);
1480 xoff
= -data
->relative
.deltaxl
* c
->size_inc
.width
;
1481 nw
= ow
+ data
->relative
.deltax
* c
->size_inc
.width
1482 + data
->relative
.deltaxl
* c
->size_inc
.width
;
1483 oh
= c
->area
.height
;
1484 yoff
= -data
->relative
.deltayu
* c
->size_inc
.height
;
1485 nh
= oh
+ data
->relative
.deltay
* c
->size_inc
.height
1486 + data
->relative
.deltayu
* c
->size_inc
.height
;
1488 g_print("deltax %d %d x %d ow %d xoff %d nw %d\n",
1489 data
->relative
.deltax
,
1490 data
->relative
.deltaxl
,
1493 client_try_configure(c
, &x
, &y
, &nw
, &nh
, &lw
, &lh
, TRUE
);
1494 xoff
= xoff
== 0 ? 0 : (xoff
< 0 ? MAX(xoff
, ow
-nw
) : MIN(xoff
, ow
-nw
));
1495 yoff
= yoff
== 0 ? 0 : (yoff
< 0 ? MAX(yoff
, oh
-nh
) : MIN(yoff
, oh
-nh
));
1496 client_move_resize(c
, x
+ xoff
, y
+ yoff
, nw
, nh
);
1497 client_action_end(data
, FALSE
);
1500 void action_maximize_full(union ActionData
*data
)
1502 client_action_start(data
);
1503 client_maximize(data
->client
.any
.c
, TRUE
, 0);
1504 client_action_end(data
, config_focus_under_mouse
);
1507 void action_unmaximize_full(union ActionData
*data
)
1509 client_action_start(data
);
1510 client_maximize(data
->client
.any
.c
, FALSE
, 0);
1511 client_action_end(data
, config_focus_under_mouse
);
1514 void action_toggle_maximize_full(union ActionData
*data
)
1516 client_action_start(data
);
1517 client_maximize(data
->client
.any
.c
,
1518 !(data
->client
.any
.c
->max_horz
||
1519 data
->client
.any
.c
->max_vert
),
1521 client_action_end(data
, config_focus_under_mouse
);
1524 void action_maximize_horz(union ActionData
*data
)
1526 client_action_start(data
);
1527 client_maximize(data
->client
.any
.c
, TRUE
, 1);
1528 client_action_end(data
, config_focus_under_mouse
);
1531 void action_unmaximize_horz(union ActionData
*data
)
1533 client_action_start(data
);
1534 client_maximize(data
->client
.any
.c
, FALSE
, 1);
1535 client_action_end(data
, config_focus_under_mouse
);
1538 void action_toggle_maximize_horz(union ActionData
*data
)
1540 client_action_start(data
);
1541 client_maximize(data
->client
.any
.c
,
1542 !data
->client
.any
.c
->max_horz
, 1);
1543 client_action_end(data
, config_focus_under_mouse
);
1546 void action_maximize_vert(union ActionData
*data
)
1548 client_action_start(data
);
1549 client_maximize(data
->client
.any
.c
, TRUE
, 2);
1550 client_action_end(data
, config_focus_under_mouse
);
1553 void action_unmaximize_vert(union ActionData
*data
)
1555 client_action_start(data
);
1556 client_maximize(data
->client
.any
.c
, FALSE
, 2);
1557 client_action_end(data
, config_focus_under_mouse
);
1560 void action_toggle_maximize_vert(union ActionData
*data
)
1562 client_action_start(data
);
1563 client_maximize(data
->client
.any
.c
,
1564 !data
->client
.any
.c
->max_vert
, 2);
1565 client_action_end(data
, config_focus_under_mouse
);
1568 void action_toggle_fullscreen(union ActionData
*data
)
1570 client_action_start(data
);
1571 client_fullscreen(data
->client
.any
.c
, !(data
->client
.any
.c
->fullscreen
));
1572 client_action_end(data
, config_focus_under_mouse
);
1575 void action_send_to_desktop(union ActionData
*data
)
1577 ObClient
*c
= data
->sendto
.any
.c
;
1579 if (!client_normal(c
)) return;
1581 if (data
->sendto
.desk
< screen_num_desktops
||
1582 data
->sendto
.desk
== DESKTOP_ALL
) {
1583 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
);
1584 if (data
->sendto
.follow
&& data
->sendto
.desk
!= screen_desktop
)
1585 screen_set_desktop(data
->sendto
.desk
, TRUE
);
1589 void action_desktop(union ActionData
*data
)
1591 /* XXX add the interactive/dialog option back again once the dialog
1592 has been made to not use grabs */
1593 if (data
->desktop
.desk
< screen_num_desktops
||
1594 data
->desktop
.desk
== DESKTOP_ALL
)
1596 screen_set_desktop(data
->desktop
.desk
, TRUE
);
1597 if (data
->inter
.any
.interactive
)
1598 screen_desktop_popup(data
->desktop
.desk
, TRUE
);
1602 void action_desktop_dir(union ActionData
*data
)
1606 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1607 data
->desktopdir
.wrap
,
1608 data
->desktopdir
.linear
,
1609 data
->desktopdir
.inter
.any
.interactive
,
1610 data
->desktopdir
.inter
.final
,
1611 data
->desktopdir
.inter
.cancel
);
1612 /* only move the desktop when the action is complete. if we switch
1613 desktops during the interactive action, focus will move but with
1614 NotifyWhileGrabbed and applications don't like that. */
1615 if (!data
->sendtodir
.inter
.any
.interactive
||
1616 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1618 if (d
!= screen_desktop
)
1619 screen_set_desktop(d
, TRUE
);
1623 void action_send_to_desktop_dir(union ActionData
*data
)
1625 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1628 if (!client_normal(c
)) return;
1630 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1631 data
->sendtodir
.linear
,
1632 data
->sendtodir
.inter
.any
.interactive
,
1633 data
->sendtodir
.inter
.final
,
1634 data
->sendtodir
.inter
.cancel
);
1635 /* only move the desktop when the action is complete. if we switch
1636 desktops during the interactive action, focus will move but with
1637 NotifyWhileGrabbed and applications don't like that. */
1638 if (!data
->sendtodir
.inter
.any
.interactive
||
1639 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1641 client_set_desktop(c
, d
, data
->sendtodir
.follow
);
1642 if (data
->sendtodir
.follow
&& d
!= screen_desktop
)
1643 screen_set_desktop(d
, TRUE
);
1647 void action_desktop_last(union ActionData
*data
)
1649 screen_set_desktop(screen_last_desktop
, TRUE
);
1652 void action_toggle_decorations(union ActionData
*data
)
1654 ObClient
*c
= data
->client
.any
.c
;
1656 client_action_start(data
);
1657 client_set_undecorated(c
, !c
->undecorated
);
1658 client_action_end(data
, FALSE
);
1661 static guint32
pick_corner(gint x
, gint y
, gint cx
, gint cy
, gint cw
, gint ch
,
1664 /* let's make x and y client relative instead of screen relative */
1666 y
= ch
- (y
- cy
); /* y is inverted, 0 is at the bottom of the window */
1669 #define A -4*X + 7*ch/3
1670 #define B 4*X -15*ch/9
1671 #define C -X/4 + 2*ch/3
1672 #define D X/4 + 5*ch/12
1673 #define E X/4 + ch/3
1674 #define F -X/4 + 7*ch/12
1675 #define G 4*X - 4*ch/3
1676 #define H -4*X + 8*ch/3
1677 #define a (y > 5*ch/9)
1678 #define b (x < 4*cw/9)
1679 #define c (x > 5*cw/9)
1680 #define d (y < 4*ch/9)
1683 Each of these defines (except X which is just there for fun), represents
1684 the equation of a line. The lines they represent are shown in the diagram
1685 below. Checking y against these lines, we are able to choose a region
1686 of the window as shown.
1688 +---------------------A-------|-------|-------B---------------------+
1695 | northwest | A north B | northeast |
1698 C---------------------+----A--+-------+--B----+---------------------D
1699 |CCCCCCC | A B | DDDDDDD|
1700 | CCCCCCCC | A | | B | DDDDDDDD |
1701 | CCCCCCC A B DDDDDDD |
1702 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
1704 | west | b move c | east | ad
1706 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
1707 | EEEEEEE G H FFFFFFF |
1708 | EEEEEEEE | G | | H | FFFFFFFF |
1709 |EEEEEEE | G H | FFFFFFF|
1710 E---------------------+----G--+-------+--H----+---------------------F
1713 | southwest | G south H | southeast |
1720 +---------------------G-------|-------|-------H---------------------+
1724 /* for shaded windows, you can only resize west/east and move */
1726 return prop_atoms
.net_wm_moveresize_size_left
;
1728 return prop_atoms
.net_wm_moveresize_size_right
;
1729 return prop_atoms
.net_wm_moveresize_move
;
1732 if (y
< A
&& y
>= C
)
1733 return prop_atoms
.net_wm_moveresize_size_topleft
;
1734 else if (y
>= A
&& y
>= B
&& a
)
1735 return prop_atoms
.net_wm_moveresize_size_top
;
1736 else if (y
< B
&& y
>= D
)
1737 return prop_atoms
.net_wm_moveresize_size_topright
;
1738 else if (y
< C
&& y
>= E
&& b
)
1739 return prop_atoms
.net_wm_moveresize_size_left
;
1740 else if (y
< D
&& y
>= F
&& c
)
1741 return prop_atoms
.net_wm_moveresize_size_right
;
1742 else if (y
< E
&& y
>= G
)
1743 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1744 else if (y
< G
&& y
< H
&& d
)
1745 return prop_atoms
.net_wm_moveresize_size_bottom
;
1746 else if (y
>= H
&& y
< F
)
1747 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1749 return prop_atoms
.net_wm_moveresize_move
;
1766 void action_move(union ActionData
*data
)
1768 ObClient
*c
= data
->moveresize
.any
.c
;
1771 if (data
->moveresize
.keyboard
)
1772 corner
= prop_atoms
.net_wm_moveresize_move_keyboard
;
1774 corner
= prop_atoms
.net_wm_moveresize_move
;
1776 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1779 void action_resize(union ActionData
*data
)
1781 ObClient
*c
= data
->moveresize
.any
.c
;
1784 if (data
->moveresize
.keyboard
)
1785 corner
= prop_atoms
.net_wm_moveresize_size_keyboard
;
1786 else if (data
->moveresize
.corner
)
1787 corner
= data
->moveresize
.corner
; /* it was specified in the binding */
1789 corner
= pick_corner(data
->any
.x
, data
->any
.y
,
1790 c
->frame
->area
.x
, c
->frame
->area
.y
,
1791 /* use the client size because the frame
1792 can be differently sized (shaded
1793 windows) and we want this based on the
1795 c
->area
.width
+ c
->frame
->size
.left
+
1796 c
->frame
->size
.right
,
1797 c
->area
.height
+ c
->frame
->size
.top
+
1798 c
->frame
->size
.bottom
, c
->shaded
);
1800 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1803 void action_reconfigure(union ActionData
*data
)
1808 void action_restart(union ActionData
*data
)
1810 ob_restart_other(data
->execute
.path
);
1813 void action_exit(union ActionData
*data
)
1818 void action_showmenu(union ActionData
*data
)
1820 if (data
->showmenu
.name
) {
1821 menu_show(data
->showmenu
.name
, data
->any
.x
, data
->any
.y
,
1822 data
->any
.button
, data
->showmenu
.any
.c
);
1826 void action_cycle_windows(union ActionData
*data
)
1828 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1830 event_halt_focus_delay();
1832 focus_cycle(data
->cycle
.forward
,
1833 data
->cycle
.all_desktops
,
1834 data
->cycle
.dock_windows
,
1835 data
->cycle
.desktop_windows
,
1836 data
->cycle
.linear
, data
->any
.interactive
,
1838 data
->cycle
.inter
.final
, data
->cycle
.inter
.cancel
);
1841 void action_directional_focus(union ActionData
*data
)
1843 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1845 event_halt_focus_delay();
1847 focus_directional_cycle(data
->interdiraction
.direction
,
1848 data
->interdiraction
.dock_windows
,
1849 data
->interdiraction
.desktop_windows
,
1850 data
->any
.interactive
,
1851 data
->interdiraction
.dialog
,
1852 data
->interdiraction
.inter
.final
,
1853 data
->interdiraction
.inter
.cancel
);
1856 void action_movetoedge(union ActionData
*data
)
1859 ObClient
*c
= data
->diraction
.any
.c
;
1861 x
= c
->frame
->area
.x
;
1862 y
= c
->frame
->area
.y
;
1864 switch(data
->diraction
.direction
) {
1865 case OB_DIRECTION_NORTH
:
1866 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
,
1867 data
->diraction
.hang
)
1868 - (data
->diraction
.hang
? c
->frame
->area
.height
: 0);
1870 case OB_DIRECTION_WEST
:
1871 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
,
1872 data
->diraction
.hang
)
1873 - (data
->diraction
.hang
? c
->frame
->area
.width
: 0);
1875 case OB_DIRECTION_SOUTH
:
1876 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
,
1877 data
->diraction
.hang
)
1878 - (data
->diraction
.hang
? 0 : c
->frame
->area
.height
);
1880 case OB_DIRECTION_EAST
:
1881 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
,
1882 data
->diraction
.hang
)
1883 - (data
->diraction
.hang
? 0 : c
->frame
->area
.width
);
1886 g_assert_not_reached();
1888 frame_frame_gravity(c
->frame
, &x
, &y
, c
->area
.width
, c
->area
.height
);
1889 client_action_start(data
);
1890 client_move(c
, x
, y
);
1891 client_action_end(data
, FALSE
);
1894 void action_growtoedge(union ActionData
*data
)
1896 gint x
, y
, width
, height
, dest
;
1897 ObClient
*c
= data
->diraction
.any
.c
;
1900 a
= screen_area(c
->desktop
);
1901 x
= c
->frame
->area
.x
;
1902 y
= c
->frame
->area
.y
;
1903 /* get the unshaded frame's dimensions..if it is shaded */
1904 width
= c
->area
.width
+ c
->frame
->size
.left
+ c
->frame
->size
.right
;
1905 height
= c
->area
.height
+ c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1907 switch(data
->diraction
.direction
) {
1908 case OB_DIRECTION_NORTH
:
1909 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1911 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
, FALSE
);
1913 height
= height
/ 2;
1915 height
= c
->frame
->area
.y
+ height
- dest
;
1919 case OB_DIRECTION_WEST
:
1920 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
, FALSE
);
1924 width
= c
->frame
->area
.x
+ width
- dest
;
1928 case OB_DIRECTION_SOUTH
:
1929 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1931 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
, FALSE
);
1932 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1933 height
= c
->frame
->area
.height
/ 2;
1934 y
= a
->y
+ a
->height
- height
;
1936 height
= dest
- c
->frame
->area
.y
;
1937 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1938 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1940 case OB_DIRECTION_EAST
:
1941 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
, FALSE
);
1942 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1943 width
= c
->frame
->area
.width
/ 2;
1944 x
= a
->x
+ a
->width
- width
;
1946 width
= dest
- c
->frame
->area
.x
;
1947 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1948 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1951 g_assert_not_reached();
1953 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1954 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1955 frame_frame_gravity(c
->frame
, &x
, &y
, width
, height
);
1956 client_action_start(data
);
1957 client_move_resize(c
, x
, y
, width
, height
);
1958 client_action_end(data
, FALSE
);
1961 void action_send_to_layer(union ActionData
*data
)
1963 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1966 void action_toggle_layer(union ActionData
*data
)
1968 ObClient
*c
= data
->layer
.any
.c
;
1970 client_action_start(data
);
1971 if (data
->layer
.layer
< 0)
1972 client_set_layer(c
, c
->below
? 0 : -1);
1973 else if (data
->layer
.layer
> 0)
1974 client_set_layer(c
, c
->above
? 0 : 1);
1975 client_action_end(data
, config_focus_under_mouse
);
1978 void action_toggle_dockautohide(union ActionData
*data
)
1980 config_dock_hide
= !config_dock_hide
;
1984 void action_toggle_show_desktop(union ActionData
*data
)
1986 screen_show_desktop(!screen_showing_desktop
, NULL
);
1989 void action_show_desktop(union ActionData
*data
)
1991 screen_show_desktop(TRUE
, NULL
);
1994 void action_unshow_desktop(union ActionData
*data
)
1996 screen_show_desktop(FALSE
, NULL
);
1999 void action_break_chroot(union ActionData
*data
)
2001 /* break out of one chroot */
2002 keyboard_reset_chains(1);