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_send_to_desktop(ObAction
**a
, ObUserAction uact
)
101 (*a
)->data
.sendto
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
102 (*a
)->data
.sendto
.follow
= TRUE
;
105 void setup_action_send_to_desktop_prev(ObAction
**a
, ObUserAction uact
)
107 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
108 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
109 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
110 (*a
)->data
.sendtodir
.linear
= TRUE
;
111 (*a
)->data
.sendtodir
.wrap
= TRUE
;
112 (*a
)->data
.sendtodir
.follow
= TRUE
;
115 void setup_action_send_to_desktop_next(ObAction
**a
, ObUserAction uact
)
117 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
118 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
119 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
120 (*a
)->data
.sendtodir
.linear
= TRUE
;
121 (*a
)->data
.sendtodir
.wrap
= TRUE
;
122 (*a
)->data
.sendtodir
.follow
= TRUE
;
125 void setup_action_send_to_desktop_left(ObAction
**a
, ObUserAction uact
)
127 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
128 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
129 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
130 (*a
)->data
.sendtodir
.linear
= FALSE
;
131 (*a
)->data
.sendtodir
.wrap
= TRUE
;
132 (*a
)->data
.sendtodir
.follow
= TRUE
;
135 void setup_action_send_to_desktop_right(ObAction
**a
, ObUserAction uact
)
137 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
138 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
139 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
140 (*a
)->data
.sendtodir
.linear
= FALSE
;
141 (*a
)->data
.sendtodir
.wrap
= TRUE
;
142 (*a
)->data
.sendtodir
.follow
= TRUE
;
145 void setup_action_send_to_desktop_up(ObAction
**a
, ObUserAction uact
)
147 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
148 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
149 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_NORTH
;
150 (*a
)->data
.sendtodir
.linear
= FALSE
;
151 (*a
)->data
.sendtodir
.wrap
= TRUE
;
152 (*a
)->data
.sendtodir
.follow
= TRUE
;
155 void setup_action_send_to_desktop_down(ObAction
**a
, ObUserAction uact
)
157 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
158 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
159 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_SOUTH
;
160 (*a
)->data
.sendtodir
.linear
= FALSE
;
161 (*a
)->data
.sendtodir
.wrap
= TRUE
;
162 (*a
)->data
.sendtodir
.follow
= TRUE
;
165 void setup_action_desktop_prev(ObAction
**a
, ObUserAction uact
)
167 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
168 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
169 (*a
)->data
.desktopdir
.linear
= TRUE
;
170 (*a
)->data
.desktopdir
.wrap
= TRUE
;
173 void setup_action_desktop_next(ObAction
**a
, ObUserAction uact
)
175 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
176 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
177 (*a
)->data
.desktopdir
.linear
= TRUE
;
178 (*a
)->data
.desktopdir
.wrap
= TRUE
;
181 void setup_action_desktop_left(ObAction
**a
, ObUserAction uact
)
183 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
184 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
185 (*a
)->data
.desktopdir
.linear
= FALSE
;
186 (*a
)->data
.desktopdir
.wrap
= TRUE
;
189 void setup_action_desktop_right(ObAction
**a
, ObUserAction uact
)
191 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
192 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
193 (*a
)->data
.desktopdir
.linear
= FALSE
;
194 (*a
)->data
.desktopdir
.wrap
= TRUE
;
197 void setup_action_desktop_up(ObAction
**a
, ObUserAction uact
)
199 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
200 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_NORTH
;
201 (*a
)->data
.desktopdir
.linear
= FALSE
;
202 (*a
)->data
.desktopdir
.wrap
= TRUE
;
205 void setup_action_desktop_down(ObAction
**a
, ObUserAction uact
)
207 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
208 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_SOUTH
;
209 (*a
)->data
.desktopdir
.linear
= FALSE
;
210 (*a
)->data
.desktopdir
.wrap
= TRUE
;
213 void setup_action_movefromedge_north(ObAction
**a
, ObUserAction uact
)
215 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
216 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
217 (*a
)->data
.diraction
.hang
= TRUE
;
220 void setup_action_movefromedge_south(ObAction
**a
, ObUserAction uact
)
222 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
223 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
224 (*a
)->data
.diraction
.hang
= TRUE
;
227 void setup_action_movefromedge_east(ObAction
**a
, ObUserAction uact
)
229 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
230 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
231 (*a
)->data
.diraction
.hang
= TRUE
;
234 void setup_action_movefromedge_west(ObAction
**a
, ObUserAction uact
)
236 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
237 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
238 (*a
)->data
.diraction
.hang
= TRUE
;
241 void setup_action_movetoedge_north(ObAction
**a
, ObUserAction uact
)
243 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
244 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
245 (*a
)->data
.diraction
.hang
= FALSE
;
248 void setup_action_movetoedge_south(ObAction
**a
, ObUserAction uact
)
250 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
251 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
252 (*a
)->data
.diraction
.hang
= FALSE
;
255 void setup_action_movetoedge_east(ObAction
**a
, ObUserAction uact
)
257 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
258 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
259 (*a
)->data
.diraction
.hang
= FALSE
;
262 void setup_action_movetoedge_west(ObAction
**a
, ObUserAction uact
)
264 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
265 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
266 (*a
)->data
.diraction
.hang
= FALSE
;
269 void setup_action_growtoedge_north(ObAction
**a
, ObUserAction uact
)
271 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
272 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
275 void setup_action_growtoedge_south(ObAction
**a
, ObUserAction uact
)
277 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
278 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
281 void setup_action_growtoedge_east(ObAction
**a
, ObUserAction uact
)
283 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
284 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
287 void setup_action_growtoedge_west(ObAction
**a
, ObUserAction uact
)
289 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
290 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
293 void setup_action_top_layer(ObAction
**a
, ObUserAction uact
)
295 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
296 (*a
)->data
.layer
.layer
= 1;
299 void setup_action_normal_layer(ObAction
**a
, ObUserAction uact
)
301 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
302 (*a
)->data
.layer
.layer
= 0;
305 void setup_action_bottom_layer(ObAction
**a
, ObUserAction uact
)
307 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
308 (*a
)->data
.layer
.layer
= -1;
311 void setup_action_resize(ObAction
**a
, ObUserAction uact
)
313 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
314 (*a
)->data
.moveresize
.keyboard
=
315 (uact
== OB_USER_ACTION_NONE
||
316 uact
== OB_USER_ACTION_KEYBOARD_KEY
||
317 uact
== OB_USER_ACTION_MENU_SELECTION
);
318 (*a
)->data
.moveresize
.corner
= 0;
321 void setup_action_addremove_desktop_current(ObAction
**a
, ObUserAction uact
)
323 (*a
)->data
.addremovedesktop
.current
= TRUE
;
326 void setup_action_addremove_desktop_last(ObAction
**a
, ObUserAction uact
)
328 (*a
)->data
.addremovedesktop
.current
= FALSE
;
331 void setup_client_action(ObAction
**a
, ObUserAction uact
)
333 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
336 ActionString actionstrings
[] =
349 "resizerelativevert",
350 action_resize_relative_vert
,
355 action_resize_relative
,
360 action_send_to_desktop
,
361 setup_action_send_to_desktop
365 action_send_to_desktop_dir
,
366 setup_action_send_to_desktop_next
369 "sendtodesktopprevious",
370 action_send_to_desktop_dir
,
371 setup_action_send_to_desktop_prev
374 "sendtodesktopright",
375 action_send_to_desktop_dir
,
376 setup_action_send_to_desktop_right
380 action_send_to_desktop_dir
,
381 setup_action_send_to_desktop_left
385 action_send_to_desktop_dir
,
386 setup_action_send_to_desktop_up
390 action_send_to_desktop_dir
,
391 setup_action_send_to_desktop_down
396 setup_action_desktop_next
401 setup_action_desktop_prev
406 setup_action_desktop_right
411 setup_action_desktop_left
416 setup_action_desktop_up
421 setup_action_desktop_down
424 "toggledockautohide",
425 action_toggle_dockautohide
,
435 action_send_to_layer
,
436 setup_action_top_layer
441 setup_action_top_layer
445 action_send_to_layer
,
446 setup_action_normal_layer
450 action_send_to_layer
,
451 setup_action_bottom_layer
454 "togglealwaysonbottom",
456 setup_action_bottom_layer
461 setup_action_movefromedge_north
466 setup_action_movefromedge_south
471 setup_action_movefromedge_west
476 setup_action_movefromedge_east
481 setup_action_movetoedge_north
486 setup_action_movetoedge_south
491 setup_action_movetoedge_west
496 setup_action_movetoedge_east
501 setup_action_growtoedge_north
506 setup_action_growtoedge_south
511 setup_action_growtoedge_west
516 setup_action_growtoedge_east
521 setup_action_addremove_desktop_last
525 action_remove_desktop
,
526 setup_action_addremove_desktop_last
531 setup_action_addremove_desktop_current
534 "removedesktopcurrent",
535 action_remove_desktop
,
536 setup_action_addremove_desktop_current
545 /* only key bindings can be interactive. thus saith the xor.
546 because of how the mouse is grabbed, mouse events dont even get
547 read during interactive events, so no dice! >:) */
548 #define INTERACTIVE_LIMIT(a, uact) \
549 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
550 a->data.any.interactive = FALSE;
552 ObAction
*action_from_string(const gchar
*name
, ObUserAction uact
)
555 gboolean exist
= FALSE
;
558 for (i
= 0; actionstrings
[i
].name
; i
++)
559 if (!g_ascii_strcasecmp(name
, actionstrings
[i
].name
)) {
561 a
= action_new(actionstrings
[i
].func
);
562 if (actionstrings
[i
].setup
)
563 actionstrings
[i
].setup(&a
, uact
);
565 INTERACTIVE_LIMIT(a
, uact
);
569 g_message(_("Invalid action '%s' requested. No such action exists."),
572 g_message(_("Invalid use of action '%s'. Action will be ignored."),
577 ObAction
*action_parse(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
581 ObAction
*act
= NULL
;
584 if (parse_attr_string("name", node
, &actname
)) {
585 if ((act
= action_from_string(actname
, uact
))) {
586 } else if (act
->func
== action_resize_relative
) {
587 if ((n
= parse_find_node("left", node
->xmlChildrenNode
)))
588 act
->data
.relative
.deltaxl
= parse_int(doc
, n
);
589 if ((n
= parse_find_node("up", node
->xmlChildrenNode
)))
590 act
->data
.relative
.deltayu
= parse_int(doc
, n
);
591 if ((n
= parse_find_node("right", node
->xmlChildrenNode
)))
592 act
->data
.relative
.deltax
= parse_int(doc
, n
);
593 if ((n
= parse_find_node("down", node
->xmlChildrenNode
)))
594 act
->data
.relative
.deltay
= parse_int(doc
, n
);
595 } else if (act
->func
== action_desktop
) {
596 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
597 act
->data
.desktop
.desk
= parse_int(doc
, n
);
598 if (act
->data
.desktop
.desk
> 0) act
->data
.desktop
.desk
--;
600 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
601 act->data.desktop.inter.any.interactive =
604 } else if (act
->func
== action_send_to_desktop
) {
605 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
606 act
->data
.sendto
.desk
= parse_int(doc
, n
);
607 if (act
->data
.sendto
.desk
> 0) act
->data
.sendto
.desk
--;
608 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
609 act
->data
.sendto
.follow
= parse_bool(doc
, n
);
610 } else if (act
->func
== action_desktop_dir
) {
611 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
612 act
->data
.desktopdir
.wrap
= parse_bool(doc
, n
);
613 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
614 act
->data
.desktopdir
.inter
.any
.interactive
=
616 } else if (act
->func
== action_send_to_desktop_dir
) {
617 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
618 act
->data
.sendtodir
.wrap
= parse_bool(doc
, n
);
619 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
620 act
->data
.sendtodir
.follow
= parse_bool(doc
, n
);
621 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
622 act
->data
.sendtodir
.inter
.any
.interactive
=
624 INTERACTIVE_LIMIT(act
, uact
);
631 void action_run_list(GSList
*acts
, ObClient
*c
, ObFrameContext context
,
632 guint state
, guint button
, gint x
, gint y
, Time time
,
633 gboolean cancel
, gboolean done
)
642 screen_pointer_pos(&x
, &y
);
644 for (it
= acts
; it
; it
= g_slist_next(it
)) {
647 if (!(a
->data
.any
.client_action
== OB_CLIENT_ACTION_ALWAYS
&& !c
)) {
648 a
->data
.any
.c
= a
->data
.any
.client_action
? c
: NULL
;
649 a
->data
.any
.context
= context
;
653 a
->data
.any
.button
= button
;
655 a
->data
.any
.time
= time
;
657 if (a
->data
.any
.interactive
) {
658 a
->data
.inter
.cancel
= cancel
;
659 a
->data
.inter
.final
= done
;
660 if (!(cancel
|| done
))
661 if (!keyboard_interactive_grab(state
, a
->data
.any
.c
, a
))
665 /* XXX UGLY HACK race with motion event starting a move and the
666 button release gettnig processed first. answer: don't queue
667 moveresize starts. UGLY HACK XXX
669 XXX ALSO don't queue showmenu events, because on button press
670 events we need to know if a mouse grab is going to take place,
671 and set the button to 0, so that later motion events don't think
672 that a drag is going on. since showmenu grabs the pointer..
674 if (a
->data
.any
.interactive
|| a
->func
== action_move
||
675 a
->func
== action_resize
|| a
->func
== action_showmenu
)
677 /* interactive actions are not queued */
679 } else if (a
->func
== action_focus
||
680 a
->func
== action_activate
||
681 a
->func
== action_showmenu
)
683 /* XXX MORE UGLY HACK
684 actions from clicks on client windows are NOT queued.
685 this solves the mysterious click-and-drag-doesnt-work
686 problem. it was because the window gets focused and stuff
687 after the button event has already been passed through. i
688 dont really know why it should care but it does and it makes
691 however this very bogus ! !
692 we want to send the button press to the window BEFORE
693 we do the action because the action might move the windows
694 (eg change desktops) and then the button press ends up on
695 the completely wrong window !
696 so, this is just for that bug, and it will only NOT queue it
697 if it is a focusing action that can be used with the mouse
700 also with the menus, there is a race going on. if the
701 desktop wants to pop up a menu, and we do too, we send them
702 the button before we pop up the menu, so they pop up their
703 menu first. but not always. if we pop up our menu before
704 sending them the button press, then the result is
707 XXX further more. focus actions are not queued at all,
708 because if you bind focus->showmenu, the menu will get
709 hidden to do the focusing
713 ob_main_loop_queue_action(ob_main_loop
, a
);
718 void action_run_string(const gchar
*name
, struct _ObClient
*c
, Time time
)
723 a
= action_from_string(name
, OB_USER_ACTION_NONE
);
726 l
= g_slist_append(NULL
, a
);
728 action_run(l
, c
, 0, time
);
731 void action_unshaderaise(union ActionData
*data
)
733 if (data
->client
.any
.c
->shaded
)
734 action_unshade(data
);
739 void action_shadelower(union ActionData
*data
)
741 if (data
->client
.any
.c
->shaded
)
747 void action_resize_relative_horz(union ActionData
*data
)
749 ObClient
*c
= data
->relative
.any
.c
;
750 client_action_start(data
);
752 c
->area
.width
+ data
->relative
.deltax
* c
->size_inc
.width
,
754 client_action_end(data
, FALSE
);
757 void action_resize_relative_vert(union ActionData
*data
)
759 ObClient
*c
= data
->relative
.any
.c
;
761 client_action_start(data
);
762 client_resize(c
, c
->area
.width
, c
->area
.height
+
763 data
->relative
.deltax
* c
->size_inc
.height
);
764 client_action_end(data
, FALSE
);
768 void action_resize_relative(union ActionData
*data
)
770 ObClient
*c
= data
->relative
.any
.c
;
771 gint x
, y
, ow
, xoff
, nw
, oh
, yoff
, nh
, lw
, lh
;
773 client_action_start(data
);
778 xoff
= -data
->relative
.deltaxl
* c
->size_inc
.width
;
779 nw
= ow
+ data
->relative
.deltax
* c
->size_inc
.width
780 + data
->relative
.deltaxl
* c
->size_inc
.width
;
782 yoff
= -data
->relative
.deltayu
* c
->size_inc
.height
;
783 nh
= oh
+ data
->relative
.deltay
* c
->size_inc
.height
784 + data
->relative
.deltayu
* c
->size_inc
.height
;
786 g_print("deltax %d %d x %d ow %d xoff %d nw %d\n",
787 data
->relative
.deltax
,
788 data
->relative
.deltaxl
,
791 client_try_configure(c
, &x
, &y
, &nw
, &nh
, &lw
, &lh
, TRUE
);
792 xoff
= xoff
== 0 ? 0 : (xoff
< 0 ? MAX(xoff
, ow
-nw
) : MIN(xoff
, ow
-nw
));
793 yoff
= yoff
== 0 ? 0 : (yoff
< 0 ? MAX(yoff
, oh
-nh
) : MIN(yoff
, oh
-nh
));
794 client_move_resize(c
, x
+ xoff
, y
+ yoff
, nw
, nh
);
795 client_action_end(data
, FALSE
);
798 void action_send_to_desktop(union ActionData
*data
)
800 ObClient
*c
= data
->sendto
.any
.c
;
802 if (!client_normal(c
)) return;
804 if (data
->sendto
.desk
< screen_num_desktops
||
805 data
->sendto
.desk
== DESKTOP_ALL
) {
806 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
, FALSE
);
807 if (data
->sendto
.follow
&& data
->sendto
.desk
!= screen_desktop
)
808 screen_set_desktop(data
->sendto
.desk
, TRUE
);
812 void action_desktop_dir(union ActionData
*data
)
816 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
817 data
->desktopdir
.wrap
,
818 data
->desktopdir
.linear
,
819 data
->desktopdir
.inter
.any
.interactive
,
820 data
->desktopdir
.inter
.final
,
821 data
->desktopdir
.inter
.cancel
);
822 /* only move the desktop when the action is complete. if we switch
823 desktops during the interactive action, focus will move but with
824 NotifyWhileGrabbed and applications don't like that. */
825 if (!data
->sendtodir
.inter
.any
.interactive
||
826 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
828 if (d
!= screen_desktop
)
829 screen_set_desktop(d
, TRUE
);
833 void action_send_to_desktop_dir(union ActionData
*data
)
835 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
838 if (!client_normal(c
)) return;
840 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
841 data
->sendtodir
.linear
,
842 data
->sendtodir
.inter
.any
.interactive
,
843 data
->sendtodir
.inter
.final
,
844 data
->sendtodir
.inter
.cancel
);
845 /* only move the desktop when the action is complete. if we switch
846 desktops during the interactive action, focus will move but with
847 NotifyWhileGrabbed and applications don't like that. */
848 if (!data
->sendtodir
.inter
.any
.interactive
||
849 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
851 client_set_desktop(c
, d
, data
->sendtodir
.follow
, FALSE
);
852 if (data
->sendtodir
.follow
&& d
!= screen_desktop
)
853 screen_set_desktop(d
, TRUE
);
857 void action_desktop_last(union ActionData
*data
)
859 if (screen_last_desktop
< screen_num_desktops
)
860 screen_set_desktop(screen_last_desktop
, TRUE
);
863 void action_directional_focus(union ActionData
*data
)
865 /* if using focus_delay, stop the timer now so that focus doesn't go moving
867 event_halt_focus_delay();
869 focus_directional_cycle(data
->interdiraction
.direction
,
870 data
->interdiraction
.dock_windows
,
871 data
->interdiraction
.desktop_windows
,
872 data
->any
.interactive
,
873 data
->interdiraction
.dialog
,
874 data
->interdiraction
.inter
.final
,
875 data
->interdiraction
.inter
.cancel
);
878 void action_movetoedge(union ActionData
*data
)
881 ObClient
*c
= data
->diraction
.any
.c
;
883 x
= c
->frame
->area
.x
;
884 y
= c
->frame
->area
.y
;
886 switch(data
->diraction
.direction
) {
887 case OB_DIRECTION_NORTH
:
888 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
,
889 data
->diraction
.hang
)
890 - (data
->diraction
.hang
? c
->frame
->area
.height
: 0);
892 case OB_DIRECTION_WEST
:
893 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
,
894 data
->diraction
.hang
)
895 - (data
->diraction
.hang
? c
->frame
->area
.width
: 0);
897 case OB_DIRECTION_SOUTH
:
898 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
,
899 data
->diraction
.hang
)
900 - (data
->diraction
.hang
? 0 : c
->frame
->area
.height
);
902 case OB_DIRECTION_EAST
:
903 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
,
904 data
->diraction
.hang
)
905 - (data
->diraction
.hang
? 0 : c
->frame
->area
.width
);
908 g_assert_not_reached();
910 frame_frame_gravity(c
->frame
, &x
, &y
, c
->area
.width
, c
->area
.height
);
911 client_action_start(data
);
912 client_move(c
, x
, y
);
913 client_action_end(data
, FALSE
);
916 void action_growtoedge(union ActionData
*data
)
918 gint x
, y
, width
, height
, dest
;
919 ObClient
*c
= data
->diraction
.any
.c
;
922 a
= screen_area(c
->desktop
, SCREEN_AREA_ALL_MONITORS
, &c
->frame
->area
);
923 x
= c
->frame
->area
.x
;
924 y
= c
->frame
->area
.y
;
925 /* get the unshaded frame's dimensions..if it is shaded */
926 width
= c
->area
.width
+ c
->frame
->size
.left
+ c
->frame
->size
.right
;
927 height
= c
->area
.height
+ c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
929 switch(data
->diraction
.direction
) {
930 case OB_DIRECTION_NORTH
:
931 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
933 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
, FALSE
);
937 height
= c
->frame
->area
.y
+ height
- dest
;
941 case OB_DIRECTION_WEST
:
942 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
, FALSE
);
946 width
= c
->frame
->area
.x
+ width
- dest
;
950 case OB_DIRECTION_SOUTH
:
951 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
953 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
, FALSE
);
954 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
955 height
= c
->frame
->area
.height
/ 2;
956 y
= a
->y
+ a
->height
- height
;
958 height
= dest
- c
->frame
->area
.y
;
959 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
960 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
962 case OB_DIRECTION_EAST
:
963 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
, FALSE
);
964 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
965 width
= c
->frame
->area
.width
/ 2;
966 x
= a
->x
+ a
->width
- width
;
968 width
= dest
- c
->frame
->area
.x
;
969 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
970 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
973 g_assert_not_reached();
975 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
976 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
977 frame_frame_gravity(c
->frame
, &x
, &y
, width
, height
);
978 client_action_start(data
);
979 client_move_resize(c
, x
, y
, width
, height
);
980 client_action_end(data
, FALSE
);
984 void action_send_to_layer(union ActionData
*data
)
986 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
989 void action_toggle_layer(union ActionData
*data
)
991 ObClient
*c
= data
->layer
.any
.c
;
993 client_action_start(data
);
994 if (data
->layer
.layer
< 0)
995 client_set_layer(c
, c
->below
? 0 : -1);
996 else if (data
->layer
.layer
> 0)
997 client_set_layer(c
, c
->above
? 0 : 1);
998 client_action_end(data
, config_focus_under_mouse
);
1001 void action_toggle_dockautohide(union ActionData
*data
)
1003 config_dock_hide
= !config_dock_hide
;
1007 void action_add_desktop(union ActionData
*data
)
1009 client_action_start(data
);
1010 screen_set_num_desktops(screen_num_desktops
+1);
1012 /* move all the clients over */
1013 if (data
->addremovedesktop
.current
) {
1016 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1017 ObClient
*c
= it
->data
;
1018 if (c
->desktop
!= DESKTOP_ALL
&& c
->desktop
>= screen_desktop
)
1019 client_set_desktop(c
, c
->desktop
+1, FALSE
, TRUE
);
1023 client_action_end(data
, config_focus_under_mouse
);
1026 void action_remove_desktop(union ActionData
*data
)
1028 guint rmdesktop
, movedesktop
;
1029 GList
*it
, *stacking_copy
;
1031 if (screen_num_desktops
< 2) return;
1033 client_action_start(data
);
1035 /* what desktop are we removing and moving to? */
1036 if (data
->addremovedesktop
.current
)
1037 rmdesktop
= screen_desktop
;
1039 rmdesktop
= screen_num_desktops
- 1;
1040 if (rmdesktop
< screen_num_desktops
- 1)
1041 movedesktop
= rmdesktop
+ 1;
1043 movedesktop
= rmdesktop
;
1045 /* make a copy of the list cuz we're changing it */
1046 stacking_copy
= g_list_copy(stacking_list
);
1047 for (it
= g_list_last(stacking_copy
); it
; it
= g_list_previous(it
)) {
1048 if (WINDOW_IS_CLIENT(it
->data
)) {
1049 ObClient
*c
= it
->data
;
1050 guint d
= c
->desktop
;
1051 if (d
!= DESKTOP_ALL
&& d
>= movedesktop
) {
1052 client_set_desktop(c
, c
->desktop
- 1, TRUE
, TRUE
);
1053 ob_debug("moving window %s\n", c
->title
);
1055 /* raise all the windows that are on the current desktop which
1057 if ((screen_desktop
== rmdesktop
- 1 ||
1058 screen_desktop
== rmdesktop
) &&
1059 (d
== DESKTOP_ALL
|| d
== screen_desktop
))
1061 stacking_raise(CLIENT_AS_WINDOW(c
));
1062 ob_debug("raising window %s\n", c
->title
);
1067 /* act like we're changing desktops */
1068 if (screen_desktop
< screen_num_desktops
- 1) {
1069 gint d
= screen_desktop
;
1070 screen_desktop
= screen_last_desktop
;
1071 screen_set_desktop(d
, TRUE
);
1072 ob_debug("fake desktop change\n");
1075 screen_set_num_desktops(screen_num_desktops
-1);
1077 client_action_end(data
, config_focus_under_mouse
);