]> Dogcows Code - chaz/openbox/blob - openbox/action.c
add the adddesktop and removedesktop actions
[chaz/openbox] / openbox / action.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3 action.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
6
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.
11
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.
16
17 See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include "debug.h"
21 #include "client.h"
22 #include "focus.h"
23 #include "focus_cycle.h"
24 #include "moveresize.h"
25 #include "menu.h"
26 #include "prop.h"
27 #include "stacking.h"
28 #include "screen.h"
29 #include "action.h"
30 #include "openbox.h"
31 #include "grab.h"
32 #include "keyboard.h"
33 #include "event.h"
34 #include "dock.h"
35 #include "config.h"
36 #include "mainloop.h"
37 #include "startupnotify.h"
38 #include "gettext.h"
39
40 #include <glib.h>
41
42
43
44 typedef struct
45 {
46 const gchar *name;
47 void (*func)(union ActionData *);
48 void (*setup)(ObAction **, ObUserAction uact);
49 } ActionString;
50
51 static ObAction *action_new(void (*func)(union ActionData *data))
52 {
53 ObAction *a = g_new0(ObAction, 1);
54 a->ref = 1;
55 a->func = func;
56
57 return a;
58 }
59
60 void action_ref(ObAction *a)
61 {
62 ++a->ref;
63 }
64
65 void action_unref(ObAction *a)
66 {
67 if (a == NULL) return;
68
69 if (--a->ref > 0) return;
70
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);
78
79 g_free(a);
80 }
81
82 ObAction* action_copy(const ObAction *src)
83 {
84 ObAction *a = action_new(src->func);
85
86 a->data = src->data;
87
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);
95
96 return a;
97 }
98
99 void setup_action_send_to_desktop_prev(ObAction **a, ObUserAction uact)
100 {
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;
107 }
108
109 void setup_action_send_to_desktop_next(ObAction **a, ObUserAction uact)
110 {
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;
117 }
118
119 void setup_action_send_to_desktop_left(ObAction **a, ObUserAction uact)
120 {
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;
127 }
128
129 void setup_action_send_to_desktop_right(ObAction **a, ObUserAction uact)
130 {
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;
137 }
138
139 void setup_action_send_to_desktop_up(ObAction **a, ObUserAction uact)
140 {
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;
147 }
148
149 void setup_action_send_to_desktop_down(ObAction **a, ObUserAction uact)
150 {
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;
157 }
158
159 void setup_action_desktop_prev(ObAction **a, ObUserAction uact)
160 {
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;
165 }
166
167 void setup_action_desktop_next(ObAction **a, ObUserAction uact)
168 {
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;
173 }
174
175 void setup_action_desktop_left(ObAction **a, ObUserAction uact)
176 {
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;
181 }
182
183 void setup_action_desktop_right(ObAction **a, ObUserAction uact)
184 {
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;
189 }
190
191 void setup_action_desktop_up(ObAction **a, ObUserAction uact)
192 {
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;
197 }
198
199 void setup_action_desktop_down(ObAction **a, ObUserAction uact)
200 {
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;
205 }
206
207 void setup_action_movefromedge_north(ObAction **a, ObUserAction uact)
208 {
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;
212 }
213
214 void setup_action_movefromedge_south(ObAction **a, ObUserAction uact)
215 {
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;
219 }
220
221 void setup_action_movefromedge_east(ObAction **a, ObUserAction uact)
222 {
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;
226 }
227
228 void setup_action_movefromedge_west(ObAction **a, ObUserAction uact)
229 {
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;
233 }
234
235 void setup_action_movetoedge_north(ObAction **a, ObUserAction uact)
236 {
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;
240 }
241
242 void setup_action_movetoedge_south(ObAction **a, ObUserAction uact)
243 {
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;
247 }
248
249 void setup_action_movetoedge_east(ObAction **a, ObUserAction uact)
250 {
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;
254 }
255
256 void setup_action_movetoedge_west(ObAction **a, ObUserAction uact)
257 {
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;
261 }
262
263 void setup_action_growtoedge_north(ObAction **a, ObUserAction uact)
264 {
265 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
266 (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
267 }
268
269 void setup_action_growtoedge_south(ObAction **a, ObUserAction uact)
270 {
271 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
272 (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
273 }
274
275 void setup_action_growtoedge_east(ObAction **a, ObUserAction uact)
276 {
277 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
278 (*a)->data.diraction.direction = OB_DIRECTION_EAST;
279 }
280
281 void setup_action_growtoedge_west(ObAction **a, ObUserAction uact)
282 {
283 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
284 (*a)->data.diraction.direction = OB_DIRECTION_WEST;
285 }
286
287 void setup_action_top_layer(ObAction **a, ObUserAction uact)
288 {
289 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
290 (*a)->data.layer.layer = 1;
291 }
292
293 void setup_action_normal_layer(ObAction **a, ObUserAction uact)
294 {
295 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
296 (*a)->data.layer.layer = 0;
297 }
298
299 void setup_action_bottom_layer(ObAction **a, ObUserAction uact)
300 {
301 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
302 (*a)->data.layer.layer = -1;
303 }
304
305 void setup_client_action(ObAction **a, ObUserAction uact)
306 {
307 (*a)->data.any.client_action = OB_CLIENT_ACTION_ALWAYS;
308 }
309
310 ActionString actionstrings[] =
311 {
312 {
313 "shadelower",
314 action_shadelower,
315 setup_client_action
316 },
317 {
318 "unshaderaise",
319 action_unshaderaise,
320 setup_client_action
321 },
322 {
323 "sendtodesktopnext",
324 action_send_to_desktop_dir,
325 setup_action_send_to_desktop_next
326 },
327 {
328 "sendtodesktopprevious",
329 action_send_to_desktop_dir,
330 setup_action_send_to_desktop_prev
331 },
332 {
333 "sendtodesktopright",
334 action_send_to_desktop_dir,
335 setup_action_send_to_desktop_right
336 },
337 {
338 "sendtodesktopleft",
339 action_send_to_desktop_dir,
340 setup_action_send_to_desktop_left
341 },
342 {
343 "sendtodesktopup",
344 action_send_to_desktop_dir,
345 setup_action_send_to_desktop_up
346 },
347 {
348 "sendtodesktopdown",
349 action_send_to_desktop_dir,
350 setup_action_send_to_desktop_down
351 },
352 {
353 "toggledockautohide",
354 action_toggle_dockautohide,
355 NULL
356 },
357 {
358 "sendtotoplayer",
359 action_send_to_layer,
360 setup_action_top_layer
361 },
362 {
363 "togglealwaysontop",
364 action_toggle_layer,
365 setup_action_top_layer
366 },
367 {
368 "sendtonormallayer",
369 action_send_to_layer,
370 setup_action_normal_layer
371 },
372 {
373 "sendtobottomlayer",
374 action_send_to_layer,
375 setup_action_bottom_layer
376 },
377 {
378 "togglealwaysonbottom",
379 action_toggle_layer,
380 setup_action_bottom_layer
381 },
382 {
383 "movefromedgenorth",
384 action_movetoedge,
385 setup_action_movefromedge_north
386 },
387 {
388 "movefromedgesouth",
389 action_movetoedge,
390 setup_action_movefromedge_south
391 },
392 {
393 "movefromedgewest",
394 action_movetoedge,
395 setup_action_movefromedge_west
396 },
397 {
398 "movefromedgeeast",
399 action_movetoedge,
400 setup_action_movefromedge_east
401 },
402 {
403 "movetoedgenorth",
404 action_movetoedge,
405 setup_action_movetoedge_north
406 },
407 {
408 "movetoedgesouth",
409 action_movetoedge,
410 setup_action_movetoedge_south
411 },
412 {
413 "movetoedgewest",
414 action_movetoedge,
415 setup_action_movetoedge_west
416 },
417 {
418 "movetoedgeeast",
419 action_movetoedge,
420 setup_action_movetoedge_east
421 },
422 {
423 "growtoedgenorth",
424 action_growtoedge,
425 setup_action_growtoedge_north
426 },
427 {
428 "growtoedgesouth",
429 action_growtoedge,
430 setup_action_growtoedge_south
431 },
432 {
433 "growtoedgewest",
434 action_growtoedge,
435 setup_action_growtoedge_west
436 },
437 {
438 "growtoedgeeast",
439 action_growtoedge,
440 setup_action_growtoedge_east
441 },
442 {
443 NULL,
444 NULL,
445 NULL
446 }
447 };
448
449 void action_unshaderaise(union ActionData *data)
450 {
451 if (data->client.any.c->shaded)
452 action_unshade(data);
453 else
454 action_raise(data);
455 }
456
457 void action_shadelower(union ActionData *data)
458 {
459 if (data->client.any.c->shaded)
460 action_lower(data);
461 else
462 action_shade(data);
463 }
464
465 void action_movetoedge(union ActionData *data)
466 {
467 gint x, y;
468 ObClient *c = data->diraction.any.c;
469
470 x = c->frame->area.x;
471 y = c->frame->area.y;
472
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);
478 break;
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);
483 break;
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);
488 break;
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);
493 break;
494 default:
495 g_assert_not_reached();
496 }
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);
501 }
502
503 void action_growtoedge(union ActionData *data)
504 {
505 gint x, y, width, height, dest;
506 ObClient *c = data->diraction.any.c;
507 Rect *a;
508
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;
515
516 switch(data->diraction.direction) {
517 case OB_DIRECTION_NORTH:
518 if (c->shaded) break; /* don't allow vertical resize if shaded */
519
520 dest = client_directional_edge_search(c, OB_DIRECTION_NORTH, FALSE);
521 if (a->y == y)
522 height = height / 2;
523 else {
524 height = c->frame->area.y + height - dest;
525 y = dest;
526 }
527 break;
528 case OB_DIRECTION_WEST:
529 dest = client_directional_edge_search(c, OB_DIRECTION_WEST, FALSE);
530 if (a->x == x)
531 width = width / 2;
532 else {
533 width = c->frame->area.x + width - dest;
534 x = dest;
535 }
536 break;
537 case OB_DIRECTION_SOUTH:
538 if (c->shaded) break; /* don't allow vertical resize if shaded */
539
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;
544 } else
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;
548 break;
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;
554 } else
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;
558 break;
559 default:
560 g_assert_not_reached();
561 }
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);
568 g_free(a);
569 }
570
571 void action_send_to_layer(union ActionData *data)
572 {
573 client_set_layer(data->layer.any.c, data->layer.layer);
574 }
575
576 void action_toggle_layer(union ActionData *data)
577 {
578 ObClient *c = data->layer.any.c;
579
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);
586 }
587
588 void action_toggle_dockautohide(union ActionData *data)
589 {
590 config_dock_hide = !config_dock_hide;
591 dock_configure();
592 }
593
594 void action_remove_desktop(union ActionData *data)
595 {
596 }
This page took 0.05925 seconds and 4 git commands to generate.