1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 action.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 See the COPYING file for a copy of the GNU General Public License.
23 #include "focus_cycle.h"
24 #include "moveresize.h"
37 #include "startupnotify.h"
42 static gulong ignore_start
= 0;
44 static void client_action_start(union ActionData
*data
)
46 ignore_start
= event_start_ignore_all_enters();
49 static void client_action_end(union ActionData
*data
, gboolean allow_enters
)
51 if (config_focus_follow
)
52 if (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
) {
53 if (!data
->any
.button
&& data
->any
.c
&& !allow_enters
) {
54 event_end_ignore_all_enters(ignore_start
);
58 /* usually this is sorta redundant, but with a press action
59 that moves windows our from under the cursor, the enter
60 event will come as a GrabNotify which is ignored, so this
61 makes a fake enter event
63 if ((c
= client_under_pointer()) && c
!= data
->any
.c
) {
64 ob_debug_type(OB_DEBUG_FOCUS
,
65 "Generating fake enter because we did a "
66 "mouse-event action");
67 event_enter_client(c
);
76 void (*func
)(union ActionData
*);
77 void (*setup
)(ObAction
**, ObUserAction uact
);
80 static ObAction
*action_new(void (*func
)(union ActionData
*data
))
82 ObAction
*a
= g_new0(ObAction
, 1);
89 void action_ref(ObAction
*a
)
94 void action_unref(ObAction
*a
)
96 if (a
== NULL
) return;
98 if (--a
->ref
> 0) return;
100 /* deal with pointers */
101 if (a
->func
== action_execute
|| a
->func
== action_restart
)
102 g_free(a
->data
.execute
.path
);
103 else if (a
->func
== action_debug
)
104 g_free(a
->data
.debug
.string
);
105 else if (a
->func
== action_showmenu
)
106 g_free(a
->data
.showmenu
.name
);
111 ObAction
* action_copy(const ObAction
*src
)
113 ObAction
*a
= action_new(src
->func
);
117 /* deal with pointers */
118 if (a
->func
== action_execute
|| a
->func
== action_restart
)
119 a
->data
.execute
.path
= g_strdup(a
->data
.execute
.path
);
120 else if (a
->func
== action_debug
)
121 a
->data
.debug
.string
= g_strdup(a
->data
.debug
.string
);
122 else if (a
->func
== action_showmenu
)
123 a
->data
.showmenu
.name
= g_strdup(a
->data
.showmenu
.name
);
128 void setup_action_directional_focus_north(ObAction
**a
, ObUserAction uact
)
130 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
131 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTH
;
132 (*a
)->data
.interdiraction
.dialog
= TRUE
;
133 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
134 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
137 void setup_action_directional_focus_east(ObAction
**a
, ObUserAction uact
)
139 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
140 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_EAST
;
141 (*a
)->data
.interdiraction
.dialog
= TRUE
;
142 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
143 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
146 void setup_action_directional_focus_south(ObAction
**a
, ObUserAction uact
)
148 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
149 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTH
;
150 (*a
)->data
.interdiraction
.dialog
= TRUE
;
151 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
152 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
155 void setup_action_directional_focus_west(ObAction
**a
, ObUserAction uact
)
157 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
158 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_WEST
;
159 (*a
)->data
.interdiraction
.dialog
= TRUE
;
160 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
161 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
164 void setup_action_directional_focus_northeast(ObAction
**a
, ObUserAction uact
)
166 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
167 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHEAST
;
168 (*a
)->data
.interdiraction
.dialog
= TRUE
;
169 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
170 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
173 void setup_action_directional_focus_southeast(ObAction
**a
, ObUserAction uact
)
175 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
176 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHEAST
;
177 (*a
)->data
.interdiraction
.dialog
= TRUE
;
178 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
179 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
182 void setup_action_directional_focus_southwest(ObAction
**a
, ObUserAction uact
)
184 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
185 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_SOUTHWEST
;
186 (*a
)->data
.interdiraction
.dialog
= TRUE
;
187 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
188 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
191 void setup_action_directional_focus_northwest(ObAction
**a
, ObUserAction uact
)
193 (*a
)->data
.interdiraction
.inter
.any
.interactive
= TRUE
;
194 (*a
)->data
.interdiraction
.direction
= OB_DIRECTION_NORTHWEST
;
195 (*a
)->data
.interdiraction
.dialog
= TRUE
;
196 (*a
)->data
.interdiraction
.dock_windows
= FALSE
;
197 (*a
)->data
.interdiraction
.desktop_windows
= FALSE
;
200 void setup_action_send_to_desktop(ObAction
**a
, ObUserAction uact
)
202 (*a
)->data
.sendto
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
203 (*a
)->data
.sendto
.follow
= TRUE
;
206 void setup_action_send_to_desktop_prev(ObAction
**a
, ObUserAction uact
)
208 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
209 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
210 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
211 (*a
)->data
.sendtodir
.linear
= TRUE
;
212 (*a
)->data
.sendtodir
.wrap
= TRUE
;
213 (*a
)->data
.sendtodir
.follow
= TRUE
;
216 void setup_action_send_to_desktop_next(ObAction
**a
, ObUserAction uact
)
218 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
219 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
220 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
221 (*a
)->data
.sendtodir
.linear
= TRUE
;
222 (*a
)->data
.sendtodir
.wrap
= TRUE
;
223 (*a
)->data
.sendtodir
.follow
= TRUE
;
226 void setup_action_send_to_desktop_left(ObAction
**a
, ObUserAction uact
)
228 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
229 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
230 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
231 (*a
)->data
.sendtodir
.linear
= FALSE
;
232 (*a
)->data
.sendtodir
.wrap
= TRUE
;
233 (*a
)->data
.sendtodir
.follow
= TRUE
;
236 void setup_action_send_to_desktop_right(ObAction
**a
, ObUserAction uact
)
238 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
239 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
240 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
241 (*a
)->data
.sendtodir
.linear
= FALSE
;
242 (*a
)->data
.sendtodir
.wrap
= TRUE
;
243 (*a
)->data
.sendtodir
.follow
= TRUE
;
246 void setup_action_send_to_desktop_up(ObAction
**a
, ObUserAction uact
)
248 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
249 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
250 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_NORTH
;
251 (*a
)->data
.sendtodir
.linear
= FALSE
;
252 (*a
)->data
.sendtodir
.wrap
= TRUE
;
253 (*a
)->data
.sendtodir
.follow
= TRUE
;
256 void setup_action_send_to_desktop_down(ObAction
**a
, ObUserAction uact
)
258 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
259 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
260 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_SOUTH
;
261 (*a
)->data
.sendtodir
.linear
= FALSE
;
262 (*a
)->data
.sendtodir
.wrap
= TRUE
;
263 (*a
)->data
.sendtodir
.follow
= TRUE
;
266 void setup_action_desktop(ObAction
**a
, ObUserAction uact
)
269 (*a)->data.desktop.inter.any.interactive = FALSE;
273 void setup_action_desktop_prev(ObAction
**a
, ObUserAction uact
)
275 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
276 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
277 (*a
)->data
.desktopdir
.linear
= TRUE
;
278 (*a
)->data
.desktopdir
.wrap
= TRUE
;
281 void setup_action_desktop_next(ObAction
**a
, ObUserAction uact
)
283 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
284 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
285 (*a
)->data
.desktopdir
.linear
= TRUE
;
286 (*a
)->data
.desktopdir
.wrap
= TRUE
;
289 void setup_action_desktop_left(ObAction
**a
, ObUserAction uact
)
291 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
292 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
293 (*a
)->data
.desktopdir
.linear
= FALSE
;
294 (*a
)->data
.desktopdir
.wrap
= TRUE
;
297 void setup_action_desktop_right(ObAction
**a
, ObUserAction uact
)
299 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
300 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
301 (*a
)->data
.desktopdir
.linear
= FALSE
;
302 (*a
)->data
.desktopdir
.wrap
= TRUE
;
305 void setup_action_desktop_up(ObAction
**a
, ObUserAction uact
)
307 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
308 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_NORTH
;
309 (*a
)->data
.desktopdir
.linear
= FALSE
;
310 (*a
)->data
.desktopdir
.wrap
= TRUE
;
313 void setup_action_desktop_down(ObAction
**a
, ObUserAction uact
)
315 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
316 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_SOUTH
;
317 (*a
)->data
.desktopdir
.linear
= FALSE
;
318 (*a
)->data
.desktopdir
.wrap
= TRUE
;
321 void setup_action_cycle_windows_next(ObAction
**a
, ObUserAction uact
)
323 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
324 (*a
)->data
.cycle
.linear
= FALSE
;
325 (*a
)->data
.cycle
.forward
= TRUE
;
326 (*a
)->data
.cycle
.dialog
= TRUE
;
327 (*a
)->data
.cycle
.dock_windows
= FALSE
;
328 (*a
)->data
.cycle
.desktop_windows
= FALSE
;
329 (*a
)->data
.cycle
.all_desktops
= FALSE
;
332 void setup_action_cycle_windows_previous(ObAction
**a
, ObUserAction uact
)
334 (*a
)->data
.cycle
.inter
.any
.interactive
= TRUE
;
335 (*a
)->data
.cycle
.linear
= FALSE
;
336 (*a
)->data
.cycle
.forward
= FALSE
;
337 (*a
)->data
.cycle
.dialog
= TRUE
;
338 (*a
)->data
.cycle
.dock_windows
= FALSE
;
339 (*a
)->data
.cycle
.desktop_windows
= FALSE
;
340 (*a
)->data
.cycle
.all_desktops
= FALSE
;
343 void setup_action_movefromedge_north(ObAction
**a
, ObUserAction uact
)
345 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
346 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
347 (*a
)->data
.diraction
.hang
= TRUE
;
350 void setup_action_movefromedge_south(ObAction
**a
, ObUserAction uact
)
352 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
353 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
354 (*a
)->data
.diraction
.hang
= TRUE
;
357 void setup_action_movefromedge_east(ObAction
**a
, ObUserAction uact
)
359 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
360 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
361 (*a
)->data
.diraction
.hang
= TRUE
;
364 void setup_action_movefromedge_west(ObAction
**a
, ObUserAction uact
)
366 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
367 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
368 (*a
)->data
.diraction
.hang
= TRUE
;
371 void setup_action_movetoedge_north(ObAction
**a
, ObUserAction uact
)
373 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
374 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
375 (*a
)->data
.diraction
.hang
= FALSE
;
378 void setup_action_movetoedge_south(ObAction
**a
, ObUserAction uact
)
380 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
381 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
382 (*a
)->data
.diraction
.hang
= FALSE
;
385 void setup_action_movetoedge_east(ObAction
**a
, ObUserAction uact
)
387 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
388 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
389 (*a
)->data
.diraction
.hang
= FALSE
;
392 void setup_action_movetoedge_west(ObAction
**a
, ObUserAction uact
)
394 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
395 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
396 (*a
)->data
.diraction
.hang
= FALSE
;
399 void setup_action_growtoedge_north(ObAction
**a
, ObUserAction uact
)
401 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
402 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
405 void setup_action_growtoedge_south(ObAction
**a
, ObUserAction uact
)
407 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
408 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
411 void setup_action_growtoedge_east(ObAction
**a
, ObUserAction uact
)
413 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
414 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
417 void setup_action_growtoedge_west(ObAction
**a
, ObUserAction uact
)
419 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
420 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
423 void setup_action_top_layer(ObAction
**a
, ObUserAction uact
)
425 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
426 (*a
)->data
.layer
.layer
= 1;
429 void setup_action_normal_layer(ObAction
**a
, ObUserAction uact
)
431 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
432 (*a
)->data
.layer
.layer
= 0;
435 void setup_action_bottom_layer(ObAction
**a
, ObUserAction uact
)
437 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
438 (*a
)->data
.layer
.layer
= -1;
441 void setup_action_move(ObAction
**a
, ObUserAction uact
)
443 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
444 (*a
)->data
.moveresize
.keyboard
=
445 (uact
== OB_USER_ACTION_NONE
||
446 uact
== OB_USER_ACTION_KEYBOARD_KEY
||
447 uact
== OB_USER_ACTION_MENU_SELECTION
);
448 (*a
)->data
.moveresize
.corner
= 0;
451 void setup_action_resize(ObAction
**a
, ObUserAction uact
)
453 (*a
)->data
.moveresize
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
454 (*a
)->data
.moveresize
.keyboard
=
455 (uact
== OB_USER_ACTION_NONE
||
456 uact
== OB_USER_ACTION_KEYBOARD_KEY
||
457 uact
== OB_USER_ACTION_MENU_SELECTION
);
458 (*a
)->data
.moveresize
.corner
= 0;
461 void setup_action_showmenu(ObAction
**a
, ObUserAction uact
)
463 (*a
)->data
.showmenu
.any
.client_action
= OB_CLIENT_ACTION_OPTIONAL
;
464 /* you cannot call ShowMenu from inside a menu, cuz the menu code makes
465 assumptions that there is only one menu (and submenus) open at
467 if (uact
== OB_USER_ACTION_MENU_SELECTION
) {
473 void setup_action_addremove_desktop_current(ObAction
**a
, ObUserAction uact
)
475 (*a
)->data
.addremovedesktop
.current
= TRUE
;
478 void setup_action_addremove_desktop_last(ObAction
**a
, ObUserAction uact
)
480 (*a
)->data
.addremovedesktop
.current
= FALSE
;
483 void setup_action_focus(ObAction
**a
, ObUserAction uact
)
485 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_OPTIONAL
;
488 void setup_client_action(ObAction
**a
, ObUserAction uact
)
490 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
493 ActionString actionstrings
[] =
506 "directionalfocusnorth",
507 action_directional_focus
,
508 setup_action_directional_focus_north
511 "directionalfocuseast",
512 action_directional_focus
,
513 setup_action_directional_focus_east
516 "directionalfocussouth",
517 action_directional_focus
,
518 setup_action_directional_focus_south
521 "directionalfocuswest",
522 action_directional_focus
,
523 setup_action_directional_focus_west
526 "directionalfocusnortheast",
527 action_directional_focus
,
528 setup_action_directional_focus_northeast
531 "directionalfocussoutheast",
532 action_directional_focus
,
533 setup_action_directional_focus_southeast
536 "directionalfocussouthwest",
537 action_directional_focus
,
538 setup_action_directional_focus_southwest
541 "directionalfocusnorthwest",
542 action_directional_focus
,
543 setup_action_directional_focus_northwest
567 action_focus_order_to_bottom
,
622 action_toggle_omnipresent
,
627 action_move_relative_horz
,
632 action_move_relative_vert
,
637 action_move_to_center
,
641 "resizerelativehorz",
642 action_resize_relative_horz
,
646 "resizerelativevert",
647 action_resize_relative_vert
,
652 action_move_relative
,
657 action_resize_relative
,
662 action_maximize_full
,
667 action_unmaximize_full
,
671 "togglemaximizefull",
672 action_toggle_maximize_full
,
677 action_maximize_horz
,
682 action_unmaximize_horz
,
686 "togglemaximizehorz",
687 action_toggle_maximize_horz
,
692 action_maximize_vert
,
697 action_unmaximize_vert
,
701 "togglemaximizevert",
702 action_toggle_maximize_vert
,
707 action_toggle_fullscreen
,
712 action_send_to_desktop
,
713 setup_action_send_to_desktop
717 action_send_to_desktop_dir
,
718 setup_action_send_to_desktop_next
721 "sendtodesktopprevious",
722 action_send_to_desktop_dir
,
723 setup_action_send_to_desktop_prev
726 "sendtodesktopright",
727 action_send_to_desktop_dir
,
728 setup_action_send_to_desktop_right
732 action_send_to_desktop_dir
,
733 setup_action_send_to_desktop_left
737 action_send_to_desktop_dir
,
738 setup_action_send_to_desktop_up
742 action_send_to_desktop_dir
,
743 setup_action_send_to_desktop_down
753 setup_action_desktop_next
758 setup_action_desktop_prev
763 setup_action_desktop_right
768 setup_action_desktop_left
773 setup_action_desktop_up
778 setup_action_desktop_down
782 action_toggle_decorations
,
796 "toggledockautohide",
797 action_toggle_dockautohide
,
802 action_toggle_show_desktop
,
812 action_unshow_desktop
,
838 setup_action_showmenu
842 action_send_to_layer
,
843 setup_action_top_layer
848 setup_action_top_layer
852 action_send_to_layer
,
853 setup_action_normal_layer
857 action_send_to_layer
,
858 setup_action_bottom_layer
861 "togglealwaysonbottom",
863 setup_action_bottom_layer
867 action_cycle_windows
,
868 setup_action_cycle_windows_next
872 action_cycle_windows
,
873 setup_action_cycle_windows_previous
878 setup_action_movefromedge_north
883 setup_action_movefromedge_south
888 setup_action_movefromedge_west
893 setup_action_movefromedge_east
898 setup_action_movetoedge_north
903 setup_action_movetoedge_south
908 setup_action_movetoedge_west
913 setup_action_movetoedge_east
918 setup_action_growtoedge_north
923 setup_action_growtoedge_south
928 setup_action_growtoedge_west
933 setup_action_growtoedge_east
943 setup_action_addremove_desktop_last
947 action_remove_desktop
,
948 setup_action_addremove_desktop_last
953 setup_action_addremove_desktop_current
956 "removedesktopcurrent",
957 action_remove_desktop
,
958 setup_action_addremove_desktop_current
967 /* only key bindings can be interactive. thus saith the xor.
968 because of how the mouse is grabbed, mouse events dont even get
969 read during interactive events, so no dice! >:) */
970 #define INTERACTIVE_LIMIT(a, uact) \
971 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
972 a->data.any.interactive = FALSE;
974 ObAction
*action_from_string(const gchar
*name
, ObUserAction uact
)
977 gboolean exist
= FALSE
;
980 for (i
= 0; actionstrings
[i
].name
; i
++)
981 if (!g_ascii_strcasecmp(name
, actionstrings
[i
].name
)) {
983 a
= action_new(actionstrings
[i
].func
);
984 if (actionstrings
[i
].setup
)
985 actionstrings
[i
].setup(&a
, uact
);
987 INTERACTIVE_LIMIT(a
, uact
);
991 g_message(_("Invalid action '%s' requested. No such action exists."),
994 g_message(_("Invalid use of action '%s'. Action will be ignored."),
999 ObAction
*action_parse(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
1003 ObAction
*act
= NULL
;
1006 if (parse_attr_string("name", node
, &actname
)) {
1007 if ((act
= action_from_string(actname
, uact
))) {
1008 if (act
->func
== action_execute
|| act
->func
== action_restart
) {
1009 if ((n
= parse_find_node("execute", node
->xmlChildrenNode
))) {
1010 gchar
*s
= parse_string(doc
, n
);
1011 act
->data
.execute
.path
= parse_expand_tilde(s
);
1014 if ((n
= parse_find_node("startupnotify", node
->xmlChildrenNode
))) {
1016 if ((m
= parse_find_node("enabled", n
->xmlChildrenNode
)))
1017 act
->data
.execute
.startupnotify
= parse_bool(doc
, m
);
1018 if ((m
= parse_find_node("name", n
->xmlChildrenNode
)))
1019 act
->data
.execute
.name
= parse_string(doc
, m
);
1020 if ((m
= parse_find_node("icon", n
->xmlChildrenNode
)))
1021 act
->data
.execute
.icon_name
= parse_string(doc
, m
);
1023 } else if (act
->func
== action_debug
) {
1024 if ((n
= parse_find_node("string", node
->xmlChildrenNode
)))
1025 act
->data
.debug
.string
= parse_string(doc
, n
);
1026 } else if (act
->func
== action_showmenu
) {
1027 if ((n
= parse_find_node("menu", node
->xmlChildrenNode
)))
1028 act
->data
.showmenu
.name
= parse_string(doc
, n
);
1029 } else if (act
->func
== action_move_relative_horz
||
1030 act
->func
== action_move_relative_vert
||
1031 act
->func
== action_resize_relative_horz
||
1032 act
->func
== action_resize_relative_vert
) {
1033 if ((n
= parse_find_node("delta", node
->xmlChildrenNode
)))
1034 act
->data
.relative
.deltax
= parse_int(doc
, n
);
1035 } else if (act
->func
== action_move_relative
) {
1036 if ((n
= parse_find_node("x", node
->xmlChildrenNode
)))
1037 act
->data
.relative
.deltax
= parse_int(doc
, n
);
1038 if ((n
= parse_find_node("y", node
->xmlChildrenNode
)))
1039 act
->data
.relative
.deltay
= parse_int(doc
, n
);
1040 } else if (act
->func
== action_resize_relative
) {
1041 if ((n
= parse_find_node("left", node
->xmlChildrenNode
)))
1042 act
->data
.relative
.deltaxl
= parse_int(doc
, n
);
1043 if ((n
= parse_find_node("up", node
->xmlChildrenNode
)))
1044 act
->data
.relative
.deltayu
= parse_int(doc
, n
);
1045 if ((n
= parse_find_node("right", node
->xmlChildrenNode
)))
1046 act
->data
.relative
.deltax
= parse_int(doc
, n
);
1047 if ((n
= parse_find_node("down", node
->xmlChildrenNode
)))
1048 act
->data
.relative
.deltay
= parse_int(doc
, n
);
1049 } else if (act
->func
== action_desktop
) {
1050 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1051 act
->data
.desktop
.desk
= parse_int(doc
, n
);
1052 if (act
->data
.desktop
.desk
> 0) act
->data
.desktop
.desk
--;
1054 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
1055 act->data.desktop.inter.any.interactive =
1058 } else if (act
->func
== action_send_to_desktop
) {
1059 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1060 act
->data
.sendto
.desk
= parse_int(doc
, n
);
1061 if (act
->data
.sendto
.desk
> 0) act
->data
.sendto
.desk
--;
1062 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
1063 act
->data
.sendto
.follow
= parse_bool(doc
, n
);
1064 } else if (act
->func
== action_desktop_dir
) {
1065 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
1066 act
->data
.desktopdir
.wrap
= parse_bool(doc
, n
);
1067 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1068 act
->data
.desktopdir
.inter
.any
.interactive
=
1070 } else if (act
->func
== action_send_to_desktop_dir
) {
1071 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
1072 act
->data
.sendtodir
.wrap
= parse_bool(doc
, n
);
1073 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
1074 act
->data
.sendtodir
.follow
= parse_bool(doc
, n
);
1075 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1076 act
->data
.sendtodir
.inter
.any
.interactive
=
1078 } else if (act
->func
== action_activate
) {
1079 if ((n
= parse_find_node("here", node
->xmlChildrenNode
)))
1080 act
->data
.activate
.here
= parse_bool(doc
, n
);
1081 } else if (act
->func
== action_cycle_windows
) {
1082 if ((n
= parse_find_node("linear", node
->xmlChildrenNode
)))
1083 act
->data
.cycle
.linear
= parse_bool(doc
, n
);
1084 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1085 act
->data
.cycle
.dialog
= parse_bool(doc
, n
);
1086 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
1087 act
->data
.cycle
.dock_windows
= parse_bool(doc
, n
);
1088 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1089 act
->data
.cycle
.desktop_windows
= parse_bool(doc
, n
);
1090 if ((n
= parse_find_node("allDesktops",
1091 node
->xmlChildrenNode
)))
1092 act
->data
.cycle
.all_desktops
= parse_bool(doc
, n
);
1093 } else if (act
->func
== action_directional_focus
) {
1094 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1095 act
->data
.interdiraction
.dialog
= parse_bool(doc
, n
);
1096 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
1097 act
->data
.interdiraction
.dock_windows
= parse_bool(doc
, n
);
1098 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1099 act
->data
.interdiraction
.desktop_windows
=
1101 } else if (act
->func
== action_resize
) {
1102 if ((n
= parse_find_node("edge", node
->xmlChildrenNode
))) {
1103 gchar
*s
= parse_string(doc
, n
);
1104 if (!g_ascii_strcasecmp(s
, "top"))
1105 act
->data
.moveresize
.corner
=
1106 prop_atoms
.net_wm_moveresize_size_top
;
1107 else if (!g_ascii_strcasecmp(s
, "bottom"))
1108 act
->data
.moveresize
.corner
=
1109 prop_atoms
.net_wm_moveresize_size_bottom
;
1110 else if (!g_ascii_strcasecmp(s
, "left"))
1111 act
->data
.moveresize
.corner
=
1112 prop_atoms
.net_wm_moveresize_size_left
;
1113 else if (!g_ascii_strcasecmp(s
, "right"))
1114 act
->data
.moveresize
.corner
=
1115 prop_atoms
.net_wm_moveresize_size_right
;
1116 else if (!g_ascii_strcasecmp(s
, "topleft"))
1117 act
->data
.moveresize
.corner
=
1118 prop_atoms
.net_wm_moveresize_size_topleft
;
1119 else if (!g_ascii_strcasecmp(s
, "topright"))
1120 act
->data
.moveresize
.corner
=
1121 prop_atoms
.net_wm_moveresize_size_topright
;
1122 else if (!g_ascii_strcasecmp(s
, "bottomleft"))
1123 act
->data
.moveresize
.corner
=
1124 prop_atoms
.net_wm_moveresize_size_bottomleft
;
1125 else if (!g_ascii_strcasecmp(s
, "bottomright"))
1126 act
->data
.moveresize
.corner
=
1127 prop_atoms
.net_wm_moveresize_size_bottomright
;
1130 } else if (act
->func
== action_raise
||
1131 act
->func
== action_lower
||
1132 act
->func
== action_raiselower
||
1133 act
->func
== action_shadelower
||
1134 act
->func
== action_unshaderaise
) {
1136 INTERACTIVE_LIMIT(act
, uact
);
1143 void action_run_list(GSList
*acts
, ObClient
*c
, ObFrameContext context
,
1144 guint state
, guint button
, gint x
, gint y
, Time time
,
1145 gboolean cancel
, gboolean done
)
1154 screen_pointer_pos(&x
, &y
);
1156 for (it
= acts
; it
; it
= g_slist_next(it
)) {
1159 if (!(a
->data
.any
.client_action
== OB_CLIENT_ACTION_ALWAYS
&& !c
)) {
1160 a
->data
.any
.c
= a
->data
.any
.client_action
? c
: NULL
;
1161 a
->data
.any
.context
= context
;
1165 a
->data
.any
.button
= button
;
1167 a
->data
.any
.time
= time
;
1169 if (a
->data
.any
.interactive
) {
1170 a
->data
.inter
.cancel
= cancel
;
1171 a
->data
.inter
.final
= done
;
1172 if (!(cancel
|| done
))
1173 if (!keyboard_interactive_grab(state
, a
->data
.any
.c
, a
))
1177 /* XXX UGLY HACK race with motion event starting a move and the
1178 button release gettnig processed first. answer: don't queue
1179 moveresize starts. UGLY HACK XXX
1181 XXX ALSO don't queue showmenu events, because on button press
1182 events we need to know if a mouse grab is going to take place,
1183 and set the button to 0, so that later motion events don't think
1184 that a drag is going on. since showmenu grabs the pointer..
1186 if (a
->data
.any
.interactive
|| a
->func
== action_move
||
1187 a
->func
== action_resize
|| a
->func
== action_showmenu
)
1189 /* interactive actions are not queued */
1191 } else if (a
->func
== action_focus
||
1192 a
->func
== action_activate
||
1193 a
->func
== action_showmenu
)
1195 /* XXX MORE UGLY HACK
1196 actions from clicks on client windows are NOT queued.
1197 this solves the mysterious click-and-drag-doesnt-work
1198 problem. it was because the window gets focused and stuff
1199 after the button event has already been passed through. i
1200 dont really know why it should care but it does and it makes
1203 however this very bogus ! !
1204 we want to send the button press to the window BEFORE
1205 we do the action because the action might move the windows
1206 (eg change desktops) and then the button press ends up on
1207 the completely wrong window !
1208 so, this is just for that bug, and it will only NOT queue it
1209 if it is a focusing action that can be used with the mouse
1212 also with the menus, there is a race going on. if the
1213 desktop wants to pop up a menu, and we do too, we send them
1214 the button before we pop up the menu, so they pop up their
1215 menu first. but not always. if we pop up our menu before
1216 sending them the button press, then the result is
1219 XXX further more. focus actions are not queued at all,
1220 because if you bind focus->showmenu, the menu will get
1221 hidden to do the focusing
1225 ob_main_loop_queue_action(ob_main_loop
, a
);
1230 void action_run_string(const gchar
*name
, struct _ObClient
*c
, Time time
)
1235 a
= action_from_string(name
, OB_USER_ACTION_NONE
);
1238 l
= g_slist_append(NULL
, a
);
1240 action_run(l
, c
, 0, time
);
1243 void action_debug(union ActionData
*data
)
1245 if (data
->debug
.string
)
1246 g_print("%s\n", data
->debug
.string
);
1249 void action_execute(union ActionData
*data
)
1252 gchar
*cmd
, **argv
= 0;
1253 if (data
->execute
.path
) {
1254 cmd
= g_filename_from_utf8(data
->execute
.path
, -1, NULL
, NULL
, NULL
);
1256 /* If there is a keyboard grab going on then we need to cancel
1257 it so the application can grab things */
1258 event_cancel_all_key_grabs();
1260 if (!g_shell_parse_argv (cmd
, NULL
, &argv
, &e
)) {
1261 g_message(_("Failed to execute '%s': %s"),
1264 } else if (data
->execute
.startupnotify
) {
1267 program
= g_path_get_basename(argv
[0]);
1268 /* sets up the environment */
1269 sn_setup_spawn_environment(program
,
1271 data
->execute
.icon_name
,
1272 /* launch it on the current
1275 data
->execute
.any
.time
);
1276 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
|
1277 G_SPAWN_DO_NOT_REAP_CHILD
,
1278 NULL
, NULL
, NULL
, &e
)) {
1279 g_message(_("Failed to execute '%s': %s"),
1284 unsetenv("DESKTOP_STARTUP_ID");
1288 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
|
1289 G_SPAWN_DO_NOT_REAP_CHILD
,
1290 NULL
, NULL
, NULL
, &e
))
1292 g_message(_("Failed to execute '%s': %s"),
1300 g_message(_("Failed to convert the path '%s' from utf8"),
1301 data
->execute
.path
);
1306 void action_activate(union ActionData
*data
)
1308 if (data
->client
.any
.c
) {
1309 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1310 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1311 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1313 /* if using focus_delay, stop the timer now so that focus doesn't
1315 event_halt_focus_delay();
1317 client_activate(data
->activate
.any
.c
, data
->activate
.here
, TRUE
);
1320 /* focus action on something other than a client, make keybindings
1321 work for this openbox instance, but don't focus any specific client
1327 void action_focus(union ActionData
*data
)
1329 if (data
->client
.any
.c
) {
1330 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1331 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1332 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1334 /* if using focus_delay, stop the timer now so that focus doesn't
1336 event_halt_focus_delay();
1338 client_focus(data
->client
.any
.c
);
1341 /* focus action on something other than a client, make keybindings
1342 work for this openbox instance, but don't focus any specific client
1348 void action_unfocus (union ActionData
*data
)
1350 if (data
->client
.any
.c
== focus_client
)
1351 focus_fallback(FALSE
, FALSE
, TRUE
);
1354 void action_iconify(union ActionData
*data
)
1356 client_action_start(data
);
1357 client_iconify(data
->client
.any
.c
, TRUE
, TRUE
, FALSE
);
1358 client_action_end(data
, config_focus_under_mouse
);
1361 void action_focus_order_to_bottom(union ActionData
*data
)
1363 focus_order_to_bottom(data
->client
.any
.c
);
1366 void action_raiselower(union ActionData
*data
)
1368 ObClient
*c
= data
->client
.any
.c
;
1370 client_action_start(data
);
1371 stacking_restack_request(c
, NULL
, Opposite
);
1372 client_action_end(data
, config_focus_under_mouse
);
1375 void action_raise(union ActionData
*data
)
1377 client_action_start(data
);
1378 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1379 client_action_end(data
, config_focus_under_mouse
);
1382 void action_unshaderaise(union ActionData
*data
)
1384 if (data
->client
.any
.c
->shaded
)
1385 action_unshade(data
);
1390 void action_shadelower(union ActionData
*data
)
1392 if (data
->client
.any
.c
->shaded
)
1398 void action_lower(union ActionData
*data
)
1400 client_action_start(data
);
1401 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1402 client_action_end(data
, config_focus_under_mouse
);
1405 void action_close(union ActionData
*data
)
1407 client_close(data
->client
.any
.c
);
1410 void action_kill(union ActionData
*data
)
1412 client_kill(data
->client
.any
.c
);
1415 void action_shade(union ActionData
*data
)
1417 client_action_start(data
);
1418 client_shade(data
->client
.any
.c
, TRUE
);
1419 client_action_end(data
, config_focus_under_mouse
);
1422 void action_unshade(union ActionData
*data
)
1424 client_action_start(data
);
1425 client_shade(data
->client
.any
.c
, FALSE
);
1426 client_action_end(data
, config_focus_under_mouse
);
1429 void action_toggle_shade(union ActionData
*data
)
1431 client_action_start(data
);
1432 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1433 client_action_end(data
, config_focus_under_mouse
);
1436 void action_toggle_omnipresent(union ActionData
*data
)
1438 client_set_desktop(data
->client
.any
.c
,
1439 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1440 screen_desktop
: DESKTOP_ALL
, FALSE
, TRUE
);
1443 void action_move_relative_horz(union ActionData
*data
)
1445 ObClient
*c
= data
->relative
.any
.c
;
1446 client_action_start(data
);
1447 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
);
1448 client_action_end(data
, FALSE
);
1451 void action_move_relative_vert(union ActionData
*data
)
1453 ObClient
*c
= data
->relative
.any
.c
;
1454 client_action_start(data
);
1455 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.deltax
);
1456 client_action_end(data
, FALSE
);
1459 void action_move_to_center(union ActionData
*data
)
1461 ObClient
*c
= data
->client
.any
.c
;
1463 area
= screen_area(c
->desktop
, client_monitor(c
), NULL
);
1464 client_action_start(data
);
1465 client_move(c
, area
->x
+ area
->width
/ 2 - c
->area
.width
/ 2,
1466 area
->y
+ area
->height
/ 2 - c
->area
.height
/ 2);
1467 client_action_end(data
, FALSE
);
1471 void action_resize_relative_horz(union ActionData
*data
)
1473 ObClient
*c
= data
->relative
.any
.c
;
1474 client_action_start(data
);
1476 c
->area
.width
+ data
->relative
.deltax
* c
->size_inc
.width
,
1478 client_action_end(data
, FALSE
);
1481 void action_resize_relative_vert(union ActionData
*data
)
1483 ObClient
*c
= data
->relative
.any
.c
;
1485 client_action_start(data
);
1486 client_resize(c
, c
->area
.width
, c
->area
.height
+
1487 data
->relative
.deltax
* c
->size_inc
.height
);
1488 client_action_end(data
, FALSE
);
1492 void action_move_relative(union ActionData
*data
)
1494 ObClient
*c
= data
->relative
.any
.c
;
1495 client_action_start(data
);
1496 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
+
1497 data
->relative
.deltay
);
1498 client_action_end(data
, FALSE
);
1501 void action_resize_relative(union ActionData
*data
)
1503 ObClient
*c
= data
->relative
.any
.c
;
1504 gint x
, y
, ow
, xoff
, nw
, oh
, yoff
, nh
, lw
, lh
;
1506 client_action_start(data
);
1511 xoff
= -data
->relative
.deltaxl
* c
->size_inc
.width
;
1512 nw
= ow
+ data
->relative
.deltax
* c
->size_inc
.width
1513 + data
->relative
.deltaxl
* c
->size_inc
.width
;
1514 oh
= c
->area
.height
;
1515 yoff
= -data
->relative
.deltayu
* c
->size_inc
.height
;
1516 nh
= oh
+ data
->relative
.deltay
* c
->size_inc
.height
1517 + data
->relative
.deltayu
* c
->size_inc
.height
;
1519 g_print("deltax %d %d x %d ow %d xoff %d nw %d\n",
1520 data
->relative
.deltax
,
1521 data
->relative
.deltaxl
,
1524 client_try_configure(c
, &x
, &y
, &nw
, &nh
, &lw
, &lh
, TRUE
);
1525 xoff
= xoff
== 0 ? 0 : (xoff
< 0 ? MAX(xoff
, ow
-nw
) : MIN(xoff
, ow
-nw
));
1526 yoff
= yoff
== 0 ? 0 : (yoff
< 0 ? MAX(yoff
, oh
-nh
) : MIN(yoff
, oh
-nh
));
1527 client_move_resize(c
, x
+ xoff
, y
+ yoff
, nw
, nh
);
1528 client_action_end(data
, FALSE
);
1531 void action_maximize_full(union ActionData
*data
)
1533 client_action_start(data
);
1534 client_maximize(data
->client
.any
.c
, TRUE
, 0);
1535 client_action_end(data
, config_focus_under_mouse
);
1538 void action_unmaximize_full(union ActionData
*data
)
1540 client_action_start(data
);
1541 client_maximize(data
->client
.any
.c
, FALSE
, 0);
1542 client_action_end(data
, config_focus_under_mouse
);
1545 void action_toggle_maximize_full(union ActionData
*data
)
1547 client_action_start(data
);
1548 client_maximize(data
->client
.any
.c
,
1549 !(data
->client
.any
.c
->max_horz
||
1550 data
->client
.any
.c
->max_vert
),
1552 client_action_end(data
, config_focus_under_mouse
);
1555 void action_maximize_horz(union ActionData
*data
)
1557 client_action_start(data
);
1558 client_maximize(data
->client
.any
.c
, TRUE
, 1);
1559 client_action_end(data
, config_focus_under_mouse
);
1562 void action_unmaximize_horz(union ActionData
*data
)
1564 client_action_start(data
);
1565 client_maximize(data
->client
.any
.c
, FALSE
, 1);
1566 client_action_end(data
, config_focus_under_mouse
);
1569 void action_toggle_maximize_horz(union ActionData
*data
)
1571 client_action_start(data
);
1572 client_maximize(data
->client
.any
.c
,
1573 !data
->client
.any
.c
->max_horz
, 1);
1574 client_action_end(data
, config_focus_under_mouse
);
1577 void action_maximize_vert(union ActionData
*data
)
1579 client_action_start(data
);
1580 client_maximize(data
->client
.any
.c
, TRUE
, 2);
1581 client_action_end(data
, config_focus_under_mouse
);
1584 void action_unmaximize_vert(union ActionData
*data
)
1586 client_action_start(data
);
1587 client_maximize(data
->client
.any
.c
, FALSE
, 2);
1588 client_action_end(data
, config_focus_under_mouse
);
1591 void action_toggle_maximize_vert(union ActionData
*data
)
1593 client_action_start(data
);
1594 client_maximize(data
->client
.any
.c
,
1595 !data
->client
.any
.c
->max_vert
, 2);
1596 client_action_end(data
, config_focus_under_mouse
);
1599 void action_toggle_fullscreen(union ActionData
*data
)
1601 client_action_start(data
);
1602 client_fullscreen(data
->client
.any
.c
, !(data
->client
.any
.c
->fullscreen
));
1603 client_action_end(data
, config_focus_under_mouse
);
1606 void action_send_to_desktop(union ActionData
*data
)
1608 ObClient
*c
= data
->sendto
.any
.c
;
1610 if (!client_normal(c
)) return;
1612 if (data
->sendto
.desk
< screen_num_desktops
||
1613 data
->sendto
.desk
== DESKTOP_ALL
) {
1614 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
, FALSE
);
1615 if (data
->sendto
.follow
&& data
->sendto
.desk
!= screen_desktop
)
1616 screen_set_desktop(data
->sendto
.desk
, TRUE
);
1620 void action_desktop(union ActionData
*data
)
1622 /* XXX add the interactive/dialog option back again once the dialog
1623 has been made to not use grabs */
1624 if (data
->desktop
.desk
< screen_num_desktops
||
1625 data
->desktop
.desk
== DESKTOP_ALL
)
1627 screen_set_desktop(data
->desktop
.desk
, TRUE
);
1628 if (data
->inter
.any
.interactive
)
1629 screen_desktop_popup(data
->desktop
.desk
, TRUE
);
1633 void action_desktop_dir(union ActionData
*data
)
1637 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1638 data
->desktopdir
.wrap
,
1639 data
->desktopdir
.linear
,
1640 data
->desktopdir
.inter
.any
.interactive
,
1641 data
->desktopdir
.inter
.final
,
1642 data
->desktopdir
.inter
.cancel
);
1643 /* only move the desktop when the action is complete. if we switch
1644 desktops during the interactive action, focus will move but with
1645 NotifyWhileGrabbed and applications don't like that. */
1646 if (!data
->sendtodir
.inter
.any
.interactive
||
1647 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1649 if (d
!= screen_desktop
)
1650 screen_set_desktop(d
, TRUE
);
1654 void action_send_to_desktop_dir(union ActionData
*data
)
1656 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1659 if (!client_normal(c
)) return;
1661 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1662 data
->sendtodir
.linear
,
1663 data
->sendtodir
.inter
.any
.interactive
,
1664 data
->sendtodir
.inter
.final
,
1665 data
->sendtodir
.inter
.cancel
);
1666 /* only move the desktop when the action is complete. if we switch
1667 desktops during the interactive action, focus will move but with
1668 NotifyWhileGrabbed and applications don't like that. */
1669 if (!data
->sendtodir
.inter
.any
.interactive
||
1670 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1672 client_set_desktop(c
, d
, data
->sendtodir
.follow
, FALSE
);
1673 if (data
->sendtodir
.follow
&& d
!= screen_desktop
)
1674 screen_set_desktop(d
, TRUE
);
1678 void action_desktop_last(union ActionData
*data
)
1680 if (screen_last_desktop
< screen_num_desktops
)
1681 screen_set_desktop(screen_last_desktop
, TRUE
);
1684 void action_toggle_decorations(union ActionData
*data
)
1686 ObClient
*c
= data
->client
.any
.c
;
1688 client_action_start(data
);
1689 client_set_undecorated(c
, !c
->undecorated
);
1690 client_action_end(data
, FALSE
);
1693 static guint32
pick_corner(gint x
, gint y
, gint cx
, gint cy
, gint cw
, gint ch
,
1696 /* let's make x and y client relative instead of screen relative */
1698 y
= ch
- (y
- cy
); /* y is inverted, 0 is at the bottom of the window */
1701 #define A -4*X + 7*ch/3
1702 #define B 4*X -15*ch/9
1703 #define C -X/4 + 2*ch/3
1704 #define D X/4 + 5*ch/12
1705 #define E X/4 + ch/3
1706 #define F -X/4 + 7*ch/12
1707 #define G 4*X - 4*ch/3
1708 #define H -4*X + 8*ch/3
1709 #define a (y > 5*ch/9)
1710 #define b (x < 4*cw/9)
1711 #define c (x > 5*cw/9)
1712 #define d (y < 4*ch/9)
1715 Each of these defines (except X which is just there for fun), represents
1716 the equation of a line. The lines they represent are shown in the diagram
1717 below. Checking y against these lines, we are able to choose a region
1718 of the window as shown.
1720 +---------------------A-------|-------|-------B---------------------+
1727 | northwest | A north B | northeast |
1730 C---------------------+----A--+-------+--B----+---------------------D
1731 |CCCCCCC | A B | DDDDDDD|
1732 | CCCCCCCC | A | | B | DDDDDDDD |
1733 | CCCCCCC A B DDDDDDD |
1734 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
1736 | west | b move c | east | ad
1738 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
1739 | EEEEEEE G H FFFFFFF |
1740 | EEEEEEEE | G | | H | FFFFFFFF |
1741 |EEEEEEE | G H | FFFFFFF|
1742 E---------------------+----G--+-------+--H----+---------------------F
1745 | southwest | G south H | southeast |
1752 +---------------------G-------|-------|-------H---------------------+
1756 /* for shaded windows, you can only resize west/east and move */
1758 return prop_atoms
.net_wm_moveresize_size_left
;
1760 return prop_atoms
.net_wm_moveresize_size_right
;
1761 return prop_atoms
.net_wm_moveresize_move
;
1764 if (y
< A
&& y
>= C
)
1765 return prop_atoms
.net_wm_moveresize_size_topleft
;
1766 else if (y
>= A
&& y
>= B
&& a
)
1767 return prop_atoms
.net_wm_moveresize_size_top
;
1768 else if (y
< B
&& y
>= D
)
1769 return prop_atoms
.net_wm_moveresize_size_topright
;
1770 else if (y
< C
&& y
>= E
&& b
)
1771 return prop_atoms
.net_wm_moveresize_size_left
;
1772 else if (y
< D
&& y
>= F
&& c
)
1773 return prop_atoms
.net_wm_moveresize_size_right
;
1774 else if (y
< E
&& y
>= G
)
1775 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1776 else if (y
< G
&& y
< H
&& d
)
1777 return prop_atoms
.net_wm_moveresize_size_bottom
;
1778 else if (y
>= H
&& y
< F
)
1779 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1781 return prop_atoms
.net_wm_moveresize_move
;
1798 void action_move(union ActionData
*data
)
1800 ObClient
*c
= data
->moveresize
.any
.c
;
1803 if (data
->moveresize
.keyboard
)
1804 corner
= prop_atoms
.net_wm_moveresize_move_keyboard
;
1806 corner
= prop_atoms
.net_wm_moveresize_move
;
1808 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1811 void action_resize(union ActionData
*data
)
1813 ObClient
*c
= data
->moveresize
.any
.c
;
1816 if (data
->moveresize
.keyboard
)
1817 corner
= prop_atoms
.net_wm_moveresize_size_keyboard
;
1818 else if (data
->moveresize
.corner
)
1819 corner
= data
->moveresize
.corner
; /* it was specified in the binding */
1821 corner
= pick_corner(data
->any
.x
, data
->any
.y
,
1822 c
->frame
->area
.x
, c
->frame
->area
.y
,
1823 /* use the client size because the frame
1824 can be differently sized (shaded
1825 windows) and we want this based on the
1827 c
->area
.width
+ c
->frame
->size
.left
+
1828 c
->frame
->size
.right
,
1829 c
->area
.height
+ c
->frame
->size
.top
+
1830 c
->frame
->size
.bottom
, c
->shaded
);
1832 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1835 void action_reconfigure(union ActionData
*data
)
1840 void action_restart(union ActionData
*data
)
1842 ob_restart_other(data
->execute
.path
);
1845 void action_exit(union ActionData
*data
)
1850 void action_showmenu(union ActionData
*data
)
1852 if (data
->showmenu
.name
) {
1853 menu_show(data
->showmenu
.name
, data
->any
.x
, data
->any
.y
,
1854 data
->any
.button
, data
->showmenu
.any
.c
);
1858 void action_cycle_windows(union ActionData
*data
)
1860 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1862 event_halt_focus_delay();
1864 focus_cycle(data
->cycle
.forward
,
1865 data
->cycle
.all_desktops
,
1866 data
->cycle
.dock_windows
,
1867 data
->cycle
.desktop_windows
,
1868 data
->cycle
.linear
, data
->any
.interactive
,
1870 data
->cycle
.inter
.final
, data
->cycle
.inter
.cancel
);
1873 void action_directional_focus(union ActionData
*data
)
1875 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1877 event_halt_focus_delay();
1879 focus_directional_cycle(data
->interdiraction
.direction
,
1880 data
->interdiraction
.dock_windows
,
1881 data
->interdiraction
.desktop_windows
,
1882 data
->any
.interactive
,
1883 data
->interdiraction
.dialog
,
1884 data
->interdiraction
.inter
.final
,
1885 data
->interdiraction
.inter
.cancel
);
1888 void action_movetoedge(union ActionData
*data
)
1891 ObClient
*c
= data
->diraction
.any
.c
;
1893 x
= c
->frame
->area
.x
;
1894 y
= c
->frame
->area
.y
;
1896 switch(data
->diraction
.direction
) {
1897 case OB_DIRECTION_NORTH
:
1898 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
,
1899 data
->diraction
.hang
)
1900 - (data
->diraction
.hang
? c
->frame
->area
.height
: 0);
1902 case OB_DIRECTION_WEST
:
1903 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
,
1904 data
->diraction
.hang
)
1905 - (data
->diraction
.hang
? c
->frame
->area
.width
: 0);
1907 case OB_DIRECTION_SOUTH
:
1908 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
,
1909 data
->diraction
.hang
)
1910 - (data
->diraction
.hang
? 0 : c
->frame
->area
.height
);
1912 case OB_DIRECTION_EAST
:
1913 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
,
1914 data
->diraction
.hang
)
1915 - (data
->diraction
.hang
? 0 : c
->frame
->area
.width
);
1918 g_assert_not_reached();
1920 frame_frame_gravity(c
->frame
, &x
, &y
, c
->area
.width
, c
->area
.height
);
1921 client_action_start(data
);
1922 client_move(c
, x
, y
);
1923 client_action_end(data
, FALSE
);
1926 void action_growtoedge(union ActionData
*data
)
1928 gint x
, y
, width
, height
, dest
;
1929 ObClient
*c
= data
->diraction
.any
.c
;
1932 a
= screen_area(c
->desktop
, SCREEN_AREA_ALL_MONITORS
, &c
->frame
->area
);
1933 x
= c
->frame
->area
.x
;
1934 y
= c
->frame
->area
.y
;
1935 /* get the unshaded frame's dimensions..if it is shaded */
1936 width
= c
->area
.width
+ c
->frame
->size
.left
+ c
->frame
->size
.right
;
1937 height
= c
->area
.height
+ c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1939 switch(data
->diraction
.direction
) {
1940 case OB_DIRECTION_NORTH
:
1941 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1943 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
, FALSE
);
1945 height
= height
/ 2;
1947 height
= c
->frame
->area
.y
+ height
- dest
;
1951 case OB_DIRECTION_WEST
:
1952 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
, FALSE
);
1956 width
= c
->frame
->area
.x
+ width
- dest
;
1960 case OB_DIRECTION_SOUTH
:
1961 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1963 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
, FALSE
);
1964 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1965 height
= c
->frame
->area
.height
/ 2;
1966 y
= a
->y
+ a
->height
- height
;
1968 height
= dest
- c
->frame
->area
.y
;
1969 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1970 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1972 case OB_DIRECTION_EAST
:
1973 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
, FALSE
);
1974 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1975 width
= c
->frame
->area
.width
/ 2;
1976 x
= a
->x
+ a
->width
- width
;
1978 width
= dest
- c
->frame
->area
.x
;
1979 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1980 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1983 g_assert_not_reached();
1985 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1986 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1987 frame_frame_gravity(c
->frame
, &x
, &y
, width
, height
);
1988 client_action_start(data
);
1989 client_move_resize(c
, x
, y
, width
, height
);
1990 client_action_end(data
, FALSE
);
1994 void action_send_to_layer(union ActionData
*data
)
1996 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1999 void action_toggle_layer(union ActionData
*data
)
2001 ObClient
*c
= data
->layer
.any
.c
;
2003 client_action_start(data
);
2004 if (data
->layer
.layer
< 0)
2005 client_set_layer(c
, c
->below
? 0 : -1);
2006 else if (data
->layer
.layer
> 0)
2007 client_set_layer(c
, c
->above
? 0 : 1);
2008 client_action_end(data
, config_focus_under_mouse
);
2011 void action_toggle_dockautohide(union ActionData
*data
)
2013 config_dock_hide
= !config_dock_hide
;
2017 void action_toggle_show_desktop(union ActionData
*data
)
2019 screen_show_desktop(!screen_showing_desktop
, NULL
);
2022 void action_show_desktop(union ActionData
*data
)
2024 screen_show_desktop(TRUE
, NULL
);
2027 void action_unshow_desktop(union ActionData
*data
)
2029 screen_show_desktop(FALSE
, NULL
);
2032 void action_break_chroot(union ActionData
*data
)
2034 /* break out of one chroot */
2035 keyboard_reset_chains(1);
2038 void action_add_desktop(union ActionData
*data
)
2040 client_action_start(data
);
2041 screen_set_num_desktops(screen_num_desktops
+1);
2043 /* move all the clients over */
2044 if (data
->addremovedesktop
.current
) {
2047 for (it
= client_list
; it
; it
= g_list_next(it
)) {
2048 ObClient
*c
= it
->data
;
2049 if (c
->desktop
!= DESKTOP_ALL
&& c
->desktop
>= screen_desktop
)
2050 client_set_desktop(c
, c
->desktop
+1, FALSE
, TRUE
);
2054 client_action_end(data
, config_focus_under_mouse
);
2057 void action_remove_desktop(union ActionData
*data
)
2059 guint rmdesktop
, movedesktop
;
2060 GList
*it
, *stacking_copy
;
2062 if (screen_num_desktops
< 2) return;
2064 client_action_start(data
);
2066 /* what desktop are we removing and moving to? */
2067 if (data
->addremovedesktop
.current
)
2068 rmdesktop
= screen_desktop
;
2070 rmdesktop
= screen_num_desktops
- 1;
2071 if (rmdesktop
< screen_num_desktops
- 1)
2072 movedesktop
= rmdesktop
+ 1;
2074 movedesktop
= rmdesktop
;
2076 /* make a copy of the list cuz we're changing it */
2077 stacking_copy
= g_list_copy(stacking_list
);
2078 for (it
= g_list_last(stacking_copy
); it
; it
= g_list_previous(it
)) {
2079 if (WINDOW_IS_CLIENT(it
->data
)) {
2080 ObClient
*c
= it
->data
;
2081 guint d
= c
->desktop
;
2082 if (d
!= DESKTOP_ALL
&& d
>= movedesktop
) {
2083 client_set_desktop(c
, c
->desktop
- 1, TRUE
, TRUE
);
2084 ob_debug("moving window %s\n", c
->title
);
2086 /* raise all the windows that are on the current desktop which
2088 if ((screen_desktop
== rmdesktop
- 1 ||
2089 screen_desktop
== rmdesktop
) &&
2090 (d
== DESKTOP_ALL
|| d
== screen_desktop
))
2092 stacking_raise(CLIENT_AS_WINDOW(c
));
2093 ob_debug("raising window %s\n", c
->title
);
2098 /* act like we're changing desktops */
2099 if (screen_desktop
< screen_num_desktops
- 1) {
2100 gint d
= screen_desktop
;
2101 screen_desktop
= screen_last_desktop
;
2102 screen_set_desktop(d
, TRUE
);
2103 ob_debug("fake desktop change\n");
2106 screen_set_num_desktops(screen_num_desktops
-1);
2108 client_action_end(data
, config_focus_under_mouse
);