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"
47 void (*func
)(union ActionData
*);
48 void (*setup
)(ObAction
**, ObUserAction uact
);
51 static ObAction
*action_new(void (*func
)(union ActionData
*data
))
53 ObAction
*a
= g_new0(ObAction
, 1);
60 void action_ref(ObAction
*a
)
65 void action_unref(ObAction
*a
)
67 if (a
== NULL
) return;
69 if (--a
->ref
> 0) return;
71 /* deal with pointers */
72 if (a
->func
== action_execute
|| a
->func
== action_restart
)
73 g_free(a
->data
.execute
.path
);
74 else if (a
->func
== action_debug
)
75 g_free(a
->data
.debug
.string
);
76 else if (a
->func
== action_showmenu
)
77 g_free(a
->data
.showmenu
.name
);
82 ObAction
* action_copy(const ObAction
*src
)
84 ObAction
*a
= action_new(src
->func
);
88 /* deal with pointers */
89 if (a
->func
== action_execute
|| a
->func
== action_restart
)
90 a
->data
.execute
.path
= g_strdup(a
->data
.execute
.path
);
91 else if (a
->func
== action_debug
)
92 a
->data
.debug
.string
= g_strdup(a
->data
.debug
.string
);
93 else if (a
->func
== action_showmenu
)
94 a
->data
.showmenu
.name
= g_strdup(a
->data
.showmenu
.name
);
99 void setup_action_directional_focus_north(ObAction
**a
, ObUserAction uact
)
101 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
102 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTH
;
103 (*a
)->data
.interdiraction
.dialog
= TRUE
;
104 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
105 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
108 void setup_action_directional_focus_east(ObAction
**a
, ObUserAction uact
)
110 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
111 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_EAST
;
112 (*a
)->data
.interdiraction
.dialog
= TRUE
;
113 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
114 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
117 void setup_action_directional_focus_south(ObAction
**a
, ObUserAction uact
)
119 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
120 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTH
;
121 (*a
)->data
.interdiraction
.dialog
= TRUE
;
122 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
123 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
126 void setup_action_directional_focus_west(ObAction
**a
, ObUserAction uact
)
128 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
129 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_WEST
;
130 (*a
)->data
.interdiraction
.dialog
= TRUE
;
131 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
132 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
135 void setup_action_directional_focus_northeast(ObAction
**a
, ObUserAction uact
)
137 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
138 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHEAST
;
139 (*a
)->data
.interdiraction
.dialog
= TRUE
;
140 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
141 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
144 void setup_action_directional_focus_southeast(ObAction
**a
, ObUserAction uact
)
146 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
147 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHEAST
;
148 (*a
)->data
.interdiraction
.dialog
= TRUE
;
149 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
150 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
153 void setup_action_directional_focus_southwest(ObAction
**a
, ObUserAction uact
)
155 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
156 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHWEST
;
157 (*a
)->data
.interdiraction
.dialog
= TRUE
;
158 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
159 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
162 void setup_action_directional_focus_northwest(ObAction
**a
, ObUserAction uact
)
164 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
165 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHWEST
;
166 (*a
)->data
.interdiraction
.dialog
= TRUE
;
167 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
168 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
171 void setup_action_send_to_desktop(ObAction
**a
, ObUserAction uact
)
173 (*a
)->data
.sendto
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
174 (*a
)->data
.sendto
.follow
= TRUE
;
177 void setup_action_send_to_desktop_prev(ObAction
**a
, ObUserAction uact
)
179 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
180 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
181 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
182 (*a
)->data
.sendtodir
.linear
= TRUE
;
183 (*a
)->data
.sendtodir
.wrap
= TRUE
;
184 (*a
)->data
.sendtodir
.follow
= TRUE
;
187 void setup_action_send_to_desktop_next(ObAction
**a
, ObUserAction uact
)
189 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
190 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
191 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
192 (*a
)->data
.sendtodir
.linear
= TRUE
;
193 (*a
)->data
.sendtodir
.wrap
= TRUE
;
194 (*a
)->data
.sendtodir
.follow
= TRUE
;
197 void setup_action_send_to_desktop_left(ObAction
**a
, ObUserAction uact
)
199 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
200 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
201 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
202 (*a
)->data
.sendtodir
.linear
= FALSE
;
203 (*a
)->data
.sendtodir
.wrap
= TRUE
;
204 (*a
)->data
.sendtodir
.follow
= TRUE
;
207 void setup_action_send_to_desktop_right(ObAction
**a
, ObUserAction uact
)
209 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
210 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
211 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
212 (*a
)->data
.sendtodir
.linear
= FALSE
;
213 (*a
)->data
.sendtodir
.wrap
= TRUE
;
214 (*a
)->data
.sendtodir
.follow
= TRUE
;
217 void setup_action_send_to_desktop_up(ObAction
**a
, ObUserAction uact
)
219 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
220 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
221 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_NORTH
;
222 (*a
)->data
.sendtodir
.linear
= FALSE
;
223 (*a
)->data
.sendtodir
.wrap
= TRUE
;
224 (*a
)->data
.sendtodir
.follow
= TRUE
;
227 void setup_action_send_to_desktop_down(ObAction
**a
, ObUserAction uact
)
229 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
230 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
231 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_SOUTH
;
232 (*a
)->data
.sendtodir
.linear
= FALSE
;
233 (*a
)->data
.sendtodir
.wrap
= TRUE
;
234 (*a
)->data
.sendtodir
.follow
= TRUE
;
237 void setup_action_desktop(ObAction
**a
, ObUserAction uact
)
240 (*a)->data.desktop.inter.any.interactive = FALSE;
244 void setup_action_desktop_prev(ObAction
**a
, ObUserAction uact
)
246 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
247 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
248 (*a
)->data
.desktopdir
.linear
= TRUE
;
249 (*a
)->data
.desktopdir
.wrap
= TRUE
;
252 void setup_action_desktop_next(ObAction
**a
, ObUserAction uact
)
254 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
255 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
256 (*a
)->data
.desktopdir
.linear
= TRUE
;
257 (*a
)->data
.desktopdir
.wrap
= TRUE
;
260 void setup_action_desktop_left(ObAction
**a
, ObUserAction uact
)
262 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
263 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
264 (*a
)->data
.desktopdir
.linear
= FALSE
;
265 (*a
)->data
.desktopdir
.wrap
= TRUE
;
268 void setup_action_desktop_right(ObAction
**a
, ObUserAction uact
)
270 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
271 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
272 (*a
)->data
.desktopdir
.linear
= FALSE
;
273 (*a
)->data
.desktopdir
.wrap
= TRUE
;
276 void setup_action_desktop_up(ObAction
**a
, ObUserAction uact
)
278 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
279 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_NORTH
;
280 (*a
)->data
.desktopdir
.linear
= FALSE
;
281 (*a
)->data
.desktopdir
.wrap
= TRUE
;
284 void setup_action_desktop_down(ObAction
**a
, ObUserAction uact
)
286 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
287 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_SOUTH
;
288 (*a
)->data
.desktopdir
.linear
= FALSE
;
289 (*a
)->data
.desktopdir
.wrap
= TRUE
;
292 void setup_action_movefromedge_north(ObAction
**a
, ObUserAction uact
)
294 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
295 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
296 (*a
)->data
.diraction
.hang
= TRUE
;
299 void setup_action_movefromedge_south(ObAction
**a
, ObUserAction uact
)
301 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
302 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
303 (*a
)->data
.diraction
.hang
= TRUE
;
306 void setup_action_movefromedge_east(ObAction
**a
, ObUserAction uact
)
308 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
309 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
310 (*a
)->data
.diraction
.hang
= TRUE
;
313 void setup_action_movefromedge_west(ObAction
**a
, ObUserAction uact
)
315 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
316 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
317 (*a
)->data
.diraction
.hang
= TRUE
;
320 void setup_action_movetoedge_north(ObAction
**a
, ObUserAction uact
)
322 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
323 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
324 (*a
)->data
.diraction
.hang
= FALSE
;
327 void setup_action_movetoedge_south(ObAction
**a
, ObUserAction uact
)
329 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
330 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
331 (*a
)->data
.diraction
.hang
= FALSE
;
334 void setup_action_movetoedge_east(ObAction
**a
, ObUserAction uact
)
336 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
337 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
338 (*a
)->data
.diraction
.hang
= FALSE
;
341 void setup_action_movetoedge_west(ObAction
**a
, ObUserAction uact
)
343 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
344 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
345 (*a
)->data
.diraction
.hang
= FALSE
;
348 void setup_action_growtoedge_north(ObAction
**a
, ObUserAction uact
)
350 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
351 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
354 void setup_action_growtoedge_south(ObAction
**a
, ObUserAction uact
)
356 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
357 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
360 void setup_action_growtoedge_east(ObAction
**a
, ObUserAction uact
)
362 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
363 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
366 void setup_action_growtoedge_west(ObAction
**a
, ObUserAction uact
)
368 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
369 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
372 void setup_action_top_layer(ObAction
**a
, ObUserAction uact
)
374 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
375 (*a
)->data
.layer
.layer
= 1;
378 void setup_action_normal_layer(ObAction
**a
, ObUserAction uact
)
380 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
381 (*a
)->data
.layer
.layer
= 0;
384 void setup_action_bottom_layer(ObAction
**a
, ObUserAction uact
)
386 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
387 (*a
)->data
.layer
.layer
= -1;
390 void setup_action_resize(ObAction
**a
, ObUserAction uact
)
392 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
393 (*a
)->data
.moveresize
.keyboard
=
394 (uact
== OB_USER_ACTION_NONE
||
395 uact
== OB_USER_ACTION_KEYBOARD_KEY
||
396 uact
== OB_USER_ACTION_MENU_SELECTION
);
397 (*a
)->data
.moveresize
.corner
= 0;
400 void setup_action_addremove_desktop_current(ObAction
**a
, ObUserAction uact
)
402 (*a
)->data
.addremovedesktop
.current
= TRUE
;
405 void setup_action_addremove_desktop_last(ObAction
**a
, ObUserAction uact
)
407 (*a
)->data
.addremovedesktop
.current
= FALSE
;
410 void setup_client_action(ObAction
**a
, ObUserAction uact
)
412 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
415 ActionString actionstrings
[] =
418 "directionalfocusnorth",
419 action_directional_focus
,
420 setup_action_directional_focus_north
423 "directionalfocuseast",
424 action_directional_focus
,
425 setup_action_directional_focus_east
428 "directionalfocussouth",
429 action_directional_focus
,
430 setup_action_directional_focus_south
433 "directionalfocuswest",
434 action_directional_focus
,
435 setup_action_directional_focus_west
438 "directionalfocusnortheast",
439 action_directional_focus
,
440 setup_action_directional_focus_northeast
443 "directionalfocussoutheast",
444 action_directional_focus
,
445 setup_action_directional_focus_southeast
448 "directionalfocussouthwest",
449 action_directional_focus
,
450 setup_action_directional_focus_southwest
453 "directionalfocusnorthwest",
454 action_directional_focus
,
455 setup_action_directional_focus_northwest
464 action_focus_order_to_bottom
,
499 action_toggle_omnipresent
,
504 action_move_relative_horz
,
509 action_move_relative_vert
,
514 action_move_to_center
,
518 "resizerelativehorz",
519 action_resize_relative_horz
,
523 "resizerelativevert",
524 action_resize_relative_vert
,
529 action_move_relative
,
534 action_resize_relative
,
539 action_maximize_full
,
544 action_unmaximize_full
,
548 "togglemaximizefull",
549 action_toggle_maximize_full
,
554 action_maximize_horz
,
559 action_unmaximize_horz
,
563 "togglemaximizehorz",
564 action_toggle_maximize_horz
,
569 action_maximize_vert
,
574 action_unmaximize_vert
,
578 "togglemaximizevert",
579 action_toggle_maximize_vert
,
584 action_toggle_fullscreen
,
589 action_send_to_desktop
,
590 setup_action_send_to_desktop
594 action_send_to_desktop_dir
,
595 setup_action_send_to_desktop_next
598 "sendtodesktopprevious",
599 action_send_to_desktop_dir
,
600 setup_action_send_to_desktop_prev
603 "sendtodesktopright",
604 action_send_to_desktop_dir
,
605 setup_action_send_to_desktop_right
609 action_send_to_desktop_dir
,
610 setup_action_send_to_desktop_left
614 action_send_to_desktop_dir
,
615 setup_action_send_to_desktop_up
619 action_send_to_desktop_dir
,
620 setup_action_send_to_desktop_down
630 setup_action_desktop_next
635 setup_action_desktop_prev
640 setup_action_desktop_right
645 setup_action_desktop_left
650 setup_action_desktop_up
655 setup_action_desktop_down
659 action_toggle_decorations
,
668 "toggledockautohide",
669 action_toggle_dockautohide
,
679 action_send_to_layer
,
680 setup_action_top_layer
685 setup_action_top_layer
689 action_send_to_layer
,
690 setup_action_normal_layer
694 action_send_to_layer
,
695 setup_action_bottom_layer
698 "togglealwaysonbottom",
700 setup_action_bottom_layer
705 setup_action_movefromedge_north
710 setup_action_movefromedge_south
715 setup_action_movefromedge_west
720 setup_action_movefromedge_east
725 setup_action_movetoedge_north
730 setup_action_movetoedge_south
735 setup_action_movetoedge_west
740 setup_action_movetoedge_east
745 setup_action_growtoedge_north
750 setup_action_growtoedge_south
755 setup_action_growtoedge_west
760 setup_action_growtoedge_east
765 setup_action_addremove_desktop_last
769 action_remove_desktop
,
770 setup_action_addremove_desktop_last
775 setup_action_addremove_desktop_current
778 "removedesktopcurrent",
779 action_remove_desktop
,
780 setup_action_addremove_desktop_current
789 /* only key bindings can be interactive. thus saith the xor.
790 because of how the mouse is grabbed, mouse events dont even get
791 read during interactive events, so no dice! >:) */
792 #define INTERACTIVE_LIMIT(a, uact) \
793 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
794 a->data.any.interactive = FALSE;
796 ObAction
*action_from_string(const gchar
*name
, ObUserAction uact
)
799 gboolean exist
= FALSE
;
802 for (i
= 0; actionstrings
[i
].name
; i
++)
803 if (!g_ascii_strcasecmp(name
, actionstrings
[i
].name
)) {
805 a
= action_new(actionstrings
[i
].func
);
806 if (actionstrings
[i
].setup
)
807 actionstrings
[i
].setup(&a
, uact
);
809 INTERACTIVE_LIMIT(a
, uact
);
813 g_message(_("Invalid action '%s' requested. No such action exists."),
816 g_message(_("Invalid use of action '%s'. Action will be ignored."),
821 ObAction
*action_parse(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
825 ObAction
*act
= NULL
;
828 if (parse_attr_string("name", node
, &actname
)) {
829 if ((act
= action_from_string(actname
, uact
))) {
830 } else if (act
->func
== action_move_relative_horz
||
831 act
->func
== action_move_relative_vert
||
832 act
->func
== action_resize_relative_horz
||
833 act
->func
== action_resize_relative_vert
) {
834 if ((n
= parse_find_node("delta", node
->xmlChildrenNode
)))
835 act
->data
.relative
.deltax
= parse_int(doc
, n
);
836 } else if (act
->func
== action_move_relative
) {
837 if ((n
= parse_find_node("x", node
->xmlChildrenNode
)))
838 act
->data
.relative
.deltax
= parse_int(doc
, n
);
839 if ((n
= parse_find_node("y", node
->xmlChildrenNode
)))
840 act
->data
.relative
.deltay
= parse_int(doc
, n
);
841 } else if (act
->func
== action_resize_relative
) {
842 if ((n
= parse_find_node("left", node
->xmlChildrenNode
)))
843 act
->data
.relative
.deltaxl
= parse_int(doc
, n
);
844 if ((n
= parse_find_node("up", node
->xmlChildrenNode
)))
845 act
->data
.relative
.deltayu
= parse_int(doc
, n
);
846 if ((n
= parse_find_node("right", node
->xmlChildrenNode
)))
847 act
->data
.relative
.deltax
= parse_int(doc
, n
);
848 if ((n
= parse_find_node("down", node
->xmlChildrenNode
)))
849 act
->data
.relative
.deltay
= parse_int(doc
, n
);
850 } else if (act
->func
== action_desktop
) {
851 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
852 act
->data
.desktop
.desk
= parse_int(doc
, n
);
853 if (act
->data
.desktop
.desk
> 0) act
->data
.desktop
.desk
--;
855 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
856 act->data.desktop.inter.any.interactive =
859 } else if (act
->func
== action_send_to_desktop
) {
860 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
861 act
->data
.sendto
.desk
= parse_int(doc
, n
);
862 if (act
->data
.sendto
.desk
> 0) act
->data
.sendto
.desk
--;
863 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
864 act
->data
.sendto
.follow
= parse_bool(doc
, n
);
865 } else if (act
->func
== action_desktop_dir
) {
866 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
867 act
->data
.desktopdir
.wrap
= parse_bool(doc
, n
);
868 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
869 act
->data
.desktopdir
.inter
.any
.interactive
=
871 } else if (act
->func
== action_send_to_desktop_dir
) {
872 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
873 act
->data
.sendtodir
.wrap
= parse_bool(doc
, n
);
874 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
875 act
->data
.sendtodir
.follow
= parse_bool(doc
, n
);
876 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
877 act
->data
.sendtodir
.inter
.any
.interactive
=
879 } else if (act
->func
== action_directional_focus
) {
880 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
881 act
->data
.interdiraction
.dialog
= parse_bool(doc
, n
);
882 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
883 act
->data
.interdiraction
.dock_windows
= parse_bool(doc
, n
);
884 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
885 act
->data
.interdiraction
.desktop_windows
=
887 } else if (act
->func
== action_resize
) {
888 if ((n
= parse_find_node("edge", node
->xmlChildrenNode
))) {
889 gchar
*s
= parse_string(doc
, n
);
890 if (!g_ascii_strcasecmp(s
, "top"))
891 act
->data
.moveresize
.corner
=
892 prop_atoms
.net_wm_moveresize_size_top
;
893 else if (!g_ascii_strcasecmp(s
, "bottom"))
894 act
->data
.moveresize
.corner
=
895 prop_atoms
.net_wm_moveresize_size_bottom
;
896 else if (!g_ascii_strcasecmp(s
, "left"))
897 act
->data
.moveresize
.corner
=
898 prop_atoms
.net_wm_moveresize_size_left
;
899 else if (!g_ascii_strcasecmp(s
, "right"))
900 act
->data
.moveresize
.corner
=
901 prop_atoms
.net_wm_moveresize_size_right
;
902 else if (!g_ascii_strcasecmp(s
, "topleft"))
903 act
->data
.moveresize
.corner
=
904 prop_atoms
.net_wm_moveresize_size_topleft
;
905 else if (!g_ascii_strcasecmp(s
, "topright"))
906 act
->data
.moveresize
.corner
=
907 prop_atoms
.net_wm_moveresize_size_topright
;
908 else if (!g_ascii_strcasecmp(s
, "bottomleft"))
909 act
->data
.moveresize
.corner
=
910 prop_atoms
.net_wm_moveresize_size_bottomleft
;
911 else if (!g_ascii_strcasecmp(s
, "bottomright"))
912 act
->data
.moveresize
.corner
=
913 prop_atoms
.net_wm_moveresize_size_bottomright
;
916 INTERACTIVE_LIMIT(act
, uact
);
923 void action_run_list(GSList
*acts
, ObClient
*c
, ObFrameContext context
,
924 guint state
, guint button
, gint x
, gint y
, Time time
,
925 gboolean cancel
, gboolean done
)
934 screen_pointer_pos(&x
, &y
);
936 for (it
= acts
; it
; it
= g_slist_next(it
)) {
939 if (!(a
->data
.any
.client_action
== OB_CLIENT_ACTION_ALWAYS
&& !c
)) {
940 a
->data
.any
.c
= a
->data
.any
.client_action
? c
: NULL
;
941 a
->data
.any
.context
= context
;
945 a
->data
.any
.button
= button
;
947 a
->data
.any
.time
= time
;
949 if (a
->data
.any
.interactive
) {
950 a
->data
.inter
.cancel
= cancel
;
951 a
->data
.inter
.final
= done
;
952 if (!(cancel
|| done
))
953 if (!keyboard_interactive_grab(state
, a
->data
.any
.c
, a
))
957 /* XXX UGLY HACK race with motion event starting a move and the
958 button release gettnig processed first. answer: don't queue
959 moveresize starts. UGLY HACK XXX
961 XXX ALSO don't queue showmenu events, because on button press
962 events we need to know if a mouse grab is going to take place,
963 and set the button to 0, so that later motion events don't think
964 that a drag is going on. since showmenu grabs the pointer..
966 if (a
->data
.any
.interactive
|| a
->func
== action_move
||
967 a
->func
== action_resize
|| a
->func
== action_showmenu
)
969 /* interactive actions are not queued */
971 } else if (a
->func
== action_focus
||
972 a
->func
== action_activate
||
973 a
->func
== action_showmenu
)
975 /* XXX MORE UGLY HACK
976 actions from clicks on client windows are NOT queued.
977 this solves the mysterious click-and-drag-doesnt-work
978 problem. it was because the window gets focused and stuff
979 after the button event has already been passed through. i
980 dont really know why it should care but it does and it makes
983 however this very bogus ! !
984 we want to send the button press to the window BEFORE
985 we do the action because the action might move the windows
986 (eg change desktops) and then the button press ends up on
987 the completely wrong window !
988 so, this is just for that bug, and it will only NOT queue it
989 if it is a focusing action that can be used with the mouse
992 also with the menus, there is a race going on. if the
993 desktop wants to pop up a menu, and we do too, we send them
994 the button before we pop up the menu, so they pop up their
995 menu first. but not always. if we pop up our menu before
996 sending them the button press, then the result is
999 XXX further more. focus actions are not queued at all,
1000 because if you bind focus->showmenu, the menu will get
1001 hidden to do the focusing
1005 ob_main_loop_queue_action(ob_main_loop
, a
);
1010 void action_run_string(const gchar
*name
, struct _ObClient
*c
, Time time
)
1015 a
= action_from_string(name
, OB_USER_ACTION_NONE
);
1018 l
= g_slist_append(NULL
, a
);
1020 action_run(l
, c
, 0, time
);
1023 void action_unfocus (union ActionData
*data
)
1025 if (data
->client
.any
.c
== focus_client
)
1026 focus_fallback(FALSE
, FALSE
, TRUE
);
1029 void action_iconify(union ActionData
*data
)
1031 client_action_start(data
);
1032 client_iconify(data
->client
.any
.c
, TRUE
, TRUE
, FALSE
);
1033 client_action_end(data
, config_focus_under_mouse
);
1036 void action_focus_order_to_bottom(union ActionData
*data
)
1038 focus_order_to_bottom(data
->client
.any
.c
);
1041 void action_unshaderaise(union ActionData
*data
)
1043 if (data
->client
.any
.c
->shaded
)
1044 action_unshade(data
);
1049 void action_shadelower(union ActionData
*data
)
1051 if (data
->client
.any
.c
->shaded
)
1057 void action_kill(union ActionData
*data
)
1059 client_kill(data
->client
.any
.c
);
1062 void action_shade(union ActionData
*data
)
1064 client_action_start(data
);
1065 client_shade(data
->client
.any
.c
, TRUE
);
1066 client_action_end(data
, config_focus_under_mouse
);
1069 void action_unshade(union ActionData
*data
)
1071 client_action_start(data
);
1072 client_shade(data
->client
.any
.c
, FALSE
);
1073 client_action_end(data
, config_focus_under_mouse
);
1076 void action_toggle_shade(union ActionData
*data
)
1078 client_action_start(data
);
1079 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1080 client_action_end(data
, config_focus_under_mouse
);
1083 void action_toggle_omnipresent(union ActionData
*data
)
1085 client_set_desktop(data
->client
.any
.c
,
1086 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1087 screen_desktop
: DESKTOP_ALL
, FALSE
, TRUE
);
1090 void action_move_relative_horz(union ActionData
*data
)
1092 ObClient
*c
= data
->relative
.any
.c
;
1093 client_action_start(data
);
1094 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
);
1095 client_action_end(data
, FALSE
);
1098 void action_move_relative_vert(union ActionData
*data
)
1100 ObClient
*c
= data
->relative
.any
.c
;
1101 client_action_start(data
);
1102 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.deltax
);
1103 client_action_end(data
, FALSE
);
1106 void action_move_to_center(union ActionData
*data
)
1108 ObClient
*c
= data
->client
.any
.c
;
1110 area
= screen_area(c
->desktop
, client_monitor(c
), NULL
);
1111 client_action_start(data
);
1112 client_move(c
, area
->x
+ area
->width
/ 2 - c
->area
.width
/ 2,
1113 area
->y
+ area
->height
/ 2 - c
->area
.height
/ 2);
1114 client_action_end(data
, FALSE
);
1118 void action_resize_relative_horz(union ActionData
*data
)
1120 ObClient
*c
= data
->relative
.any
.c
;
1121 client_action_start(data
);
1123 c
->area
.width
+ data
->relative
.deltax
* c
->size_inc
.width
,
1125 client_action_end(data
, FALSE
);
1128 void action_resize_relative_vert(union ActionData
*data
)
1130 ObClient
*c
= data
->relative
.any
.c
;
1132 client_action_start(data
);
1133 client_resize(c
, c
->area
.width
, c
->area
.height
+
1134 data
->relative
.deltax
* c
->size_inc
.height
);
1135 client_action_end(data
, FALSE
);
1139 void action_move_relative(union ActionData
*data
)
1141 ObClient
*c
= data
->relative
.any
.c
;
1142 client_action_start(data
);
1143 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
+
1144 data
->relative
.deltay
);
1145 client_action_end(data
, FALSE
);
1148 void action_resize_relative(union ActionData
*data
)
1150 ObClient
*c
= data
->relative
.any
.c
;
1151 gint x
, y
, ow
, xoff
, nw
, oh
, yoff
, nh
, lw
, lh
;
1153 client_action_start(data
);
1158 xoff
= -data
->relative
.deltaxl
* c
->size_inc
.width
;
1159 nw
= ow
+ data
->relative
.deltax
* c
->size_inc
.width
1160 + data
->relative
.deltaxl
* c
->size_inc
.width
;
1161 oh
= c
->area
.height
;
1162 yoff
= -data
->relative
.deltayu
* c
->size_inc
.height
;
1163 nh
= oh
+ data
->relative
.deltay
* c
->size_inc
.height
1164 + data
->relative
.deltayu
* c
->size_inc
.height
;
1166 g_print("deltax %d %d x %d ow %d xoff %d nw %d\n",
1167 data
->relative
.deltax
,
1168 data
->relative
.deltaxl
,
1171 client_try_configure(c
, &x
, &y
, &nw
, &nh
, &lw
, &lh
, TRUE
);
1172 xoff
= xoff
== 0 ? 0 : (xoff
< 0 ? MAX(xoff
, ow
-nw
) : MIN(xoff
, ow
-nw
));
1173 yoff
= yoff
== 0 ? 0 : (yoff
< 0 ? MAX(yoff
, oh
-nh
) : MIN(yoff
, oh
-nh
));
1174 client_move_resize(c
, x
+ xoff
, y
+ yoff
, nw
, nh
);
1175 client_action_end(data
, FALSE
);
1178 void action_maximize_full(union ActionData
*data
)
1180 client_action_start(data
);
1181 client_maximize(data
->client
.any
.c
, TRUE
, 0);
1182 client_action_end(data
, config_focus_under_mouse
);
1185 void action_unmaximize_full(union ActionData
*data
)
1187 client_action_start(data
);
1188 client_maximize(data
->client
.any
.c
, FALSE
, 0);
1189 client_action_end(data
, config_focus_under_mouse
);
1192 void action_toggle_maximize_full(union ActionData
*data
)
1194 client_action_start(data
);
1195 client_maximize(data
->client
.any
.c
,
1196 !(data
->client
.any
.c
->max_horz
||
1197 data
->client
.any
.c
->max_vert
),
1199 client_action_end(data
, config_focus_under_mouse
);
1202 void action_maximize_horz(union ActionData
*data
)
1204 client_action_start(data
);
1205 client_maximize(data
->client
.any
.c
, TRUE
, 1);
1206 client_action_end(data
, config_focus_under_mouse
);
1209 void action_unmaximize_horz(union ActionData
*data
)
1211 client_action_start(data
);
1212 client_maximize(data
->client
.any
.c
, FALSE
, 1);
1213 client_action_end(data
, config_focus_under_mouse
);
1216 void action_toggle_maximize_horz(union ActionData
*data
)
1218 client_action_start(data
);
1219 client_maximize(data
->client
.any
.c
,
1220 !data
->client
.any
.c
->max_horz
, 1);
1221 client_action_end(data
, config_focus_under_mouse
);
1224 void action_maximize_vert(union ActionData
*data
)
1226 client_action_start(data
);
1227 client_maximize(data
->client
.any
.c
, TRUE
, 2);
1228 client_action_end(data
, config_focus_under_mouse
);
1231 void action_unmaximize_vert(union ActionData
*data
)
1233 client_action_start(data
);
1234 client_maximize(data
->client
.any
.c
, FALSE
, 2);
1235 client_action_end(data
, config_focus_under_mouse
);
1238 void action_toggle_maximize_vert(union ActionData
*data
)
1240 client_action_start(data
);
1241 client_maximize(data
->client
.any
.c
,
1242 !data
->client
.any
.c
->max_vert
, 2);
1243 client_action_end(data
, config_focus_under_mouse
);
1246 void action_toggle_fullscreen(union ActionData
*data
)
1248 client_action_start(data
);
1249 client_fullscreen(data
->client
.any
.c
, !(data
->client
.any
.c
->fullscreen
));
1250 client_action_end(data
, config_focus_under_mouse
);
1253 void action_send_to_desktop(union ActionData
*data
)
1255 ObClient
*c
= data
->sendto
.any
.c
;
1257 if (!client_normal(c
)) return;
1259 if (data
->sendto
.desk
< screen_num_desktops
||
1260 data
->sendto
.desk
== DESKTOP_ALL
) {
1261 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
, FALSE
);
1262 if (data
->sendto
.follow
&& data
->sendto
.desk
!= screen_desktop
)
1263 screen_set_desktop(data
->sendto
.desk
, TRUE
);
1267 void action_desktop(union ActionData
*data
)
1269 /* XXX add the interactive/dialog option back again once the dialog
1270 has been made to not use grabs */
1271 if (data
->desktop
.desk
< screen_num_desktops
||
1272 data
->desktop
.desk
== DESKTOP_ALL
)
1274 screen_set_desktop(data
->desktop
.desk
, TRUE
);
1275 if (data
->inter
.any
.interactive
)
1276 screen_desktop_popup(data
->desktop
.desk
, TRUE
);
1280 void action_desktop_dir(union ActionData
*data
)
1284 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1285 data
->desktopdir
.wrap
,
1286 data
->desktopdir
.linear
,
1287 data
->desktopdir
.inter
.any
.interactive
,
1288 data
->desktopdir
.inter
.final
,
1289 data
->desktopdir
.inter
.cancel
);
1290 /* only move the desktop when the action is complete. if we switch
1291 desktops during the interactive action, focus will move but with
1292 NotifyWhileGrabbed and applications don't like that. */
1293 if (!data
->sendtodir
.inter
.any
.interactive
||
1294 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1296 if (d
!= screen_desktop
)
1297 screen_set_desktop(d
, TRUE
);
1301 void action_send_to_desktop_dir(union ActionData
*data
)
1303 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1306 if (!client_normal(c
)) return;
1308 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1309 data
->sendtodir
.linear
,
1310 data
->sendtodir
.inter
.any
.interactive
,
1311 data
->sendtodir
.inter
.final
,
1312 data
->sendtodir
.inter
.cancel
);
1313 /* only move the desktop when the action is complete. if we switch
1314 desktops during the interactive action, focus will move but with
1315 NotifyWhileGrabbed and applications don't like that. */
1316 if (!data
->sendtodir
.inter
.any
.interactive
||
1317 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1319 client_set_desktop(c
, d
, data
->sendtodir
.follow
, FALSE
);
1320 if (data
->sendtodir
.follow
&& d
!= screen_desktop
)
1321 screen_set_desktop(d
, TRUE
);
1325 void action_desktop_last(union ActionData
*data
)
1327 if (screen_last_desktop
< screen_num_desktops
)
1328 screen_set_desktop(screen_last_desktop
, TRUE
);
1331 void action_toggle_decorations(union ActionData
*data
)
1333 ObClient
*c
= data
->client
.any
.c
;
1335 client_action_start(data
);
1336 client_set_undecorated(c
, !c
->undecorated
);
1337 client_action_end(data
, FALSE
);
1340 static guint32
pick_corner(gint x
, gint y
, gint cx
, gint cy
, gint cw
, gint ch
,
1343 /* let's make x and y client relative instead of screen relative */
1345 y
= ch
- (y
- cy
); /* y is inverted, 0 is at the bottom of the window */
1348 #define A -4*X + 7*ch/3
1349 #define B 4*X -15*ch/9
1350 #define C -X/4 + 2*ch/3
1351 #define D X/4 + 5*ch/12
1352 #define E X/4 + ch/3
1353 #define F -X/4 + 7*ch/12
1354 #define G 4*X - 4*ch/3
1355 #define H -4*X + 8*ch/3
1356 #define a (y > 5*ch/9)
1357 #define b (x < 4*cw/9)
1358 #define c (x > 5*cw/9)
1359 #define d (y < 4*ch/9)
1362 Each of these defines (except X which is just there for fun), represents
1363 the equation of a line. The lines they represent are shown in the diagram
1364 below. Checking y against these lines, we are able to choose a region
1365 of the window as shown.
1367 +---------------------A-------|-------|-------B---------------------+
1374 | northwest | A north B | northeast |
1377 C---------------------+----A--+-------+--B----+---------------------D
1378 |CCCCCCC | A B | DDDDDDD|
1379 | CCCCCCCC | A | | B | DDDDDDDD |
1380 | CCCCCCC A B DDDDDDD |
1381 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
1383 | west | b move c | east | ad
1385 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
1386 | EEEEEEE G H FFFFFFF |
1387 | EEEEEEEE | G | | H | FFFFFFFF |
1388 |EEEEEEE | G H | FFFFFFF|
1389 E---------------------+----G--+-------+--H----+---------------------F
1392 | southwest | G south H | southeast |
1399 +---------------------G-------|-------|-------H---------------------+
1403 /* for shaded windows, you can only resize west/east and move */
1405 return prop_atoms
.net_wm_moveresize_size_left
;
1407 return prop_atoms
.net_wm_moveresize_size_right
;
1408 return prop_atoms
.net_wm_moveresize_move
;
1411 if (y
< A
&& y
>= C
)
1412 return prop_atoms
.net_wm_moveresize_size_topleft
;
1413 else if (y
>= A
&& y
>= B
&& a
)
1414 return prop_atoms
.net_wm_moveresize_size_top
;
1415 else if (y
< B
&& y
>= D
)
1416 return prop_atoms
.net_wm_moveresize_size_topright
;
1417 else if (y
< C
&& y
>= E
&& b
)
1418 return prop_atoms
.net_wm_moveresize_size_left
;
1419 else if (y
< D
&& y
>= F
&& c
)
1420 return prop_atoms
.net_wm_moveresize_size_right
;
1421 else if (y
< E
&& y
>= G
)
1422 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1423 else if (y
< G
&& y
< H
&& d
)
1424 return prop_atoms
.net_wm_moveresize_size_bottom
;
1425 else if (y
>= H
&& y
< F
)
1426 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1428 return prop_atoms
.net_wm_moveresize_move
;
1445 void action_resize(union ActionData
*data
)
1447 ObClient
*c
= data
->moveresize
.any
.c
;
1450 if (data
->moveresize
.keyboard
)
1451 corner
= prop_atoms
.net_wm_moveresize_size_keyboard
;
1452 else if (data
->moveresize
.corner
)
1453 corner
= data
->moveresize
.corner
; /* it was specified in the binding */
1455 corner
= pick_corner(data
->any
.x
, data
->any
.y
,
1456 c
->frame
->area
.x
, c
->frame
->area
.y
,
1457 /* use the client size because the frame
1458 can be differently sized (shaded
1459 windows) and we want this based on the
1461 c
->area
.width
+ c
->frame
->size
.left
+
1462 c
->frame
->size
.right
,
1463 c
->area
.height
+ c
->frame
->size
.top
+
1464 c
->frame
->size
.bottom
, c
->shaded
);
1466 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1469 void action_directional_focus(union ActionData
*data
)
1471 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1473 event_halt_focus_delay();
1475 focus_directional_cycle(data
->interdiraction
.direction
,
1476 data
->interdiraction
.dock_windows
,
1477 data
->interdiraction
.desktop_windows
,
1478 data
->any
.interactive
,
1479 data
->interdiraction
.dialog
,
1480 data
->interdiraction
.inter
.final
,
1481 data
->interdiraction
.inter
.cancel
);
1484 void action_movetoedge(union ActionData
*data
)
1487 ObClient
*c
= data
->diraction
.any
.c
;
1489 x
= c
->frame
->area
.x
;
1490 y
= c
->frame
->area
.y
;
1492 switch(data
->diraction
.direction
) {
1493 case OB_DIRECTION_NORTH
:
1494 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
,
1495 data
->diraction
.hang
)
1496 - (data
->diraction
.hang
? c
->frame
->area
.height
: 0);
1498 case OB_DIRECTION_WEST
:
1499 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
,
1500 data
->diraction
.hang
)
1501 - (data
->diraction
.hang
? c
->frame
->area
.width
: 0);
1503 case OB_DIRECTION_SOUTH
:
1504 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
,
1505 data
->diraction
.hang
)
1506 - (data
->diraction
.hang
? 0 : c
->frame
->area
.height
);
1508 case OB_DIRECTION_EAST
:
1509 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
,
1510 data
->diraction
.hang
)
1511 - (data
->diraction
.hang
? 0 : c
->frame
->area
.width
);
1514 g_assert_not_reached();
1516 frame_frame_gravity(c
->frame
, &x
, &y
, c
->area
.width
, c
->area
.height
);
1517 client_action_start(data
);
1518 client_move(c
, x
, y
);
1519 client_action_end(data
, FALSE
);
1522 void action_growtoedge(union ActionData
*data
)
1524 gint x
, y
, width
, height
, dest
;
1525 ObClient
*c
= data
->diraction
.any
.c
;
1528 a
= screen_area(c
->desktop
, SCREEN_AREA_ALL_MONITORS
, &c
->frame
->area
);
1529 x
= c
->frame
->area
.x
;
1530 y
= c
->frame
->area
.y
;
1531 /* get the unshaded frame's dimensions..if it is shaded */
1532 width
= c
->area
.width
+ c
->frame
->size
.left
+ c
->frame
->size
.right
;
1533 height
= c
->area
.height
+ c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1535 switch(data
->diraction
.direction
) {
1536 case OB_DIRECTION_NORTH
:
1537 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1539 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
, FALSE
);
1541 height
= height
/ 2;
1543 height
= c
->frame
->area
.y
+ height
- dest
;
1547 case OB_DIRECTION_WEST
:
1548 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
, FALSE
);
1552 width
= c
->frame
->area
.x
+ width
- dest
;
1556 case OB_DIRECTION_SOUTH
:
1557 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1559 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
, FALSE
);
1560 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1561 height
= c
->frame
->area
.height
/ 2;
1562 y
= a
->y
+ a
->height
- height
;
1564 height
= dest
- c
->frame
->area
.y
;
1565 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1566 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1568 case OB_DIRECTION_EAST
:
1569 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
, FALSE
);
1570 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1571 width
= c
->frame
->area
.width
/ 2;
1572 x
= a
->x
+ a
->width
- width
;
1574 width
= dest
- c
->frame
->area
.x
;
1575 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1576 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1579 g_assert_not_reached();
1581 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1582 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1583 frame_frame_gravity(c
->frame
, &x
, &y
, width
, height
);
1584 client_action_start(data
);
1585 client_move_resize(c
, x
, y
, width
, height
);
1586 client_action_end(data
, FALSE
);
1590 void action_send_to_layer(union ActionData
*data
)
1592 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1595 void action_toggle_layer(union ActionData
*data
)
1597 ObClient
*c
= data
->layer
.any
.c
;
1599 client_action_start(data
);
1600 if (data
->layer
.layer
< 0)
1601 client_set_layer(c
, c
->below
? 0 : -1);
1602 else if (data
->layer
.layer
> 0)
1603 client_set_layer(c
, c
->above
? 0 : 1);
1604 client_action_end(data
, config_focus_under_mouse
);
1607 void action_toggle_dockautohide(union ActionData
*data
)
1609 config_dock_hide
= !config_dock_hide
;
1613 void action_add_desktop(union ActionData
*data
)
1615 client_action_start(data
);
1616 screen_set_num_desktops(screen_num_desktops
+1);
1618 /* move all the clients over */
1619 if (data
->addremovedesktop
.current
) {
1622 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1623 ObClient
*c
= it
->data
;
1624 if (c
->desktop
!= DESKTOP_ALL
&& c
->desktop
>= screen_desktop
)
1625 client_set_desktop(c
, c
->desktop
+1, FALSE
, TRUE
);
1629 client_action_end(data
, config_focus_under_mouse
);
1632 void action_remove_desktop(union ActionData
*data
)
1634 guint rmdesktop
, movedesktop
;
1635 GList
*it
, *stacking_copy
;
1637 if (screen_num_desktops
< 2) return;
1639 client_action_start(data
);
1641 /* what desktop are we removing and moving to? */
1642 if (data
->addremovedesktop
.current
)
1643 rmdesktop
= screen_desktop
;
1645 rmdesktop
= screen_num_desktops
- 1;
1646 if (rmdesktop
< screen_num_desktops
- 1)
1647 movedesktop
= rmdesktop
+ 1;
1649 movedesktop
= rmdesktop
;
1651 /* make a copy of the list cuz we're changing it */
1652 stacking_copy
= g_list_copy(stacking_list
);
1653 for (it
= g_list_last(stacking_copy
); it
; it
= g_list_previous(it
)) {
1654 if (WINDOW_IS_CLIENT(it
->data
)) {
1655 ObClient
*c
= it
->data
;
1656 guint d
= c
->desktop
;
1657 if (d
!= DESKTOP_ALL
&& d
>= movedesktop
) {
1658 client_set_desktop(c
, c
->desktop
- 1, TRUE
, TRUE
);
1659 ob_debug("moving window %s\n", c
->title
);
1661 /* raise all the windows that are on the current desktop which
1663 if ((screen_desktop
== rmdesktop
- 1 ||
1664 screen_desktop
== rmdesktop
) &&
1665 (d
== DESKTOP_ALL
|| d
== screen_desktop
))
1667 stacking_raise(CLIENT_AS_WINDOW(c
));
1668 ob_debug("raising window %s\n", c
->title
);
1673 /* act like we're changing desktops */
1674 if (screen_desktop
< screen_num_desktops
- 1) {
1675 gint d
= screen_desktop
;
1676 screen_desktop
= screen_last_desktop
;
1677 screen_set_desktop(d
, TRUE
);
1678 ob_debug("fake desktop change\n");
1681 screen_set_num_desktops(screen_num_desktops
-1);
1683 client_action_end(data
, config_focus_under_mouse
);