]> Dogcows Code - chaz/openbox/blob - openbox/action.c
8e717e65f18104b8e8d8738f5419623c868217e5
[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_action_addremove_desktop_current(ObAction **a, ObUserAction uact)
306 {
307 (*a)->data.addremovedesktop.current = TRUE;
308 }
309
310 void setup_action_addremove_desktop_last(ObAction **a, ObUserAction uact)
311 {
312 (*a)->data.addremovedesktop.current = FALSE;
313 }
314
315 void setup_client_action(ObAction **a, ObUserAction uact)
316 {
317 (*a)->data.any.client_action = OB_CLIENT_ACTION_ALWAYS;
318 }
319
320 ActionString actionstrings[] =
321 {
322 {
323 "shadelower",
324 action_shadelower,
325 setup_client_action
326 },
327 {
328 "unshaderaise",
329 action_unshaderaise,
330 setup_client_action
331 },
332 {
333 "sendtodesktopnext",
334 action_send_to_desktop_dir,
335 setup_action_send_to_desktop_next
336 },
337 {
338 "sendtodesktopprevious",
339 action_send_to_desktop_dir,
340 setup_action_send_to_desktop_prev
341 },
342 {
343 "sendtodesktopright",
344 action_send_to_desktop_dir,
345 setup_action_send_to_desktop_right
346 },
347 {
348 "sendtodesktopleft",
349 action_send_to_desktop_dir,
350 setup_action_send_to_desktop_left
351 },
352 {
353 "sendtodesktopup",
354 action_send_to_desktop_dir,
355 setup_action_send_to_desktop_up
356 },
357 {
358 "sendtodesktopdown",
359 action_send_to_desktop_dir,
360 setup_action_send_to_desktop_down
361 },
362 {
363 "toggledockautohide",
364 action_toggle_dockautohide,
365 NULL
366 },
367 {
368 "sendtotoplayer",
369 action_send_to_layer,
370 setup_action_top_layer
371 },
372 {
373 "togglealwaysontop",
374 action_toggle_layer,
375 setup_action_top_layer
376 },
377 {
378 "sendtonormallayer",
379 action_send_to_layer,
380 setup_action_normal_layer
381 },
382 {
383 "sendtobottomlayer",
384 action_send_to_layer,
385 setup_action_bottom_layer
386 },
387 {
388 "togglealwaysonbottom",
389 action_toggle_layer,
390 setup_action_bottom_layer
391 },
392 {
393 "movefromedgenorth",
394 action_movetoedge,
395 setup_action_movefromedge_north
396 },
397 {
398 "movefromedgesouth",
399 action_movetoedge,
400 setup_action_movefromedge_south
401 },
402 {
403 "movefromedgewest",
404 action_movetoedge,
405 setup_action_movefromedge_west
406 },
407 {
408 "movefromedgeeast",
409 action_movetoedge,
410 setup_action_movefromedge_east
411 },
412 {
413 "movetoedgenorth",
414 action_movetoedge,
415 setup_action_movetoedge_north
416 },
417 {
418 "movetoedgesouth",
419 action_movetoedge,
420 setup_action_movetoedge_south
421 },
422 {
423 "movetoedgewest",
424 action_movetoedge,
425 setup_action_movetoedge_west
426 },
427 {
428 "movetoedgeeast",
429 action_movetoedge,
430 setup_action_movetoedge_east
431 },
432 {
433 "growtoedgenorth",
434 action_growtoedge,
435 setup_action_growtoedge_north
436 },
437 {
438 "growtoedgesouth",
439 action_growtoedge,
440 setup_action_growtoedge_south
441 },
442 {
443 "growtoedgewest",
444 action_growtoedge,
445 setup_action_growtoedge_west
446 },
447 {
448 "growtoedgeeast",
449 action_growtoedge,
450 setup_action_growtoedge_east
451 },
452 {
453 "adddesktoplast",
454 action_add_desktop,
455 setup_action_addremove_desktop_last
456 },
457 {
458 "removedesktoplast",
459 action_remove_desktop,
460 setup_action_addremove_desktop_last
461 },
462 {
463 "adddesktopcurrent",
464 action_add_desktop,
465 setup_action_addremove_desktop_current
466 },
467 {
468 "removedesktopcurrent",
469 action_remove_desktop,
470 setup_action_addremove_desktop_current
471 },
472 {
473 NULL,
474 NULL,
475 NULL
476 }
477 };
478
479 /* only key bindings can be interactive. thus saith the xor.
480 because of how the mouse is grabbed, mouse events dont even get
481 read during interactive events, so no dice! >:) */
482 #define INTERACTIVE_LIMIT(a, uact) \
483 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
484 a->data.any.interactive = FALSE;
485
486 ObAction *action_from_string(const gchar *name, ObUserAction uact)
487 {
488 ObAction *a = NULL;
489 gboolean exist = FALSE;
490 gint i;
491
492 for (i = 0; actionstrings[i].name; i++)
493 if (!g_ascii_strcasecmp(name, actionstrings[i].name)) {
494 exist = TRUE;
495 a = action_new(actionstrings[i].func);
496 if (actionstrings[i].setup)
497 actionstrings[i].setup(&a, uact);
498 if (a)
499 INTERACTIVE_LIMIT(a, uact);
500 break;
501 }
502 if (!exist)
503 g_message(_("Invalid action '%s' requested. No such action exists."),
504 name);
505 if (!a)
506 g_message(_("Invalid use of action '%s'. Action will be ignored."),
507 name);
508 return a;
509 }
510
511 ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
512 ObUserAction uact)
513 {
514 gchar *actname;
515 ObAction *act = NULL;
516 xmlNodePtr n;
517
518 if (parse_attr_string("name", node, &actname)) {
519 if ((act = action_from_string(actname, uact))) {
520 } else if (act->func == action_desktop) {
521 } else if (act->func == action_send_to_desktop_dir) {
522 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
523 act->data.sendtodir.wrap = parse_bool(doc, n);
524 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
525 act->data.sendtodir.follow = parse_bool(doc, n);
526 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
527 act->data.sendtodir.inter.any.interactive =
528 parse_bool(doc, n);
529 INTERACTIVE_LIMIT(act, uact);
530 }
531 g_free(actname);
532 }
533 return act;
534 }
535
536
537 void action_unshaderaise(union ActionData *data)
538 {
539 if (data->client.any.c->shaded)
540 action_unshade(data);
541 else
542 action_raise(data);
543 }
544
545 void action_shadelower(union ActionData *data)
546 {
547 if (data->client.any.c->shaded)
548 action_lower(data);
549 else
550 action_shade(data);
551 }
552
553 void action_send_to_desktop_dir(union ActionData *data)
554 {
555 ObClient *c = data->sendtodir.inter.any.c;
556 guint d;
557
558 if (!client_normal(c)) return;
559
560 d = screen_cycle_desktop(data->sendtodir.dir, data->sendtodir.wrap,
561 data->sendtodir.linear,
562 data->sendtodir.inter.any.interactive,
563 data->sendtodir.inter.final,
564 data->sendtodir.inter.cancel);
565 /* only move the desktop when the action is complete. if we switch
566 desktops during the interactive action, focus will move but with
567 NotifyWhileGrabbed and applications don't like that. */
568 if (!data->sendtodir.inter.any.interactive ||
569 (data->sendtodir.inter.final && !data->sendtodir.inter.cancel))
570 {
571 client_set_desktop(c, d, data->sendtodir.follow, FALSE);
572 if (data->sendtodir.follow && d != screen_desktop)
573 screen_set_desktop(d, TRUE);
574 }
575 }
576
577 void action_directional_focus(union ActionData *data)
578 {
579 /* if using focus_delay, stop the timer now so that focus doesn't go moving
580 on us */
581 event_halt_focus_delay();
582
583 focus_directional_cycle(data->interdiraction.direction,
584 data->interdiraction.dock_windows,
585 data->interdiraction.desktop_windows,
586 data->any.interactive,
587 data->interdiraction.dialog,
588 data->interdiraction.inter.final,
589 data->interdiraction.inter.cancel);
590 }
591
592 void action_movetoedge(union ActionData *data)
593 {
594 gint x, y;
595 ObClient *c = data->diraction.any.c;
596
597 x = c->frame->area.x;
598 y = c->frame->area.y;
599
600 switch(data->diraction.direction) {
601 case OB_DIRECTION_NORTH:
602 y = client_directional_edge_search(c, OB_DIRECTION_NORTH,
603 data->diraction.hang)
604 - (data->diraction.hang ? c->frame->area.height : 0);
605 break;
606 case OB_DIRECTION_WEST:
607 x = client_directional_edge_search(c, OB_DIRECTION_WEST,
608 data->diraction.hang)
609 - (data->diraction.hang ? c->frame->area.width : 0);
610 break;
611 case OB_DIRECTION_SOUTH:
612 y = client_directional_edge_search(c, OB_DIRECTION_SOUTH,
613 data->diraction.hang)
614 - (data->diraction.hang ? 0 : c->frame->area.height);
615 break;
616 case OB_DIRECTION_EAST:
617 x = client_directional_edge_search(c, OB_DIRECTION_EAST,
618 data->diraction.hang)
619 - (data->diraction.hang ? 0 : c->frame->area.width);
620 break;
621 default:
622 g_assert_not_reached();
623 }
624 frame_frame_gravity(c->frame, &x, &y, c->area.width, c->area.height);
625 client_action_start(data);
626 client_move(c, x, y);
627 client_action_end(data, FALSE);
628 }
629
630 void action_growtoedge(union ActionData *data)
631 {
632 gint x, y, width, height, dest;
633 ObClient *c = data->diraction.any.c;
634 Rect *a;
635
636 a = screen_area(c->desktop, SCREEN_AREA_ALL_MONITORS, &c->frame->area);
637 x = c->frame->area.x;
638 y = c->frame->area.y;
639 /* get the unshaded frame's dimensions..if it is shaded */
640 width = c->area.width + c->frame->size.left + c->frame->size.right;
641 height = c->area.height + c->frame->size.top + c->frame->size.bottom;
642
643 switch(data->diraction.direction) {
644 case OB_DIRECTION_NORTH:
645 if (c->shaded) break; /* don't allow vertical resize if shaded */
646
647 dest = client_directional_edge_search(c, OB_DIRECTION_NORTH, FALSE);
648 if (a->y == y)
649 height = height / 2;
650 else {
651 height = c->frame->area.y + height - dest;
652 y = dest;
653 }
654 break;
655 case OB_DIRECTION_WEST:
656 dest = client_directional_edge_search(c, OB_DIRECTION_WEST, FALSE);
657 if (a->x == x)
658 width = width / 2;
659 else {
660 width = c->frame->area.x + width - dest;
661 x = dest;
662 }
663 break;
664 case OB_DIRECTION_SOUTH:
665 if (c->shaded) break; /* don't allow vertical resize if shaded */
666
667 dest = client_directional_edge_search(c, OB_DIRECTION_SOUTH, FALSE);
668 if (a->y + a->height == y + c->frame->area.height) {
669 height = c->frame->area.height / 2;
670 y = a->y + a->height - height;
671 } else
672 height = dest - c->frame->area.y;
673 y += (height - c->frame->area.height) % c->size_inc.height;
674 height -= (height - c->frame->area.height) % c->size_inc.height;
675 break;
676 case OB_DIRECTION_EAST:
677 dest = client_directional_edge_search(c, OB_DIRECTION_EAST, FALSE);
678 if (a->x + a->width == x + c->frame->area.width) {
679 width = c->frame->area.width / 2;
680 x = a->x + a->width - width;
681 } else
682 width = dest - c->frame->area.x;
683 x += (width - c->frame->area.width) % c->size_inc.width;
684 width -= (width - c->frame->area.width) % c->size_inc.width;
685 break;
686 default:
687 g_assert_not_reached();
688 }
689 width -= c->frame->size.left + c->frame->size.right;
690 height -= c->frame->size.top + c->frame->size.bottom;
691 frame_frame_gravity(c->frame, &x, &y, width, height);
692 client_action_start(data);
693 client_move_resize(c, x, y, width, height);
694 client_action_end(data, FALSE);
695 g_free(a);
696 }
697
698 void action_send_to_layer(union ActionData *data)
699 {
700 client_set_layer(data->layer.any.c, data->layer.layer);
701 }
702
703 void action_toggle_layer(union ActionData *data)
704 {
705 ObClient *c = data->layer.any.c;
706
707 client_action_start(data);
708 if (data->layer.layer < 0)
709 client_set_layer(c, c->below ? 0 : -1);
710 else if (data->layer.layer > 0)
711 client_set_layer(c, c->above ? 0 : 1);
712 client_action_end(data, config_focus_under_mouse);
713 }
714
715 void action_toggle_dockautohide(union ActionData *data)
716 {
717 config_dock_hide = !config_dock_hide;
718 dock_configure();
719 }
720
721 void action_add_desktop(union ActionData *data)
722 {
723 client_action_start(data);
724 screen_set_num_desktops(screen_num_desktops+1);
725
726 /* move all the clients over */
727 if (data->addremovedesktop.current) {
728 GList *it;
729
730 for (it = client_list; it; it = g_list_next(it)) {
731 ObClient *c = it->data;
732 if (c->desktop != DESKTOP_ALL && c->desktop >= screen_desktop)
733 client_set_desktop(c, c->desktop+1, FALSE, TRUE);
734 }
735 }
736
737 client_action_end(data, config_focus_under_mouse);
738 }
739
740 void action_remove_desktop(union ActionData *data)
741 {
742 guint rmdesktop, movedesktop;
743 GList *it, *stacking_copy;
744
745 if (screen_num_desktops < 2) return;
746
747 client_action_start(data);
748
749 /* what desktop are we removing and moving to? */
750 if (data->addremovedesktop.current)
751 rmdesktop = screen_desktop;
752 else
753 rmdesktop = screen_num_desktops - 1;
754 if (rmdesktop < screen_num_desktops - 1)
755 movedesktop = rmdesktop + 1;
756 else
757 movedesktop = rmdesktop;
758
759 /* make a copy of the list cuz we're changing it */
760 stacking_copy = g_list_copy(stacking_list);
761 for (it = g_list_last(stacking_copy); it; it = g_list_previous(it)) {
762 if (WINDOW_IS_CLIENT(it->data)) {
763 ObClient *c = it->data;
764 guint d = c->desktop;
765 if (d != DESKTOP_ALL && d >= movedesktop) {
766 client_set_desktop(c, c->desktop - 1, TRUE, TRUE);
767 ob_debug("moving window %s\n", c->title);
768 }
769 /* raise all the windows that are on the current desktop which
770 is being merged */
771 if ((screen_desktop == rmdesktop - 1 ||
772 screen_desktop == rmdesktop) &&
773 (d == DESKTOP_ALL || d == screen_desktop))
774 {
775 stacking_raise(CLIENT_AS_WINDOW(c));
776 ob_debug("raising window %s\n", c->title);
777 }
778 }
779 }
780
781 /* act like we're changing desktops */
782 if (screen_desktop < screen_num_desktops - 1) {
783 gint d = screen_desktop;
784 screen_desktop = screen_last_desktop;
785 screen_set_desktop(d, TRUE);
786 ob_debug("fake desktop change\n");
787 }
788
789 screen_set_num_desktops(screen_num_desktops-1);
790
791 client_action_end(data, config_focus_under_mouse);
792 }
This page took 0.070405 seconds and 3 git commands to generate.