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_addremove_desktop_current(ObAction
**a
, ObUserAction uact
)
463 (*a
)->data
.addremovedesktop
.current
= TRUE
;
466 void setup_action_addremove_desktop_last(ObAction
**a
, ObUserAction uact
)
468 (*a
)->data
.addremovedesktop
.current
= FALSE
;
471 void setup_action_focus(ObAction
**a
, ObUserAction uact
)
473 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_OPTIONAL
;
476 void setup_client_action(ObAction
**a
, ObUserAction uact
)
478 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
481 ActionString actionstrings
[] =
484 "directionalfocusnorth",
485 action_directional_focus
,
486 setup_action_directional_focus_north
489 "directionalfocuseast",
490 action_directional_focus
,
491 setup_action_directional_focus_east
494 "directionalfocussouth",
495 action_directional_focus
,
496 setup_action_directional_focus_south
499 "directionalfocuswest",
500 action_directional_focus
,
501 setup_action_directional_focus_west
504 "directionalfocusnortheast",
505 action_directional_focus
,
506 setup_action_directional_focus_northeast
509 "directionalfocussoutheast",
510 action_directional_focus
,
511 setup_action_directional_focus_southeast
514 "directionalfocussouthwest",
515 action_directional_focus
,
516 setup_action_directional_focus_southwest
519 "directionalfocusnorthwest",
520 action_directional_focus
,
521 setup_action_directional_focus_northwest
545 action_focus_order_to_bottom
,
600 action_toggle_omnipresent
,
605 action_move_relative_horz
,
610 action_move_relative_vert
,
615 action_move_to_center
,
619 "resizerelativehorz",
620 action_resize_relative_horz
,
624 "resizerelativevert",
625 action_resize_relative_vert
,
630 action_move_relative
,
635 action_resize_relative
,
640 action_maximize_full
,
645 action_unmaximize_full
,
649 "togglemaximizefull",
650 action_toggle_maximize_full
,
655 action_maximize_horz
,
660 action_unmaximize_horz
,
664 "togglemaximizehorz",
665 action_toggle_maximize_horz
,
670 action_maximize_vert
,
675 action_unmaximize_vert
,
679 "togglemaximizevert",
680 action_toggle_maximize_vert
,
685 action_toggle_fullscreen
,
690 action_send_to_desktop
,
691 setup_action_send_to_desktop
695 action_send_to_desktop_dir
,
696 setup_action_send_to_desktop_next
699 "sendtodesktopprevious",
700 action_send_to_desktop_dir
,
701 setup_action_send_to_desktop_prev
704 "sendtodesktopright",
705 action_send_to_desktop_dir
,
706 setup_action_send_to_desktop_right
710 action_send_to_desktop_dir
,
711 setup_action_send_to_desktop_left
715 action_send_to_desktop_dir
,
716 setup_action_send_to_desktop_up
720 action_send_to_desktop_dir
,
721 setup_action_send_to_desktop_down
731 setup_action_desktop_next
736 setup_action_desktop_prev
741 setup_action_desktop_right
746 setup_action_desktop_left
751 setup_action_desktop_up
756 setup_action_desktop_down
760 action_toggle_decorations
,
774 "toggledockautohide",
775 action_toggle_dockautohide
,
785 action_send_to_layer
,
786 setup_action_top_layer
791 setup_action_top_layer
795 action_send_to_layer
,
796 setup_action_normal_layer
800 action_send_to_layer
,
801 setup_action_bottom_layer
804 "togglealwaysonbottom",
806 setup_action_bottom_layer
810 action_cycle_windows
,
811 setup_action_cycle_windows_next
815 action_cycle_windows
,
816 setup_action_cycle_windows_previous
821 setup_action_movefromedge_north
826 setup_action_movefromedge_south
831 setup_action_movefromedge_west
836 setup_action_movefromedge_east
841 setup_action_movetoedge_north
846 setup_action_movetoedge_south
851 setup_action_movetoedge_west
856 setup_action_movetoedge_east
861 setup_action_growtoedge_north
866 setup_action_growtoedge_south
871 setup_action_growtoedge_west
876 setup_action_growtoedge_east
886 setup_action_addremove_desktop_last
890 action_remove_desktop
,
891 setup_action_addremove_desktop_last
896 setup_action_addremove_desktop_current
899 "removedesktopcurrent",
900 action_remove_desktop
,
901 setup_action_addremove_desktop_current
910 /* only key bindings can be interactive. thus saith the xor.
911 because of how the mouse is grabbed, mouse events dont even get
912 read during interactive events, so no dice! >:) */
913 #define INTERACTIVE_LIMIT(a, uact) \
914 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
915 a->data.any.interactive = FALSE;
917 ObAction
*action_from_string(const gchar
*name
, ObUserAction uact
)
920 gboolean exist
= FALSE
;
923 for (i
= 0; actionstrings
[i
].name
; i
++)
924 if (!g_ascii_strcasecmp(name
, actionstrings
[i
].name
)) {
926 a
= action_new(actionstrings
[i
].func
);
927 if (actionstrings
[i
].setup
)
928 actionstrings
[i
].setup(&a
, uact
);
930 INTERACTIVE_LIMIT(a
, uact
);
934 g_message(_("Invalid action '%s' requested. No such action exists."),
937 g_message(_("Invalid use of action '%s'. Action will be ignored."),
942 ObAction
*action_parse(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
946 ObAction
*act
= NULL
;
949 if (parse_attr_string("name", node
, &actname
)) {
950 if ((act
= action_from_string(actname
, uact
))) {
951 } else if (act
->func
== action_move_relative_horz
||
952 act
->func
== action_move_relative_vert
||
953 act
->func
== action_resize_relative_horz
||
954 act
->func
== action_resize_relative_vert
) {
955 if ((n
= parse_find_node("delta", node
->xmlChildrenNode
)))
956 act
->data
.relative
.deltax
= parse_int(doc
, n
);
957 } else if (act
->func
== action_move_relative
) {
958 if ((n
= parse_find_node("x", node
->xmlChildrenNode
)))
959 act
->data
.relative
.deltax
= parse_int(doc
, n
);
960 if ((n
= parse_find_node("y", node
->xmlChildrenNode
)))
961 act
->data
.relative
.deltay
= parse_int(doc
, n
);
962 } else if (act
->func
== action_resize_relative
) {
963 if ((n
= parse_find_node("left", node
->xmlChildrenNode
)))
964 act
->data
.relative
.deltaxl
= parse_int(doc
, n
);
965 if ((n
= parse_find_node("up", node
->xmlChildrenNode
)))
966 act
->data
.relative
.deltayu
= parse_int(doc
, n
);
967 if ((n
= parse_find_node("right", node
->xmlChildrenNode
)))
968 act
->data
.relative
.deltax
= parse_int(doc
, n
);
969 if ((n
= parse_find_node("down", node
->xmlChildrenNode
)))
970 act
->data
.relative
.deltay
= parse_int(doc
, n
);
971 } else if (act
->func
== action_desktop
) {
972 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
973 act
->data
.desktop
.desk
= parse_int(doc
, n
);
974 if (act
->data
.desktop
.desk
> 0) act
->data
.desktop
.desk
--;
976 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
977 act->data.desktop.inter.any.interactive =
980 } else if (act
->func
== action_send_to_desktop
) {
981 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
982 act
->data
.sendto
.desk
= parse_int(doc
, n
);
983 if (act
->data
.sendto
.desk
> 0) act
->data
.sendto
.desk
--;
984 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
985 act
->data
.sendto
.follow
= parse_bool(doc
, n
);
986 } else if (act
->func
== action_desktop_dir
) {
987 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
988 act
->data
.desktopdir
.wrap
= parse_bool(doc
, n
);
989 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
990 act
->data
.desktopdir
.inter
.any
.interactive
=
992 } else if (act
->func
== action_send_to_desktop_dir
) {
993 if ((n
= parse_find_node("wrap", node
->xmlChildrenNode
)))
994 act
->data
.sendtodir
.wrap
= parse_bool(doc
, n
);
995 if ((n
= parse_find_node("follow", node
->xmlChildrenNode
)))
996 act
->data
.sendtodir
.follow
= parse_bool(doc
, n
);
997 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
998 act
->data
.sendtodir
.inter
.any
.interactive
=
1000 } else if (act
->func
== action_activate
) {
1001 if ((n
= parse_find_node("here", node
->xmlChildrenNode
)))
1002 act
->data
.activate
.here
= parse_bool(doc
, n
);
1003 } else if (act
->func
== action_cycle_windows
) {
1004 if ((n
= parse_find_node("linear", node
->xmlChildrenNode
)))
1005 act
->data
.cycle
.linear
= parse_bool(doc
, n
);
1006 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1007 act
->data
.cycle
.dialog
= parse_bool(doc
, n
);
1008 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
1009 act
->data
.cycle
.dock_windows
= parse_bool(doc
, n
);
1010 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1011 act
->data
.cycle
.desktop_windows
= parse_bool(doc
, n
);
1012 if ((n
= parse_find_node("allDesktops",
1013 node
->xmlChildrenNode
)))
1014 act
->data
.cycle
.all_desktops
= parse_bool(doc
, n
);
1015 } else if (act
->func
== action_directional_focus
) {
1016 if ((n
= parse_find_node("dialog", node
->xmlChildrenNode
)))
1017 act
->data
.interdiraction
.dialog
= parse_bool(doc
, n
);
1018 if ((n
= parse_find_node("panels", node
->xmlChildrenNode
)))
1019 act
->data
.interdiraction
.dock_windows
= parse_bool(doc
, n
);
1020 if ((n
= parse_find_node("desktop", node
->xmlChildrenNode
)))
1021 act
->data
.interdiraction
.desktop_windows
=
1023 } else if (act
->func
== action_resize
) {
1024 if ((n
= parse_find_node("edge", node
->xmlChildrenNode
))) {
1025 gchar
*s
= parse_string(doc
, n
);
1026 if (!g_ascii_strcasecmp(s
, "top"))
1027 act
->data
.moveresize
.corner
=
1028 prop_atoms
.net_wm_moveresize_size_top
;
1029 else if (!g_ascii_strcasecmp(s
, "bottom"))
1030 act
->data
.moveresize
.corner
=
1031 prop_atoms
.net_wm_moveresize_size_bottom
;
1032 else if (!g_ascii_strcasecmp(s
, "left"))
1033 act
->data
.moveresize
.corner
=
1034 prop_atoms
.net_wm_moveresize_size_left
;
1035 else if (!g_ascii_strcasecmp(s
, "right"))
1036 act
->data
.moveresize
.corner
=
1037 prop_atoms
.net_wm_moveresize_size_right
;
1038 else if (!g_ascii_strcasecmp(s
, "topleft"))
1039 act
->data
.moveresize
.corner
=
1040 prop_atoms
.net_wm_moveresize_size_topleft
;
1041 else if (!g_ascii_strcasecmp(s
, "topright"))
1042 act
->data
.moveresize
.corner
=
1043 prop_atoms
.net_wm_moveresize_size_topright
;
1044 else if (!g_ascii_strcasecmp(s
, "bottomleft"))
1045 act
->data
.moveresize
.corner
=
1046 prop_atoms
.net_wm_moveresize_size_bottomleft
;
1047 else if (!g_ascii_strcasecmp(s
, "bottomright"))
1048 act
->data
.moveresize
.corner
=
1049 prop_atoms
.net_wm_moveresize_size_bottomright
;
1052 } else if (act
->func
== action_raise
||
1053 act
->func
== action_lower
||
1054 act
->func
== action_raiselower
||
1055 act
->func
== action_shadelower
||
1056 act
->func
== action_unshaderaise
) {
1058 INTERACTIVE_LIMIT(act
, uact
);
1065 void action_run_list(GSList
*acts
, ObClient
*c
, ObFrameContext context
,
1066 guint state
, guint button
, gint x
, gint y
, Time time
,
1067 gboolean cancel
, gboolean done
)
1076 screen_pointer_pos(&x
, &y
);
1078 for (it
= acts
; it
; it
= g_slist_next(it
)) {
1081 if (!(a
->data
.any
.client_action
== OB_CLIENT_ACTION_ALWAYS
&& !c
)) {
1082 a
->data
.any
.c
= a
->data
.any
.client_action
? c
: NULL
;
1083 a
->data
.any
.context
= context
;
1087 a
->data
.any
.button
= button
;
1089 a
->data
.any
.time
= time
;
1091 if (a
->data
.any
.interactive
) {
1092 a
->data
.inter
.cancel
= cancel
;
1093 a
->data
.inter
.final
= done
;
1094 if (!(cancel
|| done
))
1095 if (!keyboard_interactive_grab(state
, a
->data
.any
.c
, a
))
1099 /* XXX UGLY HACK race with motion event starting a move and the
1100 button release gettnig processed first. answer: don't queue
1101 moveresize starts. UGLY HACK XXX
1103 XXX ALSO don't queue showmenu events, because on button press
1104 events we need to know if a mouse grab is going to take place,
1105 and set the button to 0, so that later motion events don't think
1106 that a drag is going on. since showmenu grabs the pointer..
1108 if (a
->data
.any
.interactive
|| a
->func
== action_move
||
1109 a
->func
== action_resize
|| a
->func
== action_showmenu
)
1111 /* interactive actions are not queued */
1113 } else if (a
->func
== action_focus
||
1114 a
->func
== action_activate
||
1115 a
->func
== action_showmenu
)
1117 /* XXX MORE UGLY HACK
1118 actions from clicks on client windows are NOT queued.
1119 this solves the mysterious click-and-drag-doesnt-work
1120 problem. it was because the window gets focused and stuff
1121 after the button event has already been passed through. i
1122 dont really know why it should care but it does and it makes
1125 however this very bogus ! !
1126 we want to send the button press to the window BEFORE
1127 we do the action because the action might move the windows
1128 (eg change desktops) and then the button press ends up on
1129 the completely wrong window !
1130 so, this is just for that bug, and it will only NOT queue it
1131 if it is a focusing action that can be used with the mouse
1134 also with the menus, there is a race going on. if the
1135 desktop wants to pop up a menu, and we do too, we send them
1136 the button before we pop up the menu, so they pop up their
1137 menu first. but not always. if we pop up our menu before
1138 sending them the button press, then the result is
1141 XXX further more. focus actions are not queued at all,
1142 because if you bind focus->showmenu, the menu will get
1143 hidden to do the focusing
1147 ob_main_loop_queue_action(ob_main_loop
, a
);
1152 void action_run_string(const gchar
*name
, struct _ObClient
*c
, Time time
)
1157 a
= action_from_string(name
, OB_USER_ACTION_NONE
);
1160 l
= g_slist_append(NULL
, a
);
1162 action_run(l
, c
, 0, time
);
1165 void action_activate(union ActionData
*data
)
1167 if (data
->client
.any
.c
) {
1168 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1169 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1170 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1172 /* if using focus_delay, stop the timer now so that focus doesn't
1174 event_halt_focus_delay();
1176 client_activate(data
->activate
.any
.c
, data
->activate
.here
, TRUE
);
1179 /* focus action on something other than a client, make keybindings
1180 work for this openbox instance, but don't focus any specific client
1186 void action_focus(union ActionData
*data
)
1188 if (data
->client
.any
.c
) {
1189 if (!data
->any
.button
|| client_mouse_focusable(data
->client
.any
.c
) ||
1190 (data
->any
.context
!= OB_FRAME_CONTEXT_CLIENT
&&
1191 data
->any
.context
!= OB_FRAME_CONTEXT_FRAME
))
1193 /* if using focus_delay, stop the timer now so that focus doesn't
1195 event_halt_focus_delay();
1197 client_focus(data
->client
.any
.c
);
1200 /* focus action on something other than a client, make keybindings
1201 work for this openbox instance, but don't focus any specific client
1207 void action_unfocus (union ActionData
*data
)
1209 if (data
->client
.any
.c
== focus_client
)
1210 focus_fallback(FALSE
, FALSE
, TRUE
);
1213 void action_iconify(union ActionData
*data
)
1215 client_action_start(data
);
1216 client_iconify(data
->client
.any
.c
, TRUE
, TRUE
, FALSE
);
1217 client_action_end(data
, config_focus_under_mouse
);
1220 void action_focus_order_to_bottom(union ActionData
*data
)
1222 focus_order_to_bottom(data
->client
.any
.c
);
1225 void action_raiselower(union ActionData
*data
)
1227 ObClient
*c
= data
->client
.any
.c
;
1229 client_action_start(data
);
1230 stacking_restack_request(c
, NULL
, Opposite
);
1231 client_action_end(data
, config_focus_under_mouse
);
1234 void action_raise(union ActionData
*data
)
1236 client_action_start(data
);
1237 stacking_raise(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1238 client_action_end(data
, config_focus_under_mouse
);
1241 void action_unshaderaise(union ActionData
*data
)
1243 if (data
->client
.any
.c
->shaded
)
1244 action_unshade(data
);
1249 void action_shadelower(union ActionData
*data
)
1251 if (data
->client
.any
.c
->shaded
)
1257 void action_lower(union ActionData
*data
)
1259 client_action_start(data
);
1260 stacking_lower(CLIENT_AS_WINDOW(data
->client
.any
.c
));
1261 client_action_end(data
, config_focus_under_mouse
);
1264 void action_close(union ActionData
*data
)
1266 client_close(data
->client
.any
.c
);
1269 void action_kill(union ActionData
*data
)
1271 client_kill(data
->client
.any
.c
);
1274 void action_shade(union ActionData
*data
)
1276 client_action_start(data
);
1277 client_shade(data
->client
.any
.c
, TRUE
);
1278 client_action_end(data
, config_focus_under_mouse
);
1281 void action_unshade(union ActionData
*data
)
1283 client_action_start(data
);
1284 client_shade(data
->client
.any
.c
, FALSE
);
1285 client_action_end(data
, config_focus_under_mouse
);
1288 void action_toggle_shade(union ActionData
*data
)
1290 client_action_start(data
);
1291 client_shade(data
->client
.any
.c
, !data
->client
.any
.c
->shaded
);
1292 client_action_end(data
, config_focus_under_mouse
);
1295 void action_toggle_omnipresent(union ActionData
*data
)
1297 client_set_desktop(data
->client
.any
.c
,
1298 data
->client
.any
.c
->desktop
== DESKTOP_ALL
?
1299 screen_desktop
: DESKTOP_ALL
, FALSE
, TRUE
);
1302 void action_move_relative_horz(union ActionData
*data
)
1304 ObClient
*c
= data
->relative
.any
.c
;
1305 client_action_start(data
);
1306 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
);
1307 client_action_end(data
, FALSE
);
1310 void action_move_relative_vert(union ActionData
*data
)
1312 ObClient
*c
= data
->relative
.any
.c
;
1313 client_action_start(data
);
1314 client_move(c
, c
->area
.x
, c
->area
.y
+ data
->relative
.deltax
);
1315 client_action_end(data
, FALSE
);
1318 void action_move_to_center(union ActionData
*data
)
1320 ObClient
*c
= data
->client
.any
.c
;
1322 area
= screen_area(c
->desktop
, client_monitor(c
), NULL
);
1323 client_action_start(data
);
1324 client_move(c
, area
->x
+ area
->width
/ 2 - c
->area
.width
/ 2,
1325 area
->y
+ area
->height
/ 2 - c
->area
.height
/ 2);
1326 client_action_end(data
, FALSE
);
1330 void action_resize_relative_horz(union ActionData
*data
)
1332 ObClient
*c
= data
->relative
.any
.c
;
1333 client_action_start(data
);
1335 c
->area
.width
+ data
->relative
.deltax
* c
->size_inc
.width
,
1337 client_action_end(data
, FALSE
);
1340 void action_resize_relative_vert(union ActionData
*data
)
1342 ObClient
*c
= data
->relative
.any
.c
;
1344 client_action_start(data
);
1345 client_resize(c
, c
->area
.width
, c
->area
.height
+
1346 data
->relative
.deltax
* c
->size_inc
.height
);
1347 client_action_end(data
, FALSE
);
1351 void action_move_relative(union ActionData
*data
)
1353 ObClient
*c
= data
->relative
.any
.c
;
1354 client_action_start(data
);
1355 client_move(c
, c
->area
.x
+ data
->relative
.deltax
, c
->area
.y
+
1356 data
->relative
.deltay
);
1357 client_action_end(data
, FALSE
);
1360 void action_resize_relative(union ActionData
*data
)
1362 ObClient
*c
= data
->relative
.any
.c
;
1363 gint x
, y
, ow
, xoff
, nw
, oh
, yoff
, nh
, lw
, lh
;
1365 client_action_start(data
);
1370 xoff
= -data
->relative
.deltaxl
* c
->size_inc
.width
;
1371 nw
= ow
+ data
->relative
.deltax
* c
->size_inc
.width
1372 + data
->relative
.deltaxl
* c
->size_inc
.width
;
1373 oh
= c
->area
.height
;
1374 yoff
= -data
->relative
.deltayu
* c
->size_inc
.height
;
1375 nh
= oh
+ data
->relative
.deltay
* c
->size_inc
.height
1376 + data
->relative
.deltayu
* c
->size_inc
.height
;
1378 g_print("deltax %d %d x %d ow %d xoff %d nw %d\n",
1379 data
->relative
.deltax
,
1380 data
->relative
.deltaxl
,
1383 client_try_configure(c
, &x
, &y
, &nw
, &nh
, &lw
, &lh
, TRUE
);
1384 xoff
= xoff
== 0 ? 0 : (xoff
< 0 ? MAX(xoff
, ow
-nw
) : MIN(xoff
, ow
-nw
));
1385 yoff
= yoff
== 0 ? 0 : (yoff
< 0 ? MAX(yoff
, oh
-nh
) : MIN(yoff
, oh
-nh
));
1386 client_move_resize(c
, x
+ xoff
, y
+ yoff
, nw
, nh
);
1387 client_action_end(data
, FALSE
);
1390 void action_maximize_full(union ActionData
*data
)
1392 client_action_start(data
);
1393 client_maximize(data
->client
.any
.c
, TRUE
, 0);
1394 client_action_end(data
, config_focus_under_mouse
);
1397 void action_unmaximize_full(union ActionData
*data
)
1399 client_action_start(data
);
1400 client_maximize(data
->client
.any
.c
, FALSE
, 0);
1401 client_action_end(data
, config_focus_under_mouse
);
1404 void action_toggle_maximize_full(union ActionData
*data
)
1406 client_action_start(data
);
1407 client_maximize(data
->client
.any
.c
,
1408 !(data
->client
.any
.c
->max_horz
||
1409 data
->client
.any
.c
->max_vert
),
1411 client_action_end(data
, config_focus_under_mouse
);
1414 void action_maximize_horz(union ActionData
*data
)
1416 client_action_start(data
);
1417 client_maximize(data
->client
.any
.c
, TRUE
, 1);
1418 client_action_end(data
, config_focus_under_mouse
);
1421 void action_unmaximize_horz(union ActionData
*data
)
1423 client_action_start(data
);
1424 client_maximize(data
->client
.any
.c
, FALSE
, 1);
1425 client_action_end(data
, config_focus_under_mouse
);
1428 void action_toggle_maximize_horz(union ActionData
*data
)
1430 client_action_start(data
);
1431 client_maximize(data
->client
.any
.c
,
1432 !data
->client
.any
.c
->max_horz
, 1);
1433 client_action_end(data
, config_focus_under_mouse
);
1436 void action_maximize_vert(union ActionData
*data
)
1438 client_action_start(data
);
1439 client_maximize(data
->client
.any
.c
, TRUE
, 2);
1440 client_action_end(data
, config_focus_under_mouse
);
1443 void action_unmaximize_vert(union ActionData
*data
)
1445 client_action_start(data
);
1446 client_maximize(data
->client
.any
.c
, FALSE
, 2);
1447 client_action_end(data
, config_focus_under_mouse
);
1450 void action_toggle_maximize_vert(union ActionData
*data
)
1452 client_action_start(data
);
1453 client_maximize(data
->client
.any
.c
,
1454 !data
->client
.any
.c
->max_vert
, 2);
1455 client_action_end(data
, config_focus_under_mouse
);
1458 void action_toggle_fullscreen(union ActionData
*data
)
1460 client_action_start(data
);
1461 client_fullscreen(data
->client
.any
.c
, !(data
->client
.any
.c
->fullscreen
));
1462 client_action_end(data
, config_focus_under_mouse
);
1465 void action_send_to_desktop(union ActionData
*data
)
1467 ObClient
*c
= data
->sendto
.any
.c
;
1469 if (!client_normal(c
)) return;
1471 if (data
->sendto
.desk
< screen_num_desktops
||
1472 data
->sendto
.desk
== DESKTOP_ALL
) {
1473 client_set_desktop(c
, data
->sendto
.desk
, data
->sendto
.follow
, FALSE
);
1474 if (data
->sendto
.follow
&& data
->sendto
.desk
!= screen_desktop
)
1475 screen_set_desktop(data
->sendto
.desk
, TRUE
);
1479 void action_desktop(union ActionData
*data
)
1481 /* XXX add the interactive/dialog option back again once the dialog
1482 has been made to not use grabs */
1483 if (data
->desktop
.desk
< screen_num_desktops
||
1484 data
->desktop
.desk
== DESKTOP_ALL
)
1486 screen_set_desktop(data
->desktop
.desk
, TRUE
);
1487 if (data
->inter
.any
.interactive
)
1488 screen_desktop_popup(data
->desktop
.desk
, TRUE
);
1492 void action_desktop_dir(union ActionData
*data
)
1496 d
= screen_cycle_desktop(data
->desktopdir
.dir
,
1497 data
->desktopdir
.wrap
,
1498 data
->desktopdir
.linear
,
1499 data
->desktopdir
.inter
.any
.interactive
,
1500 data
->desktopdir
.inter
.final
,
1501 data
->desktopdir
.inter
.cancel
);
1502 /* only move the desktop when the action is complete. if we switch
1503 desktops during the interactive action, focus will move but with
1504 NotifyWhileGrabbed and applications don't like that. */
1505 if (!data
->sendtodir
.inter
.any
.interactive
||
1506 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1508 if (d
!= screen_desktop
)
1509 screen_set_desktop(d
, TRUE
);
1513 void action_send_to_desktop_dir(union ActionData
*data
)
1515 ObClient
*c
= data
->sendtodir
.inter
.any
.c
;
1518 if (!client_normal(c
)) return;
1520 d
= screen_cycle_desktop(data
->sendtodir
.dir
, data
->sendtodir
.wrap
,
1521 data
->sendtodir
.linear
,
1522 data
->sendtodir
.inter
.any
.interactive
,
1523 data
->sendtodir
.inter
.final
,
1524 data
->sendtodir
.inter
.cancel
);
1525 /* only move the desktop when the action is complete. if we switch
1526 desktops during the interactive action, focus will move but with
1527 NotifyWhileGrabbed and applications don't like that. */
1528 if (!data
->sendtodir
.inter
.any
.interactive
||
1529 (data
->sendtodir
.inter
.final
&& !data
->sendtodir
.inter
.cancel
))
1531 client_set_desktop(c
, d
, data
->sendtodir
.follow
, FALSE
);
1532 if (data
->sendtodir
.follow
&& d
!= screen_desktop
)
1533 screen_set_desktop(d
, TRUE
);
1537 void action_desktop_last(union ActionData
*data
)
1539 if (screen_last_desktop
< screen_num_desktops
)
1540 screen_set_desktop(screen_last_desktop
, TRUE
);
1543 void action_toggle_decorations(union ActionData
*data
)
1545 ObClient
*c
= data
->client
.any
.c
;
1547 client_action_start(data
);
1548 client_set_undecorated(c
, !c
->undecorated
);
1549 client_action_end(data
, FALSE
);
1552 static guint32
pick_corner(gint x
, gint y
, gint cx
, gint cy
, gint cw
, gint ch
,
1555 /* let's make x and y client relative instead of screen relative */
1557 y
= ch
- (y
- cy
); /* y is inverted, 0 is at the bottom of the window */
1560 #define A -4*X + 7*ch/3
1561 #define B 4*X -15*ch/9
1562 #define C -X/4 + 2*ch/3
1563 #define D X/4 + 5*ch/12
1564 #define E X/4 + ch/3
1565 #define F -X/4 + 7*ch/12
1566 #define G 4*X - 4*ch/3
1567 #define H -4*X + 8*ch/3
1568 #define a (y > 5*ch/9)
1569 #define b (x < 4*cw/9)
1570 #define c (x > 5*cw/9)
1571 #define d (y < 4*ch/9)
1574 Each of these defines (except X which is just there for fun), represents
1575 the equation of a line. The lines they represent are shown in the diagram
1576 below. Checking y against these lines, we are able to choose a region
1577 of the window as shown.
1579 +---------------------A-------|-------|-------B---------------------+
1586 | northwest | A north B | northeast |
1589 C---------------------+----A--+-------+--B----+---------------------D
1590 |CCCCCCC | A B | DDDDDDD|
1591 | CCCCCCCC | A | | B | DDDDDDDD |
1592 | CCCCCCC A B DDDDDDD |
1593 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
1595 | west | b move c | east | ad
1597 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
1598 | EEEEEEE G H FFFFFFF |
1599 | EEEEEEEE | G | | H | FFFFFFFF |
1600 |EEEEEEE | G H | FFFFFFF|
1601 E---------------------+----G--+-------+--H----+---------------------F
1604 | southwest | G south H | southeast |
1611 +---------------------G-------|-------|-------H---------------------+
1615 /* for shaded windows, you can only resize west/east and move */
1617 return prop_atoms
.net_wm_moveresize_size_left
;
1619 return prop_atoms
.net_wm_moveresize_size_right
;
1620 return prop_atoms
.net_wm_moveresize_move
;
1623 if (y
< A
&& y
>= C
)
1624 return prop_atoms
.net_wm_moveresize_size_topleft
;
1625 else if (y
>= A
&& y
>= B
&& a
)
1626 return prop_atoms
.net_wm_moveresize_size_top
;
1627 else if (y
< B
&& y
>= D
)
1628 return prop_atoms
.net_wm_moveresize_size_topright
;
1629 else if (y
< C
&& y
>= E
&& b
)
1630 return prop_atoms
.net_wm_moveresize_size_left
;
1631 else if (y
< D
&& y
>= F
&& c
)
1632 return prop_atoms
.net_wm_moveresize_size_right
;
1633 else if (y
< E
&& y
>= G
)
1634 return prop_atoms
.net_wm_moveresize_size_bottomleft
;
1635 else if (y
< G
&& y
< H
&& d
)
1636 return prop_atoms
.net_wm_moveresize_size_bottom
;
1637 else if (y
>= H
&& y
< F
)
1638 return prop_atoms
.net_wm_moveresize_size_bottomright
;
1640 return prop_atoms
.net_wm_moveresize_move
;
1657 void action_move(union ActionData
*data
)
1659 ObClient
*c
= data
->moveresize
.any
.c
;
1662 if (data
->moveresize
.keyboard
)
1663 corner
= prop_atoms
.net_wm_moveresize_move_keyboard
;
1665 corner
= prop_atoms
.net_wm_moveresize_move
;
1667 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1670 void action_resize(union ActionData
*data
)
1672 ObClient
*c
= data
->moveresize
.any
.c
;
1675 if (data
->moveresize
.keyboard
)
1676 corner
= prop_atoms
.net_wm_moveresize_size_keyboard
;
1677 else if (data
->moveresize
.corner
)
1678 corner
= data
->moveresize
.corner
; /* it was specified in the binding */
1680 corner
= pick_corner(data
->any
.x
, data
->any
.y
,
1681 c
->frame
->area
.x
, c
->frame
->area
.y
,
1682 /* use the client size because the frame
1683 can be differently sized (shaded
1684 windows) and we want this based on the
1686 c
->area
.width
+ c
->frame
->size
.left
+
1687 c
->frame
->size
.right
,
1688 c
->area
.height
+ c
->frame
->size
.top
+
1689 c
->frame
->size
.bottom
, c
->shaded
);
1691 moveresize_start(c
, data
->any
.x
, data
->any
.y
, data
->any
.button
, corner
);
1694 void action_cycle_windows(union ActionData
*data
)
1696 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1698 event_halt_focus_delay();
1700 focus_cycle(data
->cycle
.forward
,
1701 data
->cycle
.all_desktops
,
1702 data
->cycle
.dock_windows
,
1703 data
->cycle
.desktop_windows
,
1704 data
->cycle
.linear
, data
->any
.interactive
,
1706 data
->cycle
.inter
.final
, data
->cycle
.inter
.cancel
);
1709 void action_directional_focus(union ActionData
*data
)
1711 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1713 event_halt_focus_delay();
1715 focus_directional_cycle(data
->interdiraction
.direction
,
1716 data
->interdiraction
.dock_windows
,
1717 data
->interdiraction
.desktop_windows
,
1718 data
->any
.interactive
,
1719 data
->interdiraction
.dialog
,
1720 data
->interdiraction
.inter
.final
,
1721 data
->interdiraction
.inter
.cancel
);
1724 void action_movetoedge(union ActionData
*data
)
1727 ObClient
*c
= data
->diraction
.any
.c
;
1729 x
= c
->frame
->area
.x
;
1730 y
= c
->frame
->area
.y
;
1732 switch(data
->diraction
.direction
) {
1733 case OB_DIRECTION_NORTH
:
1734 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
,
1735 data
->diraction
.hang
)
1736 - (data
->diraction
.hang
? c
->frame
->area
.height
: 0);
1738 case OB_DIRECTION_WEST
:
1739 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
,
1740 data
->diraction
.hang
)
1741 - (data
->diraction
.hang
? c
->frame
->area
.width
: 0);
1743 case OB_DIRECTION_SOUTH
:
1744 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
,
1745 data
->diraction
.hang
)
1746 - (data
->diraction
.hang
? 0 : c
->frame
->area
.height
);
1748 case OB_DIRECTION_EAST
:
1749 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
,
1750 data
->diraction
.hang
)
1751 - (data
->diraction
.hang
? 0 : c
->frame
->area
.width
);
1754 g_assert_not_reached();
1756 frame_frame_gravity(c
->frame
, &x
, &y
, c
->area
.width
, c
->area
.height
);
1757 client_action_start(data
);
1758 client_move(c
, x
, y
);
1759 client_action_end(data
, FALSE
);
1762 void action_growtoedge(union ActionData
*data
)
1764 gint x
, y
, width
, height
, dest
;
1765 ObClient
*c
= data
->diraction
.any
.c
;
1768 a
= screen_area(c
->desktop
, SCREEN_AREA_ALL_MONITORS
, &c
->frame
->area
);
1769 x
= c
->frame
->area
.x
;
1770 y
= c
->frame
->area
.y
;
1771 /* get the unshaded frame's dimensions..if it is shaded */
1772 width
= c
->area
.width
+ c
->frame
->size
.left
+ c
->frame
->size
.right
;
1773 height
= c
->area
.height
+ c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1775 switch(data
->diraction
.direction
) {
1776 case OB_DIRECTION_NORTH
:
1777 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1779 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
, FALSE
);
1781 height
= height
/ 2;
1783 height
= c
->frame
->area
.y
+ height
- dest
;
1787 case OB_DIRECTION_WEST
:
1788 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
, FALSE
);
1792 width
= c
->frame
->area
.x
+ width
- dest
;
1796 case OB_DIRECTION_SOUTH
:
1797 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
1799 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
, FALSE
);
1800 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
1801 height
= c
->frame
->area
.height
/ 2;
1802 y
= a
->y
+ a
->height
- height
;
1804 height
= dest
- c
->frame
->area
.y
;
1805 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1806 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
1808 case OB_DIRECTION_EAST
:
1809 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
, FALSE
);
1810 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
1811 width
= c
->frame
->area
.width
/ 2;
1812 x
= a
->x
+ a
->width
- width
;
1814 width
= dest
- c
->frame
->area
.x
;
1815 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1816 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
1819 g_assert_not_reached();
1821 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
1822 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
1823 frame_frame_gravity(c
->frame
, &x
, &y
, width
, height
);
1824 client_action_start(data
);
1825 client_move_resize(c
, x
, y
, width
, height
);
1826 client_action_end(data
, FALSE
);
1830 void action_send_to_layer(union ActionData
*data
)
1832 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
1835 void action_toggle_layer(union ActionData
*data
)
1837 ObClient
*c
= data
->layer
.any
.c
;
1839 client_action_start(data
);
1840 if (data
->layer
.layer
< 0)
1841 client_set_layer(c
, c
->below
? 0 : -1);
1842 else if (data
->layer
.layer
> 0)
1843 client_set_layer(c
, c
->above
? 0 : 1);
1844 client_action_end(data
, config_focus_under_mouse
);
1847 void action_toggle_dockautohide(union ActionData
*data
)
1849 config_dock_hide
= !config_dock_hide
;
1853 void action_break_chroot(union ActionData
*data
)
1855 /* break out of one chroot */
1856 keyboard_reset_chains(1);
1859 void action_add_desktop(union ActionData
*data
)
1861 client_action_start(data
);
1862 screen_set_num_desktops(screen_num_desktops
+1);
1864 /* move all the clients over */
1865 if (data
->addremovedesktop
.current
) {
1868 for (it
= client_list
; it
; it
= g_list_next(it
)) {
1869 ObClient
*c
= it
->data
;
1870 if (c
->desktop
!= DESKTOP_ALL
&& c
->desktop
>= screen_desktop
)
1871 client_set_desktop(c
, c
->desktop
+1, FALSE
, TRUE
);
1875 client_action_end(data
, config_focus_under_mouse
);
1878 void action_remove_desktop(union ActionData
*data
)
1880 guint rmdesktop
, movedesktop
;
1881 GList
*it
, *stacking_copy
;
1883 if (screen_num_desktops
< 2) return;
1885 client_action_start(data
);
1887 /* what desktop are we removing and moving to? */
1888 if (data
->addremovedesktop
.current
)
1889 rmdesktop
= screen_desktop
;
1891 rmdesktop
= screen_num_desktops
- 1;
1892 if (rmdesktop
< screen_num_desktops
- 1)
1893 movedesktop
= rmdesktop
+ 1;
1895 movedesktop
= rmdesktop
;
1897 /* make a copy of the list cuz we're changing it */
1898 stacking_copy
= g_list_copy(stacking_list
);
1899 for (it
= g_list_last(stacking_copy
); it
; it
= g_list_previous(it
)) {
1900 if (WINDOW_IS_CLIENT(it
->data
)) {
1901 ObClient
*c
= it
->data
;
1902 guint d
= c
->desktop
;
1903 if (d
!= DESKTOP_ALL
&& d
>= movedesktop
) {
1904 client_set_desktop(c
, c
->desktop
- 1, TRUE
, TRUE
);
1905 ob_debug("moving window %s\n", c
->title
);
1907 /* raise all the windows that are on the current desktop which
1909 if ((screen_desktop
== rmdesktop
- 1 ||
1910 screen_desktop
== rmdesktop
) &&
1911 (d
== DESKTOP_ALL
|| d
== screen_desktop
))
1913 stacking_raise(CLIENT_AS_WINDOW(c
));
1914 ob_debug("raising window %s\n", c
->title
);
1919 /* act like we're changing desktops */
1920 if (screen_desktop
< screen_num_desktops
- 1) {
1921 gint d
= screen_desktop
;
1922 screen_desktop
= screen_last_desktop
;
1923 screen_set_desktop(d
, TRUE
);
1924 ob_debug("fake desktop change\n");
1927 screen_set_num_desktops(screen_num_desktops
-1);
1929 client_action_end(data
, config_focus_under_mouse
);