1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 action.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 See the COPYING file for a copy of the GNU General Public License.
23 #include "focus_cycle.h"
24 #include "moveresize.h"
37 #include "startupnotify.h"
42 static void client_action_start(union ActionData
*data
)
46 static void client_action_end(union ActionData
*data
)
48 if (config_focus_follow
)
49 if (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
) {
50 if (!data
->any
.button
&& data
->any
.c
)
51 event_ignore_all_queued_enters();
53 /* we USED to create a fake enter event here, so that when you
54 used a Press context, and the button was still down,
55 you could still get enter events that weren't
58 only problem with this is that then the resulting focus
59 change events can ALSO be NotifyWhileGrabbed. And that is
60 bad. So, don't create fake enter events anymore. */
68 void (*func
)(union ActionData
*);
69 void (*setup
)(ObAction
**, ObUserAction uact
);
72 static ObAction
*action_new(void (*func
)(union ActionData
*data
))
74 ObAction
*a
= g_new0(ObAction
, 1);
81 void action_ref(ObAction
*a
)
86 void action_unref(ObAction
*a
)
88 if (a
== NULL
) return;
90 if (--a
->ref
> 0) return;
92 /* deal with pointers */
93 if (a
->func
== action_execute
|| a
->func
== action_restart
)
94 g_free(a
->data
.execute
.path
);
95 else if (a
->func
== action_debug
)
96 g_free(a
->data
.debug
.string
);
97 else if (a
->func
== action_showmenu
)
98 g_free(a
->data
.showmenu
.name
);
103 ObAction
* action_copy(const ObAction
*src
)
105 ObAction
*a
= action_new(src
->func
);
109 /* deal with pointers */
110 if (a
->func
== action_execute
|| a
->func
== action_restart
)
111 a
->data
.execute
.path
= g_strdup(a
->data
.execute
.path
);
112 else if (a
->func
== action_debug
)
113 a
->data
.debug
.string
= g_strdup(a
->data
.debug
.string
);
114 else if (a
->func
== action_showmenu
)
115 a
->data
.showmenu
.name
= g_strdup(a
->data
.showmenu
.name
);
120 void setup_action_directional_focus_north(ObAction
**a
, ObUserAction uact
)
122 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
123 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTH
;
124 (*a
)->data
.interdiraction
.dialog
= TRUE
;
125 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
126 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
129 void setup_action_directional_focus_east(ObAction
**a
, ObUserAction uact
)
131 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
132 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_EAST
;
133 (*a
)->data
.interdiraction
.dialog
= TRUE
;
134 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
135 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
138 void setup_action_directional_focus_south(ObAction
**a
, ObUserAction uact
)
140 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
141 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTH
;
142 (*a
)->data
.interdiraction
.dialog
= TRUE
;
143 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
144 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
147 void setup_action_directional_focus_west(ObAction
**a
, ObUserAction uact
)
149 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
150 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_WEST
;
151 (*a
)->data
.interdiraction
.dialog
= TRUE
;
152 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
153 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
156 void setup_action_directional_focus_northeast(ObAction
**a
, ObUserAction uact
)
158 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
159 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHEAST
;
160 (*a
)->data
.interdiraction
.dialog
= TRUE
;
161 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
162 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
165 void setup_action_directional_focus_southeast(ObAction
**a
, ObUserAction uact
)
167 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
168 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHEAST
;
169 (*a
)->data
.interdiraction
.dialog
= TRUE
;
170 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
171 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
174 void setup_action_directional_focus_southwest(ObAction
**a
, ObUserAction uact
)
176 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
177 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHWEST
;
178 (*a
)->data
.interdiraction
.dialog
= TRUE
;
179 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
180 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
183 void setup_action_directional_focus_northwest(ObAction
**a
, ObUserAction uact
)
185 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
186 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHWEST
;
187 (*a
)->data
.interdiraction
.dialog
= TRUE
;
188 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
189 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
192 void setup_action_send_to_desktop(ObAction
**a
, ObUserAction uact
)
194 (*a
)->data
.sendto
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
195 (*a
)->data
.sendto
.follow
= TRUE
;
198 void setup_action_send_to_desktop_prev(ObAction
**a
, ObUserAction uact
)
200 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
201 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
202 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
203 (*a
)->data
.sendtodir
.linear
= TRUE
;
204 (*a
)->data
.sendtodir
.wrap
= TRUE
;
205 (*a
)->data
.sendtodir
.follow
= TRUE
;
208 void setup_action_send_to_desktop_next(ObAction
**a
, ObUserAction uact
)
210 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
211 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
212 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
213 (*a
)->data
.sendtodir
.linear
= TRUE
;
214 (*a
)->data
.sendtodir
.wrap
= TRUE
;
215 (*a
)->data
.sendtodir
.follow
= TRUE
;
218 void setup_action_send_to_desktop_left(ObAction
**a
, ObUserAction uact
)
220 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
221 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
222 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
223 (*a
)->data
.sendtodir
.linear
= FALSE
;
224 (*a
)->data
.sendtodir
.wrap
= TRUE
;
225 (*a
)->data
.sendtodir
.follow
= TRUE
;
228 void setup_action_send_to_desktop_right(ObAction
**a
, ObUserAction uact
)
230 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
231 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
232 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
233 (*a
)->data
.sendtodir
.linear
= FALSE
;
234 (*a
)->data
.sendtodir
.wrap
= TRUE
;
235 (*a
)->data
.sendtodir
.follow
= TRUE
;
238 void setup_action_send_to_desktop_up(ObAction
**a
, ObUserAction uact
)
240 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
241 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
242 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_NORTH
;
243 (*a
)->data
.sendtodir
.linear
= FALSE
;
244 (*a
)->data
.sendtodir
.wrap
= TRUE
;
245 (*a
)->data
.sendtodir
.follow
= TRUE
;
248 void setup_action_send_to_desktop_down(ObAction
**a
, ObUserAction uact
)
250 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
251 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
252 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_SOUTH
;
253 (*a
)->data
.sendtodir
.linear
= FALSE
;
254 (*a
)->data
.sendtodir
.wrap
= TRUE
;
255 (*a
)->data
.sendtodir
.follow
= TRUE
;
258 void setup_action_desktop(ObAction
**a
, ObUserAction uact
)
261 (*a)->data.desktop.inter.any.interactive = FALSE;
265 void setup_action_desktop_prev(ObAction
**a
, ObUserAction uact
)
267 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
268 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
269 (*a
)->data
.desktopdir
.linear
= TRUE
;
270 (*a
)->data
.desktopdir
.wrap
= TRUE
;
273 void setup_action_desktop_next(ObAction
**a
, ObUserAction uact
)
275 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
276 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
277 (*a
)->data
.desktopdir
.linear
= TRUE
;
278 (*a
)->data
.desktopdir
.wrap
= TRUE
;
281 void setup_action_desktop_left(ObAction
**a
, ObUserAction uact
)
283 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
284 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
285 (*a
)->data
.desktopdir
.linear
= FALSE
;
286 (*a
)->data
.desktopdir
.wrap
= TRUE
;
289 void setup_action_desktop_right(ObAction
**a
, ObUserAction uact
)
291 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
292 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
293 (*a
)->data
.desktopdir
.linear
= FALSE
;
294 (*a
)->data
.desktopdir
.wrap
= TRUE
;
297 void setup_action_desktop_up(ObAction
**a
, ObUserAction uact
)
299 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
300 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_NORTH
;
301 (*a
)->data
.desktopdir
.linear
= FALSE
;
302 (*a
)->data
.desktopdir
.wrap
= TRUE
;
305 void setup_action_desktop_down(ObAction
**a
, ObUserAction uact
)
307 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
308 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_SOUTH
;
309 (*a
)->data
.desktopdir
.linear
= FALSE
;
310 (*a
)->data
.desktopdir
.wrap
= TRUE
;
313 void setup_action_cycle_windows_next(ObAction
**a
, ObUserAction uact
)
315 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
316 (*a
)->data
.cycle
.linear
= FALSE
;
317 (*a
)->data
.cycle
.forward
= TRUE
;
318 (*a
)->data
.cycle
.dialog
= TRUE
;
319 (*a
)->data
.cycle
.dock_windows
= FALSE
;
320 (*a
)->data
.cycle
.desktop_windows
= FALSE
;
321 (*a
)->data
.cycle
.all_desktops
= FALSE
;
324 void setup_action_cycle_windows_previous(ObAction
**a
, ObUserAction uact
)
326 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
327 (*a
)->data
.cycle
.linear
= FALSE
;
328 (*a
)->data
.cycle
.forward
= FALSE
;
329 (*a
)->data
.cycle
.dialog
= TRUE
;
330 (*a
)->data
.cycle
.dock_windows
= FALSE
;
331 (*a
)->data
.cycle
.desktop_windows
= FALSE
;
332 (*a
)->data
.cycle
.all_desktops
= FALSE
;
335 void setup_action_movefromedge_north(ObAction
**a
, ObUserAction uact
)
337 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
338 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
339 (*a
)->data
.diraction
.hang
= TRUE
;
342 void setup_action_movefromedge_south(ObAction
**a
, ObUserAction uact
)
344 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
345 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
346 (*a
)->data
.diraction
.hang
= TRUE
;
349 void setup_action_movefromedge_east(ObAction
**a
, ObUserAction uact
)
351 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
352 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
353 (*a
)->data
.diraction
.hang
= TRUE
;
356 void setup_action_movefromedge_west(ObAction
**a
, ObUserAction uact
)
358 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
359 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
360 (*a
)->data
.diraction
.hang
= TRUE
;
363 void setup_action_movetoedge_north(ObAction
**a
, ObUserAction uact
)
365 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
366 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
367 (*a
)->data
.diraction
.hang
= FALSE
;
370 void setup_action_movetoedge_south(ObAction
**a
, ObUserAction uact
)
372 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
373 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
374 (*a
)->data
.diraction
.hang
= FALSE
;
377 void setup_action_movetoedge_east(ObAction
**a
, ObUserAction uact
)
379 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
380 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
381 (*a
)->data
.diraction
.hang
= FALSE
;
384 void setup_action_movetoedge_west(ObAction
**a
, ObUserAction uact
)
386 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
387 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
388 (*a
)->data
.diraction
.hang
= FALSE
;
391 void setup_action_growtoedge_north(ObAction
**a
, ObUserAction uact
)
393 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
394 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
397 void setup_action_growtoedge_south(ObAction
**a
, ObUserAction uact
)
399 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
400 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
403 void setup_action_growtoedge_east(ObAction
**a
, ObUserAction uact
)
405 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
406 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
409 void setup_action_growtoedge_west(ObAction
**a
, ObUserAction uact
)
411 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
412 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
415 void setup_action_top_layer(ObAction
**a
, ObUserAction uact
)
417 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
418 (*a
)->data
.layer
.layer
= 1;
421 void setup_action_normal_layer(ObAction
**a
, ObUserAction uact
)
423 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
424 (*a
)->data
.layer
.layer
= 0;
427 void setup_action_bottom_layer(ObAction
**a
, ObUserAction uact
)
429 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
430 (*a
)->data
.layer
.layer
= -1;
433 void setup_action_move(ObAction
**a
, ObUserAction uact
)
435 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
436 (*a
)->data
.moveresize
.keyboard
=
437 (uact
== OB_USER_ACTION_NONE
||
438 uact
== OB_USER_ACTION_KEYBOARD_KEY
||
439 uact
== OB_USER_ACTION_MENU_SELECTION
);
440 (*a
)->data
.moveresize
.corner
= 0;
443 void setup_action_resize(ObAction
**a
, ObUserAction uact
)
445 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
446 (*a
)->data
.moveresize
.keyboard
=
447 (uact
== OB_USER_ACTION_NONE
||
448 uact
== OB_USER_ACTION_KEYBOARD_KEY
||
449 uact
== OB_USER_ACTION_MENU_SELECTION
);
450 (*a
)->data
.moveresize
.corner
= 0;
453 void setup_action_showmenu(ObAction
**a
, ObUserAction uact
)
455 (*a
)->data
.showmenu
.any
.client_action
= OB_CLIENT_ACTION_OPTIONAL
;
456 /* you cannot call ShowMenu from inside a menu, cuz the menu code makes
457 assumptions that there is only one menu (and submenus) open at
459 if (uact
== OB_USER_ACTION_MENU_SELECTION
) {
465 void setup_action_focus(ObAction
**a
, ObUserAction uact
)
467 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_OPTIONAL
;
470 void setup_client_action(ObAction
**a
, ObUserAction uact
)
472 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
475 ActionString actionstrings
[] =
488 "directionalfocusnorth",
489 action_directional_focus
,
490 setup_action_directional_focus_north
493 "directionalfocuseast",
494 action_directional_focus
,
495 setup_action_directional_focus_east
498 "directionalfocussouth",
499 action_directional_focus
,
500 setup_action_directional_focus_south
503 "directionalfocuswest",
504 action_directional_focus
,
505 setup_action_directional_focus_west
508 "directionalfocusnortheast",
509 action_directional_focus
,
510 setup_action_directional_focus_northeast
513 "directionalfocussoutheast",
514 action_directional_focus
,
515 setup_action_directional_focus_southeast
518 "directionalfocussouthwest",
519 action_directional_focus
,
520 setup_action_directional_focus_southwest
523 "directionalfocusnorthwest",
524 action_directional_focus
,
525 setup_action_directional_focus_northwest
549 action_focus_order_to_bottom
,
604 action_toggle_omnipresent
,
609 action_move_relative_horz
,
614 action_move_relative_vert
,
619 action_move_to_center
,
623 "resizerelativehorz",
624 action_resize_relative_horz
,
628 "resizerelativevert",
629 action_resize_relative_vert
,
634 action_move_relative
,
639 action_resize_relative
,
644 action_maximize_full
,
649 action_unmaximize_full
,
653 "togglemaximizefull",
654 action_toggle_maximize_full
,
659 action_maximize_horz
,
664 action_unmaximize_horz
,
668 "togglemaximizehorz",
669 action_toggle_maximize_horz
,
674 action_maximize_vert
,
679 action_unmaximize_vert
,
683 "togglemaximizevert",
684 action_toggle_maximize_vert
,
689 action_toggle_fullscreen
,
694 action_send_to_desktop
,
695 setup_action_send_to_desktop
699 action_send_to_desktop_dir
,
700 setup_action_send_to_desktop_next
703 "sendtodesktopprevious",
704 action_send_to_desktop_dir
,
705 setup_action_send_to_desktop_prev
708 "sendtodesktopright",
709 action_send_to_desktop_dir
,
710 setup_action_send_to_desktop_right
714 action_send_to_desktop_dir
,
715 setup_action_send_to_desktop_left
719 action_send_to_desktop_dir
,
720 setup_action_send_to_desktop_up
724 action_send_to_desktop_dir
,
725 setup_action_send_to_desktop_down
735 setup_action_desktop_next
740 setup_action_desktop_prev
745 setup_action_desktop_right
750 setup_action_desktop_left
755 setup_action_desktop_up
760 setup_action_desktop_down
764 action_toggle_decorations
,
778 "toggledockautohide",
779 action_toggle_dockautohide
,
784 action_toggle_show_desktop
,
794 action_unshow_desktop
,
820 setup_action_showmenu
824 action_send_to_layer
,
825 setup_action_top_layer
830 setup_action_top_layer
834 action_send_to_layer
,
835 setup_action_normal_layer
839 action_send_to_layer
,
840 setup_action_bottom_layer
843 "togglealwaysonbottom",
845 setup_action_bottom_layer
849 action_cycle_windows
,
850 setup_action_cycle_windows_next
854 action_cycle_windows
,
855 setup_action_cycle_windows_previous
860 setup_action_movefromedge_north
865 setup_action_movefromedge_south
870 setup_action_movefromedge_west
875 setup_action_movefromedge_east
880 setup_action_movetoedge_north
885 setup_action_movetoedge_south
890 setup_action_movetoedge_west
895 setup_action_movetoedge_east
900 setup_action_growtoedge_north
905 setup_action_growtoedge_south
910 setup_action_growtoedge_west
915 setup_action_growtoedge_east
929 /* only key bindings can be interactive. thus saith the xor.
930 because of how the mouse is grabbed, mouse events dont even get
931 read during interactive events, so no dice! >:) */
932 #define INTERACTIVE_LIMIT(a, uact) \
933 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
934 a->data.any.interactive = FALSE;
936 ObAction
*action_from_string(const gchar
*name
, ObUserAction uact
)
939 gboolean exist
= FALSE
;
942 for (i
= 0; actionstrings
[i
].name
; i
++)
943 if (!g_ascii_strcasecmp(name
, actionstrings
[i
].name
)) {
945 a
= action_new(actionstrings
[i
].func
);
946 if (actionstrings
[i
].setup
)
947 actionstrings
[i
].setup(&a
, uact
);
949 INTERACTIVE_LIMIT(a
, uact
);
953 g_message(_("Invalid action '%s' requested. No such action exists."),
956 g_message(_("Invalid use of action '%s'. Action will be ignored."),
961 ObAction
*action_parse(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
965 ObAction
*act
= NULL
;
968 if (parse_attr_string("name", node
, &actname
)) {
969 if ((act
= action_from_string(actname
, uact
))) {
970 if (act
->func
== action_execute
|| act
->func
== action_restart
) {
971 if ((n
= parse_find_node("execute", node
->xmlChildrenNode
))) {
972 gchar
*s
= parse_string(doc
, n
);
973 act
->data
.execute
.path
= parse_expand_tilde(s
);
976 if ((n
= parse_find_node("startupnotify", node
->xmlChildrenNode
))) {
978 if ((m
= parse_find_node("enabled", n
->xmlChildrenNode
)))
979 act
->data
.execute
.startupnotify
= parse_bool(doc
, m
);
980 if ((m
= parse_find_node("name", n
->xmlChildrenNode
)))
981 act
->data
.execute
.name
= parse_string(doc
, m
);
982 if ((m
= parse_find_node("icon", n
->xmlChildrenNode
)))
983 act
->data
.execute
.icon_name
= parse_string(doc
, m
);
985 } else if (act
->func
== action_debug
) {
986 if ((n
= parse_find_node("string", node
->xmlChildrenNode
)))
987 act
->data
.debug
.string
= parse_string(doc
, n
);
988 } else if (act
->func
== action_showmenu
) {
989 if ((n
= parse_find_node("menu", node
->xmlChildrenNode
)))
990 act
->data
.showmenu
.name
= parse_string(doc
, n
);
991 } else if (act
->func
== action_move_relative_horz
||
992 act
->func
== action_move_relative_vert
||
993 act
->func
== action_resize_relative_horz
||
994 act
->func
== action_resize_relative_vert
) {
995 if ((n
= parse_find_node("delta", node
->xmlChildrenNode
)))
996 act
->data
.relative
.deltax
= parse_int(doc
, n
);
997 } else if (act
->func
== action_move_relative
) {
998 if ((n
= parse_find_node("x", node
->xmlChildrenNode
)))
999 act
->data
.relative
.deltax
= parse_int(doc
, n
);
1000 if ((n
= parse_find_node("y", node
->xmlChildrenNode
)))
1001 act
->data
.relative
.deltay
= parse_int(doc
, n
);
1002 } else if (act
->func
== action_resize_relative
) {
1003 if ((n
= parse_find_node("left", node
->xmlChildrenNode
)))
1004 act
->data
.relative
.deltaxl
= parse_int(doc
, n
);
1005 if ((n
= parse_find_node("up", node
->xmlChildrenNode
)))
1006 act
->data
.relative
.deltayu
= parse_int(doc
, n
);
1007 if ((n
= parse_find_node("right", node
->xmlChildrenNode
)))
1008 act
->data
.relative
.deltax
= parse_int(doc
, n
);
1009 if ((n
= parse_find_node("down", node
->xmlChildrenNode
)))
1010 act
->data
.relative
.deltay
= parse_int(doc
, n
);
1011 } else if (act
->func
== action_desktop
) {
1012 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1013 act
->data
.desktop
.desk
= parse_int(doc
, n
);
1014 if (act
->data
.desktop
.desk
> 0) act
->data
.desktop
.desk
--;
1016 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
1017 act->data.desktop.inter.any.interactive =
1020 } else if (act
->func
== action_send_to_desktop
) {
1021 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1022 act
->data
.sendto
.desk
= parse_int(doc
, n
);
1023 if (act
->data
.sendto
.desk
> 0) act
->data
.sendto
.desk
--;
1024 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
1025 act
->data
.sendto
.follow
= parse_bool(doc
, n
);
1026 } else if (act
->func
== action_desktop_dir
) {
1027 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
1028 act
->data
.desktopdir
.wrap
= parse_bool(doc
, n
);
1029 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1030 act
->data
.desktopdir
.inter
.any
.interactive
=
1032 } else if (act
->func
== action_send_to_desktop_dir
) {
1033 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
1034 act
->data
.sendtodir
.wrap
= parse_bool(doc
, n
);
1035 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
1036 act
->data
.sendtodir
.follow
= parse_bool(doc
, n
);
1037 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1038 act
->data
.sendtodir
.inter
.any
.interactive
=
1040 } else if (act
->func
== action_activate
) {
1041 if ((n
= parse_find_node("here", node
->xmlChildrenNode
)))
1042 act
->data
.activate
.here
= parse_bool(doc
, n
);
1043 } else if (act
->func
== action_cycle_windows
) {
1044 if ((n
= parse_find_node("linear", node
->xmlChildrenNode
)))
1045 act
->data
.cycle
.linear
= parse_bool(doc
, n
);
1046 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1047 act
->data
.cycle
.dialog
= parse_bool(doc
, n
);
1048 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
1049 act
->data
.cycle
.dock_windows
= parse_bool(doc
, n
);
1050 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1051 act
->data
.cycle
.desktop_windows
= parse_bool(doc
, n
);
1052 if ((n
= parse_find_node("allDesktops",
1053 node
->xmlChildrenNode
)))
1054 act
->data
.cycle
.all_desktops
= parse_bool(doc
, n
);
1055 } else if (act
->func
== action_directional_focus
) {
1056 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1057 act
->data
.interdiraction
.dialog
= parse_bool(doc
, n
);
1058 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
1059 act
->data
.interdiraction
.dock_windows
= parse_bool(doc
, n
);
1060 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1061 act
->data
.interdiraction
.desktop_windows
=
1063 } else if (act
->func
== action_resize
) {
1064 if ((n
= parse_find_node("edge", node
->xmlChildrenNode
))) {
1065 gchar
*s
= parse_string(doc
, n
);
1066 if (!g_ascii_strcasecmp(s
, "top"))
1067 act
->data
.moveresize
.corner
=
1068 prop_atoms
.net_wm_moveresize_size_top
;
1069 else if (!g_ascii_strcasecmp(s
, "bottom"))
1070 act
->data
.moveresize
.corner
=
1071 prop_atoms
.net_wm_moveresize_size_bottom
;
1072 else if (!g_ascii_strcasecmp(s
, "left"))
1073 act
->data
.moveresize
.corner
=
1074 prop_atoms
.net_wm_moveresize_size_left
;
1075 else if (!g_ascii_strcasecmp(s
, "right"))
1076 act
->data
.moveresize
.corner
=
1077 prop_atoms
.net_wm_moveresize_size_right
;
1078 else if (!g_ascii_strcasecmp(s
, "topleft"))
1079 act
->data
.moveresize
.corner
=
1080 prop_atoms
.net_wm_moveresize_size_topleft
;
1081 else if (!g_ascii_strcasecmp(s
, "topright"))
1082 act
->data
.moveresize
.corner
=
1083 prop_atoms
.net_wm_moveresize_size_topright
;
1084 else if (!g_ascii_strcasecmp(s
, "bottomleft"))
1085 act
->data
.moveresize
.corner
=
1086 prop_atoms
.net_wm_moveresize_size_bottomleft
;
1087 else if (!g_ascii_strcasecmp(s
, "bottomright"))
1088 act
->data
.moveresize
.corner
=
1089 prop_atoms
.net_wm_moveresize_size_bottomright
;
1092 } else if (act
->func
== action_raise
||
1093 act
->func
== action_lower
||
1094 act
->func
== action_raiselower
||
1095 act
->func
== action_shadelower
||
1096 act
->func
== action_unshaderaise
) {
1098 INTERACTIVE_LIMIT(act
, uact
);
1105 void action_run_list(GSList
*acts
, ObClient
*c
, ObFrameContext context
,
1106 guint state
, guint button
, gint x
, gint y
, Time time
,
1107 gboolean cancel
, gboolean done
)
1116 screen_pointer_pos(&x
, &y
);
1118 for (it
= acts
; it
; it
= g_slist_next(it
)) {
1121 if (!(a
->data
.any
.client_action
== OB_CLIENT_ACTION_ALWAYS
&& !c
)) {
1122 a
->data
.any
.c
= a
->data
.any
.client_action
? c
: NULL
;
1123 a
->data
.any
.context
= context
;
1127 a
->data
.any
.button
= button
;
1129 a
->data
.any
.time
= time
;
1131 if (a
->data
.any
.interactive
) {
1132 a
->data
.inter
.cancel
= cancel
;
1133 a
->data
.inter
.final
= done
;
1134 if (!(cancel
|| done
))
1135 if (!keyboard_interactive_grab(state
, a
->data
.any
.c
, a
))
1139 /* XXX UGLY HACK race with motion event starting a move and the
1140 button release gettnig processed first. answer: don't queue
1141 moveresize starts. UGLY HACK XXX
1143 XXX ALSO don't queue showmenu events, because on button press
1144 events we need to know if a mouse grab is going to take place,
1145 and set the button to 0, so that later motion events don't think
1146 that a drag is going on. since showmenu grabs the pointer..
1148 if (a
->data
.any
.interactive
|| a
->func
== action_move
||
1149 a
->func
== action_resize
|| a
->func
== action_showmenu
)
1151 /* interactive actions are not queued */
1154 (context
== OB_FRAME_CONTEXT_CLIENT
||
1155 (c
->type
== OB_CLIENT_TYPE_DESKTOP
&&
1156 context
== OB_FRAME_CONTEXT_DESKTOP
)) &&
1157 (a
->func
== action_focus
||
1158 a
->func
== action_activate
||
1159 a
->func
== action_showmenu
))
1161 /* XXX MORE UGLY HACK
1162 actions from clicks on client windows are NOT queued.
1163 this solves the mysterious click-and-drag-doesnt-work
1164 problem. it was because the window gets focused and stuff
1165 after the button event has already been passed through. i
1166 dont really know why it should care but it does and it makes
1169 however this very bogus ! !
1170 we want to send the button press to the window BEFORE
1171 we do the action because the action might move the windows
1172 (eg change desktops) and then the button press ends up on
1173 the completely wrong window !
1174 so, this is just for that bug, and it will only NOT queue it
1175 if it is a focusing action that can be used with the mouse
1178 also with the menus, there is a race going on. if the
1179 desktop wants to pop up a menu, and we do to, we send them
1180 the button before we pop up the menu, so they pop up their
1181 menu first. but not always. if we pop up our menu before
1182 sending them the button press, then the result is
1187 ob_main_loop_queue_action(ob_main_loop
, a
);
1192 void action_run_string(const gchar
*name
, struct _ObClient
*c
, Time time
)
1197 a
= action_from_string(name
, OB_USER_ACTION_NONE
);
1200 l
= g_slist_append(NULL
, a
);
1202 action_run(l
, c
, 0, time
);
1205 void action_debug(union ActionData
*data
)
1207 if (data
->debug
.string
)
1208 g_print("%s\n", data
->debug
.string
);
1211 void action_execute(union ActionData
*data
)
1214 gchar
*cmd
, **argv
= 0;
1215 if (data
->execute
.path
) {
1216 cmd
= g_filename_from_utf8(data
->execute
.path
, -1, NULL
, NULL
, NULL
);
1218 /* If there is an interactive action going on, then cancel it
1219 to release the keyboard, so that the run application
1220 can grab the keyboard if it wants to. */
1221 if (keyboard_interactively_grabbed())
1222 keyboard_interactive_cancel();
1224 if (!g_shell_parse_argv (cmd
, NULL
, &argv
, &e
)) {
1225 g_message(_("Failed to execute '%s': %s"),
1228 } else if (data
->execute
.startupnotify
) {
1231 program
= g_path_get_basename(argv
[0]);
1232 /* sets up the environment */
1233 sn_setup_spawn_environment(program
,
1235 data
->execute
.icon_name
,
1236 /* launch it on the current
1239 data
->execute
.any
.time
);
1240 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
|
1241 G_SPAWN_DO_NOT_REAP_CHILD
,
1242 NULL
, NULL
, NULL
, &e
)) {
1243 g_message(_("Failed to execute '%s': %s"),
1248 unsetenv("DESKTOP_STARTUP_ID");
1252 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
|
1253 G_SPAWN_DO_NOT_REAP_CHILD
,
1254 NULL
, NULL
, NULL
, &e
))
1256 g_message(_("Failed to execute '%s': %s"),
1264 g_message(_("Failed to convert the path '%s' from utf8"),
1265 data
->execute
.path
);
1270 void action_activate(union ActionData
*data
)
1272 if (data
->client
.any
.c
) {
1273 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1274 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1275 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1277 /* if using focus_delay, stop the timer now so that focus doesn't
1279 event_halt_focus_delay();
1281 client_activate(data
->activate
.any
.c
, data
->activate
.here
, TRUE
);
1284 /* focus action on something other than a client, make keybindings
1285 work for this openbox instance, but don't focus any specific client
1291 void action_focus(union ActionData
*data
)
1293 if (data
->client
.any
.c
) {
1294 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1295 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1296 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1298 /* if using focus_delay, stop the timer now so that focus doesn't
1300 event_halt_focus_delay();
1302 client_focus(data
->client
.any
.c
);
1305 /* focus action on something other than a client, make keybindings
1306 work for this openbox instance, but don't focus any specific client
1312 void action_unfocus (union ActionData
*data
)
1314 if (data
->client
.any
.c
== focus_client
)
1315 focus_fallback(FALSE
);
1318 void action_iconify(union ActionData
*data
)
1320 client_action_start(data
);
1321 client_iconify(data
->client
.any
.c
, TRUE
, TRUE
, FALSE
);
1322 client_action_end(data
);
1325 void action_focus_order_to_bottom(union ActionData
*data
)
1327 focus_order_to_bottom(data
->client
.any
.c
);
1330 void action_raiselower(union ActionData
*data
)
1332 ObClient
*c
= data
->client
.any
.c
;
1334 gboolean raise
= FALSE
;
1336 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
1337 if (WINDOW_IS_CLIENT(it
->data
)) {
1338 ObClient
*cit
= it
->data
;
1340 if (cit
== c
) break;
1341 if (client_normal(cit
) == client_normal(c
) &&
1342 cit
->layer
== c
->layer
&&
1343 cit
->frame
->visible
&&
1344 !client_search_transient(c
, cit
))
1346 if (RECT_INTERSECTS_RECT(cit
->frame
->area
, c
->frame
->area
)) {
1360 void action_raise(union ActionData
*data
)
1362 client_action_start(data
);
1363 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1364 client_action_end(data
);
1367 void action_unshaderaise(union ActionData
*data
)
1369 if (data
->client
.any
.c
->shaded
)
1370 action_unshade(data
);
1375 void action_shadelower(union ActionData
*data
)
1377 if (data
->client
.any
.c
->shaded
)
1383 void action_lower(union ActionData
*data
)
1385 client_action_start(data
);
1386 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1387 client_action_end(data
);
1390 void action_close(union ActionData
*data
)
1392 client_close(data
->client
.any
.c
);
1395 void action_kill(union ActionData
*data
)
1397 client_kill(data
->client
.any
.c
);
1400 void action_shade(union ActionData
*data
)
1402 client_action_start(data
);
1403 client_shade(data
->client
.any
.c
, TRUE
);
1404 client_action_end(data
);
1407 void action_unshade(union ActionData
*data
)
1409 client_action_start(data
);
1410 client_shade(data
->client
.any
.c
, FALSE
);
1411 client_action_end(data
);
1414 void action_toggle_shade(union ActionData
*data
)
1416 client_action_start(data
);
1417 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1418 client_action_end(data
);
1421 void action_toggle_omnipresent(union ActionData
*data
)
1423 client_set_desktop(data
->client
.any
.c
,
1424 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1425 screen_desktop
: DESKTOP_ALL
, FALSE
);
1428 void action_move_relative_horz(union ActionData
*data
)
1430 ObClient
*c
= data
->relative
.any
.c
;
1431 client_action_start(data
);
1432 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
);
1433 client_action_end(data
);
1436 void action_move_relative_vert(union ActionData
*data
)
1438 ObClient
*c
= data
->relative
.any
.c
;
1439 client_action_start(data
);
1440 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.deltax
);
1441 client_action_end(data
);
1444 void action_move_to_center(union ActionData
*data
)
1446 ObClient
*c
= data
->client
.any
.c
;
1448 area
= screen_area_monitor(c
->desktop
, 0);
1449 client_action_start(data
);
1450 client_move(c
, area
->width
/ 2 - c
->area
.width
/ 2,
1451 area
->height
/ 2 - c
->area
.height
/ 2);
1452 client_action_end(data
);
1455 void action_resize_relative_horz(union ActionData
*data
)
1457 ObClient
*c
= data
->relative
.any
.c
;
1458 client_action_start(data
);
1460 c
->area
.width
+ data
->relative
.deltax
* c
->size_inc
.width
,
1462 client_action_end(data
);
1465 void action_resize_relative_vert(union ActionData
*data
)
1467 ObClient
*c
= data
->relative
.any
.c
;
1469 client_action_start(data
);
1470 client_resize(c
, c
->area
.width
, c
->area
.height
+
1471 data
->relative
.deltax
* c
->size_inc
.height
);
1472 client_action_end(data
);
1476 void action_move_relative(union ActionData
*data
)
1478 ObClient
*c
= data
->relative
.any
.c
;
1479 client_action_start(data
);
1480 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
+
1481 data
->relative
.deltay
);
1482 client_action_end(data
);
1485 void action_resize_relative(union ActionData
*data
)
1487 ObClient
*c
= data
->relative
.any
.c
;
1488 gint x
, y
, ow
, w
, oh
, h
, lw
, lh
;
1490 client_action_start(data
);
1495 w
= ow
+ data
->relative
.deltax
* c
->size_inc
.width
1496 + data
->relative
.deltaxl
* c
->size_inc
.width
;
1497 oh
= c
->area
.height
;
1498 h
= oh
+ data
->relative
.deltay
* c
->size_inc
.height
1499 + data
->relative
.deltayu
* c
->size_inc
.height
;
1501 client_try_configure(c
, &x
, &y
, &w
, &h
, &lw
, &lh
, TRUE
);
1502 client_move_resize(c
, x
+ (ow
- w
), y
+ (oh
- h
), w
, h
);
1503 client_action_end(data
);
1506 void action_maximize_full(union ActionData
*data
)
1508 client_action_start(data
);
1509 client_maximize(data
->client
.any
.c
, TRUE
, 0);
1510 client_action_end(data
);
1513 void action_unmaximize_full(union ActionData
*data
)
1515 client_action_start(data
);
1516 client_maximize(data
->client
.any
.c
, FALSE
, 0);
1517 client_action_end(data
);
1520 void action_toggle_maximize_full(union ActionData
*data
)
1522 client_action_start(data
);
1523 client_maximize(data
->client
.any
.c
,
1524 !(data
->client
.any
.c
->max_horz
||
1525 data
->client
.any
.c
->max_vert
),
1527 client_action_end(data
);
1530 void action_maximize_horz(union ActionData
*data
)
1532 client_action_start(data
);
1533 client_maximize(data
->client
.any
.c
, TRUE
, 1);
1534 client_action_end(data
);
1537 void action_unmaximize_horz(union ActionData
*data
)
1539 client_action_start(data
);
1540 client_maximize(data
->client
.any
.c
, FALSE
, 1);
1541 client_action_end(data
);
1544 void action_toggle_maximize_horz(union ActionData
*data
)
1546 client_action_start(data
);
1547 client_maximize(data
->client
.any
.c
,
1548 !data
->client
.any
.c
->max_horz
, 1);
1549 client_action_end(data
);
1552 void action_maximize_vert(union ActionData
*data
)
1554 client_action_start(data
);
1555 client_maximize(data
->client
.any
.c
, TRUE
, 2);
1556 client_action_end(data
);
1559 void action_unmaximize_vert(union ActionData
*data
)
1561 client_action_start(data
);
1562 client_maximize(data
->client
.any
.c
, FALSE
, 2);
1563 client_action_end(data
);
1566 void action_toggle_maximize_vert(union ActionData
*data
)
1568 client_action_start(data
);
1569 client_maximize(data
->client
.any
.c
,
1570 !data
->client
.any
.c
->max_vert
, 2);
1571 client_action_end(data
);
1574 void action_toggle_fullscreen(union ActionData
*data
)
1576 client_action_start(data
);
1577 client_fullscreen(data
->client
.any
.c
, !(data
->client
.any
.c
->fullscreen
));
1578 client_action_end(data
);
1581 void action_send_to_desktop(union ActionData
*data
)
1583 ObClient
*c
= data
->sendto
.any
.c
;
1585 if (!client_normal(c
)) return;
1587 if (data
->sendto
.desk
< screen_num_desktops
||
1588 data
->sendto
.desk
== DESKTOP_ALL
) {
1589 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
);
1590 if (data
->sendto
.follow
)
1591 screen_set_desktop(data
->sendto
.desk
, TRUE
);
1595 void action_desktop(union ActionData
*data
)
1597 /* XXX add the interactive/dialog option back again once the dialog
1598 has been made to not use grabs */
1599 if (data
->desktop
.desk
< screen_num_desktops
||
1600 data
->desktop
.desk
== DESKTOP_ALL
)
1602 screen_set_desktop(data
->desktop
.desk
, TRUE
);
1603 if (data
->inter
.any
.interactive
)
1604 screen_desktop_popup(data
->desktop
.desk
, TRUE
);
1608 void action_desktop_dir(union ActionData
*data
)
1612 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1613 data
->desktopdir
.wrap
,
1614 data
->desktopdir
.linear
,
1615 data
->desktopdir
.inter
.any
.interactive
,
1616 data
->desktopdir
.inter
.final
,
1617 data
->desktopdir
.inter
.cancel
);
1618 /* only move the desktop when the action is complete. if we switch
1619 desktops during the interactive action, focus will move but with
1620 NotifyWhileGrabbed and applications don't like that. */
1621 if (!data
->sendtodir
.inter
.any
.interactive
||
1622 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1624 if (d
!= screen_desktop
) screen_set_desktop(d
, TRUE
);
1628 void action_send_to_desktop_dir(union ActionData
*data
)
1630 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1633 if (!client_normal(c
)) return;
1635 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1636 data
->sendtodir
.linear
,
1637 data
->sendtodir
.inter
.any
.interactive
,
1638 data
->sendtodir
.inter
.final
,
1639 data
->sendtodir
.inter
.cancel
);
1640 /* only move the desktop when the action is complete. if we switch
1641 desktops during the interactive action, focus will move but with
1642 NotifyWhileGrabbed and applications don't like that. */
1643 if (!data
->sendtodir
.inter
.any
.interactive
||
1644 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1646 client_set_desktop(c
, d
, data
->sendtodir
.follow
);
1647 if (data
->sendtodir
.follow
&& d
!= screen_desktop
)
1648 screen_set_desktop(d
, TRUE
);
1652 void action_desktop_last(union ActionData
*data
)
1654 screen_set_desktop(screen_last_desktop
, TRUE
);
1657 void action_toggle_decorations(union ActionData
*data
)
1659 ObClient
*c
= data
->client
.any
.c
;
1661 client_action_start(data
);
1662 client_set_undecorated(c
, !c
->undecorated
);
1663 client_action_end(data
);
1666 static guint32
pick_corner(gint x
, gint y
, gint cx
, gint cy
, gint cw
, gint ch
,
1669 /* let's make x and y client relative instead of screen relative */
1671 y
= ch
- (y
- cy
); /* y is inverted, 0 is at the bottom of the window */
1674 #define A -4*X + 7*ch/3
1675 #define B 4*X -15*ch/9
1676 #define C -X/4 + 2*ch/3
1677 #define D X/4 + 5*ch/12
1678 #define E X/4 + ch/3
1679 #define F -X/4 + 7*ch/12
1680 #define G 4*X - 4*ch/3
1681 #define H -4*X + 8*ch/3
1682 #define a (y > 5*ch/9)
1683 #define b (x < 4*cw/9)
1684 #define c (x > 5*cw/9)
1685 #define d (y < 4*ch/9)
1688 Each of these defines (except X which is just there for fun), represents
1689 the equation of a line. The lines they represent are shown in the diagram
1690 below. Checking y against these lines, we are able to choose a region
1691 of the window as shown.
1693 +---------------------A-------|-------|-------B---------------------+
1700 | northwest | A north B | northeast |
1703 C---------------------+----A--+-------+--B----+---------------------D
1704 |CCCCCCC | A B | DDDDDDD|
1705 | CCCCCCCC | A | | B | DDDDDDDD |
1706 | CCCCCCC A B DDDDDDD |
1707 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
1709 | west | b move c | east | ad
1711 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
1712 | EEEEEEE G H FFFFFFF |
1713 | EEEEEEEE | G | | H | FFFFFFFF |
1714 |EEEEEEE | G H | FFFFFFF|
1715 E---------------------+----G--+-------+--H----+---------------------F
1718 | southwest | G south H | southeast |
1725 +---------------------G-------|-------|-------H---------------------+
1729 /* for shaded windows, you can only resize west/east and move */
1731 return prop_atoms
.net_wm_moveresize_size_left
;
1733 return prop_atoms
.net_wm_moveresize_size_right
;
1734 return prop_atoms
.net_wm_moveresize_move
;
1737 if (y
< A
&& y
>= C
)
1738 return prop_atoms
.net_wm_moveresize_size_topleft
;
1739 else if (y
>= A
&& y
>= B
&& a
)
1740 return prop_atoms
.net_wm_moveresize_size_top
;
1741 else if (y
< B
&& y
>= D
)
1742 return prop_atoms
.net_wm_moveresize_size_topright
;
1743 else if (y
< C
&& y
>= E
&& b
)
1744 return prop_atoms
.net_wm_moveresize_size_left
;
1745 else if (y
< D
&& y
>= F
&& c
)
1746 return prop_atoms
.net_wm_moveresize_size_right
;
1747 else if (y
< E
&& y
>= G
)
1748 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1749 else if (y
< G
&& y
< H
&& d
)
1750 return prop_atoms
.net_wm_moveresize_size_bottom
;
1751 else if (y
>= H
&& y
< F
)
1752 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1754 return prop_atoms
.net_wm_moveresize_move
;
1771 void action_move(union ActionData
*data
)
1773 ObClient
*c
= data
->moveresize
.any
.c
;
1776 if (data
->moveresize
.keyboard
)
1777 corner
= prop_atoms
.net_wm_moveresize_move_keyboard
;
1779 corner
= prop_atoms
.net_wm_moveresize_move
;
1781 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1784 void action_resize(union ActionData
*data
)
1786 ObClient
*c
= data
->moveresize
.any
.c
;
1789 if (data
->moveresize
.keyboard
)
1790 corner
= prop_atoms
.net_wm_moveresize_size_keyboard
;
1791 else if (data
->moveresize
.corner
)
1792 corner
= data
->moveresize
.corner
; /* it was specified in the binding */
1794 corner
= pick_corner(data
->any
.x
, data
->any
.y
,
1795 c
->frame
->area
.x
, c
->frame
->area
.y
,
1796 /* use the client size because the frame
1797 can be differently sized (shaded
1798 windows) and we want this based on the
1800 c
->area
.width
+ c
->frame
->size
.left
+
1801 c
->frame
->size
.right
,
1802 c
->area
.height
+ c
->frame
->size
.top
+
1803 c
->frame
->size
.bottom
, c
->shaded
);
1805 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1808 void action_reconfigure(union ActionData
*data
)
1813 void action_restart(union ActionData
*data
)
1815 ob_restart_other(data
->execute
.path
);
1818 void action_exit(union ActionData
*data
)
1823 void action_showmenu(union ActionData
*data
)
1825 if (data
->showmenu
.name
) {
1826 menu_show(data
->showmenu
.name
, data
->any
.x
, data
->any
.y
,
1827 data
->any
.button
, data
->showmenu
.any
.c
);
1831 void action_cycle_windows(union ActionData
*data
)
1833 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1835 event_halt_focus_delay();
1837 focus_cycle(data
->cycle
.forward
,
1838 data
->cycle
.all_desktops
,
1839 data
->cycle
.dock_windows
,
1840 data
->cycle
.desktop_windows
,
1841 data
->cycle
.linear
, data
->any
.interactive
,
1843 data
->cycle
.inter
.final
, data
->cycle
.inter
.cancel
);
1846 void action_directional_focus(union ActionData
*data
)
1848 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1850 event_halt_focus_delay();
1852 focus_directional_cycle(data
->interdiraction
.direction
,
1853 data
->interdiraction
.dock_windows
,
1854 data
->interdiraction
.desktop_windows
,
1855 data
->any
.interactive
,
1856 data
->interdiraction
.dialog
,
1857 data
->interdiraction
.inter
.final
,
1858 data
->interdiraction
.inter
.cancel
);
1861 void action_movetoedge(union ActionData
*data
)
1864 ObClient
*c
= data
->diraction
.any
.c
;
1866 x
= c
->frame
->area
.x
;
1867 y
= c
->frame
->area
.y
;
1869 switch(data
->diraction
.direction
) {
1870 case OB_DIRECTION_NORTH
:
1871 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
,
1872 data
->diraction
.hang
)
1873 - (data
->diraction
.hang
? c
->frame
->area
.height
: 0);
1875 case OB_DIRECTION_WEST
:
1876 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
,
1877 data
->diraction
.hang
)
1878 - (data
->diraction
.hang
? c
->frame
->area
.width
: 0);
1880 case OB_DIRECTION_SOUTH
:
1881 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
,
1882 data
->diraction
.hang
)
1883 - (data
->diraction
.hang
? 0 : c
->frame
->area
.height
);
1885 case OB_DIRECTION_EAST
:
1886 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
,
1887 data
->diraction
.hang
)
1888 - (data
->diraction
.hang
? 0 : c
->frame
->area
.width
);
1891 g_assert_not_reached();
1893 frame_frame_gravity(c
->frame
, &x
, &y
, c
->area
.width
, c
->area
.height
);
1894 client_action_start(data
);
1895 client_move(c
, x
, y
);
1896 client_action_end(data
);
1899 void action_growtoedge(union ActionData
*data
)
1901 gint x
, y
, width
, height
, dest
;
1902 ObClient
*c
= data
->diraction
.any
.c
;
1905 a
= screen_area(c
->desktop
);
1906 x
= c
->frame
->area
.x
;
1907 y
= c
->frame
->area
.y
;
1908 /* get the unshaded frame's dimensions..if it is shaded */
1909 width
= c
->area
.width
+ c
->frame
->size
.left
+ c
->frame
->size
.right
;
1910 height
= c
->area
.height
+ c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1912 switch(data
->diraction
.direction
) {
1913 case OB_DIRECTION_NORTH
:
1914 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1916 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
, FALSE
);
1918 height
= height
/ 2;
1920 height
= c
->frame
->area
.y
+ height
- dest
;
1924 case OB_DIRECTION_WEST
:
1925 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
, FALSE
);
1929 width
= c
->frame
->area
.x
+ width
- dest
;
1933 case OB_DIRECTION_SOUTH
:
1934 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1936 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
, FALSE
);
1937 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1938 height
= c
->frame
->area
.height
/ 2;
1939 y
= a
->y
+ a
->height
- height
;
1941 height
= dest
- c
->frame
->area
.y
;
1942 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1943 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1945 case OB_DIRECTION_EAST
:
1946 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
, FALSE
);
1947 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1948 width
= c
->frame
->area
.width
/ 2;
1949 x
= a
->x
+ a
->width
- width
;
1951 width
= dest
- c
->frame
->area
.x
;
1952 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1953 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1956 g_assert_not_reached();
1958 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1959 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1960 frame_frame_gravity(c
->frame
, &x
, &y
, width
, height
);
1961 client_action_start(data
);
1962 client_move_resize(c
, x
, y
, width
, height
);
1963 client_action_end(data
);
1966 void action_send_to_layer(union ActionData
*data
)
1968 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1971 void action_toggle_layer(union ActionData
*data
)
1973 ObClient
*c
= data
->layer
.any
.c
;
1975 client_action_start(data
);
1976 if (data
->layer
.layer
< 0)
1977 client_set_layer(c
, c
->below
? 0 : -1);
1978 else if (data
->layer
.layer
> 0)
1979 client_set_layer(c
, c
->above
? 0 : 1);
1980 client_action_end(data
);
1983 void action_toggle_dockautohide(union ActionData
*data
)
1985 config_dock_hide
= !config_dock_hide
;
1989 void action_toggle_show_desktop(union ActionData
*data
)
1991 screen_show_desktop(!screen_showing_desktop
, NULL
);
1994 void action_show_desktop(union ActionData
*data
)
1996 screen_show_desktop(TRUE
, NULL
);
1999 void action_unshow_desktop(union ActionData
*data
)
2001 screen_show_desktop(FALSE
, NULL
);
2004 void action_break_chroot(union ActionData
*data
)
2006 /* break out of one chroot */
2007 keyboard_reset_chains(1);