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)