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_resize(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_addremove_desktop_current(ObAction
**a
, ObUserAction uact
)
431 (*a
)->data
.addremovedesktop
.current
= TRUE
;
434 void setup_action_addremove_desktop_last(ObAction
**a
, ObUserAction uact
)
436 (*a
)->data
.addremovedesktop
.current
= FALSE
;
439 void setup_client_action(ObAction
**a
, ObUserAction uact
)
441 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
444 ActionString actionstrings
[] =
447 "directionalfocusnorth",
448 action_directional_focus
,
449 setup_action_directional_focus_north
452 "directionalfocuseast",
453 action_directional_focus
,
454 setup_action_directional_focus_east
457 "directionalfocussouth",
458 action_directional_focus
,
459 setup_action_directional_focus_south
462 "directionalfocuswest",
463 action_directional_focus
,
464 setup_action_directional_focus_west
467 "directionalfocusnortheast",
468 action_directional_focus
,
469 setup_action_directional_focus_northeast
472 "directionalfocussoutheast",
473 action_directional_focus
,
474 setup_action_directional_focus_southeast
477 "directionalfocussouthwest",
478 action_directional_focus
,
479 setup_action_directional_focus_southwest
482 "directionalfocusnorthwest",
483 action_directional_focus
,
484 setup_action_directional_focus_northwest
493 action_focus_order_to_bottom
,
543 action_toggle_omnipresent
,
548 action_move_relative_horz
,
553 action_move_relative_vert
,
558 action_move_to_center
,
562 "resizerelativehorz",
563 action_resize_relative_horz
,
567 "resizerelativevert",
568 action_resize_relative_vert
,
573 action_move_relative
,
578 action_resize_relative
,
583 action_maximize_full
,
588 action_unmaximize_full
,
592 "togglemaximizefull",
593 action_toggle_maximize_full
,
598 action_maximize_horz
,
603 action_unmaximize_horz
,
607 "togglemaximizehorz",
608 action_toggle_maximize_horz
,
613 action_maximize_vert
,
618 action_unmaximize_vert
,
622 "togglemaximizevert",
623 action_toggle_maximize_vert
,
628 action_toggle_fullscreen
,
633 action_send_to_desktop
,
634 setup_action_send_to_desktop
638 action_send_to_desktop_dir
,
639 setup_action_send_to_desktop_next
642 "sendtodesktopprevious",
643 action_send_to_desktop_dir
,
644 setup_action_send_to_desktop_prev
647 "sendtodesktopright",
648 action_send_to_desktop_dir
,
649 setup_action_send_to_desktop_right
653 action_send_to_desktop_dir
,
654 setup_action_send_to_desktop_left
658 action_send_to_desktop_dir
,
659 setup_action_send_to_desktop_up
663 action_send_to_desktop_dir
,
664 setup_action_send_to_desktop_down
674 setup_action_desktop_next
679 setup_action_desktop_prev
684 setup_action_desktop_right
689 setup_action_desktop_left
694 setup_action_desktop_up
699 setup_action_desktop_down
703 action_toggle_decorations
,
712 "toggledockautohide",
713 action_toggle_dockautohide
,
723 action_send_to_layer
,
724 setup_action_top_layer
729 setup_action_top_layer
733 action_send_to_layer
,
734 setup_action_normal_layer
738 action_send_to_layer
,
739 setup_action_bottom_layer
742 "togglealwaysonbottom",
744 setup_action_bottom_layer
749 setup_action_movefromedge_north
754 setup_action_movefromedge_south
759 setup_action_movefromedge_west
764 setup_action_movefromedge_east
769 setup_action_movetoedge_north
774 setup_action_movetoedge_south
779 setup_action_movetoedge_west
784 setup_action_movetoedge_east
789 setup_action_growtoedge_north
794 setup_action_growtoedge_south
799 setup_action_growtoedge_west
804 setup_action_growtoedge_east
809 setup_action_addremove_desktop_last
813 action_remove_desktop
,
814 setup_action_addremove_desktop_last
819 setup_action_addremove_desktop_current
822 "removedesktopcurrent",
823 action_remove_desktop
,
824 setup_action_addremove_desktop_current
833 /* only key bindings can be interactive. thus saith the xor.
834 because of how the mouse is grabbed, mouse events dont even get
835 read during interactive events, so no dice! >:) */
836 #define INTERACTIVE_LIMIT(a, uact) \
837 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
838 a->data.any.interactive = FALSE;
840 ObAction
*action_from_string(const gchar
*name
, ObUserAction uact
)
843 gboolean exist
= FALSE
;
846 for (i
= 0; actionstrings
[i
].name
; i
++)
847 if (!g_ascii_strcasecmp(name
, actionstrings
[i
].name
)) {
849 a
= action_new(actionstrings
[i
].func
);
850 if (actionstrings
[i
].setup
)
851 actionstrings
[i
].setup(&a
, uact
);
853 INTERACTIVE_LIMIT(a
, uact
);
857 g_message(_("Invalid action '%s' requested. No such action exists."),
860 g_message(_("Invalid use of action '%s'. Action will be ignored."),
865 ObAction
*action_parse(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
869 ObAction
*act
= NULL
;
872 if (parse_attr_string("name", node
, &actname
)) {
873 if ((act
= action_from_string(actname
, uact
))) {
874 } else if (act
->func
== action_move_relative_horz
||
875 act
->func
== action_move_relative_vert
||
876 act
->func
== action_resize_relative_horz
||
877 act
->func
== action_resize_relative_vert
) {
878 if ((n
= parse_find_node("delta", node
->xmlChildrenNode
)))
879 act
->data
.relative
.deltax
= parse_int(doc
, n
);
880 } else if (act
->func
== action_move_relative
) {
881 if ((n
= parse_find_node("x", node
->xmlChildrenNode
)))
882 act
->data
.relative
.deltax
= parse_int(doc
, n
);
883 if ((n
= parse_find_node("y", node
->xmlChildrenNode
)))
884 act
->data
.relative
.deltay
= parse_int(doc
, n
);
885 } else if (act
->func
== action_resize_relative
) {
886 if ((n
= parse_find_node("left", node
->xmlChildrenNode
)))
887 act
->data
.relative
.deltaxl
= parse_int(doc
, n
);
888 if ((n
= parse_find_node("up", node
->xmlChildrenNode
)))
889 act
->data
.relative
.deltayu
= parse_int(doc
, n
);
890 if ((n
= parse_find_node("right", node
->xmlChildrenNode
)))
891 act
->data
.relative
.deltax
= parse_int(doc
, n
);
892 if ((n
= parse_find_node("down", node
->xmlChildrenNode
)))
893 act
->data
.relative
.deltay
= parse_int(doc
, n
);
894 } else if (act
->func
== action_desktop
) {
895 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
896 act
->data
.desktop
.desk
= parse_int(doc
, n
);
897 if (act
->data
.desktop
.desk
> 0) act
->data
.desktop
.desk
--;
899 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
900 act->data.desktop.inter.any.interactive =
903 } else if (act
->func
== action_send_to_desktop
) {
904 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
905 act
->data
.sendto
.desk
= parse_int(doc
, n
);
906 if (act
->data
.sendto
.desk
> 0) act
->data
.sendto
.desk
--;
907 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
908 act
->data
.sendto
.follow
= parse_bool(doc
, n
);
909 } else if (act
->func
== action_desktop_dir
) {
910 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
911 act
->data
.desktopdir
.wrap
= parse_bool(doc
, n
);
912 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
913 act
->data
.desktopdir
.inter
.any
.interactive
=
915 } else if (act
->func
== action_send_to_desktop_dir
) {
916 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
917 act
->data
.sendtodir
.wrap
= parse_bool(doc
, n
);
918 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
919 act
->data
.sendtodir
.follow
= parse_bool(doc
, n
);
920 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
921 act
->data
.sendtodir
.inter
.any
.interactive
=
923 } else if (act
->func
== action_directional_focus
) {
924 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
925 act
->data
.interdiraction
.dialog
= parse_bool(doc
, n
);
926 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
927 act
->data
.interdiraction
.dock_windows
= parse_bool(doc
, n
);
928 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
929 act
->data
.interdiraction
.desktop_windows
=
931 } else if (act
->func
== action_resize
) {
932 if ((n
= parse_find_node("edge", node
->xmlChildrenNode
))) {
933 gchar
*s
= parse_string(doc
, n
);
934 if (!g_ascii_strcasecmp(s
, "top"))
935 act
->data
.moveresize
.corner
=
936 prop_atoms
.net_wm_moveresize_size_top
;
937 else if (!g_ascii_strcasecmp(s
, "bottom"))
938 act
->data
.moveresize
.corner
=
939 prop_atoms
.net_wm_moveresize_size_bottom
;
940 else if (!g_ascii_strcasecmp(s
, "left"))
941 act
->data
.moveresize
.corner
=
942 prop_atoms
.net_wm_moveresize_size_left
;
943 else if (!g_ascii_strcasecmp(s
, "right"))
944 act
->data
.moveresize
.corner
=
945 prop_atoms
.net_wm_moveresize_size_right
;
946 else if (!g_ascii_strcasecmp(s
, "topleft"))
947 act
->data
.moveresize
.corner
=
948 prop_atoms
.net_wm_moveresize_size_topleft
;
949 else if (!g_ascii_strcasecmp(s
, "topright"))
950 act
->data
.moveresize
.corner
=
951 prop_atoms
.net_wm_moveresize_size_topright
;
952 else if (!g_ascii_strcasecmp(s
, "bottomleft"))
953 act
->data
.moveresize
.corner
=
954 prop_atoms
.net_wm_moveresize_size_bottomleft
;
955 else if (!g_ascii_strcasecmp(s
, "bottomright"))
956 act
->data
.moveresize
.corner
=
957 prop_atoms
.net_wm_moveresize_size_bottomright
;
960 } else if (act
->func
== action_raise
||
961 act
->func
== action_lower
||
962 act
->func
== action_raiselower
||
963 act
->func
== action_shadelower
||
964 act
->func
== action_unshaderaise
) {
966 INTERACTIVE_LIMIT(act
, uact
);
973 void action_run_list(GSList
*acts
, ObClient
*c
, ObFrameContext context
,
974 guint state
, guint button
, gint x
, gint y
, Time time
,
975 gboolean cancel
, gboolean done
)
984 screen_pointer_pos(&x
, &y
);
986 for (it
= acts
; it
; it
= g_slist_next(it
)) {
989 if (!(a
->data
.any
.client_action
== OB_CLIENT_ACTION_ALWAYS
&& !c
)) {
990 a
->data
.any
.c
= a
->data
.any
.client_action
? c
: NULL
;
991 a
->data
.any
.context
= context
;
995 a
->data
.any
.button
= button
;
997 a
->data
.any
.time
= time
;
999 if (a
->data
.any
.interactive
) {
1000 a
->data
.inter
.cancel
= cancel
;
1001 a
->data
.inter
.final
= done
;
1002 if (!(cancel
|| done
))
1003 if (!keyboard_interactive_grab(state
, a
->data
.any
.c
, a
))
1007 /* XXX UGLY HACK race with motion event starting a move and the
1008 button release gettnig processed first. answer: don't queue
1009 moveresize starts. UGLY HACK XXX
1011 XXX ALSO don't queue showmenu events, because on button press
1012 events we need to know if a mouse grab is going to take place,
1013 and set the button to 0, so that later motion events don't think
1014 that a drag is going on. since showmenu grabs the pointer..
1016 if (a
->data
.any
.interactive
|| a
->func
== action_move
||
1017 a
->func
== action_resize
|| a
->func
== action_showmenu
)
1019 /* interactive actions are not queued */
1021 } else if (a
->func
== action_focus
||
1022 a
->func
== action_activate
||
1023 a
->func
== action_showmenu
)
1025 /* XXX MORE UGLY HACK
1026 actions from clicks on client windows are NOT queued.
1027 this solves the mysterious click-and-drag-doesnt-work
1028 problem. it was because the window gets focused and stuff
1029 after the button event has already been passed through. i
1030 dont really know why it should care but it does and it makes
1033 however this very bogus ! !
1034 we want to send the button press to the window BEFORE
1035 we do the action because the action might move the windows
1036 (eg change desktops) and then the button press ends up on
1037 the completely wrong window !
1038 so, this is just for that bug, and it will only NOT queue it
1039 if it is a focusing action that can be used with the mouse
1042 also with the menus, there is a race going on. if the
1043 desktop wants to pop up a menu, and we do too, we send them
1044 the button before we pop up the menu, so they pop up their
1045 menu first. but not always. if we pop up our menu before
1046 sending them the button press, then the result is
1049 XXX further more. focus actions are not queued at all,
1050 because if you bind focus->showmenu, the menu will get
1051 hidden to do the focusing
1055 ob_main_loop_queue_action(ob_main_loop
, a
);
1060 void action_run_string(const gchar
*name
, struct _ObClient
*c
, Time time
)
1065 a
= action_from_string(name
, OB_USER_ACTION_NONE
);
1068 l
= g_slist_append(NULL
, a
);
1070 action_run(l
, c
, 0, time
);
1073 void action_unfocus (union ActionData
*data
)
1075 if (data
->client
.any
.c
== focus_client
)
1076 focus_fallback(FALSE
, FALSE
, TRUE
);
1079 void action_iconify(union ActionData
*data
)
1081 client_action_start(data
);
1082 client_iconify(data
->client
.any
.c
, TRUE
, TRUE
, FALSE
);
1083 client_action_end(data
, config_focus_under_mouse
);
1086 void action_focus_order_to_bottom(union ActionData
*data
)
1088 focus_order_to_bottom(data
->client
.any
.c
);
1091 void action_raiselower(union ActionData
*data
)
1093 ObClient
*c
= data
->client
.any
.c
;
1095 client_action_start(data
);
1096 stacking_restack_request(c
, NULL
, Opposite
);
1097 client_action_end(data
, config_focus_under_mouse
);
1100 void action_raise(union ActionData
*data
)
1102 client_action_start(data
);
1103 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1104 client_action_end(data
, config_focus_under_mouse
);
1107 void action_unshaderaise(union ActionData
*data
)
1109 if (data
->client
.any
.c
->shaded
)
1110 action_unshade(data
);
1115 void action_shadelower(union ActionData
*data
)
1117 if (data
->client
.any
.c
->shaded
)
1123 void action_lower(union ActionData
*data
)
1125 client_action_start(data
);
1126 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1127 client_action_end(data
, config_focus_under_mouse
);
1130 void action_kill(union ActionData
*data
)
1132 client_kill(data
->client
.any
.c
);
1135 void action_shade(union ActionData
*data
)
1137 client_action_start(data
);
1138 client_shade(data
->client
.any
.c
, TRUE
);
1139 client_action_end(data
, config_focus_under_mouse
);
1142 void action_unshade(union ActionData
*data
)
1144 client_action_start(data
);
1145 client_shade(data
->client
.any
.c
, FALSE
);
1146 client_action_end(data
, config_focus_under_mouse
);
1149 void action_toggle_shade(union ActionData
*data
)
1151 client_action_start(data
);
1152 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1153 client_action_end(data
, config_focus_under_mouse
);
1156 void action_toggle_omnipresent(union ActionData
*data
)
1158 client_set_desktop(data
->client
.any
.c
,
1159 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1160 screen_desktop
: DESKTOP_ALL
, FALSE
, TRUE
);
1163 void action_move_relative_horz(union ActionData
*data
)
1165 ObClient
*c
= data
->relative
.any
.c
;
1166 client_action_start(data
);
1167 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
);
1168 client_action_end(data
, FALSE
);
1171 void action_move_relative_vert(union ActionData
*data
)
1173 ObClient
*c
= data
->relative
.any
.c
;
1174 client_action_start(data
);
1175 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.deltax
);
1176 client_action_end(data
, FALSE
);
1179 void action_move_to_center(union ActionData
*data
)
1181 ObClient
*c
= data
->client
.any
.c
;
1183 area
= screen_area(c
->desktop
, client_monitor(c
), NULL
);
1184 client_action_start(data
);
1185 client_move(c
, area
->x
+ area
->width
/ 2 - c
->area
.width
/ 2,
1186 area
->y
+ area
->height
/ 2 - c
->area
.height
/ 2);
1187 client_action_end(data
, FALSE
);
1191 void action_resize_relative_horz(union ActionData
*data
)
1193 ObClient
*c
= data
->relative
.any
.c
;
1194 client_action_start(data
);
1196 c
->area
.width
+ data
->relative
.deltax
* c
->size_inc
.width
,
1198 client_action_end(data
, FALSE
);
1201 void action_resize_relative_vert(union ActionData
*data
)
1203 ObClient
*c
= data
->relative
.any
.c
;
1205 client_action_start(data
);
1206 client_resize(c
, c
->area
.width
, c
->area
.height
+
1207 data
->relative
.deltax
* c
->size_inc
.height
);
1208 client_action_end(data
, FALSE
);
1212 void action_move_relative(union ActionData
*data
)
1214 ObClient
*c
= data
->relative
.any
.c
;
1215 client_action_start(data
);
1216 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
+
1217 data
->relative
.deltay
);
1218 client_action_end(data
, FALSE
);
1221 void action_resize_relative(union ActionData
*data
)
1223 ObClient
*c
= data
->relative
.any
.c
;
1224 gint x
, y
, ow
, xoff
, nw
, oh
, yoff
, nh
, lw
, lh
;
1226 client_action_start(data
);
1231 xoff
= -data
->relative
.deltaxl
* c
->size_inc
.width
;
1232 nw
= ow
+ data
->relative
.deltax
* c
->size_inc
.width
1233 + data
->relative
.deltaxl
* c
->size_inc
.width
;
1234 oh
= c
->area
.height
;
1235 yoff
= -data
->relative
.deltayu
* c
->size_inc
.height
;
1236 nh
= oh
+ data
->relative
.deltay
* c
->size_inc
.height
1237 + data
->relative
.deltayu
* c
->size_inc
.height
;
1239 g_print("deltax %d %d x %d ow %d xoff %d nw %d\n",
1240 data
->relative
.deltax
,
1241 data
->relative
.deltaxl
,
1244 client_try_configure(c
, &x
, &y
, &nw
, &nh
, &lw
, &lh
, TRUE
);
1245 xoff
= xoff
== 0 ? 0 : (xoff
< 0 ? MAX(xoff
, ow
-nw
) : MIN(xoff
, ow
-nw
));
1246 yoff
= yoff
== 0 ? 0 : (yoff
< 0 ? MAX(yoff
, oh
-nh
) : MIN(yoff
, oh
-nh
));
1247 client_move_resize(c
, x
+ xoff
, y
+ yoff
, nw
, nh
);
1248 client_action_end(data
, FALSE
);
1251 void action_maximize_full(union ActionData
*data
)
1253 client_action_start(data
);
1254 client_maximize(data
->client
.any
.c
, TRUE
, 0);
1255 client_action_end(data
, config_focus_under_mouse
);
1258 void action_unmaximize_full(union ActionData
*data
)
1260 client_action_start(data
);
1261 client_maximize(data
->client
.any
.c
, FALSE
, 0);
1262 client_action_end(data
, config_focus_under_mouse
);
1265 void action_toggle_maximize_full(union ActionData
*data
)
1267 client_action_start(data
);
1268 client_maximize(data
->client
.any
.c
,
1269 !(data
->client
.any
.c
->max_horz
||
1270 data
->client
.any
.c
->max_vert
),
1272 client_action_end(data
, config_focus_under_mouse
);
1275 void action_maximize_horz(union ActionData
*data
)
1277 client_action_start(data
);
1278 client_maximize(data
->client
.any
.c
, TRUE
, 1);
1279 client_action_end(data
, config_focus_under_mouse
);
1282 void action_unmaximize_horz(union ActionData
*data
)
1284 client_action_start(data
);
1285 client_maximize(data
->client
.any
.c
, FALSE
, 1);
1286 client_action_end(data
, config_focus_under_mouse
);
1289 void action_toggle_maximize_horz(union ActionData
*data
)
1291 client_action_start(data
);
1292 client_maximize(data
->client
.any
.c
,
1293 !data
->client
.any
.c
->max_horz
, 1);
1294 client_action_end(data
, config_focus_under_mouse
);
1297 void action_maximize_vert(union ActionData
*data
)
1299 client_action_start(data
);
1300 client_maximize(data
->client
.any
.c
, TRUE
, 2);
1301 client_action_end(data
, config_focus_under_mouse
);
1304 void action_unmaximize_vert(union ActionData
*data
)
1306 client_action_start(data
);
1307 client_maximize(data
->client
.any
.c
, FALSE
, 2);
1308 client_action_end(data
, config_focus_under_mouse
);
1311 void action_toggle_maximize_vert(union ActionData
*data
)
1313 client_action_start(data
);
1314 client_maximize(data
->client
.any
.c
,
1315 !data
->client
.any
.c
->max_vert
, 2);
1316 client_action_end(data
, config_focus_under_mouse
);
1319 void action_toggle_fullscreen(union ActionData
*data
)
1321 client_action_start(data
);
1322 client_fullscreen(data
->client
.any
.c
, !(data
->client
.any
.c
->fullscreen
));
1323 client_action_end(data
, config_focus_under_mouse
);
1326 void action_send_to_desktop(union ActionData
*data
)
1328 ObClient
*c
= data
->sendto
.any
.c
;
1330 if (!client_normal(c
)) return;
1332 if (data
->sendto
.desk
< screen_num_desktops
||
1333 data
->sendto
.desk
== DESKTOP_ALL
) {
1334 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
, FALSE
);
1335 if (data
->sendto
.follow
&& data
->sendto
.desk
!= screen_desktop
)
1336 screen_set_desktop(data
->sendto
.desk
, TRUE
);
1340 void action_desktop(union ActionData
*data
)
1342 /* XXX add the interactive/dialog option back again once the dialog
1343 has been made to not use grabs */
1344 if (data
->desktop
.desk
< screen_num_desktops
||
1345 data
->desktop
.desk
== DESKTOP_ALL
)
1347 screen_set_desktop(data
->desktop
.desk
, TRUE
);
1348 if (data
->inter
.any
.interactive
)
1349 screen_desktop_popup(data
->desktop
.desk
, TRUE
);
1353 void action_desktop_dir(union ActionData
*data
)
1357 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1358 data
->desktopdir
.wrap
,
1359 data
->desktopdir
.linear
,
1360 data
->desktopdir
.inter
.any
.interactive
,
1361 data
->desktopdir
.inter
.final
,
1362 data
->desktopdir
.inter
.cancel
);
1363 /* only move the desktop when the action is complete. if we switch
1364 desktops during the interactive action, focus will move but with
1365 NotifyWhileGrabbed and applications don't like that. */
1366 if (!data
->sendtodir
.inter
.any
.interactive
||
1367 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1369 if (d
!= screen_desktop
)
1370 screen_set_desktop(d
, TRUE
);
1374 void action_send_to_desktop_dir(union ActionData
*data
)
1376 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1379 if (!client_normal(c
)) return;
1381 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1382 data
->sendtodir
.linear
,
1383 data
->sendtodir
.inter
.any
.interactive
,
1384 data
->sendtodir
.inter
.final
,
1385 data
->sendtodir
.inter
.cancel
);
1386 /* only move the desktop when the action is complete. if we switch
1387 desktops during the interactive action, focus will move but with
1388 NotifyWhileGrabbed and applications don't like that. */
1389 if (!data
->sendtodir
.inter
.any
.interactive
||
1390 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1392 client_set_desktop(c
, d
, data
->sendtodir
.follow
, FALSE
);
1393 if (data
->sendtodir
.follow
&& d
!= screen_desktop
)
1394 screen_set_desktop(d
, TRUE
);
1398 void action_desktop_last(union ActionData
*data
)
1400 if (screen_last_desktop
< screen_num_desktops
)
1401 screen_set_desktop(screen_last_desktop
, TRUE
);
1404 void action_toggle_decorations(union ActionData
*data
)
1406 ObClient
*c
= data
->client
.any
.c
;
1408 client_action_start(data
);
1409 client_set_undecorated(c
, !c
->undecorated
);
1410 client_action_end(data
, FALSE
);
1413 static guint32
pick_corner(gint x
, gint y
, gint cx
, gint cy
, gint cw
, gint ch
,
1416 /* let's make x and y client relative instead of screen relative */
1418 y
= ch
- (y
- cy
); /* y is inverted, 0 is at the bottom of the window */
1421 #define A -4*X + 7*ch/3
1422 #define B 4*X -15*ch/9
1423 #define C -X/4 + 2*ch/3
1424 #define D X/4 + 5*ch/12
1425 #define E X/4 + ch/3
1426 #define F -X/4 + 7*ch/12
1427 #define G 4*X - 4*ch/3
1428 #define H -4*X + 8*ch/3
1429 #define a (y > 5*ch/9)
1430 #define b (x < 4*cw/9)
1431 #define c (x > 5*cw/9)
1432 #define d (y < 4*ch/9)
1435 Each of these defines (except X which is just there for fun), represents
1436 the equation of a line. The lines they represent are shown in the diagram
1437 below. Checking y against these lines, we are able to choose a region
1438 of the window as shown.
1440 +---------------------A-------|-------|-------B---------------------+
1447 | northwest | A north B | northeast |
1450 C---------------------+----A--+-------+--B----+---------------------D
1451 |CCCCCCC | A B | DDDDDDD|
1452 | CCCCCCCC | A | | B | DDDDDDDD |
1453 | CCCCCCC A B DDDDDDD |
1454 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
1456 | west | b move c | east | ad
1458 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
1459 | EEEEEEE G H FFFFFFF |
1460 | EEEEEEEE | G | | H | FFFFFFFF |
1461 |EEEEEEE | G H | FFFFFFF|
1462 E---------------------+----G--+-------+--H----+---------------------F
1465 | southwest | G south H | southeast |
1472 +---------------------G-------|-------|-------H---------------------+
1476 /* for shaded windows, you can only resize west/east and move */
1478 return prop_atoms
.net_wm_moveresize_size_left
;
1480 return prop_atoms
.net_wm_moveresize_size_right
;
1481 return prop_atoms
.net_wm_moveresize_move
;
1484 if (y
< A
&& y
>= C
)
1485 return prop_atoms
.net_wm_moveresize_size_topleft
;
1486 else if (y
>= A
&& y
>= B
&& a
)
1487 return prop_atoms
.net_wm_moveresize_size_top
;
1488 else if (y
< B
&& y
>= D
)
1489 return prop_atoms
.net_wm_moveresize_size_topright
;
1490 else if (y
< C
&& y
>= E
&& b
)
1491 return prop_atoms
.net_wm_moveresize_size_left
;
1492 else if (y
< D
&& y
>= F
&& c
)
1493 return prop_atoms
.net_wm_moveresize_size_right
;
1494 else if (y
< E
&& y
>= G
)
1495 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1496 else if (y
< G
&& y
< H
&& d
)
1497 return prop_atoms
.net_wm_moveresize_size_bottom
;
1498 else if (y
>= H
&& y
< F
)
1499 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1501 return prop_atoms
.net_wm_moveresize_move
;
1518 void action_resize(union ActionData
*data
)
1520 ObClient
*c
= data
->moveresize
.any
.c
;
1523 if (data
->moveresize
.keyboard
)
1524 corner
= prop_atoms
.net_wm_moveresize_size_keyboard
;
1525 else if (data
->moveresize
.corner
)
1526 corner
= data
->moveresize
.corner
; /* it was specified in the binding */
1528 corner
= pick_corner(data
->any
.x
, data
->any
.y
,
1529 c
->frame
->area
.x
, c
->frame
->area
.y
,
1530 /* use the client size because the frame
1531 can be differently sized (shaded
1532 windows) and we want this based on the
1534 c
->area
.width
+ c
->frame
->size
.left
+
1535 c
->frame
->size
.right
,
1536 c
->area
.height
+ c
->frame
->size
.top
+
1537 c
->frame
->size
.bottom
, c
->shaded
);
1539 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1542 void action_directional_focus(union ActionData
*data
)
1544 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1546 event_halt_focus_delay();
1548 focus_directional_cycle(data
->interdiraction
.direction
,
1549 data
->interdiraction
.dock_windows
,
1550 data
->interdiraction
.desktop_windows
,
1551 data
->any
.interactive
,
1552 data
->interdiraction
.dialog
,
1553 data
->interdiraction
.inter
.final
,
1554 data
->interdiraction
.inter
.cancel
);
1557 void action_movetoedge(union ActionData
*data
)
1560 ObClient
*c
= data
->diraction
.any
.c
;
1562 x
= c
->frame
->area
.x
;
1563 y
= c
->frame
->area
.y
;
1565 switch(data
->diraction
.direction
) {
1566 case OB_DIRECTION_NORTH
:
1567 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
,
1568 data
->diraction
.hang
)
1569 - (data
->diraction
.hang
? c
->frame
->area
.height
: 0);
1571 case OB_DIRECTION_WEST
:
1572 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
,
1573 data
->diraction
.hang
)
1574 - (data
->diraction
.hang
? c
->frame
->area
.width
: 0);
1576 case OB_DIRECTION_SOUTH
:
1577 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
,
1578 data
->diraction
.hang
)
1579 - (data
->diraction
.hang
? 0 : c
->frame
->area
.height
);
1581 case OB_DIRECTION_EAST
:
1582 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
,
1583 data
->diraction
.hang
)
1584 - (data
->diraction
.hang
? 0 : c
->frame
->area
.width
);
1587 g_assert_not_reached();
1589 frame_frame_gravity(c
->frame
, &x
, &y
, c
->area
.width
, c
->area
.height
);
1590 client_action_start(data
);
1591 client_move(c
, x
, y
);
1592 client_action_end(data
, FALSE
);
1595 void action_growtoedge(union ActionData
*data
)
1597 gint x
, y
, width
, height
, dest
;
1598 ObClient
*c
= data
->diraction
.any
.c
;
1601 a
= screen_area(c
->desktop
, SCREEN_AREA_ALL_MONITORS
, &c
->frame
->area
);
1602 x
= c
->frame
->area
.x
;
1603 y
= c
->frame
->area
.y
;
1604 /* get the unshaded frame's dimensions..if it is shaded */
1605 width
= c
->area
.width
+ c
->frame
->size
.left
+ c
->frame
->size
.right
;
1606 height
= c
->area
.height
+ c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1608 switch(data
->diraction
.direction
) {
1609 case OB_DIRECTION_NORTH
:
1610 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1612 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
, FALSE
);
1614 height
= height
/ 2;
1616 height
= c
->frame
->area
.y
+ height
- dest
;
1620 case OB_DIRECTION_WEST
:
1621 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
, FALSE
);
1625 width
= c
->frame
->area
.x
+ width
- dest
;
1629 case OB_DIRECTION_SOUTH
:
1630 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1632 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
, FALSE
);
1633 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1634 height
= c
->frame
->area
.height
/ 2;
1635 y
= a
->y
+ a
->height
- height
;
1637 height
= dest
- c
->frame
->area
.y
;
1638 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1639 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1641 case OB_DIRECTION_EAST
:
1642 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
, FALSE
);
1643 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1644 width
= c
->frame
->area
.width
/ 2;
1645 x
= a
->x
+ a
->width
- width
;
1647 width
= dest
- c
->frame
->area
.x
;
1648 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1649 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1652 g_assert_not_reached();
1654 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1655 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1656 frame_frame_gravity(c
->frame
, &x
, &y
, width
, height
);
1657 client_action_start(data
);
1658 client_move_resize(c
, x
, y
, width
, height
);
1659 client_action_end(data
, FALSE
);
1663 void action_send_to_layer(union ActionData
*data
)
1665 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1668 void action_toggle_layer(union ActionData
*data
)
1670 ObClient
*c
= data
->layer
.any
.c
;
1672 client_action_start(data
);
1673 if (data
->layer
.layer
< 0)
1674 client_set_layer(c
, c
->below
? 0 : -1);
1675 else if (data
->layer
.layer
> 0)
1676 client_set_layer(c
, c
->above
? 0 : 1);
1677 client_action_end(data
, config_focus_under_mouse
);
1680 void action_toggle_dockautohide(union ActionData
*data
)
1682 config_dock_hide
= !config_dock_hide
;
1686 void action_add_desktop(union ActionData
*data
)
1688 client_action_start(data
);
1689 screen_set_num_desktops(screen_num_desktops
+1);
1691 /* move all the clients over */
1692 if (data
->addremovedesktop
.current
) {
1695 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1696 ObClient
*c
= it
->data
;
1697 if (c
->desktop
!= DESKTOP_ALL
&& c
->desktop
>= screen_desktop
)
1698 client_set_desktop(c
, c
->desktop
+1, FALSE
, TRUE
);
1702 client_action_end(data
, config_focus_under_mouse
);
1705 void action_remove_desktop(union ActionData
*data
)
1707 guint rmdesktop
, movedesktop
;
1708 GList
*it
, *stacking_copy
;
1710 if (screen_num_desktops
< 2) return;
1712 client_action_start(data
);
1714 /* what desktop are we removing and moving to? */
1715 if (data
->addremovedesktop
.current
)
1716 rmdesktop
= screen_desktop
;
1718 rmdesktop
= screen_num_desktops
- 1;
1719 if (rmdesktop
< screen_num_desktops
- 1)
1720 movedesktop
= rmdesktop
+ 1;
1722 movedesktop
= rmdesktop
;
1724 /* make a copy of the list cuz we're changing it */
1725 stacking_copy
= g_list_copy(stacking_list
);
1726 for (it
= g_list_last(stacking_copy
); it
; it
= g_list_previous(it
)) {
1727 if (WINDOW_IS_CLIENT(it
->data
)) {
1728 ObClient
*c
= it
->data
;
1729 guint d
= c
->desktop
;
1730 if (d
!= DESKTOP_ALL
&& d
>= movedesktop
) {
1731 client_set_desktop(c
, c
->desktop
- 1, TRUE
, TRUE
);
1732 ob_debug("moving window %s\n", c
->title
);
1734 /* raise all the windows that are on the current desktop which
1736 if ((screen_desktop
== rmdesktop
- 1 ||
1737 screen_desktop
== rmdesktop
) &&
1738 (d
== DESKTOP_ALL
|| d
== screen_desktop
))
1740 stacking_raise(CLIENT_AS_WINDOW(c
));
1741 ob_debug("raising window %s\n", c
->title
);
1746 /* act like we're changing desktops */
1747 if (screen_desktop
< screen_num_desktops
- 1) {
1748 gint d
= screen_desktop
;
1749 screen_desktop
= screen_last_desktop
;
1750 screen_set_desktop(d
, TRUE
);
1751 ob_debug("fake desktop change\n");
1754 screen_set_num_desktops(screen_num_desktops
-1);
1756 client_action_end(data
, config_focus_under_mouse
);