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
489 action_toggle_omnipresent
,
494 action_move_relative_horz
,
499 action_move_relative_vert
,
504 action_move_to_center
,
508 "resizerelativehorz",
509 action_resize_relative_horz
,
513 "resizerelativevert",
514 action_resize_relative_vert
,
519 action_move_relative
,
524 action_resize_relative
,
529 action_maximize_horz
,
534 action_unmaximize_horz
,
538 "togglemaximizehorz",
539 action_toggle_maximize_horz
,
544 action_maximize_vert
,
549 action_unmaximize_vert
,
553 "togglemaximizevert",
554 action_toggle_maximize_vert
,
559 action_send_to_desktop
,
560 setup_action_send_to_desktop
564 action_send_to_desktop_dir
,
565 setup_action_send_to_desktop_next
568 "sendtodesktopprevious",
569 action_send_to_desktop_dir
,
570 setup_action_send_to_desktop_prev
573 "sendtodesktopright",
574 action_send_to_desktop_dir
,
575 setup_action_send_to_desktop_right
579 action_send_to_desktop_dir
,
580 setup_action_send_to_desktop_left
584 action_send_to_desktop_dir
,
585 setup_action_send_to_desktop_up
589 action_send_to_desktop_dir
,
590 setup_action_send_to_desktop_down
600 setup_action_desktop_next
605 setup_action_desktop_prev
610 setup_action_desktop_right
615 setup_action_desktop_left
620 setup_action_desktop_up
625 setup_action_desktop_down
629 action_toggle_decorations
,
638 "toggledockautohide",
639 action_toggle_dockautohide
,
649 action_send_to_layer
,
650 setup_action_top_layer
655 setup_action_top_layer
659 action_send_to_layer
,
660 setup_action_normal_layer
664 action_send_to_layer
,
665 setup_action_bottom_layer
668 "togglealwaysonbottom",
670 setup_action_bottom_layer
675 setup_action_movefromedge_north
680 setup_action_movefromedge_south
685 setup_action_movefromedge_west
690 setup_action_movefromedge_east
695 setup_action_movetoedge_north
700 setup_action_movetoedge_south
705 setup_action_movetoedge_west
710 setup_action_movetoedge_east
715 setup_action_growtoedge_north
720 setup_action_growtoedge_south
725 setup_action_growtoedge_west
730 setup_action_growtoedge_east
735 setup_action_addremove_desktop_last
739 action_remove_desktop
,
740 setup_action_addremove_desktop_last
745 setup_action_addremove_desktop_current
748 "removedesktopcurrent",
749 action_remove_desktop
,
750 setup_action_addremove_desktop_current
759 /* only key bindings can be interactive. thus saith the xor.
760 because of how the mouse is grabbed, mouse events dont even get
761 read during interactive events, so no dice! >:) */
762 #define INTERACTIVE_LIMIT(a, uact) \
763 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
764 a->data.any.interactive = FALSE;
766 ObAction
*action_from_string(const gchar
*name
, ObUserAction uact
)
769 gboolean exist
= FALSE
;
772 for (i
= 0; actionstrings
[i
].name
; i
++)
773 if (!g_ascii_strcasecmp(name
, actionstrings
[i
].name
)) {
775 a
= action_new(actionstrings
[i
].func
);
776 if (actionstrings
[i
].setup
)
777 actionstrings
[i
].setup(&a
, uact
);
779 INTERACTIVE_LIMIT(a
, uact
);
783 g_message(_("Invalid action '%s' requested. No such action exists."),
786 g_message(_("Invalid use of action '%s'. Action will be ignored."),
791 ObAction
*action_parse(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
795 ObAction
*act
= NULL
;
798 if (parse_attr_string("name", node
, &actname
)) {
799 if ((act
= action_from_string(actname
, uact
))) {
800 } else if (act
->func
== action_move_relative_horz
||
801 act
->func
== action_move_relative_vert
||
802 act
->func
== action_resize_relative_horz
||
803 act
->func
== action_resize_relative_vert
) {
804 if ((n
= parse_find_node("delta", node
->xmlChildrenNode
)))
805 act
->data
.relative
.deltax
= parse_int(doc
, n
);
806 } else if (act
->func
== action_move_relative
) {
807 if ((n
= parse_find_node("x", node
->xmlChildrenNode
)))
808 act
->data
.relative
.deltax
= parse_int(doc
, n
);
809 if ((n
= parse_find_node("y", node
->xmlChildrenNode
)))
810 act
->data
.relative
.deltay
= parse_int(doc
, n
);
811 } else if (act
->func
== action_resize_relative
) {
812 if ((n
= parse_find_node("left", node
->xmlChildrenNode
)))
813 act
->data
.relative
.deltaxl
= parse_int(doc
, n
);
814 if ((n
= parse_find_node("up", node
->xmlChildrenNode
)))
815 act
->data
.relative
.deltayu
= parse_int(doc
, n
);
816 if ((n
= parse_find_node("right", node
->xmlChildrenNode
)))
817 act
->data
.relative
.deltax
= parse_int(doc
, n
);
818 if ((n
= parse_find_node("down", node
->xmlChildrenNode
)))
819 act
->data
.relative
.deltay
= parse_int(doc
, n
);
820 } else if (act
->func
== action_desktop
) {
821 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
822 act
->data
.desktop
.desk
= parse_int(doc
, n
);
823 if (act
->data
.desktop
.desk
> 0) act
->data
.desktop
.desk
--;
825 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
826 act->data.desktop.inter.any.interactive =
829 } else if (act
->func
== action_send_to_desktop
) {
830 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
831 act
->data
.sendto
.desk
= parse_int(doc
, n
);
832 if (act
->data
.sendto
.desk
> 0) act
->data
.sendto
.desk
--;
833 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
834 act
->data
.sendto
.follow
= parse_bool(doc
, n
);
835 } else if (act
->func
== action_desktop_dir
) {
836 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
837 act
->data
.desktopdir
.wrap
= parse_bool(doc
, n
);
838 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
839 act
->data
.desktopdir
.inter
.any
.interactive
=
841 } else if (act
->func
== action_send_to_desktop_dir
) {
842 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
843 act
->data
.sendtodir
.wrap
= parse_bool(doc
, n
);
844 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
845 act
->data
.sendtodir
.follow
= parse_bool(doc
, n
);
846 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
847 act
->data
.sendtodir
.inter
.any
.interactive
=
849 } else if (act
->func
== action_directional_focus
) {
850 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
851 act
->data
.interdiraction
.dialog
= parse_bool(doc
, n
);
852 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
853 act
->data
.interdiraction
.dock_windows
= parse_bool(doc
, n
);
854 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
855 act
->data
.interdiraction
.desktop_windows
=
857 } else if (act
->func
== action_resize
) {
858 if ((n
= parse_find_node("edge", node
->xmlChildrenNode
))) {
859 gchar
*s
= parse_string(doc
, n
);
860 if (!g_ascii_strcasecmp(s
, "top"))
861 act
->data
.moveresize
.corner
=
862 prop_atoms
.net_wm_moveresize_size_top
;
863 else if (!g_ascii_strcasecmp(s
, "bottom"))
864 act
->data
.moveresize
.corner
=
865 prop_atoms
.net_wm_moveresize_size_bottom
;
866 else if (!g_ascii_strcasecmp(s
, "left"))
867 act
->data
.moveresize
.corner
=
868 prop_atoms
.net_wm_moveresize_size_left
;
869 else if (!g_ascii_strcasecmp(s
, "right"))
870 act
->data
.moveresize
.corner
=
871 prop_atoms
.net_wm_moveresize_size_right
;
872 else if (!g_ascii_strcasecmp(s
, "topleft"))
873 act
->data
.moveresize
.corner
=
874 prop_atoms
.net_wm_moveresize_size_topleft
;
875 else if (!g_ascii_strcasecmp(s
, "topright"))
876 act
->data
.moveresize
.corner
=
877 prop_atoms
.net_wm_moveresize_size_topright
;
878 else if (!g_ascii_strcasecmp(s
, "bottomleft"))
879 act
->data
.moveresize
.corner
=
880 prop_atoms
.net_wm_moveresize_size_bottomleft
;
881 else if (!g_ascii_strcasecmp(s
, "bottomright"))
882 act
->data
.moveresize
.corner
=
883 prop_atoms
.net_wm_moveresize_size_bottomright
;
886 INTERACTIVE_LIMIT(act
, uact
);
893 void action_run_list(GSList
*acts
, ObClient
*c
, ObFrameContext context
,
894 guint state
, guint button
, gint x
, gint y
, Time time
,
895 gboolean cancel
, gboolean done
)
904 screen_pointer_pos(&x
, &y
);
906 for (it
= acts
; it
; it
= g_slist_next(it
)) {
909 if (!(a
->data
.any
.client_action
== OB_CLIENT_ACTION_ALWAYS
&& !c
)) {
910 a
->data
.any
.c
= a
->data
.any
.client_action
? c
: NULL
;
911 a
->data
.any
.context
= context
;
915 a
->data
.any
.button
= button
;
917 a
->data
.any
.time
= time
;
919 if (a
->data
.any
.interactive
) {
920 a
->data
.inter
.cancel
= cancel
;
921 a
->data
.inter
.final
= done
;
922 if (!(cancel
|| done
))
923 if (!keyboard_interactive_grab(state
, a
->data
.any
.c
, a
))
927 /* XXX UGLY HACK race with motion event starting a move and the
928 button release gettnig processed first. answer: don't queue
929 moveresize starts. UGLY HACK XXX
931 XXX ALSO don't queue showmenu events, because on button press
932 events we need to know if a mouse grab is going to take place,
933 and set the button to 0, so that later motion events don't think
934 that a drag is going on. since showmenu grabs the pointer..
936 if (a
->data
.any
.interactive
|| a
->func
== action_move
||
937 a
->func
== action_resize
|| a
->func
== action_showmenu
)
939 /* interactive actions are not queued */
941 } else if (a
->func
== action_focus
||
942 a
->func
== action_activate
||
943 a
->func
== action_showmenu
)
945 /* XXX MORE UGLY HACK
946 actions from clicks on client windows are NOT queued.
947 this solves the mysterious click-and-drag-doesnt-work
948 problem. it was because the window gets focused and stuff
949 after the button event has already been passed through. i
950 dont really know why it should care but it does and it makes
953 however this very bogus ! !
954 we want to send the button press to the window BEFORE
955 we do the action because the action might move the windows
956 (eg change desktops) and then the button press ends up on
957 the completely wrong window !
958 so, this is just for that bug, and it will only NOT queue it
959 if it is a focusing action that can be used with the mouse
962 also with the menus, there is a race going on. if the
963 desktop wants to pop up a menu, and we do too, we send them
964 the button before we pop up the menu, so they pop up their
965 menu first. but not always. if we pop up our menu before
966 sending them the button press, then the result is
969 XXX further more. focus actions are not queued at all,
970 because if you bind focus->showmenu, the menu will get
971 hidden to do the focusing
975 ob_main_loop_queue_action(ob_main_loop
, a
);
980 void action_run_string(const gchar
*name
, struct _ObClient
*c
, Time time
)
985 a
= action_from_string(name
, OB_USER_ACTION_NONE
);
988 l
= g_slist_append(NULL
, a
);
990 action_run(l
, c
, 0, time
);
993 void action_unshaderaise(union ActionData
*data
)
995 if (data
->client
.any
.c
->shaded
)
996 action_unshade(data
);
1001 void action_shadelower(union ActionData
*data
)
1003 if (data
->client
.any
.c
->shaded
)
1009 void action_kill(union ActionData
*data
)
1011 client_kill(data
->client
.any
.c
);
1014 void action_shade(union ActionData
*data
)
1016 client_action_start(data
);
1017 client_shade(data
->client
.any
.c
, TRUE
);
1018 client_action_end(data
, config_focus_under_mouse
);
1021 void action_unshade(union ActionData
*data
)
1023 client_action_start(data
);
1024 client_shade(data
->client
.any
.c
, FALSE
);
1025 client_action_end(data
, config_focus_under_mouse
);
1028 void action_toggle_shade(union ActionData
*data
)
1030 client_action_start(data
);
1031 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1032 client_action_end(data
, config_focus_under_mouse
);
1035 void action_toggle_omnipresent(union ActionData
*data
)
1037 client_set_desktop(data
->client
.any
.c
,
1038 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1039 screen_desktop
: DESKTOP_ALL
, FALSE
, TRUE
);
1042 void action_move_relative_horz(union ActionData
*data
)
1044 ObClient
*c
= data
->relative
.any
.c
;
1045 client_action_start(data
);
1046 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
);
1047 client_action_end(data
, FALSE
);
1050 void action_move_relative_vert(union ActionData
*data
)
1052 ObClient
*c
= data
->relative
.any
.c
;
1053 client_action_start(data
);
1054 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.deltax
);
1055 client_action_end(data
, FALSE
);
1058 void action_move_to_center(union ActionData
*data
)
1060 ObClient
*c
= data
->client
.any
.c
;
1062 area
= screen_area(c
->desktop
, client_monitor(c
), NULL
);
1063 client_action_start(data
);
1064 client_move(c
, area
->x
+ area
->width
/ 2 - c
->area
.width
/ 2,
1065 area
->y
+ area
->height
/ 2 - c
->area
.height
/ 2);
1066 client_action_end(data
, FALSE
);
1070 void action_resize_relative_horz(union ActionData
*data
)
1072 ObClient
*c
= data
->relative
.any
.c
;
1073 client_action_start(data
);
1075 c
->area
.width
+ data
->relative
.deltax
* c
->size_inc
.width
,
1077 client_action_end(data
, FALSE
);
1080 void action_resize_relative_vert(union ActionData
*data
)
1082 ObClient
*c
= data
->relative
.any
.c
;
1084 client_action_start(data
);
1085 client_resize(c
, c
->area
.width
, c
->area
.height
+
1086 data
->relative
.deltax
* c
->size_inc
.height
);
1087 client_action_end(data
, FALSE
);
1091 void action_move_relative(union ActionData
*data
)
1093 ObClient
*c
= data
->relative
.any
.c
;
1094 client_action_start(data
);
1095 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
+
1096 data
->relative
.deltay
);
1097 client_action_end(data
, FALSE
);
1100 void action_resize_relative(union ActionData
*data
)
1102 ObClient
*c
= data
->relative
.any
.c
;
1103 gint x
, y
, ow
, xoff
, nw
, oh
, yoff
, nh
, lw
, lh
;
1105 client_action_start(data
);
1110 xoff
= -data
->relative
.deltaxl
* c
->size_inc
.width
;
1111 nw
= ow
+ data
->relative
.deltax
* c
->size_inc
.width
1112 + data
->relative
.deltaxl
* c
->size_inc
.width
;
1113 oh
= c
->area
.height
;
1114 yoff
= -data
->relative
.deltayu
* c
->size_inc
.height
;
1115 nh
= oh
+ data
->relative
.deltay
* c
->size_inc
.height
1116 + data
->relative
.deltayu
* c
->size_inc
.height
;
1118 g_print("deltax %d %d x %d ow %d xoff %d nw %d\n",
1119 data
->relative
.deltax
,
1120 data
->relative
.deltaxl
,
1123 client_try_configure(c
, &x
, &y
, &nw
, &nh
, &lw
, &lh
, TRUE
);
1124 xoff
= xoff
== 0 ? 0 : (xoff
< 0 ? MAX(xoff
, ow
-nw
) : MIN(xoff
, ow
-nw
));
1125 yoff
= yoff
== 0 ? 0 : (yoff
< 0 ? MAX(yoff
, oh
-nh
) : MIN(yoff
, oh
-nh
));
1126 client_move_resize(c
, x
+ xoff
, y
+ yoff
, nw
, nh
);
1127 client_action_end(data
, FALSE
);
1130 void action_toggle_maximize_vert(union ActionData
*data
)
1132 client_action_start(data
);
1133 client_maximize(data
->client
.any
.c
,
1134 !data
->client
.any
.c
->max_vert
, 2);
1135 client_action_end(data
, config_focus_under_mouse
);
1138 void action_send_to_desktop(union ActionData
*data
)
1140 ObClient
*c
= data
->sendto
.any
.c
;
1142 if (!client_normal(c
)) return;
1144 if (data
->sendto
.desk
< screen_num_desktops
||
1145 data
->sendto
.desk
== DESKTOP_ALL
) {
1146 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
, FALSE
);
1147 if (data
->sendto
.follow
&& data
->sendto
.desk
!= screen_desktop
)
1148 screen_set_desktop(data
->sendto
.desk
, TRUE
);
1152 void action_desktop(union ActionData
*data
)
1154 /* XXX add the interactive/dialog option back again once the dialog
1155 has been made to not use grabs */
1156 if (data
->desktop
.desk
< screen_num_desktops
||
1157 data
->desktop
.desk
== DESKTOP_ALL
)
1159 screen_set_desktop(data
->desktop
.desk
, TRUE
);
1160 if (data
->inter
.any
.interactive
)
1161 screen_desktop_popup(data
->desktop
.desk
, TRUE
);
1165 void action_desktop_dir(union ActionData
*data
)
1169 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1170 data
->desktopdir
.wrap
,
1171 data
->desktopdir
.linear
,
1172 data
->desktopdir
.inter
.any
.interactive
,
1173 data
->desktopdir
.inter
.final
,
1174 data
->desktopdir
.inter
.cancel
);
1175 /* only move the desktop when the action is complete. if we switch
1176 desktops during the interactive action, focus will move but with
1177 NotifyWhileGrabbed and applications don't like that. */
1178 if (!data
->sendtodir
.inter
.any
.interactive
||
1179 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1181 if (d
!= screen_desktop
)
1182 screen_set_desktop(d
, TRUE
);
1186 void action_send_to_desktop_dir(union ActionData
*data
)
1188 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1191 if (!client_normal(c
)) return;
1193 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1194 data
->sendtodir
.linear
,
1195 data
->sendtodir
.inter
.any
.interactive
,
1196 data
->sendtodir
.inter
.final
,
1197 data
->sendtodir
.inter
.cancel
);
1198 /* only move the desktop when the action is complete. if we switch
1199 desktops during the interactive action, focus will move but with
1200 NotifyWhileGrabbed and applications don't like that. */
1201 if (!data
->sendtodir
.inter
.any
.interactive
||
1202 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1204 client_set_desktop(c
, d
, data
->sendtodir
.follow
, FALSE
);
1205 if (data
->sendtodir
.follow
&& d
!= screen_desktop
)
1206 screen_set_desktop(d
, TRUE
);
1210 void action_desktop_last(union ActionData
*data
)
1212 if (screen_last_desktop
< screen_num_desktops
)
1213 screen_set_desktop(screen_last_desktop
, TRUE
);
1216 void action_toggle_decorations(union ActionData
*data
)
1218 ObClient
*c
= data
->client
.any
.c
;
1220 client_action_start(data
);
1221 client_set_undecorated(c
, !c
->undecorated
);
1222 client_action_end(data
, FALSE
);
1225 static guint32
pick_corner(gint x
, gint y
, gint cx
, gint cy
, gint cw
, gint ch
,
1228 /* let's make x and y client relative instead of screen relative */
1230 y
= ch
- (y
- cy
); /* y is inverted, 0 is at the bottom of the window */
1233 #define A -4*X + 7*ch/3
1234 #define B 4*X -15*ch/9
1235 #define C -X/4 + 2*ch/3
1236 #define D X/4 + 5*ch/12
1237 #define E X/4 + ch/3
1238 #define F -X/4 + 7*ch/12
1239 #define G 4*X - 4*ch/3
1240 #define H -4*X + 8*ch/3
1241 #define a (y > 5*ch/9)
1242 #define b (x < 4*cw/9)
1243 #define c (x > 5*cw/9)
1244 #define d (y < 4*ch/9)
1247 Each of these defines (except X which is just there for fun), represents
1248 the equation of a line. The lines they represent are shown in the diagram
1249 below. Checking y against these lines, we are able to choose a region
1250 of the window as shown.
1252 +---------------------A-------|-------|-------B---------------------+
1259 | northwest | A north B | northeast |
1262 C---------------------+----A--+-------+--B----+---------------------D
1263 |CCCCCCC | A B | DDDDDDD|
1264 | CCCCCCCC | A | | B | DDDDDDDD |
1265 | CCCCCCC A B DDDDDDD |
1266 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
1268 | west | b move c | east | ad
1270 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
1271 | EEEEEEE G H FFFFFFF |
1272 | EEEEEEEE | G | | H | FFFFFFFF |
1273 |EEEEEEE | G H | FFFFFFF|
1274 E---------------------+----G--+-------+--H----+---------------------F
1277 | southwest | G south H | southeast |
1284 +---------------------G-------|-------|-------H---------------------+
1288 /* for shaded windows, you can only resize west/east and move */
1290 return prop_atoms
.net_wm_moveresize_size_left
;
1292 return prop_atoms
.net_wm_moveresize_size_right
;
1293 return prop_atoms
.net_wm_moveresize_move
;
1296 if (y
< A
&& y
>= C
)
1297 return prop_atoms
.net_wm_moveresize_size_topleft
;
1298 else if (y
>= A
&& y
>= B
&& a
)
1299 return prop_atoms
.net_wm_moveresize_size_top
;
1300 else if (y
< B
&& y
>= D
)
1301 return prop_atoms
.net_wm_moveresize_size_topright
;
1302 else if (y
< C
&& y
>= E
&& b
)
1303 return prop_atoms
.net_wm_moveresize_size_left
;
1304 else if (y
< D
&& y
>= F
&& c
)
1305 return prop_atoms
.net_wm_moveresize_size_right
;
1306 else if (y
< E
&& y
>= G
)
1307 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1308 else if (y
< G
&& y
< H
&& d
)
1309 return prop_atoms
.net_wm_moveresize_size_bottom
;
1310 else if (y
>= H
&& y
< F
)
1311 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1313 return prop_atoms
.net_wm_moveresize_move
;
1330 void action_resize(union ActionData
*data
)
1332 ObClient
*c
= data
->moveresize
.any
.c
;
1335 if (data
->moveresize
.keyboard
)
1336 corner
= prop_atoms
.net_wm_moveresize_size_keyboard
;
1337 else if (data
->moveresize
.corner
)
1338 corner
= data
->moveresize
.corner
; /* it was specified in the binding */
1340 corner
= pick_corner(data
->any
.x
, data
->any
.y
,
1341 c
->frame
->area
.x
, c
->frame
->area
.y
,
1342 /* use the client size because the frame
1343 can be differently sized (shaded
1344 windows) and we want this based on the
1346 c
->area
.width
+ c
->frame
->size
.left
+
1347 c
->frame
->size
.right
,
1348 c
->area
.height
+ c
->frame
->size
.top
+
1349 c
->frame
->size
.bottom
, c
->shaded
);
1351 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1354 void action_directional_focus(union ActionData
*data
)
1356 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1358 event_halt_focus_delay();
1360 focus_directional_cycle(data
->interdiraction
.direction
,
1361 data
->interdiraction
.dock_windows
,
1362 data
->interdiraction
.desktop_windows
,
1363 data
->any
.interactive
,
1364 data
->interdiraction
.dialog
,
1365 data
->interdiraction
.inter
.final
,
1366 data
->interdiraction
.inter
.cancel
);
1369 void action_movetoedge(union ActionData
*data
)
1372 ObClient
*c
= data
->diraction
.any
.c
;
1374 x
= c
->frame
->area
.x
;
1375 y
= c
->frame
->area
.y
;
1377 switch(data
->diraction
.direction
) {
1378 case OB_DIRECTION_NORTH
:
1379 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
,
1380 data
->diraction
.hang
)
1381 - (data
->diraction
.hang
? c
->frame
->area
.height
: 0);
1383 case OB_DIRECTION_WEST
:
1384 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
,
1385 data
->diraction
.hang
)
1386 - (data
->diraction
.hang
? c
->frame
->area
.width
: 0);
1388 case OB_DIRECTION_SOUTH
:
1389 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
,
1390 data
->diraction
.hang
)
1391 - (data
->diraction
.hang
? 0 : c
->frame
->area
.height
);
1393 case OB_DIRECTION_EAST
:
1394 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
,
1395 data
->diraction
.hang
)
1396 - (data
->diraction
.hang
? 0 : c
->frame
->area
.width
);
1399 g_assert_not_reached();
1401 frame_frame_gravity(c
->frame
, &x
, &y
, c
->area
.width
, c
->area
.height
);
1402 client_action_start(data
);
1403 client_move(c
, x
, y
);
1404 client_action_end(data
, FALSE
);
1407 void action_growtoedge(union ActionData
*data
)
1409 gint x
, y
, width
, height
, dest
;
1410 ObClient
*c
= data
->diraction
.any
.c
;
1413 a
= screen_area(c
->desktop
, SCREEN_AREA_ALL_MONITORS
, &c
->frame
->area
);
1414 x
= c
->frame
->area
.x
;
1415 y
= c
->frame
->area
.y
;
1416 /* get the unshaded frame's dimensions..if it is shaded */
1417 width
= c
->area
.width
+ c
->frame
->size
.left
+ c
->frame
->size
.right
;
1418 height
= c
->area
.height
+ c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1420 switch(data
->diraction
.direction
) {
1421 case OB_DIRECTION_NORTH
:
1422 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1424 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
, FALSE
);
1426 height
= height
/ 2;
1428 height
= c
->frame
->area
.y
+ height
- dest
;
1432 case OB_DIRECTION_WEST
:
1433 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
, FALSE
);
1437 width
= c
->frame
->area
.x
+ width
- dest
;
1441 case OB_DIRECTION_SOUTH
:
1442 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1444 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
, FALSE
);
1445 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1446 height
= c
->frame
->area
.height
/ 2;
1447 y
= a
->y
+ a
->height
- height
;
1449 height
= dest
- c
->frame
->area
.y
;
1450 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1451 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1453 case OB_DIRECTION_EAST
:
1454 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
, FALSE
);
1455 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1456 width
= c
->frame
->area
.width
/ 2;
1457 x
= a
->x
+ a
->width
- width
;
1459 width
= dest
- c
->frame
->area
.x
;
1460 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1461 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1464 g_assert_not_reached();
1466 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1467 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1468 frame_frame_gravity(c
->frame
, &x
, &y
, width
, height
);
1469 client_action_start(data
);
1470 client_move_resize(c
, x
, y
, width
, height
);
1471 client_action_end(data
, FALSE
);
1475 void action_send_to_layer(union ActionData
*data
)
1477 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1480 void action_toggle_layer(union ActionData
*data
)
1482 ObClient
*c
= data
->layer
.any
.c
;
1484 client_action_start(data
);
1485 if (data
->layer
.layer
< 0)
1486 client_set_layer(c
, c
->below
? 0 : -1);
1487 else if (data
->layer
.layer
> 0)
1488 client_set_layer(c
, c
->above
? 0 : 1);
1489 client_action_end(data
, config_focus_under_mouse
);
1492 void action_toggle_dockautohide(union ActionData
*data
)
1494 config_dock_hide
= !config_dock_hide
;
1498 void action_add_desktop(union ActionData
*data
)
1500 client_action_start(data
);
1501 screen_set_num_desktops(screen_num_desktops
+1);
1503 /* move all the clients over */
1504 if (data
->addremovedesktop
.current
) {
1507 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1508 ObClient
*c
= it
->data
;
1509 if (c
->desktop
!= DESKTOP_ALL
&& c
->desktop
>= screen_desktop
)
1510 client_set_desktop(c
, c
->desktop
+1, FALSE
, TRUE
);
1514 client_action_end(data
, config_focus_under_mouse
);
1517 void action_remove_desktop(union ActionData
*data
)
1519 guint rmdesktop
, movedesktop
;
1520 GList
*it
, *stacking_copy
;
1522 if (screen_num_desktops
< 2) return;
1524 client_action_start(data
);
1526 /* what desktop are we removing and moving to? */
1527 if (data
->addremovedesktop
.current
)
1528 rmdesktop
= screen_desktop
;
1530 rmdesktop
= screen_num_desktops
- 1;
1531 if (rmdesktop
< screen_num_desktops
- 1)
1532 movedesktop
= rmdesktop
+ 1;
1534 movedesktop
= rmdesktop
;
1536 /* make a copy of the list cuz we're changing it */
1537 stacking_copy
= g_list_copy(stacking_list
);
1538 for (it
= g_list_last(stacking_copy
); it
; it
= g_list_previous(it
)) {
1539 if (WINDOW_IS_CLIENT(it
->data
)) {
1540 ObClient
*c
= it
->data
;
1541 guint d
= c
->desktop
;
1542 if (d
!= DESKTOP_ALL
&& d
>= movedesktop
) {
1543 client_set_desktop(c
, c
->desktop
- 1, TRUE
, TRUE
);
1544 ob_debug("moving window %s\n", c
->title
);
1546 /* raise all the windows that are on the current desktop which
1548 if ((screen_desktop
== rmdesktop
- 1 ||
1549 screen_desktop
== rmdesktop
) &&
1550 (d
== DESKTOP_ALL
|| d
== screen_desktop
))
1552 stacking_raise(CLIENT_AS_WINDOW(c
));
1553 ob_debug("raising window %s\n", c
->title
);
1558 /* act like we're changing desktops */
1559 if (screen_desktop
< screen_num_desktops
- 1) {
1560 gint d
= screen_desktop
;
1561 screen_desktop
= screen_last_desktop
;
1562 screen_set_desktop(d
, TRUE
);
1563 ob_debug("fake desktop change\n");
1566 screen_set_num_desktops(screen_num_desktops
-1);
1568 client_action_end(data
, config_focus_under_mouse
);