1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 action.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 See the COPYING file for a copy of the GNU General Public License.
23 #include "focus_cycle.h"
24 #include "moveresize.h"
37 #include "startupnotify.h"
47 void (*func
)(union ActionData
*);
48 void (*setup
)(ObAction
**, ObUserAction uact
);
51 static ObAction
*action_new(void (*func
)(union ActionData
*data
))
53 ObAction
*a
= g_new0(ObAction
, 1);
60 void action_ref(ObAction
*a
)
65 void action_unref(ObAction
*a
)
67 if (a
== NULL
) return;
69 if (--a
->ref
> 0) return;
71 /* deal with pointers */
72 if (a
->func
== action_execute
|| a
->func
== action_restart
)
73 g_free(a
->data
.execute
.path
);
74 else if (a
->func
== action_debug
)
75 g_free(a
->data
.debug
.string
);
76 else if (a
->func
== action_showmenu
)
77 g_free(a
->data
.showmenu
.name
);
82 ObAction
* action_copy(const ObAction
*src
)
84 ObAction
*a
= action_new(src
->func
);
88 /* deal with pointers */
89 if (a
->func
== action_execute
|| a
->func
== action_restart
)
90 a
->data
.execute
.path
= g_strdup(a
->data
.execute
.path
);
91 else if (a
->func
== action_debug
)
92 a
->data
.debug
.string
= g_strdup(a
->data
.debug
.string
);
93 else if (a
->func
== action_showmenu
)
94 a
->data
.showmenu
.name
= g_strdup(a
->data
.showmenu
.name
);
99 void setup_action_send_to_desktop_prev(ObAction
**a
, ObUserAction uact
)
101 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
102 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
103 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
104 (*a
)->data
.sendtodir
.linear
= TRUE
;
105 (*a
)->data
.sendtodir
.wrap
= TRUE
;
106 (*a
)->data
.sendtodir
.follow
= TRUE
;
109 void setup_action_send_to_desktop_next(ObAction
**a
, ObUserAction uact
)
111 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
112 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
113 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
114 (*a
)->data
.sendtodir
.linear
= TRUE
;
115 (*a
)->data
.sendtodir
.wrap
= TRUE
;
116 (*a
)->data
.sendtodir
.follow
= TRUE
;
119 void setup_action_send_to_desktop_left(ObAction
**a
, ObUserAction uact
)
121 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
122 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
123 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_WEST
;
124 (*a
)->data
.sendtodir
.linear
= FALSE
;
125 (*a
)->data
.sendtodir
.wrap
= TRUE
;
126 (*a
)->data
.sendtodir
.follow
= TRUE
;
129 void setup_action_send_to_desktop_right(ObAction
**a
, ObUserAction uact
)
131 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
132 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
133 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_EAST
;
134 (*a
)->data
.sendtodir
.linear
= FALSE
;
135 (*a
)->data
.sendtodir
.wrap
= TRUE
;
136 (*a
)->data
.sendtodir
.follow
= TRUE
;
139 void setup_action_send_to_desktop_up(ObAction
**a
, ObUserAction uact
)
141 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
142 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
143 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_NORTH
;
144 (*a
)->data
.sendtodir
.linear
= FALSE
;
145 (*a
)->data
.sendtodir
.wrap
= TRUE
;
146 (*a
)->data
.sendtodir
.follow
= TRUE
;
149 void setup_action_send_to_desktop_down(ObAction
**a
, ObUserAction uact
)
151 (*a
)->data
.sendtodir
.inter
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
152 (*a
)->data
.sendtodir
.inter
.any
.interactive
= TRUE
;
153 (*a
)->data
.sendtodir
.dir
= OB_DIRECTION_SOUTH
;
154 (*a
)->data
.sendtodir
.linear
= FALSE
;
155 (*a
)->data
.sendtodir
.wrap
= TRUE
;
156 (*a
)->data
.sendtodir
.follow
= TRUE
;
159 void setup_action_desktop_prev(ObAction
**a
, ObUserAction uact
)
161 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
162 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
163 (*a
)->data
.desktopdir
.linear
= TRUE
;
164 (*a
)->data
.desktopdir
.wrap
= TRUE
;
167 void setup_action_desktop_next(ObAction
**a
, ObUserAction uact
)
169 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
170 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
171 (*a
)->data
.desktopdir
.linear
= TRUE
;
172 (*a
)->data
.desktopdir
.wrap
= TRUE
;
175 void setup_action_desktop_left(ObAction
**a
, ObUserAction uact
)
177 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
178 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_WEST
;
179 (*a
)->data
.desktopdir
.linear
= FALSE
;
180 (*a
)->data
.desktopdir
.wrap
= TRUE
;
183 void setup_action_desktop_right(ObAction
**a
, ObUserAction uact
)
185 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
186 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_EAST
;
187 (*a
)->data
.desktopdir
.linear
= FALSE
;
188 (*a
)->data
.desktopdir
.wrap
= TRUE
;
191 void setup_action_desktop_up(ObAction
**a
, ObUserAction uact
)
193 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
194 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_NORTH
;
195 (*a
)->data
.desktopdir
.linear
= FALSE
;
196 (*a
)->data
.desktopdir
.wrap
= TRUE
;
199 void setup_action_desktop_down(ObAction
**a
, ObUserAction uact
)
201 (*a
)->data
.desktopdir
.inter
.any
.interactive
= TRUE
;
202 (*a
)->data
.desktopdir
.dir
= OB_DIRECTION_SOUTH
;
203 (*a
)->data
.desktopdir
.linear
= FALSE
;
204 (*a
)->data
.desktopdir
.wrap
= TRUE
;
207 void setup_action_movefromedge_north(ObAction
**a
, ObUserAction uact
)
209 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
210 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
211 (*a
)->data
.diraction
.hang
= TRUE
;
214 void setup_action_movefromedge_south(ObAction
**a
, ObUserAction uact
)
216 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
217 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
218 (*a
)->data
.diraction
.hang
= TRUE
;
221 void setup_action_movefromedge_east(ObAction
**a
, ObUserAction uact
)
223 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
224 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
225 (*a
)->data
.diraction
.hang
= TRUE
;
228 void setup_action_movefromedge_west(ObAction
**a
, ObUserAction uact
)
230 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
231 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
232 (*a
)->data
.diraction
.hang
= TRUE
;
235 void setup_action_movetoedge_north(ObAction
**a
, ObUserAction uact
)
237 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
238 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
239 (*a
)->data
.diraction
.hang
= FALSE
;
242 void setup_action_movetoedge_south(ObAction
**a
, ObUserAction uact
)
244 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
245 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
246 (*a
)->data
.diraction
.hang
= FALSE
;
249 void setup_action_movetoedge_east(ObAction
**a
, ObUserAction uact
)
251 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
252 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
253 (*a
)->data
.diraction
.hang
= FALSE
;
256 void setup_action_movetoedge_west(ObAction
**a
, ObUserAction uact
)
258 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
259 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
260 (*a
)->data
.diraction
.hang
= FALSE
;
263 void setup_action_growtoedge_north(ObAction
**a
, ObUserAction uact
)
265 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
266 (*a
)->data
.diraction
.direction
= OB_DIRECTION_NORTH
;
269 void setup_action_growtoedge_south(ObAction
**a
, ObUserAction uact
)
271 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
272 (*a
)->data
.diraction
.direction
= OB_DIRECTION_SOUTH
;
275 void setup_action_growtoedge_east(ObAction
**a
, ObUserAction uact
)
277 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
278 (*a
)->data
.diraction
.direction
= OB_DIRECTION_EAST
;
281 void setup_action_growtoedge_west(ObAction
**a
, ObUserAction uact
)
283 (*a
)->data
.diraction
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
284 (*a
)->data
.diraction
.direction
= OB_DIRECTION_WEST
;
287 void setup_action_top_layer(ObAction
**a
, ObUserAction uact
)
289 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
290 (*a
)->data
.layer
.layer
= 1;
293 void setup_action_normal_layer(ObAction
**a
, ObUserAction uact
)
295 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
296 (*a
)->data
.layer
.layer
= 0;
299 void setup_action_bottom_layer(ObAction
**a
, ObUserAction uact
)
301 (*a
)->data
.layer
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
302 (*a
)->data
.layer
.layer
= -1;
305 void setup_client_action(ObAction
**a
, ObUserAction uact
)
307 (*a
)->data
.any
.client_action
= OB_CLIENT_ACTION_ALWAYS
;
310 ActionString actionstrings
[] =
324 action_send_to_desktop_dir
,
325 setup_action_send_to_desktop_next
328 "sendtodesktopprevious",
329 action_send_to_desktop_dir
,
330 setup_action_send_to_desktop_prev
333 "sendtodesktopright",
334 action_send_to_desktop_dir
,
335 setup_action_send_to_desktop_right
339 action_send_to_desktop_dir
,
340 setup_action_send_to_desktop_left
344 action_send_to_desktop_dir
,
345 setup_action_send_to_desktop_up
349 action_send_to_desktop_dir
,
350 setup_action_send_to_desktop_down
353 "toggledockautohide",
354 action_toggle_dockautohide
,
359 action_send_to_layer
,
360 setup_action_top_layer
365 setup_action_top_layer
369 action_send_to_layer
,
370 setup_action_normal_layer
374 action_send_to_layer
,
375 setup_action_bottom_layer
378 "togglealwaysonbottom",
380 setup_action_bottom_layer
385 setup_action_movefromedge_north
390 setup_action_movefromedge_south
395 setup_action_movefromedge_west
400 setup_action_movefromedge_east
405 setup_action_movetoedge_north
410 setup_action_movetoedge_south
415 setup_action_movetoedge_west
420 setup_action_movetoedge_east
425 setup_action_growtoedge_north
430 setup_action_growtoedge_south
435 setup_action_growtoedge_west
440 setup_action_growtoedge_east
449 void action_unshaderaise(union ActionData
*data
)
451 if (data
->client
.any
.c
->shaded
)
452 action_unshade(data
);
457 void action_shadelower(union ActionData
*data
)
459 if (data
->client
.any
.c
->shaded
)
465 void action_movetoedge(union ActionData
*data
)
468 ObClient
*c
= data
->diraction
.any
.c
;
470 x
= c
->frame
->area
.x
;
471 y
= c
->frame
->area
.y
;
473 switch(data
->diraction
.direction
) {
474 case OB_DIRECTION_NORTH
:
475 y
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
,
476 data
->diraction
.hang
)
477 - (data
->diraction
.hang
? c
->frame
->area
.height
: 0);
479 case OB_DIRECTION_WEST
:
480 x
= client_directional_edge_search(c
, OB_DIRECTION_WEST
,
481 data
->diraction
.hang
)
482 - (data
->diraction
.hang
? c
->frame
->area
.width
: 0);
484 case OB_DIRECTION_SOUTH
:
485 y
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
,
486 data
->diraction
.hang
)
487 - (data
->diraction
.hang
? 0 : c
->frame
->area
.height
);
489 case OB_DIRECTION_EAST
:
490 x
= client_directional_edge_search(c
, OB_DIRECTION_EAST
,
491 data
->diraction
.hang
)
492 - (data
->diraction
.hang
? 0 : c
->frame
->area
.width
);
495 g_assert_not_reached();
497 frame_frame_gravity(c
->frame
, &x
, &y
, c
->area
.width
, c
->area
.height
);
498 client_action_start(data
);
499 client_move(c
, x
, y
);
500 client_action_end(data
, FALSE
);
503 void action_growtoedge(union ActionData
*data
)
505 gint x
, y
, width
, height
, dest
;
506 ObClient
*c
= data
->diraction
.any
.c
;
509 a
= screen_area(c
->desktop
, SCREEN_AREA_ALL_MONITORS
, &c
->frame
->area
);
510 x
= c
->frame
->area
.x
;
511 y
= c
->frame
->area
.y
;
512 /* get the unshaded frame's dimensions..if it is shaded */
513 width
= c
->area
.width
+ c
->frame
->size
.left
+ c
->frame
->size
.right
;
514 height
= c
->area
.height
+ c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
516 switch(data
->diraction
.direction
) {
517 case OB_DIRECTION_NORTH
:
518 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
520 dest
= client_directional_edge_search(c
, OB_DIRECTION_NORTH
, FALSE
);
524 height
= c
->frame
->area
.y
+ height
- dest
;
528 case OB_DIRECTION_WEST
:
529 dest
= client_directional_edge_search(c
, OB_DIRECTION_WEST
, FALSE
);
533 width
= c
->frame
->area
.x
+ width
- dest
;
537 case OB_DIRECTION_SOUTH
:
538 if (c
->shaded
) break; /* don't allow vertical resize if shaded */
540 dest
= client_directional_edge_search(c
, OB_DIRECTION_SOUTH
, FALSE
);
541 if (a
->y
+ a
->height
== y
+ c
->frame
->area
.height
) {
542 height
= c
->frame
->area
.height
/ 2;
543 y
= a
->y
+ a
->height
- height
;
545 height
= dest
- c
->frame
->area
.y
;
546 y
+= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
547 height
-= (height
- c
->frame
->area
.height
) % c
->size_inc
.height
;
549 case OB_DIRECTION_EAST
:
550 dest
= client_directional_edge_search(c
, OB_DIRECTION_EAST
, FALSE
);
551 if (a
->x
+ a
->width
== x
+ c
->frame
->area
.width
) {
552 width
= c
->frame
->area
.width
/ 2;
553 x
= a
->x
+ a
->width
- width
;
555 width
= dest
- c
->frame
->area
.x
;
556 x
+= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
557 width
-= (width
- c
->frame
->area
.width
) % c
->size_inc
.width
;
560 g_assert_not_reached();
562 width
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
563 height
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
564 frame_frame_gravity(c
->frame
, &x
, &y
, width
, height
);
565 client_action_start(data
);
566 client_move_resize(c
, x
, y
, width
, height
);
567 client_action_end(data
, FALSE
);
571 void action_send_to_layer(union ActionData
*data
)
573 client_set_layer(data
->layer
.any
.c
, data
->layer
.layer
);
576 void action_toggle_layer(union ActionData
*data
)
578 ObClient
*c
= data
->layer
.any
.c
;
580 client_action_start(data
);
581 if (data
->layer
.layer
< 0)
582 client_set_layer(c
, c
->below
? 0 : -1);
583 else if (data
->layer
.layer
> 0)
584 client_set_layer(c
, c
->above
? 0 : 1);
585 client_action_end(data
, config_focus_under_mouse
);
588 void action_toggle_dockautohide(union ActionData
*data
)
590 config_dock_hide
= !config_dock_hide
;
594 void action_remove_desktop(union ActionData
*data
)