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 event_enter_client(c
);
72 void (*func
)(union ActionData
*);
73 void (*setup
)(ObAction
**, ObUserAction uact
);
76 static ObAction
*action_new(void (*func
)(union ActionData
*data
))
78 ObAction
*a
= g_new0(ObAction
, 1);
85 void action_ref(ObAction
*a
)
90 void action_unref(ObAction
*a
)
92 if (a
== NULL
) return;
94 if (--a
->ref
> 0) return;
96 /* deal with pointers */
97 if (a
->func
== action_execute
|| a
->func
== action_restart
)
98 g_free(a
->data
.execute
.path
);
99 else if (a
->func
== action_debug
)
100 g_free(a
->data
.debug
.string
);
101 else if (a
->func
== action_showmenu
)
102 g_free(a
->data
.showmenu
.name
);
107 ObAction
* action_copy(const ObAction
*src
)
109 ObAction
*a
= action_new(src
->func
);
113 /* deal with pointers */
114 if (a
->func
== action_execute
|| a
->func
== action_restart
)
115 a
->data
.execute
.path
= g_strdup(a
->data
.execute
.path
);
116 else if (a
->func
== action_debug
)
117 a
->data
.debug
.string
= g_strdup(a
->data
.debug
.string
);
118 else if (a
->func
== action_showmenu
)
119 a
->data
.showmenu
.name
= g_strdup(a
->data
.showmenu
.name
);
124 void setup_action_directional_focus_north(ObAction
**a
, ObUserAction uact
)
126 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
127 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTH
;
128 (*a
)->data
.interdiraction
.dialog
= TRUE
;
129 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
130 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
133 void setup_action_directional_focus_east(ObAction
**a
, ObUserAction uact
)
135 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
136 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_EAST
;
137 (*a
)->data
.interdiraction
.dialog
= TRUE
;
138 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
139 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
142 void setup_action_directional_focus_south(ObAction
**a
, ObUserAction uact
)
144 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
145 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTH
;
146 (*a
)->data
.interdiraction
.dialog
= TRUE
;
147 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
148 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
151 void setup_action_directional_focus_west(ObAction
**a
, ObUserAction uact
)
153 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
154 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_WEST
;
155 (*a
)->data
.interdiraction
.dialog
= TRUE
;
156 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
157 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
160 void setup_action_directional_focus_northeast(ObAction
**a
, ObUserAction uact
)
162 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
163 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHEAST
;
164 (*a
)->data
.interdiraction
.dialog
= TRUE
;
165 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
166 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
169 void setup_action_directional_focus_southeast(ObAction
**a
, ObUserAction uact
)
171 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
172 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHEAST
;
173 (*a
)->data
.interdiraction
.dialog
= TRUE
;
174 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
175 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
178 void setup_action_directional_focus_southwest(ObAction
**a
, ObUserAction uact
)
180 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
181 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHWEST
;
182 (*a
)->data
.interdiraction
.dialog
= TRUE
;
183 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
184 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
187 void setup_action_directional_focus_northwest(ObAction
**a
, ObUserAction uact
)
189 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
190 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHWEST
;
191 (*a
)->data
.interdiraction
.dialog
= TRUE
;
192 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
193 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
196 void setup_action_send_to_desktop(ObAction
**a
, ObUserAction uact
)
198 (*a
)->data
.sendto
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
199 (*a
)->data
.sendto
.follow
= TRUE
;
202 void setup_action_send_to_desktop_prev(ObAction
**a
, ObUserAction uact
)
204 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
205 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
206 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
207 (*a
)->data
.sendtodir
.linear
= TRUE
;
208 (*a
)->data
.sendtodir
.wrap
= TRUE
;
209 (*a
)->data
.sendtodir
.follow
= TRUE
;
212 void setup_action_send_to_desktop_next(ObAction
**a
, ObUserAction uact
)
214 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
215 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
216 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
217 (*a
)->data
.sendtodir
.linear
= TRUE
;
218 (*a
)->data
.sendtodir
.wrap
= TRUE
;
219 (*a
)->data
.sendtodir
.follow
= TRUE
;
222 void setup_action_send_to_desktop_left(ObAction
**a
, ObUserAction uact
)
224 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
225 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
226 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
227 (*a
)->data
.sendtodir
.linear
= FALSE
;
228 (*a
)->data
.sendtodir
.wrap
= TRUE
;
229 (*a
)->data
.sendtodir
.follow
= TRUE
;
232 void setup_action_send_to_desktop_right(ObAction
**a
, ObUserAction uact
)
234 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
235 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
236 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
237 (*a
)->data
.sendtodir
.linear
= FALSE
;
238 (*a
)->data
.sendtodir
.wrap
= TRUE
;
239 (*a
)->data
.sendtodir
.follow
= TRUE
;
242 void setup_action_send_to_desktop_up(ObAction
**a
, ObUserAction uact
)
244 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
245 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
246 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_NORTH
;
247 (*a
)->data
.sendtodir
.linear
= FALSE
;
248 (*a
)->data
.sendtodir
.wrap
= TRUE
;
249 (*a
)->data
.sendtodir
.follow
= TRUE
;
252 void setup_action_send_to_desktop_down(ObAction
**a
, ObUserAction uact
)
254 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
255 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
256 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_SOUTH
;
257 (*a
)->data
.sendtodir
.linear
= FALSE
;
258 (*a
)->data
.sendtodir
.wrap
= TRUE
;
259 (*a
)->data
.sendtodir
.follow
= TRUE
;
262 void setup_action_desktop(ObAction
**a
, ObUserAction uact
)
265 (*a)->data.desktop.inter.any.interactive = FALSE;
269 void setup_action_desktop_prev(ObAction
**a
, ObUserAction uact
)
271 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
272 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
273 (*a
)->data
.desktopdir
.linear
= TRUE
;
274 (*a
)->data
.desktopdir
.wrap
= TRUE
;
277 void setup_action_desktop_next(ObAction
**a
, ObUserAction uact
)
279 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
280 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
281 (*a
)->data
.desktopdir
.linear
= TRUE
;
282 (*a
)->data
.desktopdir
.wrap
= TRUE
;
285 void setup_action_desktop_left(ObAction
**a
, ObUserAction uact
)
287 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
288 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
289 (*a
)->data
.desktopdir
.linear
= FALSE
;
290 (*a
)->data
.desktopdir
.wrap
= TRUE
;
293 void setup_action_desktop_right(ObAction
**a
, ObUserAction uact
)
295 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
296 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
297 (*a
)->data
.desktopdir
.linear
= FALSE
;
298 (*a
)->data
.desktopdir
.wrap
= TRUE
;
301 void setup_action_desktop_up(ObAction
**a
, ObUserAction uact
)
303 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
304 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_NORTH
;
305 (*a
)->data
.desktopdir
.linear
= FALSE
;
306 (*a
)->data
.desktopdir
.wrap
= TRUE
;
309 void setup_action_desktop_down(ObAction
**a
, ObUserAction uact
)
311 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
312 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_SOUTH
;
313 (*a
)->data
.desktopdir
.linear
= FALSE
;
314 (*a
)->data
.desktopdir
.wrap
= TRUE
;
317 void setup_action_cycle_windows_next(ObAction
**a
, ObUserAction uact
)
319 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
320 (*a
)->data
.cycle
.linear
= FALSE
;
321 (*a
)->data
.cycle
.forward
= TRUE
;
322 (*a
)->data
.cycle
.dialog
= TRUE
;
323 (*a
)->data
.cycle
.dock_windows
= FALSE
;
324 (*a
)->data
.cycle
.desktop_windows
= FALSE
;
325 (*a
)->data
.cycle
.all_desktops
= FALSE
;
328 void setup_action_cycle_windows_previous(ObAction
**a
, ObUserAction uact
)
330 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
331 (*a
)->data
.cycle
.linear
= FALSE
;
332 (*a
)->data
.cycle
.forward
= FALSE
;
333 (*a
)->data
.cycle
.dialog
= TRUE
;
334 (*a
)->data
.cycle
.dock_windows
= FALSE
;
335 (*a
)->data
.cycle
.desktop_windows
= FALSE
;
336 (*a
)->data
.cycle
.all_desktops
= FALSE
;
339 void setup_action_movefromedge_north(ObAction
**a
, ObUserAction uact
)
341 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
342 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
343 (*a
)->data
.diraction
.hang
= TRUE
;
346 void setup_action_movefromedge_south(ObAction
**a
, ObUserAction uact
)
348 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
349 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
350 (*a
)->data
.diraction
.hang
= TRUE
;
353 void setup_action_movefromedge_east(ObAction
**a
, ObUserAction uact
)
355 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
356 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
357 (*a
)->data
.diraction
.hang
= TRUE
;
360 void setup_action_movefromedge_west(ObAction
**a
, ObUserAction uact
)
362 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
363 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
364 (*a
)->data
.diraction
.hang
= TRUE
;
367 void setup_action_movetoedge_north(ObAction
**a
, ObUserAction uact
)
369 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
370 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
371 (*a
)->data
.diraction
.hang
= FALSE
;
374 void setup_action_movetoedge_south(ObAction
**a
, ObUserAction uact
)
376 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
377 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
378 (*a
)->data
.diraction
.hang
= FALSE
;
381 void setup_action_movetoedge_east(ObAction
**a
, ObUserAction uact
)
383 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
384 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
385 (*a
)->data
.diraction
.hang
= FALSE
;
388 void setup_action_movetoedge_west(ObAction
**a
, ObUserAction uact
)
390 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
391 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
392 (*a
)->data
.diraction
.hang
= FALSE
;
395 void setup_action_growtoedge_north(ObAction
**a
, ObUserAction uact
)
397 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
398 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
401 void setup_action_growtoedge_south(ObAction
**a
, ObUserAction uact
)
403 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
404 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
407 void setup_action_growtoedge_east(ObAction
**a
, ObUserAction uact
)
409 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
410 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
413 void setup_action_growtoedge_west(ObAction
**a
, ObUserAction uact
)
415 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
416 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
419 void setup_action_top_layer(ObAction
**a
, ObUserAction uact
)
421 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
422 (*a
)->data
.layer
.layer
= 1;
425 void setup_action_normal_layer(ObAction
**a
, ObUserAction uact
)
427 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
428 (*a
)->data
.layer
.layer
= 0;
431 void setup_action_bottom_layer(ObAction
**a
, ObUserAction uact
)
433 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
434 (*a
)->data
.layer
.layer
= -1;
437 void setup_action_move(ObAction
**a
, ObUserAction uact
)
439 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
440 (*a
)->data
.moveresize
.keyboard
=
441 (uact
== OB_USER_ACTION_NONE
||
442 uact
== OB_USER_ACTION_KEYBOARD_KEY
||
443 uact
== OB_USER_ACTION_MENU_SELECTION
);
444 (*a
)->data
.moveresize
.corner
= 0;
447 void setup_action_resize(ObAction
**a
, ObUserAction uact
)
449 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
450 (*a
)->data
.moveresize
.keyboard
=
451 (uact
== OB_USER_ACTION_NONE
||
452 uact
== OB_USER_ACTION_KEYBOARD_KEY
||
453 uact
== OB_USER_ACTION_MENU_SELECTION
);
454 (*a
)->data
.moveresize
.corner
= 0;
457 void setup_action_showmenu(ObAction
**a
, ObUserAction uact
)
459 (*a
)->data
.showmenu
.any
.client_action
= OB_CLIENT_ACTION_OPTIONAL
;
460 /* you cannot call ShowMenu from inside a menu, cuz the menu code makes
461 assumptions that there is only one menu (and submenus) open at
463 if (uact
== OB_USER_ACTION_MENU_SELECTION
) {
469 void setup_action_focus(ObAction
**a
, ObUserAction uact
)
471 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_OPTIONAL
;
474 void setup_client_action(ObAction
**a
, ObUserAction uact
)
476 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
479 ActionString actionstrings
[] =
492 "directionalfocusnorth",
493 action_directional_focus
,
494 setup_action_directional_focus_north
497 "directionalfocuseast",
498 action_directional_focus
,
499 setup_action_directional_focus_east
502 "directionalfocussouth",
503 action_directional_focus
,
504 setup_action_directional_focus_south
507 "directionalfocuswest",
508 action_directional_focus
,
509 setup_action_directional_focus_west
512 "directionalfocusnortheast",
513 action_directional_focus
,
514 setup_action_directional_focus_northeast
517 "directionalfocussoutheast",
518 action_directional_focus
,
519 setup_action_directional_focus_southeast
522 "directionalfocussouthwest",
523 action_directional_focus
,
524 setup_action_directional_focus_southwest
527 "directionalfocusnorthwest",
528 action_directional_focus
,
529 setup_action_directional_focus_northwest
553 action_focus_order_to_bottom
,
608 action_toggle_omnipresent
,
613 action_move_relative_horz
,
618 action_move_relative_vert
,
623 action_move_to_center
,
627 "resizerelativehorz",
628 action_resize_relative_horz
,
632 "resizerelativevert",
633 action_resize_relative_vert
,
638 action_move_relative
,
643 action_resize_relative
,
648 action_maximize_full
,
653 action_unmaximize_full
,
657 "togglemaximizefull",
658 action_toggle_maximize_full
,
663 action_maximize_horz
,
668 action_unmaximize_horz
,
672 "togglemaximizehorz",
673 action_toggle_maximize_horz
,
678 action_maximize_vert
,
683 action_unmaximize_vert
,
687 "togglemaximizevert",
688 action_toggle_maximize_vert
,
693 action_toggle_fullscreen
,
698 action_send_to_desktop
,
699 setup_action_send_to_desktop
703 action_send_to_desktop_dir
,
704 setup_action_send_to_desktop_next
707 "sendtodesktopprevious",
708 action_send_to_desktop_dir
,
709 setup_action_send_to_desktop_prev
712 "sendtodesktopright",
713 action_send_to_desktop_dir
,
714 setup_action_send_to_desktop_right
718 action_send_to_desktop_dir
,
719 setup_action_send_to_desktop_left
723 action_send_to_desktop_dir
,
724 setup_action_send_to_desktop_up
728 action_send_to_desktop_dir
,
729 setup_action_send_to_desktop_down
739 setup_action_desktop_next
744 setup_action_desktop_prev
749 setup_action_desktop_right
754 setup_action_desktop_left
759 setup_action_desktop_up
764 setup_action_desktop_down
768 action_toggle_decorations
,
782 "toggledockautohide",
783 action_toggle_dockautohide
,
788 action_toggle_show_desktop
,
798 action_unshow_desktop
,
824 setup_action_showmenu
828 action_send_to_layer
,
829 setup_action_top_layer
834 setup_action_top_layer
838 action_send_to_layer
,
839 setup_action_normal_layer
843 action_send_to_layer
,
844 setup_action_bottom_layer
847 "togglealwaysonbottom",
849 setup_action_bottom_layer
853 action_cycle_windows
,
854 setup_action_cycle_windows_next
858 action_cycle_windows
,
859 setup_action_cycle_windows_previous
864 setup_action_movefromedge_north
869 setup_action_movefromedge_south
874 setup_action_movefromedge_west
879 setup_action_movefromedge_east
884 setup_action_movetoedge_north
889 setup_action_movetoedge_south
894 setup_action_movetoedge_west
899 setup_action_movetoedge_east
904 setup_action_growtoedge_north
909 setup_action_growtoedge_south
914 setup_action_growtoedge_west
919 setup_action_growtoedge_east
933 /* only key bindings can be interactive. thus saith the xor.
934 because of how the mouse is grabbed, mouse events dont even get
935 read during interactive events, so no dice! >:) */
936 #define INTERACTIVE_LIMIT(a, uact) \
937 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
938 a->data.any.interactive = FALSE;
940 ObAction
*action_from_string(const gchar
*name
, ObUserAction uact
)
943 gboolean exist
= FALSE
;
946 for (i
= 0; actionstrings
[i
].name
; i
++)
947 if (!g_ascii_strcasecmp(name
, actionstrings
[i
].name
)) {
949 a
= action_new(actionstrings
[i
].func
);
950 if (actionstrings
[i
].setup
)
951 actionstrings
[i
].setup(&a
, uact
);
953 INTERACTIVE_LIMIT(a
, uact
);
957 g_message(_("Invalid action '%s' requested. No such action exists."),
960 g_message(_("Invalid use of action '%s'. Action will be ignored."),
965 ObAction
*action_parse(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
969 ObAction
*act
= NULL
;
972 if (parse_attr_string("name", node
, &actname
)) {
973 if ((act
= action_from_string(actname
, uact
))) {
974 if (act
->func
== action_execute
|| act
->func
== action_restart
) {
975 if ((n
= parse_find_node("execute", node
->xmlChildrenNode
))) {
976 gchar
*s
= parse_string(doc
, n
);
977 act
->data
.execute
.path
= parse_expand_tilde(s
);
980 if ((n
= parse_find_node("startupnotify", node
->xmlChildrenNode
))) {
982 if ((m
= parse_find_node("enabled", n
->xmlChildrenNode
)))
983 act
->data
.execute
.startupnotify
= parse_bool(doc
, m
);
984 if ((m
= parse_find_node("name", n
->xmlChildrenNode
)))
985 act
->data
.execute
.name
= parse_string(doc
, m
);
986 if ((m
= parse_find_node("icon", n
->xmlChildrenNode
)))
987 act
->data
.execute
.icon_name
= parse_string(doc
, m
);
989 } else if (act
->func
== action_debug
) {
990 if ((n
= parse_find_node("string", node
->xmlChildrenNode
)))
991 act
->data
.debug
.string
= parse_string(doc
, n
);
992 } else if (act
->func
== action_showmenu
) {
993 if ((n
= parse_find_node("menu", node
->xmlChildrenNode
)))
994 act
->data
.showmenu
.name
= parse_string(doc
, n
);
995 } else if (act
->func
== action_move_relative_horz
||
996 act
->func
== action_move_relative_vert
||
997 act
->func
== action_resize_relative_horz
||
998 act
->func
== action_resize_relative_vert
) {
999 if ((n
= parse_find_node("delta", node
->xmlChildrenNode
)))
1000 act
->data
.relative
.deltax
= parse_int(doc
, n
);
1001 } else if (act
->func
== action_move_relative
) {
1002 if ((n
= parse_find_node("x", node
->xmlChildrenNode
)))
1003 act
->data
.relative
.deltax
= parse_int(doc
, n
);
1004 if ((n
= parse_find_node("y", node
->xmlChildrenNode
)))
1005 act
->data
.relative
.deltay
= parse_int(doc
, n
);
1006 } else if (act
->func
== action_resize_relative
) {
1007 if ((n
= parse_find_node("left", node
->xmlChildrenNode
)))
1008 act
->data
.relative
.deltaxl
= parse_int(doc
, n
);
1009 if ((n
= parse_find_node("up", node
->xmlChildrenNode
)))
1010 act
->data
.relative
.deltayu
= parse_int(doc
, n
);
1011 if ((n
= parse_find_node("right", node
->xmlChildrenNode
)))
1012 act
->data
.relative
.deltax
= parse_int(doc
, n
);
1013 if ((n
= parse_find_node("down", node
->xmlChildrenNode
)))
1014 act
->data
.relative
.deltay
= parse_int(doc
, n
);
1015 } else if (act
->func
== action_desktop
) {
1016 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1017 act
->data
.desktop
.desk
= parse_int(doc
, n
);
1018 if (act
->data
.desktop
.desk
> 0) act
->data
.desktop
.desk
--;
1020 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
1021 act->data.desktop.inter.any.interactive =
1024 } else if (act
->func
== action_send_to_desktop
) {
1025 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1026 act
->data
.sendto
.desk
= parse_int(doc
, n
);
1027 if (act
->data
.sendto
.desk
> 0) act
->data
.sendto
.desk
--;
1028 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
1029 act
->data
.sendto
.follow
= parse_bool(doc
, n
);
1030 } else if (act
->func
== action_desktop_dir
) {
1031 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
1032 act
->data
.desktopdir
.wrap
= parse_bool(doc
, n
);
1033 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1034 act
->data
.desktopdir
.inter
.any
.interactive
=
1036 } else if (act
->func
== action_send_to_desktop_dir
) {
1037 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
1038 act
->data
.sendtodir
.wrap
= parse_bool(doc
, n
);
1039 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
1040 act
->data
.sendtodir
.follow
= parse_bool(doc
, n
);
1041 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1042 act
->data
.sendtodir
.inter
.any
.interactive
=
1044 } else if (act
->func
== action_activate
) {
1045 if ((n
= parse_find_node("here", node
->xmlChildrenNode
)))
1046 act
->data
.activate
.here
= parse_bool(doc
, n
);
1047 } else if (act
->func
== action_cycle_windows
) {
1048 if ((n
= parse_find_node("linear", node
->xmlChildrenNode
)))
1049 act
->data
.cycle
.linear
= parse_bool(doc
, n
);
1050 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1051 act
->data
.cycle
.dialog
= parse_bool(doc
, n
);
1052 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
1053 act
->data
.cycle
.dock_windows
= parse_bool(doc
, n
);
1054 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1055 act
->data
.cycle
.desktop_windows
= parse_bool(doc
, n
);
1056 if ((n
= parse_find_node("allDesktops",
1057 node
->xmlChildrenNode
)))
1058 act
->data
.cycle
.all_desktops
= parse_bool(doc
, n
);
1059 } else if (act
->func
== action_directional_focus
) {
1060 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1061 act
->data
.interdiraction
.dialog
= parse_bool(doc
, n
);
1062 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
1063 act
->data
.interdiraction
.dock_windows
= parse_bool(doc
, n
);
1064 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1065 act
->data
.interdiraction
.desktop_windows
=
1067 } else if (act
->func
== action_resize
) {
1068 if ((n
= parse_find_node("edge", node
->xmlChildrenNode
))) {
1069 gchar
*s
= parse_string(doc
, n
);
1070 if (!g_ascii_strcasecmp(s
, "top"))
1071 act
->data
.moveresize
.corner
=
1072 prop_atoms
.net_wm_moveresize_size_top
;
1073 else if (!g_ascii_strcasecmp(s
, "bottom"))
1074 act
->data
.moveresize
.corner
=
1075 prop_atoms
.net_wm_moveresize_size_bottom
;
1076 else if (!g_ascii_strcasecmp(s
, "left"))
1077 act
->data
.moveresize
.corner
=
1078 prop_atoms
.net_wm_moveresize_size_left
;
1079 else if (!g_ascii_strcasecmp(s
, "right"))
1080 act
->data
.moveresize
.corner
=
1081 prop_atoms
.net_wm_moveresize_size_right
;
1082 else if (!g_ascii_strcasecmp(s
, "topleft"))
1083 act
->data
.moveresize
.corner
=
1084 prop_atoms
.net_wm_moveresize_size_topleft
;
1085 else if (!g_ascii_strcasecmp(s
, "topright"))
1086 act
->data
.moveresize
.corner
=
1087 prop_atoms
.net_wm_moveresize_size_topright
;
1088 else if (!g_ascii_strcasecmp(s
, "bottomleft"))
1089 act
->data
.moveresize
.corner
=
1090 prop_atoms
.net_wm_moveresize_size_bottomleft
;
1091 else if (!g_ascii_strcasecmp(s
, "bottomright"))
1092 act
->data
.moveresize
.corner
=
1093 prop_atoms
.net_wm_moveresize_size_bottomright
;
1096 } else if (act
->func
== action_raise
||
1097 act
->func
== action_lower
||
1098 act
->func
== action_raiselower
||
1099 act
->func
== action_shadelower
||
1100 act
->func
== action_unshaderaise
) {
1102 INTERACTIVE_LIMIT(act
, uact
);
1109 void action_run_list(GSList
*acts
, ObClient
*c
, ObFrameContext context
,
1110 guint state
, guint button
, gint x
, gint y
, Time time
,
1111 gboolean cancel
, gboolean done
)
1120 screen_pointer_pos(&x
, &y
);
1122 for (it
= acts
; it
; it
= g_slist_next(it
)) {
1125 if (!(a
->data
.any
.client_action
== OB_CLIENT_ACTION_ALWAYS
&& !c
)) {
1126 a
->data
.any
.c
= a
->data
.any
.client_action
? c
: NULL
;
1127 a
->data
.any
.context
= context
;
1131 a
->data
.any
.button
= button
;
1133 a
->data
.any
.time
= time
;
1135 if (a
->data
.any
.interactive
) {
1136 a
->data
.inter
.cancel
= cancel
;
1137 a
->data
.inter
.final
= done
;
1138 if (!(cancel
|| done
))
1139 if (!keyboard_interactive_grab(state
, a
->data
.any
.c
, a
))
1143 /* XXX UGLY HACK race with motion event starting a move and the
1144 button release gettnig processed first. answer: don't queue
1145 moveresize starts. UGLY HACK XXX
1147 XXX ALSO don't queue showmenu events, because on button press
1148 events we need to know if a mouse grab is going to take place,
1149 and set the button to 0, so that later motion events don't think
1150 that a drag is going on. since showmenu grabs the pointer..
1152 if (a
->data
.any
.interactive
|| a
->func
== action_move
||
1153 a
->func
== action_resize
|| a
->func
== action_showmenu
)
1155 /* interactive actions are not queued */
1157 } else if (a
->func
== action_focus
||
1158 a
->func
== action_activate
||
1159 a
->func
== action_showmenu
)
1161 /* XXX MORE UGLY HACK
1162 actions from clicks on client windows are NOT queued.
1163 this solves the mysterious click-and-drag-doesnt-work
1164 problem. it was because the window gets focused and stuff
1165 after the button event has already been passed through. i
1166 dont really know why it should care but it does and it makes
1169 however this very bogus ! !
1170 we want to send the button press to the window BEFORE
1171 we do the action because the action might move the windows
1172 (eg change desktops) and then the button press ends up on
1173 the completely wrong window !
1174 so, this is just for that bug, and it will only NOT queue it
1175 if it is a focusing action that can be used with the mouse
1178 also with the menus, there is a race going on. if the
1179 desktop wants to pop up a menu, and we do too, we send them
1180 the button before we pop up the menu, so they pop up their
1181 menu first. but not always. if we pop up our menu before
1182 sending them the button press, then the result is
1185 XXX further more. focus actions are not queued at all,
1186 because if you bind focus->showmenu, the menu will get
1187 hidden to do the focusing
1191 ob_main_loop_queue_action(ob_main_loop
, a
);
1196 void action_run_string(const gchar
*name
, struct _ObClient
*c
, Time time
)
1201 a
= action_from_string(name
, OB_USER_ACTION_NONE
);
1204 l
= g_slist_append(NULL
, a
);
1206 action_run(l
, c
, 0, time
);
1209 void action_debug(union ActionData
*data
)
1211 if (data
->debug
.string
)
1212 g_print("%s\n", data
->debug
.string
);
1215 void action_execute(union ActionData
*data
)
1218 gchar
*cmd
, **argv
= 0;
1219 if (data
->execute
.path
) {
1220 cmd
= g_filename_from_utf8(data
->execute
.path
, -1, NULL
, NULL
, NULL
);
1222 /* If there is a keyboard grab going on then we need to cancel
1223 it so the application can grab things */
1224 event_cancel_all_key_grabs();
1226 if (!g_shell_parse_argv (cmd
, NULL
, &argv
, &e
)) {
1227 g_message(_("Failed to execute '%s': %s"),
1230 } else if (data
->execute
.startupnotify
) {
1233 program
= g_path_get_basename(argv
[0]);
1234 /* sets up the environment */
1235 sn_setup_spawn_environment(program
,
1237 data
->execute
.icon_name
,
1238 /* launch it on the current
1241 data
->execute
.any
.time
);
1242 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
|
1243 G_SPAWN_DO_NOT_REAP_CHILD
,
1244 NULL
, NULL
, NULL
, &e
)) {
1245 g_message(_("Failed to execute '%s': %s"),
1250 unsetenv("DESKTOP_STARTUP_ID");
1254 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
|
1255 G_SPAWN_DO_NOT_REAP_CHILD
,
1256 NULL
, NULL
, NULL
, &e
))
1258 g_message(_("Failed to execute '%s': %s"),
1266 g_message(_("Failed to convert the path '%s' from utf8"),
1267 data
->execute
.path
);
1272 void action_activate(union ActionData
*data
)
1274 if (data
->client
.any
.c
) {
1275 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1276 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1277 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1279 /* if using focus_delay, stop the timer now so that focus doesn't
1281 event_halt_focus_delay();
1283 client_activate(data
->activate
.any
.c
, data
->activate
.here
, TRUE
);
1286 /* focus action on something other than a client, make keybindings
1287 work for this openbox instance, but don't focus any specific client
1293 void action_focus(union ActionData
*data
)
1295 if (data
->client
.any
.c
) {
1296 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1297 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1298 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1300 /* if using focus_delay, stop the timer now so that focus doesn't
1302 event_halt_focus_delay();
1304 client_focus(data
->client
.any
.c
);
1307 /* focus action on something other than a client, make keybindings
1308 work for this openbox instance, but don't focus any specific client
1314 void action_unfocus (union ActionData
*data
)
1316 if (data
->client
.any
.c
== focus_client
)
1317 focus_fallback(FALSE
, FALSE
, TRUE
);
1320 void action_iconify(union ActionData
*data
)
1322 client_action_start(data
);
1323 client_iconify(data
->client
.any
.c
, TRUE
, TRUE
, FALSE
);
1324 client_action_end(data
, config_focus_under_mouse
);
1327 void action_focus_order_to_bottom(union ActionData
*data
)
1329 focus_order_to_bottom(data
->client
.any
.c
);
1332 void action_raiselower(union ActionData
*data
)
1334 ObClient
*c
= data
->client
.any
.c
;
1336 client_action_start(data
);
1337 stacking_restack_request(c
, NULL
, Opposite
, FALSE
);
1338 client_action_end(data
, config_focus_under_mouse
);
1341 void action_raise(union ActionData
*data
)
1343 client_action_start(data
);
1344 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1345 client_action_end(data
, config_focus_under_mouse
);
1348 void action_unshaderaise(union ActionData
*data
)
1350 if (data
->client
.any
.c
->shaded
)
1351 action_unshade(data
);
1356 void action_shadelower(union ActionData
*data
)
1358 if (data
->client
.any
.c
->shaded
)
1364 void action_lower(union ActionData
*data
)
1366 client_action_start(data
);
1367 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1368 client_action_end(data
, config_focus_under_mouse
);
1371 void action_close(union ActionData
*data
)
1373 client_close(data
->client
.any
.c
);
1376 void action_kill(union ActionData
*data
)
1378 client_kill(data
->client
.any
.c
);
1381 void action_shade(union ActionData
*data
)
1383 client_action_start(data
);
1384 client_shade(data
->client
.any
.c
, TRUE
);
1385 client_action_end(data
, config_focus_under_mouse
);
1388 void action_unshade(union ActionData
*data
)
1390 client_action_start(data
);
1391 client_shade(data
->client
.any
.c
, FALSE
);
1392 client_action_end(data
, config_focus_under_mouse
);
1395 void action_toggle_shade(union ActionData
*data
)
1397 client_action_start(data
);
1398 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1399 client_action_end(data
, config_focus_under_mouse
);
1402 void action_toggle_omnipresent(union ActionData
*data
)
1404 client_set_desktop(data
->client
.any
.c
,
1405 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1406 screen_desktop
: DESKTOP_ALL
, FALSE
);
1409 void action_move_relative_horz(union ActionData
*data
)
1411 ObClient
*c
= data
->relative
.any
.c
;
1412 client_action_start(data
);
1413 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
);
1414 client_action_end(data
, FALSE
);
1417 void action_move_relative_vert(union ActionData
*data
)
1419 ObClient
*c
= data
->relative
.any
.c
;
1420 client_action_start(data
);
1421 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.deltax
);
1422 client_action_end(data
, FALSE
);
1425 void action_move_to_center(union ActionData
*data
)
1427 ObClient
*c
= data
->client
.any
.c
;
1429 area
= screen_area_monitor(c
->desktop
, 0);
1430 client_action_start(data
);
1431 client_move(c
, area
->width
/ 2 - c
->area
.width
/ 2,
1432 area
->height
/ 2 - c
->area
.height
/ 2);
1433 client_action_end(data
, FALSE
);
1436 void action_resize_relative_horz(union ActionData
*data
)
1438 ObClient
*c
= data
->relative
.any
.c
;
1439 client_action_start(data
);
1441 c
->area
.width
+ data
->relative
.deltax
* c
->size_inc
.width
,
1443 client_action_end(data
, FALSE
);
1446 void action_resize_relative_vert(union ActionData
*data
)
1448 ObClient
*c
= data
->relative
.any
.c
;
1450 client_action_start(data
);
1451 client_resize(c
, c
->area
.width
, c
->area
.height
+
1452 data
->relative
.deltax
* c
->size_inc
.height
);
1453 client_action_end(data
, FALSE
);
1457 void action_move_relative(union ActionData
*data
)
1459 ObClient
*c
= data
->relative
.any
.c
;
1460 client_action_start(data
);
1461 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
+
1462 data
->relative
.deltay
);
1463 client_action_end(data
, FALSE
);
1466 void action_resize_relative(union ActionData
*data
)
1468 ObClient
*c
= data
->relative
.any
.c
;
1469 gint x
, y
, ow
, w
, oh
, h
, lw
, lh
;
1471 client_action_start(data
);
1476 w
= ow
+ data
->relative
.deltax
* c
->size_inc
.width
1477 + data
->relative
.deltaxl
* c
->size_inc
.width
;
1478 oh
= c
->area
.height
;
1479 h
= oh
+ data
->relative
.deltay
* c
->size_inc
.height
1480 + data
->relative
.deltayu
* c
->size_inc
.height
;
1482 client_try_configure(c
, &x
, &y
, &w
, &h
, &lw
, &lh
, TRUE
);
1483 client_move_resize(c
, x
+ (ow
- w
), y
+ (oh
- h
), w
, h
);
1484 client_action_end(data
, FALSE
);
1487 void action_maximize_full(union ActionData
*data
)
1489 client_action_start(data
);
1490 client_maximize(data
->client
.any
.c
, TRUE
, 0);
1491 client_action_end(data
, config_focus_under_mouse
);
1494 void action_unmaximize_full(union ActionData
*data
)
1496 client_action_start(data
);
1497 client_maximize(data
->client
.any
.c
, FALSE
, 0);
1498 client_action_end(data
, config_focus_under_mouse
);
1501 void action_toggle_maximize_full(union ActionData
*data
)
1503 client_action_start(data
);
1504 client_maximize(data
->client
.any
.c
,
1505 !(data
->client
.any
.c
->max_horz
||
1506 data
->client
.any
.c
->max_vert
),
1508 client_action_end(data
, config_focus_under_mouse
);
1511 void action_maximize_horz(union ActionData
*data
)
1513 client_action_start(data
);
1514 client_maximize(data
->client
.any
.c
, TRUE
, 1);
1515 client_action_end(data
, config_focus_under_mouse
);
1518 void action_unmaximize_horz(union ActionData
*data
)
1520 client_action_start(data
);
1521 client_maximize(data
->client
.any
.c
, FALSE
, 1);
1522 client_action_end(data
, config_focus_under_mouse
);
1525 void action_toggle_maximize_horz(union ActionData
*data
)
1527 client_action_start(data
);
1528 client_maximize(data
->client
.any
.c
,
1529 !data
->client
.any
.c
->max_horz
, 1);
1530 client_action_end(data
, config_focus_under_mouse
);
1533 void action_maximize_vert(union ActionData
*data
)
1535 client_action_start(data
);
1536 client_maximize(data
->client
.any
.c
, TRUE
, 2);
1537 client_action_end(data
, config_focus_under_mouse
);
1540 void action_unmaximize_vert(union ActionData
*data
)
1542 client_action_start(data
);
1543 client_maximize(data
->client
.any
.c
, FALSE
, 2);
1544 client_action_end(data
, config_focus_under_mouse
);
1547 void action_toggle_maximize_vert(union ActionData
*data
)
1549 client_action_start(data
);
1550 client_maximize(data
->client
.any
.c
,
1551 !data
->client
.any
.c
->max_vert
, 2);
1552 client_action_end(data
, config_focus_under_mouse
);
1555 void action_toggle_fullscreen(union ActionData
*data
)
1557 client_action_start(data
);
1558 client_fullscreen(data
->client
.any
.c
, !(data
->client
.any
.c
->fullscreen
));
1559 client_action_end(data
, config_focus_under_mouse
);
1562 void action_send_to_desktop(union ActionData
*data
)
1564 ObClient
*c
= data
->sendto
.any
.c
;
1566 if (!client_normal(c
)) return;
1568 if (data
->sendto
.desk
< screen_num_desktops
||
1569 data
->sendto
.desk
== DESKTOP_ALL
) {
1570 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
);
1571 if (data
->sendto
.follow
&& data
->sendto
.desk
!= screen_desktop
)
1572 screen_set_desktop(data
->sendto
.desk
, TRUE
);
1576 void action_desktop(union ActionData
*data
)
1578 /* XXX add the interactive/dialog option back again once the dialog
1579 has been made to not use grabs */
1580 if (data
->desktop
.desk
< screen_num_desktops
||
1581 data
->desktop
.desk
== DESKTOP_ALL
)
1583 screen_set_desktop(data
->desktop
.desk
, TRUE
);
1584 if (data
->inter
.any
.interactive
)
1585 screen_desktop_popup(data
->desktop
.desk
, TRUE
);
1589 void action_desktop_dir(union ActionData
*data
)
1593 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1594 data
->desktopdir
.wrap
,
1595 data
->desktopdir
.linear
,
1596 data
->desktopdir
.inter
.any
.interactive
,
1597 data
->desktopdir
.inter
.final
,
1598 data
->desktopdir
.inter
.cancel
);
1599 /* only move the desktop when the action is complete. if we switch
1600 desktops during the interactive action, focus will move but with
1601 NotifyWhileGrabbed and applications don't like that. */
1602 if (!data
->sendtodir
.inter
.any
.interactive
||
1603 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1605 if (d
!= screen_desktop
)
1606 screen_set_desktop(d
, TRUE
);
1610 void action_send_to_desktop_dir(union ActionData
*data
)
1612 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1615 if (!client_normal(c
)) return;
1617 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1618 data
->sendtodir
.linear
,
1619 data
->sendtodir
.inter
.any
.interactive
,
1620 data
->sendtodir
.inter
.final
,
1621 data
->sendtodir
.inter
.cancel
);
1622 /* only move the desktop when the action is complete. if we switch
1623 desktops during the interactive action, focus will move but with
1624 NotifyWhileGrabbed and applications don't like that. */
1625 if (!data
->sendtodir
.inter
.any
.interactive
||
1626 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1628 client_set_desktop(c
, d
, data
->sendtodir
.follow
);
1629 if (data
->sendtodir
.follow
&& d
!= screen_desktop
)
1630 screen_set_desktop(d
, TRUE
);
1634 void action_desktop_last(union ActionData
*data
)
1636 screen_set_desktop(screen_last_desktop
, TRUE
);
1639 void action_toggle_decorations(union ActionData
*data
)
1641 ObClient
*c
= data
->client
.any
.c
;
1643 client_action_start(data
);
1644 client_set_undecorated(c
, !c
->undecorated
);
1645 client_action_end(data
, FALSE
);
1648 static guint32
pick_corner(gint x
, gint y
, gint cx
, gint cy
, gint cw
, gint ch
,
1651 /* let's make x and y client relative instead of screen relative */
1653 y
= ch
- (y
- cy
); /* y is inverted, 0 is at the bottom of the window */
1656 #define A -4*X + 7*ch/3
1657 #define B 4*X -15*ch/9
1658 #define C -X/4 + 2*ch/3
1659 #define D X/4 + 5*ch/12
1660 #define E X/4 + ch/3
1661 #define F -X/4 + 7*ch/12
1662 #define G 4*X - 4*ch/3
1663 #define H -4*X + 8*ch/3
1664 #define a (y > 5*ch/9)
1665 #define b (x < 4*cw/9)
1666 #define c (x > 5*cw/9)
1667 #define d (y < 4*ch/9)
1670 Each of these defines (except X which is just there for fun), represents
1671 the equation of a line. The lines they represent are shown in the diagram
1672 below. Checking y against these lines, we are able to choose a region
1673 of the window as shown.
1675 +---------------------A-------|-------|-------B---------------------+
1682 | northwest | A north B | northeast |
1685 C---------------------+----A--+-------+--B----+---------------------D
1686 |CCCCCCC | A B | DDDDDDD|
1687 | CCCCCCCC | A | | B | DDDDDDDD |
1688 | CCCCCCC A B DDDDDDD |
1689 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
1691 | west | b move c | east | ad
1693 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
1694 | EEEEEEE G H FFFFFFF |
1695 | EEEEEEEE | G | | H | FFFFFFFF |
1696 |EEEEEEE | G H | FFFFFFF|
1697 E---------------------+----G--+-------+--H----+---------------------F
1700 | southwest | G south H | southeast |
1707 +---------------------G-------|-------|-------H---------------------+
1711 /* for shaded windows, you can only resize west/east and move */
1713 return prop_atoms
.net_wm_moveresize_size_left
;
1715 return prop_atoms
.net_wm_moveresize_size_right
;
1716 return prop_atoms
.net_wm_moveresize_move
;
1719 if (y
< A
&& y
>= C
)
1720 return prop_atoms
.net_wm_moveresize_size_topleft
;
1721 else if (y
>= A
&& y
>= B
&& a
)
1722 return prop_atoms
.net_wm_moveresize_size_top
;
1723 else if (y
< B
&& y
>= D
)
1724 return prop_atoms
.net_wm_moveresize_size_topright
;
1725 else if (y
< C
&& y
>= E
&& b
)
1726 return prop_atoms
.net_wm_moveresize_size_left
;
1727 else if (y
< D
&& y
>= F
&& c
)
1728 return prop_atoms
.net_wm_moveresize_size_right
;
1729 else if (y
< E
&& y
>= G
)
1730 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1731 else if (y
< G
&& y
< H
&& d
)
1732 return prop_atoms
.net_wm_moveresize_size_bottom
;
1733 else if (y
>= H
&& y
< F
)
1734 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1736 return prop_atoms
.net_wm_moveresize_move
;
1753 void action_move(union ActionData
*data
)
1755 ObClient
*c
= data
->moveresize
.any
.c
;
1758 if (data
->moveresize
.keyboard
)
1759 corner
= prop_atoms
.net_wm_moveresize_move_keyboard
;
1761 corner
= prop_atoms
.net_wm_moveresize_move
;
1763 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1766 void action_resize(union ActionData
*data
)
1768 ObClient
*c
= data
->moveresize
.any
.c
;
1771 if (data
->moveresize
.keyboard
)
1772 corner
= prop_atoms
.net_wm_moveresize_size_keyboard
;
1773 else if (data
->moveresize
.corner
)
1774 corner
= data
->moveresize
.corner
; /* it was specified in the binding */
1776 corner
= pick_corner(data
->any
.x
, data
->any
.y
,
1777 c
->frame
->area
.x
, c
->frame
->area
.y
,
1778 /* use the client size because the frame
1779 can be differently sized (shaded
1780 windows) and we want this based on the
1782 c
->area
.width
+ c
->frame
->size
.left
+
1783 c
->frame
->size
.right
,
1784 c
->area
.height
+ c
->frame
->size
.top
+
1785 c
->frame
->size
.bottom
, c
->shaded
);
1787 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1790 void action_reconfigure(union ActionData
*data
)
1795 void action_restart(union ActionData
*data
)
1797 ob_restart_other(data
->execute
.path
);
1800 void action_exit(union ActionData
*data
)
1805 void action_showmenu(union ActionData
*data
)
1807 if (data
->showmenu
.name
) {
1808 menu_show(data
->showmenu
.name
, data
->any
.x
, data
->any
.y
,
1809 data
->any
.button
, data
->showmenu
.any
.c
);
1813 void action_cycle_windows(union ActionData
*data
)
1815 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1817 event_halt_focus_delay();
1819 focus_cycle(data
->cycle
.forward
,
1820 data
->cycle
.all_desktops
,
1821 data
->cycle
.dock_windows
,
1822 data
->cycle
.desktop_windows
,
1823 data
->cycle
.linear
, data
->any
.interactive
,
1825 data
->cycle
.inter
.final
, data
->cycle
.inter
.cancel
);
1828 void action_directional_focus(union ActionData
*data
)
1830 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1832 event_halt_focus_delay();
1834 focus_directional_cycle(data
->interdiraction
.direction
,
1835 data
->interdiraction
.dock_windows
,
1836 data
->interdiraction
.desktop_windows
,
1837 data
->any
.interactive
,
1838 data
->interdiraction
.dialog
,
1839 data
->interdiraction
.inter
.final
,
1840 data
->interdiraction
.inter
.cancel
);
1843 void action_movetoedge(union ActionData
*data
)
1846 ObClient
*c
= data
->diraction
.any
.c
;
1848 x
= c
->frame
->area
.x
;
1849 y
= c
->frame
->area
.y
;
1851 switch(data
->diraction
.direction
) {
1852 case OB_DIRECTION_NORTH
:
1853 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
,
1854 data
->diraction
.hang
)
1855 - (data
->diraction
.hang
? c
->frame
->area
.height
: 0);
1857 case OB_DIRECTION_WEST
:
1858 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
,
1859 data
->diraction
.hang
)
1860 - (data
->diraction
.hang
? c
->frame
->area
.width
: 0);
1862 case OB_DIRECTION_SOUTH
:
1863 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
,
1864 data
->diraction
.hang
)
1865 - (data
->diraction
.hang
? 0 : c
->frame
->area
.height
);
1867 case OB_DIRECTION_EAST
:
1868 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
,
1869 data
->diraction
.hang
)
1870 - (data
->diraction
.hang
? 0 : c
->frame
->area
.width
);
1873 g_assert_not_reached();
1875 frame_frame_gravity(c
->frame
, &x
, &y
, c
->area
.width
, c
->area
.height
);
1876 client_action_start(data
);
1877 client_move(c
, x
, y
);
1878 client_action_end(data
, FALSE
);
1881 void action_growtoedge(union ActionData
*data
)
1883 gint x
, y
, width
, height
, dest
;
1884 ObClient
*c
= data
->diraction
.any
.c
;
1887 a
= screen_area(c
->desktop
);
1888 x
= c
->frame
->area
.x
;
1889 y
= c
->frame
->area
.y
;
1890 /* get the unshaded frame's dimensions..if it is shaded */
1891 width
= c
->area
.width
+ c
->frame
->size
.left
+ c
->frame
->size
.right
;
1892 height
= c
->area
.height
+ c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1894 switch(data
->diraction
.direction
) {
1895 case OB_DIRECTION_NORTH
:
1896 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1898 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
, FALSE
);
1900 height
= height
/ 2;
1902 height
= c
->frame
->area
.y
+ height
- dest
;
1906 case OB_DIRECTION_WEST
:
1907 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
, FALSE
);
1911 width
= c
->frame
->area
.x
+ width
- dest
;
1915 case OB_DIRECTION_SOUTH
:
1916 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1918 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
, FALSE
);
1919 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1920 height
= c
->frame
->area
.height
/ 2;
1921 y
= a
->y
+ a
->height
- height
;
1923 height
= dest
- c
->frame
->area
.y
;
1924 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1925 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1927 case OB_DIRECTION_EAST
:
1928 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
, FALSE
);
1929 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1930 width
= c
->frame
->area
.width
/ 2;
1931 x
= a
->x
+ a
->width
- width
;
1933 width
= dest
- c
->frame
->area
.x
;
1934 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1935 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1938 g_assert_not_reached();
1940 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1941 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1942 frame_frame_gravity(c
->frame
, &x
, &y
, width
, height
);
1943 client_action_start(data
);
1944 client_move_resize(c
, x
, y
, width
, height
);
1945 client_action_end(data
, FALSE
);
1948 void action_send_to_layer(union ActionData
*data
)
1950 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1953 void action_toggle_layer(union ActionData
*data
)
1955 ObClient
*c
= data
->layer
.any
.c
;
1957 client_action_start(data
);
1958 if (data
->layer
.layer
< 0)
1959 client_set_layer(c
, c
->below
? 0 : -1);
1960 else if (data
->layer
.layer
> 0)
1961 client_set_layer(c
, c
->above
? 0 : 1);
1962 client_action_end(data
, config_focus_under_mouse
);
1965 void action_toggle_dockautohide(union ActionData
*data
)
1967 config_dock_hide
= !config_dock_hide
;
1971 void action_toggle_show_desktop(union ActionData
*data
)
1973 screen_show_desktop(!screen_showing_desktop
, NULL
);
1976 void action_show_desktop(union ActionData
*data
)
1978 screen_show_desktop(TRUE
, NULL
);
1981 void action_unshow_desktop(union ActionData
*data
)
1983 screen_show_desktop(FALSE
, NULL
);
1986 void action_break_chroot(union ActionData
*data
)
1988 /* break out of one chroot */
1989 keyboard_reset_chains(1);