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_client_action(ObAction
**a
, ObUserAction uact
)
451 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
454 ActionString actionstrings
[] =
457 "directionalfocusnorth",
458 action_directional_focus
,
459 setup_action_directional_focus_north
462 "directionalfocuseast",
463 action_directional_focus
,
464 setup_action_directional_focus_east
467 "directionalfocussouth",
468 action_directional_focus
,
469 setup_action_directional_focus_south
472 "directionalfocuswest",
473 action_directional_focus
,
474 setup_action_directional_focus_west
477 "directionalfocusnortheast",
478 action_directional_focus
,
479 setup_action_directional_focus_northeast
482 "directionalfocussoutheast",
483 action_directional_focus
,
484 setup_action_directional_focus_southeast
487 "directionalfocussouthwest",
488 action_directional_focus
,
489 setup_action_directional_focus_southwest
492 "directionalfocusnorthwest",
493 action_directional_focus
,
494 setup_action_directional_focus_northwest
508 action_focus_order_to_bottom
,
563 action_toggle_omnipresent
,
568 action_move_relative_horz
,
573 action_move_relative_vert
,
578 action_move_to_center
,
582 "resizerelativehorz",
583 action_resize_relative_horz
,
587 "resizerelativevert",
588 action_resize_relative_vert
,
593 action_move_relative
,
598 action_resize_relative
,
603 action_maximize_full
,
608 action_unmaximize_full
,
612 "togglemaximizefull",
613 action_toggle_maximize_full
,
618 action_maximize_horz
,
623 action_unmaximize_horz
,
627 "togglemaximizehorz",
628 action_toggle_maximize_horz
,
633 action_maximize_vert
,
638 action_unmaximize_vert
,
642 "togglemaximizevert",
643 action_toggle_maximize_vert
,
648 action_toggle_fullscreen
,
653 action_send_to_desktop
,
654 setup_action_send_to_desktop
658 action_send_to_desktop_dir
,
659 setup_action_send_to_desktop_next
662 "sendtodesktopprevious",
663 action_send_to_desktop_dir
,
664 setup_action_send_to_desktop_prev
667 "sendtodesktopright",
668 action_send_to_desktop_dir
,
669 setup_action_send_to_desktop_right
673 action_send_to_desktop_dir
,
674 setup_action_send_to_desktop_left
678 action_send_to_desktop_dir
,
679 setup_action_send_to_desktop_up
683 action_send_to_desktop_dir
,
684 setup_action_send_to_desktop_down
694 setup_action_desktop_next
699 setup_action_desktop_prev
704 setup_action_desktop_right
709 setup_action_desktop_left
714 setup_action_desktop_up
719 setup_action_desktop_down
723 action_toggle_decorations
,
737 "toggledockautohide",
738 action_toggle_dockautohide
,
748 action_send_to_layer
,
749 setup_action_top_layer
754 setup_action_top_layer
758 action_send_to_layer
,
759 setup_action_normal_layer
763 action_send_to_layer
,
764 setup_action_bottom_layer
767 "togglealwaysonbottom",
769 setup_action_bottom_layer
774 setup_action_movefromedge_north
779 setup_action_movefromedge_south
784 setup_action_movefromedge_west
789 setup_action_movefromedge_east
794 setup_action_movetoedge_north
799 setup_action_movetoedge_south
804 setup_action_movetoedge_west
809 setup_action_movetoedge_east
814 setup_action_growtoedge_north
819 setup_action_growtoedge_south
824 setup_action_growtoedge_west
829 setup_action_growtoedge_east
834 setup_action_addremove_desktop_last
838 action_remove_desktop
,
839 setup_action_addremove_desktop_last
844 setup_action_addremove_desktop_current
847 "removedesktopcurrent",
848 action_remove_desktop
,
849 setup_action_addremove_desktop_current
858 /* only key bindings can be interactive. thus saith the xor.
859 because of how the mouse is grabbed, mouse events dont even get
860 read during interactive events, so no dice! >:) */
861 #define INTERACTIVE_LIMIT(a, uact) \
862 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
863 a->data.any.interactive = FALSE;
865 ObAction
*action_from_string(const gchar
*name
, ObUserAction uact
)
868 gboolean exist
= FALSE
;
871 for (i
= 0; actionstrings
[i
].name
; i
++)
872 if (!g_ascii_strcasecmp(name
, actionstrings
[i
].name
)) {
874 a
= action_new(actionstrings
[i
].func
);
875 if (actionstrings
[i
].setup
)
876 actionstrings
[i
].setup(&a
, uact
);
878 INTERACTIVE_LIMIT(a
, uact
);
882 g_message(_("Invalid action '%s' requested. No such action exists."),
885 g_message(_("Invalid use of action '%s'. Action will be ignored."),
890 ObAction
*action_parse(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
894 ObAction
*act
= NULL
;
897 if (parse_attr_string("name", node
, &actname
)) {
898 if ((act
= action_from_string(actname
, uact
))) {
899 } else if (act
->func
== action_move_relative_horz
||
900 act
->func
== action_move_relative_vert
||
901 act
->func
== action_resize_relative_horz
||
902 act
->func
== action_resize_relative_vert
) {
903 if ((n
= parse_find_node("delta", node
->xmlChildrenNode
)))
904 act
->data
.relative
.deltax
= parse_int(doc
, n
);
905 } else if (act
->func
== action_move_relative
) {
906 if ((n
= parse_find_node("x", node
->xmlChildrenNode
)))
907 act
->data
.relative
.deltax
= parse_int(doc
, n
);
908 if ((n
= parse_find_node("y", node
->xmlChildrenNode
)))
909 act
->data
.relative
.deltay
= parse_int(doc
, n
);
910 } else if (act
->func
== action_resize_relative
) {
911 if ((n
= parse_find_node("left", node
->xmlChildrenNode
)))
912 act
->data
.relative
.deltaxl
= parse_int(doc
, n
);
913 if ((n
= parse_find_node("up", node
->xmlChildrenNode
)))
914 act
->data
.relative
.deltayu
= parse_int(doc
, n
);
915 if ((n
= parse_find_node("right", node
->xmlChildrenNode
)))
916 act
->data
.relative
.deltax
= parse_int(doc
, n
);
917 if ((n
= parse_find_node("down", node
->xmlChildrenNode
)))
918 act
->data
.relative
.deltay
= parse_int(doc
, n
);
919 } else if (act
->func
== action_desktop
) {
920 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
921 act
->data
.desktop
.desk
= parse_int(doc
, n
);
922 if (act
->data
.desktop
.desk
> 0) act
->data
.desktop
.desk
--;
924 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
925 act->data.desktop.inter.any.interactive =
928 } else if (act
->func
== action_send_to_desktop
) {
929 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
930 act
->data
.sendto
.desk
= parse_int(doc
, n
);
931 if (act
->data
.sendto
.desk
> 0) act
->data
.sendto
.desk
--;
932 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
933 act
->data
.sendto
.follow
= parse_bool(doc
, n
);
934 } else if (act
->func
== action_desktop_dir
) {
935 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
936 act
->data
.desktopdir
.wrap
= parse_bool(doc
, n
);
937 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
938 act
->data
.desktopdir
.inter
.any
.interactive
=
940 } else if (act
->func
== action_send_to_desktop_dir
) {
941 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
942 act
->data
.sendtodir
.wrap
= parse_bool(doc
, n
);
943 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
944 act
->data
.sendtodir
.follow
= parse_bool(doc
, n
);
945 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
946 act
->data
.sendtodir
.inter
.any
.interactive
=
948 } else if (act
->func
== action_directional_focus
) {
949 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
950 act
->data
.interdiraction
.dialog
= parse_bool(doc
, n
);
951 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
952 act
->data
.interdiraction
.dock_windows
= parse_bool(doc
, n
);
953 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
954 act
->data
.interdiraction
.desktop_windows
=
956 } else if (act
->func
== action_resize
) {
957 if ((n
= parse_find_node("edge", node
->xmlChildrenNode
))) {
958 gchar
*s
= parse_string(doc
, n
);
959 if (!g_ascii_strcasecmp(s
, "top"))
960 act
->data
.moveresize
.corner
=
961 prop_atoms
.net_wm_moveresize_size_top
;
962 else if (!g_ascii_strcasecmp(s
, "bottom"))
963 act
->data
.moveresize
.corner
=
964 prop_atoms
.net_wm_moveresize_size_bottom
;
965 else if (!g_ascii_strcasecmp(s
, "left"))
966 act
->data
.moveresize
.corner
=
967 prop_atoms
.net_wm_moveresize_size_left
;
968 else if (!g_ascii_strcasecmp(s
, "right"))
969 act
->data
.moveresize
.corner
=
970 prop_atoms
.net_wm_moveresize_size_right
;
971 else if (!g_ascii_strcasecmp(s
, "topleft"))
972 act
->data
.moveresize
.corner
=
973 prop_atoms
.net_wm_moveresize_size_topleft
;
974 else if (!g_ascii_strcasecmp(s
, "topright"))
975 act
->data
.moveresize
.corner
=
976 prop_atoms
.net_wm_moveresize_size_topright
;
977 else if (!g_ascii_strcasecmp(s
, "bottomleft"))
978 act
->data
.moveresize
.corner
=
979 prop_atoms
.net_wm_moveresize_size_bottomleft
;
980 else if (!g_ascii_strcasecmp(s
, "bottomright"))
981 act
->data
.moveresize
.corner
=
982 prop_atoms
.net_wm_moveresize_size_bottomright
;
985 } else if (act
->func
== action_raise
||
986 act
->func
== action_lower
||
987 act
->func
== action_raiselower
||
988 act
->func
== action_shadelower
||
989 act
->func
== action_unshaderaise
) {
991 INTERACTIVE_LIMIT(act
, uact
);
998 void action_run_list(GSList
*acts
, ObClient
*c
, ObFrameContext context
,
999 guint state
, guint button
, gint x
, gint y
, Time time
,
1000 gboolean cancel
, gboolean done
)
1009 screen_pointer_pos(&x
, &y
);
1011 for (it
= acts
; it
; it
= g_slist_next(it
)) {
1014 if (!(a
->data
.any
.client_action
== OB_CLIENT_ACTION_ALWAYS
&& !c
)) {
1015 a
->data
.any
.c
= a
->data
.any
.client_action
? c
: NULL
;
1016 a
->data
.any
.context
= context
;
1020 a
->data
.any
.button
= button
;
1022 a
->data
.any
.time
= time
;
1024 if (a
->data
.any
.interactive
) {
1025 a
->data
.inter
.cancel
= cancel
;
1026 a
->data
.inter
.final
= done
;
1027 if (!(cancel
|| done
))
1028 if (!keyboard_interactive_grab(state
, a
->data
.any
.c
, a
))
1032 /* XXX UGLY HACK race with motion event starting a move and the
1033 button release gettnig processed first. answer: don't queue
1034 moveresize starts. UGLY HACK XXX
1036 XXX ALSO don't queue showmenu events, because on button press
1037 events we need to know if a mouse grab is going to take place,
1038 and set the button to 0, so that later motion events don't think
1039 that a drag is going on. since showmenu grabs the pointer..
1041 if (a
->data
.any
.interactive
|| a
->func
== action_move
||
1042 a
->func
== action_resize
|| a
->func
== action_showmenu
)
1044 /* interactive actions are not queued */
1046 } else if (a
->func
== action_focus
||
1047 a
->func
== action_activate
||
1048 a
->func
== action_showmenu
)
1050 /* XXX MORE UGLY HACK
1051 actions from clicks on client windows are NOT queued.
1052 this solves the mysterious click-and-drag-doesnt-work
1053 problem. it was because the window gets focused and stuff
1054 after the button event has already been passed through. i
1055 dont really know why it should care but it does and it makes
1058 however this very bogus ! !
1059 we want to send the button press to the window BEFORE
1060 we do the action because the action might move the windows
1061 (eg change desktops) and then the button press ends up on
1062 the completely wrong window !
1063 so, this is just for that bug, and it will only NOT queue it
1064 if it is a focusing action that can be used with the mouse
1067 also with the menus, there is a race going on. if the
1068 desktop wants to pop up a menu, and we do too, we send them
1069 the button before we pop up the menu, so they pop up their
1070 menu first. but not always. if we pop up our menu before
1071 sending them the button press, then the result is
1074 XXX further more. focus actions are not queued at all,
1075 because if you bind focus->showmenu, the menu will get
1076 hidden to do the focusing
1080 ob_main_loop_queue_action(ob_main_loop
, a
);
1085 void action_run_string(const gchar
*name
, struct _ObClient
*c
, Time time
)
1090 a
= action_from_string(name
, OB_USER_ACTION_NONE
);
1093 l
= g_slist_append(NULL
, a
);
1095 action_run(l
, c
, 0, time
);
1098 void action_unfocus (union ActionData
*data
)
1100 if (data
->client
.any
.c
== focus_client
)
1101 focus_fallback(FALSE
, FALSE
, TRUE
);
1104 void action_iconify(union ActionData
*data
)
1106 client_action_start(data
);
1107 client_iconify(data
->client
.any
.c
, TRUE
, TRUE
, FALSE
);
1108 client_action_end(data
, config_focus_under_mouse
);
1111 void action_focus_order_to_bottom(union ActionData
*data
)
1113 focus_order_to_bottom(data
->client
.any
.c
);
1116 void action_raiselower(union ActionData
*data
)
1118 ObClient
*c
= data
->client
.any
.c
;
1120 client_action_start(data
);
1121 stacking_restack_request(c
, NULL
, Opposite
);
1122 client_action_end(data
, config_focus_under_mouse
);
1125 void action_raise(union ActionData
*data
)
1127 client_action_start(data
);
1128 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1129 client_action_end(data
, config_focus_under_mouse
);
1132 void action_unshaderaise(union ActionData
*data
)
1134 if (data
->client
.any
.c
->shaded
)
1135 action_unshade(data
);
1140 void action_shadelower(union ActionData
*data
)
1142 if (data
->client
.any
.c
->shaded
)
1148 void action_lower(union ActionData
*data
)
1150 client_action_start(data
);
1151 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1152 client_action_end(data
, config_focus_under_mouse
);
1155 void action_close(union ActionData
*data
)
1157 client_close(data
->client
.any
.c
);
1160 void action_kill(union ActionData
*data
)
1162 client_kill(data
->client
.any
.c
);
1165 void action_shade(union ActionData
*data
)
1167 client_action_start(data
);
1168 client_shade(data
->client
.any
.c
, TRUE
);
1169 client_action_end(data
, config_focus_under_mouse
);
1172 void action_unshade(union ActionData
*data
)
1174 client_action_start(data
);
1175 client_shade(data
->client
.any
.c
, FALSE
);
1176 client_action_end(data
, config_focus_under_mouse
);
1179 void action_toggle_shade(union ActionData
*data
)
1181 client_action_start(data
);
1182 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1183 client_action_end(data
, config_focus_under_mouse
);
1186 void action_toggle_omnipresent(union ActionData
*data
)
1188 client_set_desktop(data
->client
.any
.c
,
1189 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1190 screen_desktop
: DESKTOP_ALL
, FALSE
, TRUE
);
1193 void action_move_relative_horz(union ActionData
*data
)
1195 ObClient
*c
= data
->relative
.any
.c
;
1196 client_action_start(data
);
1197 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
);
1198 client_action_end(data
, FALSE
);
1201 void action_move_relative_vert(union ActionData
*data
)
1203 ObClient
*c
= data
->relative
.any
.c
;
1204 client_action_start(data
);
1205 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.deltax
);
1206 client_action_end(data
, FALSE
);
1209 void action_move_to_center(union ActionData
*data
)
1211 ObClient
*c
= data
->client
.any
.c
;
1213 area
= screen_area(c
->desktop
, client_monitor(c
), NULL
);
1214 client_action_start(data
);
1215 client_move(c
, area
->x
+ area
->width
/ 2 - c
->area
.width
/ 2,
1216 area
->y
+ area
->height
/ 2 - c
->area
.height
/ 2);
1217 client_action_end(data
, FALSE
);
1221 void action_resize_relative_horz(union ActionData
*data
)
1223 ObClient
*c
= data
->relative
.any
.c
;
1224 client_action_start(data
);
1226 c
->area
.width
+ data
->relative
.deltax
* c
->size_inc
.width
,
1228 client_action_end(data
, FALSE
);
1231 void action_resize_relative_vert(union ActionData
*data
)
1233 ObClient
*c
= data
->relative
.any
.c
;
1235 client_action_start(data
);
1236 client_resize(c
, c
->area
.width
, c
->area
.height
+
1237 data
->relative
.deltax
* c
->size_inc
.height
);
1238 client_action_end(data
, FALSE
);
1242 void action_move_relative(union ActionData
*data
)
1244 ObClient
*c
= data
->relative
.any
.c
;
1245 client_action_start(data
);
1246 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
+
1247 data
->relative
.deltay
);
1248 client_action_end(data
, FALSE
);
1251 void action_resize_relative(union ActionData
*data
)
1253 ObClient
*c
= data
->relative
.any
.c
;
1254 gint x
, y
, ow
, xoff
, nw
, oh
, yoff
, nh
, lw
, lh
;
1256 client_action_start(data
);
1261 xoff
= -data
->relative
.deltaxl
* c
->size_inc
.width
;
1262 nw
= ow
+ data
->relative
.deltax
* c
->size_inc
.width
1263 + data
->relative
.deltaxl
* c
->size_inc
.width
;
1264 oh
= c
->area
.height
;
1265 yoff
= -data
->relative
.deltayu
* c
->size_inc
.height
;
1266 nh
= oh
+ data
->relative
.deltay
* c
->size_inc
.height
1267 + data
->relative
.deltayu
* c
->size_inc
.height
;
1269 g_print("deltax %d %d x %d ow %d xoff %d nw %d\n",
1270 data
->relative
.deltax
,
1271 data
->relative
.deltaxl
,
1274 client_try_configure(c
, &x
, &y
, &nw
, &nh
, &lw
, &lh
, TRUE
);
1275 xoff
= xoff
== 0 ? 0 : (xoff
< 0 ? MAX(xoff
, ow
-nw
) : MIN(xoff
, ow
-nw
));
1276 yoff
= yoff
== 0 ? 0 : (yoff
< 0 ? MAX(yoff
, oh
-nh
) : MIN(yoff
, oh
-nh
));
1277 client_move_resize(c
, x
+ xoff
, y
+ yoff
, nw
, nh
);
1278 client_action_end(data
, FALSE
);
1281 void action_maximize_full(union ActionData
*data
)
1283 client_action_start(data
);
1284 client_maximize(data
->client
.any
.c
, TRUE
, 0);
1285 client_action_end(data
, config_focus_under_mouse
);
1288 void action_unmaximize_full(union ActionData
*data
)
1290 client_action_start(data
);
1291 client_maximize(data
->client
.any
.c
, FALSE
, 0);
1292 client_action_end(data
, config_focus_under_mouse
);
1295 void action_toggle_maximize_full(union ActionData
*data
)
1297 client_action_start(data
);
1298 client_maximize(data
->client
.any
.c
,
1299 !(data
->client
.any
.c
->max_horz
||
1300 data
->client
.any
.c
->max_vert
),
1302 client_action_end(data
, config_focus_under_mouse
);
1305 void action_maximize_horz(union ActionData
*data
)
1307 client_action_start(data
);
1308 client_maximize(data
->client
.any
.c
, TRUE
, 1);
1309 client_action_end(data
, config_focus_under_mouse
);
1312 void action_unmaximize_horz(union ActionData
*data
)
1314 client_action_start(data
);
1315 client_maximize(data
->client
.any
.c
, FALSE
, 1);
1316 client_action_end(data
, config_focus_under_mouse
);
1319 void action_toggle_maximize_horz(union ActionData
*data
)
1321 client_action_start(data
);
1322 client_maximize(data
->client
.any
.c
,
1323 !data
->client
.any
.c
->max_horz
, 1);
1324 client_action_end(data
, config_focus_under_mouse
);
1327 void action_maximize_vert(union ActionData
*data
)
1329 client_action_start(data
);
1330 client_maximize(data
->client
.any
.c
, TRUE
, 2);
1331 client_action_end(data
, config_focus_under_mouse
);
1334 void action_unmaximize_vert(union ActionData
*data
)
1336 client_action_start(data
);
1337 client_maximize(data
->client
.any
.c
, FALSE
, 2);
1338 client_action_end(data
, config_focus_under_mouse
);
1341 void action_toggle_maximize_vert(union ActionData
*data
)
1343 client_action_start(data
);
1344 client_maximize(data
->client
.any
.c
,
1345 !data
->client
.any
.c
->max_vert
, 2);
1346 client_action_end(data
, config_focus_under_mouse
);
1349 void action_toggle_fullscreen(union ActionData
*data
)
1351 client_action_start(data
);
1352 client_fullscreen(data
->client
.any
.c
, !(data
->client
.any
.c
->fullscreen
));
1353 client_action_end(data
, config_focus_under_mouse
);
1356 void action_send_to_desktop(union ActionData
*data
)
1358 ObClient
*c
= data
->sendto
.any
.c
;
1360 if (!client_normal(c
)) return;
1362 if (data
->sendto
.desk
< screen_num_desktops
||
1363 data
->sendto
.desk
== DESKTOP_ALL
) {
1364 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
, FALSE
);
1365 if (data
->sendto
.follow
&& data
->sendto
.desk
!= screen_desktop
)
1366 screen_set_desktop(data
->sendto
.desk
, TRUE
);
1370 void action_desktop(union ActionData
*data
)
1372 /* XXX add the interactive/dialog option back again once the dialog
1373 has been made to not use grabs */
1374 if (data
->desktop
.desk
< screen_num_desktops
||
1375 data
->desktop
.desk
== DESKTOP_ALL
)
1377 screen_set_desktop(data
->desktop
.desk
, TRUE
);
1378 if (data
->inter
.any
.interactive
)
1379 screen_desktop_popup(data
->desktop
.desk
, TRUE
);
1383 void action_desktop_dir(union ActionData
*data
)
1387 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1388 data
->desktopdir
.wrap
,
1389 data
->desktopdir
.linear
,
1390 data
->desktopdir
.inter
.any
.interactive
,
1391 data
->desktopdir
.inter
.final
,
1392 data
->desktopdir
.inter
.cancel
);
1393 /* only move the desktop when the action is complete. if we switch
1394 desktops during the interactive action, focus will move but with
1395 NotifyWhileGrabbed and applications don't like that. */
1396 if (!data
->sendtodir
.inter
.any
.interactive
||
1397 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1399 if (d
!= screen_desktop
)
1400 screen_set_desktop(d
, TRUE
);
1404 void action_send_to_desktop_dir(union ActionData
*data
)
1406 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1409 if (!client_normal(c
)) return;
1411 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1412 data
->sendtodir
.linear
,
1413 data
->sendtodir
.inter
.any
.interactive
,
1414 data
->sendtodir
.inter
.final
,
1415 data
->sendtodir
.inter
.cancel
);
1416 /* only move the desktop when the action is complete. if we switch
1417 desktops during the interactive action, focus will move but with
1418 NotifyWhileGrabbed and applications don't like that. */
1419 if (!data
->sendtodir
.inter
.any
.interactive
||
1420 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1422 client_set_desktop(c
, d
, data
->sendtodir
.follow
, FALSE
);
1423 if (data
->sendtodir
.follow
&& d
!= screen_desktop
)
1424 screen_set_desktop(d
, TRUE
);
1428 void action_desktop_last(union ActionData
*data
)
1430 if (screen_last_desktop
< screen_num_desktops
)
1431 screen_set_desktop(screen_last_desktop
, TRUE
);
1434 void action_toggle_decorations(union ActionData
*data
)
1436 ObClient
*c
= data
->client
.any
.c
;
1438 client_action_start(data
);
1439 client_set_undecorated(c
, !c
->undecorated
);
1440 client_action_end(data
, FALSE
);
1443 static guint32
pick_corner(gint x
, gint y
, gint cx
, gint cy
, gint cw
, gint ch
,
1446 /* let's make x and y client relative instead of screen relative */
1448 y
= ch
- (y
- cy
); /* y is inverted, 0 is at the bottom of the window */
1451 #define A -4*X + 7*ch/3
1452 #define B 4*X -15*ch/9
1453 #define C -X/4 + 2*ch/3
1454 #define D X/4 + 5*ch/12
1455 #define E X/4 + ch/3
1456 #define F -X/4 + 7*ch/12
1457 #define G 4*X - 4*ch/3
1458 #define H -4*X + 8*ch/3
1459 #define a (y > 5*ch/9)
1460 #define b (x < 4*cw/9)
1461 #define c (x > 5*cw/9)
1462 #define d (y < 4*ch/9)
1465 Each of these defines (except X which is just there for fun), represents
1466 the equation of a line. The lines they represent are shown in the diagram
1467 below. Checking y against these lines, we are able to choose a region
1468 of the window as shown.
1470 +---------------------A-------|-------|-------B---------------------+
1477 | northwest | A north B | northeast |
1480 C---------------------+----A--+-------+--B----+---------------------D
1481 |CCCCCCC | A B | DDDDDDD|
1482 | CCCCCCCC | A | | B | DDDDDDDD |
1483 | CCCCCCC A B DDDDDDD |
1484 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
1486 | west | b move c | east | ad
1488 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
1489 | EEEEEEE G H FFFFFFF |
1490 | EEEEEEEE | G | | H | FFFFFFFF |
1491 |EEEEEEE | G H | FFFFFFF|
1492 E---------------------+----G--+-------+--H----+---------------------F
1495 | southwest | G south H | southeast |
1502 +---------------------G-------|-------|-------H---------------------+
1506 /* for shaded windows, you can only resize west/east and move */
1508 return prop_atoms
.net_wm_moveresize_size_left
;
1510 return prop_atoms
.net_wm_moveresize_size_right
;
1511 return prop_atoms
.net_wm_moveresize_move
;
1514 if (y
< A
&& y
>= C
)
1515 return prop_atoms
.net_wm_moveresize_size_topleft
;
1516 else if (y
>= A
&& y
>= B
&& a
)
1517 return prop_atoms
.net_wm_moveresize_size_top
;
1518 else if (y
< B
&& y
>= D
)
1519 return prop_atoms
.net_wm_moveresize_size_topright
;
1520 else if (y
< C
&& y
>= E
&& b
)
1521 return prop_atoms
.net_wm_moveresize_size_left
;
1522 else if (y
< D
&& y
>= F
&& c
)
1523 return prop_atoms
.net_wm_moveresize_size_right
;
1524 else if (y
< E
&& y
>= G
)
1525 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1526 else if (y
< G
&& y
< H
&& d
)
1527 return prop_atoms
.net_wm_moveresize_size_bottom
;
1528 else if (y
>= H
&& y
< F
)
1529 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1531 return prop_atoms
.net_wm_moveresize_move
;
1548 void action_move(union ActionData
*data
)
1550 ObClient
*c
= data
->moveresize
.any
.c
;
1553 if (data
->moveresize
.keyboard
)
1554 corner
= prop_atoms
.net_wm_moveresize_move_keyboard
;
1556 corner
= prop_atoms
.net_wm_moveresize_move
;
1558 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1561 void action_resize(union ActionData
*data
)
1563 ObClient
*c
= data
->moveresize
.any
.c
;
1566 if (data
->moveresize
.keyboard
)
1567 corner
= prop_atoms
.net_wm_moveresize_size_keyboard
;
1568 else if (data
->moveresize
.corner
)
1569 corner
= data
->moveresize
.corner
; /* it was specified in the binding */
1571 corner
= pick_corner(data
->any
.x
, data
->any
.y
,
1572 c
->frame
->area
.x
, c
->frame
->area
.y
,
1573 /* use the client size because the frame
1574 can be differently sized (shaded
1575 windows) and we want this based on the
1577 c
->area
.width
+ c
->frame
->size
.left
+
1578 c
->frame
->size
.right
,
1579 c
->area
.height
+ c
->frame
->size
.top
+
1580 c
->frame
->size
.bottom
, c
->shaded
);
1582 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1585 void action_directional_focus(union ActionData
*data
)
1587 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1589 event_halt_focus_delay();
1591 focus_directional_cycle(data
->interdiraction
.direction
,
1592 data
->interdiraction
.dock_windows
,
1593 data
->interdiraction
.desktop_windows
,
1594 data
->any
.interactive
,
1595 data
->interdiraction
.dialog
,
1596 data
->interdiraction
.inter
.final
,
1597 data
->interdiraction
.inter
.cancel
);
1600 void action_movetoedge(union ActionData
*data
)
1603 ObClient
*c
= data
->diraction
.any
.c
;
1605 x
= c
->frame
->area
.x
;
1606 y
= c
->frame
->area
.y
;
1608 switch(data
->diraction
.direction
) {
1609 case OB_DIRECTION_NORTH
:
1610 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
,
1611 data
->diraction
.hang
)
1612 - (data
->diraction
.hang
? c
->frame
->area
.height
: 0);
1614 case OB_DIRECTION_WEST
:
1615 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
,
1616 data
->diraction
.hang
)
1617 - (data
->diraction
.hang
? c
->frame
->area
.width
: 0);
1619 case OB_DIRECTION_SOUTH
:
1620 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
,
1621 data
->diraction
.hang
)
1622 - (data
->diraction
.hang
? 0 : c
->frame
->area
.height
);
1624 case OB_DIRECTION_EAST
:
1625 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
,
1626 data
->diraction
.hang
)
1627 - (data
->diraction
.hang
? 0 : c
->frame
->area
.width
);
1630 g_assert_not_reached();
1632 frame_frame_gravity(c
->frame
, &x
, &y
, c
->area
.width
, c
->area
.height
);
1633 client_action_start(data
);
1634 client_move(c
, x
, y
);
1635 client_action_end(data
, FALSE
);
1638 void action_growtoedge(union ActionData
*data
)
1640 gint x
, y
, width
, height
, dest
;
1641 ObClient
*c
= data
->diraction
.any
.c
;
1644 a
= screen_area(c
->desktop
, SCREEN_AREA_ALL_MONITORS
, &c
->frame
->area
);
1645 x
= c
->frame
->area
.x
;
1646 y
= c
->frame
->area
.y
;
1647 /* get the unshaded frame's dimensions..if it is shaded */
1648 width
= c
->area
.width
+ c
->frame
->size
.left
+ c
->frame
->size
.right
;
1649 height
= c
->area
.height
+ c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1651 switch(data
->diraction
.direction
) {
1652 case OB_DIRECTION_NORTH
:
1653 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1655 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
, FALSE
);
1657 height
= height
/ 2;
1659 height
= c
->frame
->area
.y
+ height
- dest
;
1663 case OB_DIRECTION_WEST
:
1664 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
, FALSE
);
1668 width
= c
->frame
->area
.x
+ width
- dest
;
1672 case OB_DIRECTION_SOUTH
:
1673 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1675 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
, FALSE
);
1676 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1677 height
= c
->frame
->area
.height
/ 2;
1678 y
= a
->y
+ a
->height
- height
;
1680 height
= dest
- c
->frame
->area
.y
;
1681 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1682 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1684 case OB_DIRECTION_EAST
:
1685 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
, FALSE
);
1686 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1687 width
= c
->frame
->area
.width
/ 2;
1688 x
= a
->x
+ a
->width
- width
;
1690 width
= dest
- c
->frame
->area
.x
;
1691 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1692 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1695 g_assert_not_reached();
1697 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1698 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1699 frame_frame_gravity(c
->frame
, &x
, &y
, width
, height
);
1700 client_action_start(data
);
1701 client_move_resize(c
, x
, y
, width
, height
);
1702 client_action_end(data
, FALSE
);
1706 void action_send_to_layer(union ActionData
*data
)
1708 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1711 void action_toggle_layer(union ActionData
*data
)
1713 ObClient
*c
= data
->layer
.any
.c
;
1715 client_action_start(data
);
1716 if (data
->layer
.layer
< 0)
1717 client_set_layer(c
, c
->below
? 0 : -1);
1718 else if (data
->layer
.layer
> 0)
1719 client_set_layer(c
, c
->above
? 0 : 1);
1720 client_action_end(data
, config_focus_under_mouse
);
1723 void action_toggle_dockautohide(union ActionData
*data
)
1725 config_dock_hide
= !config_dock_hide
;
1729 void action_add_desktop(union ActionData
*data
)
1731 client_action_start(data
);
1732 screen_set_num_desktops(screen_num_desktops
+1);
1734 /* move all the clients over */
1735 if (data
->addremovedesktop
.current
) {
1738 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1739 ObClient
*c
= it
->data
;
1740 if (c
->desktop
!= DESKTOP_ALL
&& c
->desktop
>= screen_desktop
)
1741 client_set_desktop(c
, c
->desktop
+1, FALSE
, TRUE
);
1745 client_action_end(data
, config_focus_under_mouse
);
1748 void action_remove_desktop(union ActionData
*data
)
1750 guint rmdesktop
, movedesktop
;
1751 GList
*it
, *stacking_copy
;
1753 if (screen_num_desktops
< 2) return;
1755 client_action_start(data
);
1757 /* what desktop are we removing and moving to? */
1758 if (data
->addremovedesktop
.current
)
1759 rmdesktop
= screen_desktop
;
1761 rmdesktop
= screen_num_desktops
- 1;
1762 if (rmdesktop
< screen_num_desktops
- 1)
1763 movedesktop
= rmdesktop
+ 1;
1765 movedesktop
= rmdesktop
;
1767 /* make a copy of the list cuz we're changing it */
1768 stacking_copy
= g_list_copy(stacking_list
);
1769 for (it
= g_list_last(stacking_copy
); it
; it
= g_list_previous(it
)) {
1770 if (WINDOW_IS_CLIENT(it
->data
)) {
1771 ObClient
*c
= it
->data
;
1772 guint d
= c
->desktop
;
1773 if (d
!= DESKTOP_ALL
&& d
>= movedesktop
) {
1774 client_set_desktop(c
, c
->desktop
- 1, TRUE
, TRUE
);
1775 ob_debug("moving window %s\n", c
->title
);
1777 /* raise all the windows that are on the current desktop which
1779 if ((screen_desktop
== rmdesktop
- 1 ||
1780 screen_desktop
== rmdesktop
) &&
1781 (d
== DESKTOP_ALL
|| d
== screen_desktop
))
1783 stacking_raise(CLIENT_AS_WINDOW(c
));
1784 ob_debug("raising window %s\n", c
->title
);
1789 /* act like we're changing desktops */
1790 if (screen_desktop
< screen_num_desktops
- 1) {
1791 gint d
= screen_desktop
;
1792 screen_desktop
= screen_last_desktop
;
1793 screen_set_desktop(d
, TRUE
);
1794 ob_debug("fake desktop change\n");
1797 screen_set_num_desktops(screen_num_desktops
-1);
1799 client_action_end(data
, config_focus_under_mouse
);