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_movefromedge_north(ObAction
**a
, ObUserAction uact
)
323 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
324 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
325 (*a
)->data
.diraction
.hang
= TRUE
;
328 void setup_action_movefromedge_south(ObAction
**a
, ObUserAction uact
)
330 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
331 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
332 (*a
)->data
.diraction
.hang
= TRUE
;
335 void setup_action_movefromedge_east(ObAction
**a
, ObUserAction uact
)
337 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
338 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
339 (*a
)->data
.diraction
.hang
= TRUE
;
342 void setup_action_movefromedge_west(ObAction
**a
, ObUserAction uact
)
344 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
345 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
346 (*a
)->data
.diraction
.hang
= TRUE
;
349 void setup_action_movetoedge_north(ObAction
**a
, ObUserAction uact
)
351 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
352 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
353 (*a
)->data
.diraction
.hang
= FALSE
;
356 void setup_action_movetoedge_south(ObAction
**a
, ObUserAction uact
)
358 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
359 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
360 (*a
)->data
.diraction
.hang
= FALSE
;
363 void setup_action_movetoedge_east(ObAction
**a
, ObUserAction uact
)
365 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
366 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
367 (*a
)->data
.diraction
.hang
= FALSE
;
370 void setup_action_movetoedge_west(ObAction
**a
, ObUserAction uact
)
372 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
373 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
374 (*a
)->data
.diraction
.hang
= FALSE
;
377 void setup_action_growtoedge_north(ObAction
**a
, ObUserAction uact
)
379 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
380 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
383 void setup_action_growtoedge_south(ObAction
**a
, ObUserAction uact
)
385 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
386 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
389 void setup_action_growtoedge_east(ObAction
**a
, ObUserAction uact
)
391 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
392 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
395 void setup_action_growtoedge_west(ObAction
**a
, ObUserAction uact
)
397 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
398 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
401 void setup_action_top_layer(ObAction
**a
, ObUserAction uact
)
403 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
404 (*a
)->data
.layer
.layer
= 1;
407 void setup_action_normal_layer(ObAction
**a
, ObUserAction uact
)
409 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
410 (*a
)->data
.layer
.layer
= 0;
413 void setup_action_bottom_layer(ObAction
**a
, ObUserAction uact
)
415 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
416 (*a
)->data
.layer
.layer
= -1;
419 void setup_action_move(ObAction
**a
, ObUserAction uact
)
421 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
422 (*a
)->data
.moveresize
.keyboard
=
423 (uact
== OB_USER_ACTION_NONE
||
424 uact
== OB_USER_ACTION_KEYBOARD_KEY
||
425 uact
== OB_USER_ACTION_MENU_SELECTION
);
426 (*a
)->data
.moveresize
.corner
= 0;
429 void setup_action_resize(ObAction
**a
, ObUserAction uact
)
431 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
432 (*a
)->data
.moveresize
.keyboard
=
433 (uact
== OB_USER_ACTION_NONE
||
434 uact
== OB_USER_ACTION_KEYBOARD_KEY
||
435 uact
== OB_USER_ACTION_MENU_SELECTION
);
436 (*a
)->data
.moveresize
.corner
= 0;
439 void setup_action_addremove_desktop_current(ObAction
**a
, ObUserAction uact
)
441 (*a
)->data
.addremovedesktop
.current
= TRUE
;
444 void setup_action_addremove_desktop_last(ObAction
**a
, ObUserAction uact
)
446 (*a
)->data
.addremovedesktop
.current
= FALSE
;
449 void setup_action_focus(ObAction
**a
, ObUserAction uact
)
451 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_OPTIONAL
;
454 void setup_client_action(ObAction
**a
, ObUserAction uact
)
456 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
459 ActionString actionstrings
[] =
462 "directionalfocusnorth",
463 action_directional_focus
,
464 setup_action_directional_focus_north
467 "directionalfocuseast",
468 action_directional_focus
,
469 setup_action_directional_focus_east
472 "directionalfocussouth",
473 action_directional_focus
,
474 setup_action_directional_focus_south
477 "directionalfocuswest",
478 action_directional_focus
,
479 setup_action_directional_focus_west
482 "directionalfocusnortheast",
483 action_directional_focus
,
484 setup_action_directional_focus_northeast
487 "directionalfocussoutheast",
488 action_directional_focus
,
489 setup_action_directional_focus_southeast
492 "directionalfocussouthwest",
493 action_directional_focus
,
494 setup_action_directional_focus_southwest
497 "directionalfocusnorthwest",
498 action_directional_focus
,
499 setup_action_directional_focus_northwest
518 action_focus_order_to_bottom
,
573 action_toggle_omnipresent
,
578 action_move_relative_horz
,
583 action_move_relative_vert
,
588 action_move_to_center
,
592 "resizerelativehorz",
593 action_resize_relative_horz
,
597 "resizerelativevert",
598 action_resize_relative_vert
,
603 action_move_relative
,
608 action_resize_relative
,
613 action_maximize_full
,
618 action_unmaximize_full
,
622 "togglemaximizefull",
623 action_toggle_maximize_full
,
628 action_maximize_horz
,
633 action_unmaximize_horz
,
637 "togglemaximizehorz",
638 action_toggle_maximize_horz
,
643 action_maximize_vert
,
648 action_unmaximize_vert
,
652 "togglemaximizevert",
653 action_toggle_maximize_vert
,
658 action_toggle_fullscreen
,
663 action_send_to_desktop
,
664 setup_action_send_to_desktop
668 action_send_to_desktop_dir
,
669 setup_action_send_to_desktop_next
672 "sendtodesktopprevious",
673 action_send_to_desktop_dir
,
674 setup_action_send_to_desktop_prev
677 "sendtodesktopright",
678 action_send_to_desktop_dir
,
679 setup_action_send_to_desktop_right
683 action_send_to_desktop_dir
,
684 setup_action_send_to_desktop_left
688 action_send_to_desktop_dir
,
689 setup_action_send_to_desktop_up
693 action_send_to_desktop_dir
,
694 setup_action_send_to_desktop_down
704 setup_action_desktop_next
709 setup_action_desktop_prev
714 setup_action_desktop_right
719 setup_action_desktop_left
724 setup_action_desktop_up
729 setup_action_desktop_down
733 action_toggle_decorations
,
747 "toggledockautohide",
748 action_toggle_dockautohide
,
758 action_send_to_layer
,
759 setup_action_top_layer
764 setup_action_top_layer
768 action_send_to_layer
,
769 setup_action_normal_layer
773 action_send_to_layer
,
774 setup_action_bottom_layer
777 "togglealwaysonbottom",
779 setup_action_bottom_layer
784 setup_action_movefromedge_north
789 setup_action_movefromedge_south
794 setup_action_movefromedge_west
799 setup_action_movefromedge_east
804 setup_action_movetoedge_north
809 setup_action_movetoedge_south
814 setup_action_movetoedge_west
819 setup_action_movetoedge_east
824 setup_action_growtoedge_north
829 setup_action_growtoedge_south
834 setup_action_growtoedge_west
839 setup_action_growtoedge_east
849 setup_action_addremove_desktop_last
853 action_remove_desktop
,
854 setup_action_addremove_desktop_last
859 setup_action_addremove_desktop_current
862 "removedesktopcurrent",
863 action_remove_desktop
,
864 setup_action_addremove_desktop_current
873 /* only key bindings can be interactive. thus saith the xor.
874 because of how the mouse is grabbed, mouse events dont even get
875 read during interactive events, so no dice! >:) */
876 #define INTERACTIVE_LIMIT(a, uact) \
877 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
878 a->data.any.interactive = FALSE;
880 ObAction
*action_from_string(const gchar
*name
, ObUserAction uact
)
883 gboolean exist
= FALSE
;
886 for (i
= 0; actionstrings
[i
].name
; i
++)
887 if (!g_ascii_strcasecmp(name
, actionstrings
[i
].name
)) {
889 a
= action_new(actionstrings
[i
].func
);
890 if (actionstrings
[i
].setup
)
891 actionstrings
[i
].setup(&a
, uact
);
893 INTERACTIVE_LIMIT(a
, uact
);
897 g_message(_("Invalid action '%s' requested. No such action exists."),
900 g_message(_("Invalid use of action '%s'. Action will be ignored."),
905 ObAction
*action_parse(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
909 ObAction
*act
= NULL
;
912 if (parse_attr_string("name", node
, &actname
)) {
913 if ((act
= action_from_string(actname
, uact
))) {
914 } else if (act
->func
== action_move_relative_horz
||
915 act
->func
== action_move_relative_vert
||
916 act
->func
== action_resize_relative_horz
||
917 act
->func
== action_resize_relative_vert
) {
918 if ((n
= parse_find_node("delta", node
->xmlChildrenNode
)))
919 act
->data
.relative
.deltax
= parse_int(doc
, n
);
920 } else if (act
->func
== action_move_relative
) {
921 if ((n
= parse_find_node("x", node
->xmlChildrenNode
)))
922 act
->data
.relative
.deltax
= parse_int(doc
, n
);
923 if ((n
= parse_find_node("y", node
->xmlChildrenNode
)))
924 act
->data
.relative
.deltay
= parse_int(doc
, n
);
925 } else if (act
->func
== action_resize_relative
) {
926 if ((n
= parse_find_node("left", node
->xmlChildrenNode
)))
927 act
->data
.relative
.deltaxl
= parse_int(doc
, n
);
928 if ((n
= parse_find_node("up", node
->xmlChildrenNode
)))
929 act
->data
.relative
.deltayu
= parse_int(doc
, n
);
930 if ((n
= parse_find_node("right", node
->xmlChildrenNode
)))
931 act
->data
.relative
.deltax
= parse_int(doc
, n
);
932 if ((n
= parse_find_node("down", node
->xmlChildrenNode
)))
933 act
->data
.relative
.deltay
= parse_int(doc
, n
);
934 } else if (act
->func
== action_desktop
) {
935 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
936 act
->data
.desktop
.desk
= parse_int(doc
, n
);
937 if (act
->data
.desktop
.desk
> 0) act
->data
.desktop
.desk
--;
939 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
940 act->data.desktop.inter.any.interactive =
943 } else if (act
->func
== action_send_to_desktop
) {
944 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
945 act
->data
.sendto
.desk
= parse_int(doc
, n
);
946 if (act
->data
.sendto
.desk
> 0) act
->data
.sendto
.desk
--;
947 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
948 act
->data
.sendto
.follow
= parse_bool(doc
, n
);
949 } else if (act
->func
== action_desktop_dir
) {
950 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
951 act
->data
.desktopdir
.wrap
= parse_bool(doc
, n
);
952 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
953 act
->data
.desktopdir
.inter
.any
.interactive
=
955 } else if (act
->func
== action_send_to_desktop_dir
) {
956 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
957 act
->data
.sendtodir
.wrap
= parse_bool(doc
, n
);
958 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
959 act
->data
.sendtodir
.follow
= parse_bool(doc
, n
);
960 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
961 act
->data
.sendtodir
.inter
.any
.interactive
=
963 } else if (act
->func
== action_directional_focus
) {
964 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
965 act
->data
.interdiraction
.dialog
= parse_bool(doc
, n
);
966 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
967 act
->data
.interdiraction
.dock_windows
= parse_bool(doc
, n
);
968 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
969 act
->data
.interdiraction
.desktop_windows
=
971 } else if (act
->func
== action_resize
) {
972 if ((n
= parse_find_node("edge", node
->xmlChildrenNode
))) {
973 gchar
*s
= parse_string(doc
, n
);
974 if (!g_ascii_strcasecmp(s
, "top"))
975 act
->data
.moveresize
.corner
=
976 prop_atoms
.net_wm_moveresize_size_top
;
977 else if (!g_ascii_strcasecmp(s
, "bottom"))
978 act
->data
.moveresize
.corner
=
979 prop_atoms
.net_wm_moveresize_size_bottom
;
980 else if (!g_ascii_strcasecmp(s
, "left"))
981 act
->data
.moveresize
.corner
=
982 prop_atoms
.net_wm_moveresize_size_left
;
983 else if (!g_ascii_strcasecmp(s
, "right"))
984 act
->data
.moveresize
.corner
=
985 prop_atoms
.net_wm_moveresize_size_right
;
986 else if (!g_ascii_strcasecmp(s
, "topleft"))
987 act
->data
.moveresize
.corner
=
988 prop_atoms
.net_wm_moveresize_size_topleft
;
989 else if (!g_ascii_strcasecmp(s
, "topright"))
990 act
->data
.moveresize
.corner
=
991 prop_atoms
.net_wm_moveresize_size_topright
;
992 else if (!g_ascii_strcasecmp(s
, "bottomleft"))
993 act
->data
.moveresize
.corner
=
994 prop_atoms
.net_wm_moveresize_size_bottomleft
;
995 else if (!g_ascii_strcasecmp(s
, "bottomright"))
996 act
->data
.moveresize
.corner
=
997 prop_atoms
.net_wm_moveresize_size_bottomright
;
1000 } else if (act
->func
== action_raise
||
1001 act
->func
== action_lower
||
1002 act
->func
== action_raiselower
||
1003 act
->func
== action_shadelower
||
1004 act
->func
== action_unshaderaise
) {
1006 INTERACTIVE_LIMIT(act
, uact
);
1013 void action_run_list(GSList
*acts
, ObClient
*c
, ObFrameContext context
,
1014 guint state
, guint button
, gint x
, gint y
, Time time
,
1015 gboolean cancel
, gboolean done
)
1024 screen_pointer_pos(&x
, &y
);
1026 for (it
= acts
; it
; it
= g_slist_next(it
)) {
1029 if (!(a
->data
.any
.client_action
== OB_CLIENT_ACTION_ALWAYS
&& !c
)) {
1030 a
->data
.any
.c
= a
->data
.any
.client_action
? c
: NULL
;
1031 a
->data
.any
.context
= context
;
1035 a
->data
.any
.button
= button
;
1037 a
->data
.any
.time
= time
;
1039 if (a
->data
.any
.interactive
) {
1040 a
->data
.inter
.cancel
= cancel
;
1041 a
->data
.inter
.final
= done
;
1042 if (!(cancel
|| done
))
1043 if (!keyboard_interactive_grab(state
, a
->data
.any
.c
, a
))
1047 /* XXX UGLY HACK race with motion event starting a move and the
1048 button release gettnig processed first. answer: don't queue
1049 moveresize starts. UGLY HACK XXX
1051 XXX ALSO don't queue showmenu events, because on button press
1052 events we need to know if a mouse grab is going to take place,
1053 and set the button to 0, so that later motion events don't think
1054 that a drag is going on. since showmenu grabs the pointer..
1056 if (a
->data
.any
.interactive
|| a
->func
== action_move
||
1057 a
->func
== action_resize
|| a
->func
== action_showmenu
)
1059 /* interactive actions are not queued */
1061 } else if (a
->func
== action_focus
||
1062 a
->func
== action_activate
||
1063 a
->func
== action_showmenu
)
1065 /* XXX MORE UGLY HACK
1066 actions from clicks on client windows are NOT queued.
1067 this solves the mysterious click-and-drag-doesnt-work
1068 problem. it was because the window gets focused and stuff
1069 after the button event has already been passed through. i
1070 dont really know why it should care but it does and it makes
1073 however this very bogus ! !
1074 we want to send the button press to the window BEFORE
1075 we do the action because the action might move the windows
1076 (eg change desktops) and then the button press ends up on
1077 the completely wrong window !
1078 so, this is just for that bug, and it will only NOT queue it
1079 if it is a focusing action that can be used with the mouse
1082 also with the menus, there is a race going on. if the
1083 desktop wants to pop up a menu, and we do too, we send them
1084 the button before we pop up the menu, so they pop up their
1085 menu first. but not always. if we pop up our menu before
1086 sending them the button press, then the result is
1089 XXX further more. focus actions are not queued at all,
1090 because if you bind focus->showmenu, the menu will get
1091 hidden to do the focusing
1095 ob_main_loop_queue_action(ob_main_loop
, a
);
1100 void action_run_string(const gchar
*name
, struct _ObClient
*c
, Time time
)
1105 a
= action_from_string(name
, OB_USER_ACTION_NONE
);
1108 l
= g_slist_append(NULL
, a
);
1110 action_run(l
, c
, 0, time
);
1113 void action_focus(union ActionData
*data
)
1115 if (data
->client
.any
.c
) {
1116 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1117 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1118 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1120 /* if using focus_delay, stop the timer now so that focus doesn't
1122 event_halt_focus_delay();
1124 client_focus(data
->client
.any
.c
);
1127 /* focus action on something other than a client, make keybindings
1128 work for this openbox instance, but don't focus any specific client
1134 void action_unfocus (union ActionData
*data
)
1136 if (data
->client
.any
.c
== focus_client
)
1137 focus_fallback(FALSE
, FALSE
, TRUE
);
1140 void action_iconify(union ActionData
*data
)
1142 client_action_start(data
);
1143 client_iconify(data
->client
.any
.c
, TRUE
, TRUE
, FALSE
);
1144 client_action_end(data
, config_focus_under_mouse
);
1147 void action_focus_order_to_bottom(union ActionData
*data
)
1149 focus_order_to_bottom(data
->client
.any
.c
);
1152 void action_raiselower(union ActionData
*data
)
1154 ObClient
*c
= data
->client
.any
.c
;
1156 client_action_start(data
);
1157 stacking_restack_request(c
, NULL
, Opposite
);
1158 client_action_end(data
, config_focus_under_mouse
);
1161 void action_raise(union ActionData
*data
)
1163 client_action_start(data
);
1164 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1165 client_action_end(data
, config_focus_under_mouse
);
1168 void action_unshaderaise(union ActionData
*data
)
1170 if (data
->client
.any
.c
->shaded
)
1171 action_unshade(data
);
1176 void action_shadelower(union ActionData
*data
)
1178 if (data
->client
.any
.c
->shaded
)
1184 void action_lower(union ActionData
*data
)
1186 client_action_start(data
);
1187 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1188 client_action_end(data
, config_focus_under_mouse
);
1191 void action_close(union ActionData
*data
)
1193 client_close(data
->client
.any
.c
);
1196 void action_kill(union ActionData
*data
)
1198 client_kill(data
->client
.any
.c
);
1201 void action_shade(union ActionData
*data
)
1203 client_action_start(data
);
1204 client_shade(data
->client
.any
.c
, TRUE
);
1205 client_action_end(data
, config_focus_under_mouse
);
1208 void action_unshade(union ActionData
*data
)
1210 client_action_start(data
);
1211 client_shade(data
->client
.any
.c
, FALSE
);
1212 client_action_end(data
, config_focus_under_mouse
);
1215 void action_toggle_shade(union ActionData
*data
)
1217 client_action_start(data
);
1218 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1219 client_action_end(data
, config_focus_under_mouse
);
1222 void action_toggle_omnipresent(union ActionData
*data
)
1224 client_set_desktop(data
->client
.any
.c
,
1225 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1226 screen_desktop
: DESKTOP_ALL
, FALSE
, TRUE
);
1229 void action_move_relative_horz(union ActionData
*data
)
1231 ObClient
*c
= data
->relative
.any
.c
;
1232 client_action_start(data
);
1233 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
);
1234 client_action_end(data
, FALSE
);
1237 void action_move_relative_vert(union ActionData
*data
)
1239 ObClient
*c
= data
->relative
.any
.c
;
1240 client_action_start(data
);
1241 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.deltax
);
1242 client_action_end(data
, FALSE
);
1245 void action_move_to_center(union ActionData
*data
)
1247 ObClient
*c
= data
->client
.any
.c
;
1249 area
= screen_area(c
->desktop
, client_monitor(c
), NULL
);
1250 client_action_start(data
);
1251 client_move(c
, area
->x
+ area
->width
/ 2 - c
->area
.width
/ 2,
1252 area
->y
+ area
->height
/ 2 - c
->area
.height
/ 2);
1253 client_action_end(data
, FALSE
);
1257 void action_resize_relative_horz(union ActionData
*data
)
1259 ObClient
*c
= data
->relative
.any
.c
;
1260 client_action_start(data
);
1262 c
->area
.width
+ data
->relative
.deltax
* c
->size_inc
.width
,
1264 client_action_end(data
, FALSE
);
1267 void action_resize_relative_vert(union ActionData
*data
)
1269 ObClient
*c
= data
->relative
.any
.c
;
1271 client_action_start(data
);
1272 client_resize(c
, c
->area
.width
, c
->area
.height
+
1273 data
->relative
.deltax
* c
->size_inc
.height
);
1274 client_action_end(data
, FALSE
);
1278 void action_move_relative(union ActionData
*data
)
1280 ObClient
*c
= data
->relative
.any
.c
;
1281 client_action_start(data
);
1282 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
+
1283 data
->relative
.deltay
);
1284 client_action_end(data
, FALSE
);
1287 void action_resize_relative(union ActionData
*data
)
1289 ObClient
*c
= data
->relative
.any
.c
;
1290 gint x
, y
, ow
, xoff
, nw
, oh
, yoff
, nh
, lw
, lh
;
1292 client_action_start(data
);
1297 xoff
= -data
->relative
.deltaxl
* c
->size_inc
.width
;
1298 nw
= ow
+ data
->relative
.deltax
* c
->size_inc
.width
1299 + data
->relative
.deltaxl
* c
->size_inc
.width
;
1300 oh
= c
->area
.height
;
1301 yoff
= -data
->relative
.deltayu
* c
->size_inc
.height
;
1302 nh
= oh
+ data
->relative
.deltay
* c
->size_inc
.height
1303 + data
->relative
.deltayu
* c
->size_inc
.height
;
1305 g_print("deltax %d %d x %d ow %d xoff %d nw %d\n",
1306 data
->relative
.deltax
,
1307 data
->relative
.deltaxl
,
1310 client_try_configure(c
, &x
, &y
, &nw
, &nh
, &lw
, &lh
, TRUE
);
1311 xoff
= xoff
== 0 ? 0 : (xoff
< 0 ? MAX(xoff
, ow
-nw
) : MIN(xoff
, ow
-nw
));
1312 yoff
= yoff
== 0 ? 0 : (yoff
< 0 ? MAX(yoff
, oh
-nh
) : MIN(yoff
, oh
-nh
));
1313 client_move_resize(c
, x
+ xoff
, y
+ yoff
, nw
, nh
);
1314 client_action_end(data
, FALSE
);
1317 void action_maximize_full(union ActionData
*data
)
1319 client_action_start(data
);
1320 client_maximize(data
->client
.any
.c
, TRUE
, 0);
1321 client_action_end(data
, config_focus_under_mouse
);
1324 void action_unmaximize_full(union ActionData
*data
)
1326 client_action_start(data
);
1327 client_maximize(data
->client
.any
.c
, FALSE
, 0);
1328 client_action_end(data
, config_focus_under_mouse
);
1331 void action_toggle_maximize_full(union ActionData
*data
)
1333 client_action_start(data
);
1334 client_maximize(data
->client
.any
.c
,
1335 !(data
->client
.any
.c
->max_horz
||
1336 data
->client
.any
.c
->max_vert
),
1338 client_action_end(data
, config_focus_under_mouse
);
1341 void action_maximize_horz(union ActionData
*data
)
1343 client_action_start(data
);
1344 client_maximize(data
->client
.any
.c
, TRUE
, 1);
1345 client_action_end(data
, config_focus_under_mouse
);
1348 void action_unmaximize_horz(union ActionData
*data
)
1350 client_action_start(data
);
1351 client_maximize(data
->client
.any
.c
, FALSE
, 1);
1352 client_action_end(data
, config_focus_under_mouse
);
1355 void action_toggle_maximize_horz(union ActionData
*data
)
1357 client_action_start(data
);
1358 client_maximize(data
->client
.any
.c
,
1359 !data
->client
.any
.c
->max_horz
, 1);
1360 client_action_end(data
, config_focus_under_mouse
);
1363 void action_maximize_vert(union ActionData
*data
)
1365 client_action_start(data
);
1366 client_maximize(data
->client
.any
.c
, TRUE
, 2);
1367 client_action_end(data
, config_focus_under_mouse
);
1370 void action_unmaximize_vert(union ActionData
*data
)
1372 client_action_start(data
);
1373 client_maximize(data
->client
.any
.c
, FALSE
, 2);
1374 client_action_end(data
, config_focus_under_mouse
);
1377 void action_toggle_maximize_vert(union ActionData
*data
)
1379 client_action_start(data
);
1380 client_maximize(data
->client
.any
.c
,
1381 !data
->client
.any
.c
->max_vert
, 2);
1382 client_action_end(data
, config_focus_under_mouse
);
1385 void action_toggle_fullscreen(union ActionData
*data
)
1387 client_action_start(data
);
1388 client_fullscreen(data
->client
.any
.c
, !(data
->client
.any
.c
->fullscreen
));
1389 client_action_end(data
, config_focus_under_mouse
);
1392 void action_send_to_desktop(union ActionData
*data
)
1394 ObClient
*c
= data
->sendto
.any
.c
;
1396 if (!client_normal(c
)) return;
1398 if (data
->sendto
.desk
< screen_num_desktops
||
1399 data
->sendto
.desk
== DESKTOP_ALL
) {
1400 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
, FALSE
);
1401 if (data
->sendto
.follow
&& data
->sendto
.desk
!= screen_desktop
)
1402 screen_set_desktop(data
->sendto
.desk
, TRUE
);
1406 void action_desktop(union ActionData
*data
)
1408 /* XXX add the interactive/dialog option back again once the dialog
1409 has been made to not use grabs */
1410 if (data
->desktop
.desk
< screen_num_desktops
||
1411 data
->desktop
.desk
== DESKTOP_ALL
)
1413 screen_set_desktop(data
->desktop
.desk
, TRUE
);
1414 if (data
->inter
.any
.interactive
)
1415 screen_desktop_popup(data
->desktop
.desk
, TRUE
);
1419 void action_desktop_dir(union ActionData
*data
)
1423 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1424 data
->desktopdir
.wrap
,
1425 data
->desktopdir
.linear
,
1426 data
->desktopdir
.inter
.any
.interactive
,
1427 data
->desktopdir
.inter
.final
,
1428 data
->desktopdir
.inter
.cancel
);
1429 /* only move the desktop when the action is complete. if we switch
1430 desktops during the interactive action, focus will move but with
1431 NotifyWhileGrabbed and applications don't like that. */
1432 if (!data
->sendtodir
.inter
.any
.interactive
||
1433 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1435 if (d
!= screen_desktop
)
1436 screen_set_desktop(d
, TRUE
);
1440 void action_send_to_desktop_dir(union ActionData
*data
)
1442 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1445 if (!client_normal(c
)) return;
1447 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1448 data
->sendtodir
.linear
,
1449 data
->sendtodir
.inter
.any
.interactive
,
1450 data
->sendtodir
.inter
.final
,
1451 data
->sendtodir
.inter
.cancel
);
1452 /* only move the desktop when the action is complete. if we switch
1453 desktops during the interactive action, focus will move but with
1454 NotifyWhileGrabbed and applications don't like that. */
1455 if (!data
->sendtodir
.inter
.any
.interactive
||
1456 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1458 client_set_desktop(c
, d
, data
->sendtodir
.follow
, FALSE
);
1459 if (data
->sendtodir
.follow
&& d
!= screen_desktop
)
1460 screen_set_desktop(d
, TRUE
);
1464 void action_desktop_last(union ActionData
*data
)
1466 if (screen_last_desktop
< screen_num_desktops
)
1467 screen_set_desktop(screen_last_desktop
, TRUE
);
1470 void action_toggle_decorations(union ActionData
*data
)
1472 ObClient
*c
= data
->client
.any
.c
;
1474 client_action_start(data
);
1475 client_set_undecorated(c
, !c
->undecorated
);
1476 client_action_end(data
, FALSE
);
1479 static guint32
pick_corner(gint x
, gint y
, gint cx
, gint cy
, gint cw
, gint ch
,
1482 /* let's make x and y client relative instead of screen relative */
1484 y
= ch
- (y
- cy
); /* y is inverted, 0 is at the bottom of the window */
1487 #define A -4*X + 7*ch/3
1488 #define B 4*X -15*ch/9
1489 #define C -X/4 + 2*ch/3
1490 #define D X/4 + 5*ch/12
1491 #define E X/4 + ch/3
1492 #define F -X/4 + 7*ch/12
1493 #define G 4*X - 4*ch/3
1494 #define H -4*X + 8*ch/3
1495 #define a (y > 5*ch/9)
1496 #define b (x < 4*cw/9)
1497 #define c (x > 5*cw/9)
1498 #define d (y < 4*ch/9)
1501 Each of these defines (except X which is just there for fun), represents
1502 the equation of a line. The lines they represent are shown in the diagram
1503 below. Checking y against these lines, we are able to choose a region
1504 of the window as shown.
1506 +---------------------A-------|-------|-------B---------------------+
1513 | northwest | A north B | northeast |
1516 C---------------------+----A--+-------+--B----+---------------------D
1517 |CCCCCCC | A B | DDDDDDD|
1518 | CCCCCCCC | A | | B | DDDDDDDD |
1519 | CCCCCCC A B DDDDDDD |
1520 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
1522 | west | b move c | east | ad
1524 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
1525 | EEEEEEE G H FFFFFFF |
1526 | EEEEEEEE | G | | H | FFFFFFFF |
1527 |EEEEEEE | G H | FFFFFFF|
1528 E---------------------+----G--+-------+--H----+---------------------F
1531 | southwest | G south H | southeast |
1538 +---------------------G-------|-------|-------H---------------------+
1542 /* for shaded windows, you can only resize west/east and move */
1544 return prop_atoms
.net_wm_moveresize_size_left
;
1546 return prop_atoms
.net_wm_moveresize_size_right
;
1547 return prop_atoms
.net_wm_moveresize_move
;
1550 if (y
< A
&& y
>= C
)
1551 return prop_atoms
.net_wm_moveresize_size_topleft
;
1552 else if (y
>= A
&& y
>= B
&& a
)
1553 return prop_atoms
.net_wm_moveresize_size_top
;
1554 else if (y
< B
&& y
>= D
)
1555 return prop_atoms
.net_wm_moveresize_size_topright
;
1556 else if (y
< C
&& y
>= E
&& b
)
1557 return prop_atoms
.net_wm_moveresize_size_left
;
1558 else if (y
< D
&& y
>= F
&& c
)
1559 return prop_atoms
.net_wm_moveresize_size_right
;
1560 else if (y
< E
&& y
>= G
)
1561 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1562 else if (y
< G
&& y
< H
&& d
)
1563 return prop_atoms
.net_wm_moveresize_size_bottom
;
1564 else if (y
>= H
&& y
< F
)
1565 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1567 return prop_atoms
.net_wm_moveresize_move
;
1584 void action_move(union ActionData
*data
)
1586 ObClient
*c
= data
->moveresize
.any
.c
;
1589 if (data
->moveresize
.keyboard
)
1590 corner
= prop_atoms
.net_wm_moveresize_move_keyboard
;
1592 corner
= prop_atoms
.net_wm_moveresize_move
;
1594 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1597 void action_resize(union ActionData
*data
)
1599 ObClient
*c
= data
->moveresize
.any
.c
;
1602 if (data
->moveresize
.keyboard
)
1603 corner
= prop_atoms
.net_wm_moveresize_size_keyboard
;
1604 else if (data
->moveresize
.corner
)
1605 corner
= data
->moveresize
.corner
; /* it was specified in the binding */
1607 corner
= pick_corner(data
->any
.x
, data
->any
.y
,
1608 c
->frame
->area
.x
, c
->frame
->area
.y
,
1609 /* use the client size because the frame
1610 can be differently sized (shaded
1611 windows) and we want this based on the
1613 c
->area
.width
+ c
->frame
->size
.left
+
1614 c
->frame
->size
.right
,
1615 c
->area
.height
+ c
->frame
->size
.top
+
1616 c
->frame
->size
.bottom
, c
->shaded
);
1618 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1621 void action_directional_focus(union ActionData
*data
)
1623 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1625 event_halt_focus_delay();
1627 focus_directional_cycle(data
->interdiraction
.direction
,
1628 data
->interdiraction
.dock_windows
,
1629 data
->interdiraction
.desktop_windows
,
1630 data
->any
.interactive
,
1631 data
->interdiraction
.dialog
,
1632 data
->interdiraction
.inter
.final
,
1633 data
->interdiraction
.inter
.cancel
);
1636 void action_movetoedge(union ActionData
*data
)
1639 ObClient
*c
= data
->diraction
.any
.c
;
1641 x
= c
->frame
->area
.x
;
1642 y
= c
->frame
->area
.y
;
1644 switch(data
->diraction
.direction
) {
1645 case OB_DIRECTION_NORTH
:
1646 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
,
1647 data
->diraction
.hang
)
1648 - (data
->diraction
.hang
? c
->frame
->area
.height
: 0);
1650 case OB_DIRECTION_WEST
:
1651 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
,
1652 data
->diraction
.hang
)
1653 - (data
->diraction
.hang
? c
->frame
->area
.width
: 0);
1655 case OB_DIRECTION_SOUTH
:
1656 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
,
1657 data
->diraction
.hang
)
1658 - (data
->diraction
.hang
? 0 : c
->frame
->area
.height
);
1660 case OB_DIRECTION_EAST
:
1661 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
,
1662 data
->diraction
.hang
)
1663 - (data
->diraction
.hang
? 0 : c
->frame
->area
.width
);
1666 g_assert_not_reached();
1668 frame_frame_gravity(c
->frame
, &x
, &y
, c
->area
.width
, c
->area
.height
);
1669 client_action_start(data
);
1670 client_move(c
, x
, y
);
1671 client_action_end(data
, FALSE
);
1674 void action_growtoedge(union ActionData
*data
)
1676 gint x
, y
, width
, height
, dest
;
1677 ObClient
*c
= data
->diraction
.any
.c
;
1680 a
= screen_area(c
->desktop
, SCREEN_AREA_ALL_MONITORS
, &c
->frame
->area
);
1681 x
= c
->frame
->area
.x
;
1682 y
= c
->frame
->area
.y
;
1683 /* get the unshaded frame's dimensions..if it is shaded */
1684 width
= c
->area
.width
+ c
->frame
->size
.left
+ c
->frame
->size
.right
;
1685 height
= c
->area
.height
+ c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1687 switch(data
->diraction
.direction
) {
1688 case OB_DIRECTION_NORTH
:
1689 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1691 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
, FALSE
);
1693 height
= height
/ 2;
1695 height
= c
->frame
->area
.y
+ height
- dest
;
1699 case OB_DIRECTION_WEST
:
1700 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
, FALSE
);
1704 width
= c
->frame
->area
.x
+ width
- dest
;
1708 case OB_DIRECTION_SOUTH
:
1709 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1711 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
, FALSE
);
1712 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1713 height
= c
->frame
->area
.height
/ 2;
1714 y
= a
->y
+ a
->height
- height
;
1716 height
= dest
- c
->frame
->area
.y
;
1717 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1718 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1720 case OB_DIRECTION_EAST
:
1721 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
, FALSE
);
1722 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1723 width
= c
->frame
->area
.width
/ 2;
1724 x
= a
->x
+ a
->width
- width
;
1726 width
= dest
- c
->frame
->area
.x
;
1727 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1728 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1731 g_assert_not_reached();
1733 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1734 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1735 frame_frame_gravity(c
->frame
, &x
, &y
, width
, height
);
1736 client_action_start(data
);
1737 client_move_resize(c
, x
, y
, width
, height
);
1738 client_action_end(data
, FALSE
);
1742 void action_send_to_layer(union ActionData
*data
)
1744 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1747 void action_toggle_layer(union ActionData
*data
)
1749 ObClient
*c
= data
->layer
.any
.c
;
1751 client_action_start(data
);
1752 if (data
->layer
.layer
< 0)
1753 client_set_layer(c
, c
->below
? 0 : -1);
1754 else if (data
->layer
.layer
> 0)
1755 client_set_layer(c
, c
->above
? 0 : 1);
1756 client_action_end(data
, config_focus_under_mouse
);
1759 void action_toggle_dockautohide(union ActionData
*data
)
1761 config_dock_hide
= !config_dock_hide
;
1765 void action_break_chroot(union ActionData
*data
)
1767 /* break out of one chroot */
1768 keyboard_reset_chains(1);
1771 void action_add_desktop(union ActionData
*data
)
1773 client_action_start(data
);
1774 screen_set_num_desktops(screen_num_desktops
+1);
1776 /* move all the clients over */
1777 if (data
->addremovedesktop
.current
) {
1780 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1781 ObClient
*c
= it
->data
;
1782 if (c
->desktop
!= DESKTOP_ALL
&& c
->desktop
>= screen_desktop
)
1783 client_set_desktop(c
, c
->desktop
+1, FALSE
, TRUE
);
1787 client_action_end(data
, config_focus_under_mouse
);
1790 void action_remove_desktop(union ActionData
*data
)
1792 guint rmdesktop
, movedesktop
;
1793 GList
*it
, *stacking_copy
;
1795 if (screen_num_desktops
< 2) return;
1797 client_action_start(data
);
1799 /* what desktop are we removing and moving to? */
1800 if (data
->addremovedesktop
.current
)
1801 rmdesktop
= screen_desktop
;
1803 rmdesktop
= screen_num_desktops
- 1;
1804 if (rmdesktop
< screen_num_desktops
- 1)
1805 movedesktop
= rmdesktop
+ 1;
1807 movedesktop
= rmdesktop
;
1809 /* make a copy of the list cuz we're changing it */
1810 stacking_copy
= g_list_copy(stacking_list
);
1811 for (it
= g_list_last(stacking_copy
); it
; it
= g_list_previous(it
)) {
1812 if (WINDOW_IS_CLIENT(it
->data
)) {
1813 ObClient
*c
= it
->data
;
1814 guint d
= c
->desktop
;
1815 if (d
!= DESKTOP_ALL
&& d
>= movedesktop
) {
1816 client_set_desktop(c
, c
->desktop
- 1, TRUE
, TRUE
);
1817 ob_debug("moving window %s\n", c
->title
);
1819 /* raise all the windows that are on the current desktop which
1821 if ((screen_desktop
== rmdesktop
- 1 ||
1822 screen_desktop
== rmdesktop
) &&
1823 (d
== DESKTOP_ALL
|| d
== screen_desktop
))
1825 stacking_raise(CLIENT_AS_WINDOW(c
));
1826 ob_debug("raising window %s\n", c
->title
);
1831 /* act like we're changing desktops */
1832 if (screen_desktop
< screen_num_desktops
- 1) {
1833 gint d
= screen_desktop
;
1834 screen_desktop
= screen_last_desktop
;
1835 screen_set_desktop(d
, TRUE
);
1836 ob_debug("fake desktop change\n");
1839 screen_set_num_desktops(screen_num_desktops
-1);
1841 client_action_end(data
, config_focus_under_mouse
);