]> Dogcows Code - chaz/openbox/blob - openbox/action.c
110a9fd49e322cdc45e4800e74492c9210896693
[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_directional_focus_north(ObAction **a, ObUserAction uact)
100 {
101 (*a)->data.interdiraction.inter.any.interactive = TRUE;
102 (*a)->data.interdiraction.direction = OB_DIRECTION_NORTH;
103 (*a)->data.interdiraction.dialog = TRUE;
104 (*a)->data.interdiraction.dock_windows = FALSE;
105 (*a)->data.interdiraction.desktop_windows = FALSE;
106 }
107
108 void setup_action_directional_focus_east(ObAction **a, ObUserAction uact)
109 {
110 (*a)->data.interdiraction.inter.any.interactive = TRUE;
111 (*a)->data.interdiraction.direction = OB_DIRECTION_EAST;
112 (*a)->data.interdiraction.dialog = TRUE;
113 (*a)->data.interdiraction.dock_windows = FALSE;
114 (*a)->data.interdiraction.desktop_windows = FALSE;
115 }
116
117 void setup_action_directional_focus_south(ObAction **a, ObUserAction uact)
118 {
119 (*a)->data.interdiraction.inter.any.interactive = TRUE;
120 (*a)->data.interdiraction.direction = OB_DIRECTION_SOUTH;
121 (*a)->data.interdiraction.dialog = TRUE;
122 (*a)->data.interdiraction.dock_windows = FALSE;
123 (*a)->data.interdiraction.desktop_windows = FALSE;
124 }
125
126 void setup_action_directional_focus_west(ObAction **a, ObUserAction uact)
127 {
128 (*a)->data.interdiraction.inter.any.interactive = TRUE;
129 (*a)->data.interdiraction.direction = OB_DIRECTION_WEST;
130 (*a)->data.interdiraction.dialog = TRUE;
131 (*a)->data.interdiraction.dock_windows = FALSE;
132 (*a)->data.interdiraction.desktop_windows = FALSE;
133 }
134
135 void setup_action_directional_focus_northeast(ObAction **a, ObUserAction uact)
136 {
137 (*a)->data.interdiraction.inter.any.interactive = TRUE;
138 (*a)->data.interdiraction.direction = OB_DIRECTION_NORTHEAST;
139 (*a)->data.interdiraction.dialog = TRUE;
140 (*a)->data.interdiraction.dock_windows = FALSE;
141 (*a)->data.interdiraction.desktop_windows = FALSE;
142 }
143
144 void setup_action_directional_focus_southeast(ObAction **a, ObUserAction uact)
145 {
146 (*a)->data.interdiraction.inter.any.interactive = TRUE;
147 (*a)->data.interdiraction.direction = OB_DIRECTION_SOUTHEAST;
148 (*a)->data.interdiraction.dialog = TRUE;
149 (*a)->data.interdiraction.dock_windows = FALSE;
150 (*a)->data.interdiraction.desktop_windows = FALSE;
151 }
152
153 void setup_action_directional_focus_southwest(ObAction **a, ObUserAction uact)
154 {
155 (*a)->data.interdiraction.inter.any.interactive = TRUE;
156 (*a)->data.interdiraction.direction = OB_DIRECTION_SOUTHWEST;
157 (*a)->data.interdiraction.dialog = TRUE;
158 (*a)->data.interdiraction.dock_windows = FALSE;
159 (*a)->data.interdiraction.desktop_windows = FALSE;
160 }
161
162 void setup_action_directional_focus_northwest(ObAction **a, ObUserAction uact)
163 {
164 (*a)->data.interdiraction.inter.any.interactive = TRUE;
165 (*a)->data.interdiraction.direction = OB_DIRECTION_NORTHWEST;
166 (*a)->data.interdiraction.dialog = TRUE;
167 (*a)->data.interdiraction.dock_windows = FALSE;
168 (*a)->data.interdiraction.desktop_windows = FALSE;
169 }
170
171 void setup_action_send_to_desktop(ObAction **a, ObUserAction uact)
172 {
173 (*a)->data.sendto.any.client_action = OB_CLIENT_ACTION_ALWAYS;
174 (*a)->data.sendto.follow = TRUE;
175 }
176
177 void setup_action_send_to_desktop_prev(ObAction **a, ObUserAction uact)
178 {
179 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
180 (*a)->data.sendtodir.inter.any.interactive = TRUE;
181 (*a)->data.sendtodir.dir = OB_DIRECTION_WEST;
182 (*a)->data.sendtodir.linear = TRUE;
183 (*a)->data.sendtodir.wrap = TRUE;
184 (*a)->data.sendtodir.follow = TRUE;
185 }
186
187 void setup_action_send_to_desktop_next(ObAction **a, ObUserAction uact)
188 {
189 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
190 (*a)->data.sendtodir.inter.any.interactive = TRUE;
191 (*a)->data.sendtodir.dir = OB_DIRECTION_EAST;
192 (*a)->data.sendtodir.linear = TRUE;
193 (*a)->data.sendtodir.wrap = TRUE;
194 (*a)->data.sendtodir.follow = TRUE;
195 }
196
197 void setup_action_send_to_desktop_left(ObAction **a, ObUserAction uact)
198 {
199 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
200 (*a)->data.sendtodir.inter.any.interactive = TRUE;
201 (*a)->data.sendtodir.dir = OB_DIRECTION_WEST;
202 (*a)->data.sendtodir.linear = FALSE;
203 (*a)->data.sendtodir.wrap = TRUE;
204 (*a)->data.sendtodir.follow = TRUE;
205 }
206
207 void setup_action_send_to_desktop_right(ObAction **a, ObUserAction uact)
208 {
209 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
210 (*a)->data.sendtodir.inter.any.interactive = TRUE;
211 (*a)->data.sendtodir.dir = OB_DIRECTION_EAST;
212 (*a)->data.sendtodir.linear = FALSE;
213 (*a)->data.sendtodir.wrap = TRUE;
214 (*a)->data.sendtodir.follow = TRUE;
215 }
216
217 void setup_action_send_to_desktop_up(ObAction **a, ObUserAction uact)
218 {
219 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
220 (*a)->data.sendtodir.inter.any.interactive = TRUE;
221 (*a)->data.sendtodir.dir = OB_DIRECTION_NORTH;
222 (*a)->data.sendtodir.linear = FALSE;
223 (*a)->data.sendtodir.wrap = TRUE;
224 (*a)->data.sendtodir.follow = TRUE;
225 }
226
227 void setup_action_send_to_desktop_down(ObAction **a, ObUserAction uact)
228 {
229 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
230 (*a)->data.sendtodir.inter.any.interactive = TRUE;
231 (*a)->data.sendtodir.dir = OB_DIRECTION_SOUTH;
232 (*a)->data.sendtodir.linear = FALSE;
233 (*a)->data.sendtodir.wrap = TRUE;
234 (*a)->data.sendtodir.follow = TRUE;
235 }
236
237 void setup_action_desktop(ObAction **a, ObUserAction uact)
238 {
239 /*
240 (*a)->data.desktop.inter.any.interactive = FALSE;
241 */
242 }
243
244 void setup_action_desktop_prev(ObAction **a, ObUserAction uact)
245 {
246 (*a)->data.desktopdir.inter.any.interactive = TRUE;
247 (*a)->data.desktopdir.dir = OB_DIRECTION_WEST;
248 (*a)->data.desktopdir.linear = TRUE;
249 (*a)->data.desktopdir.wrap = TRUE;
250 }
251
252 void setup_action_desktop_next(ObAction **a, ObUserAction uact)
253 {
254 (*a)->data.desktopdir.inter.any.interactive = TRUE;
255 (*a)->data.desktopdir.dir = OB_DIRECTION_EAST;
256 (*a)->data.desktopdir.linear = TRUE;
257 (*a)->data.desktopdir.wrap = TRUE;
258 }
259
260 void setup_action_desktop_left(ObAction **a, ObUserAction uact)
261 {
262 (*a)->data.desktopdir.inter.any.interactive = TRUE;
263 (*a)->data.desktopdir.dir = OB_DIRECTION_WEST;
264 (*a)->data.desktopdir.linear = FALSE;
265 (*a)->data.desktopdir.wrap = TRUE;
266 }
267
268 void setup_action_desktop_right(ObAction **a, ObUserAction uact)
269 {
270 (*a)->data.desktopdir.inter.any.interactive = TRUE;
271 (*a)->data.desktopdir.dir = OB_DIRECTION_EAST;
272 (*a)->data.desktopdir.linear = FALSE;
273 (*a)->data.desktopdir.wrap = TRUE;
274 }
275
276 void setup_action_desktop_up(ObAction **a, ObUserAction uact)
277 {
278 (*a)->data.desktopdir.inter.any.interactive = TRUE;
279 (*a)->data.desktopdir.dir = OB_DIRECTION_NORTH;
280 (*a)->data.desktopdir.linear = FALSE;
281 (*a)->data.desktopdir.wrap = TRUE;
282 }
283
284 void setup_action_desktop_down(ObAction **a, ObUserAction uact)
285 {
286 (*a)->data.desktopdir.inter.any.interactive = TRUE;
287 (*a)->data.desktopdir.dir = OB_DIRECTION_SOUTH;
288 (*a)->data.desktopdir.linear = FALSE;
289 (*a)->data.desktopdir.wrap = TRUE;
290 }
291
292 void setup_action_movefromedge_north(ObAction **a, ObUserAction uact)
293 {
294 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
295 (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
296 (*a)->data.diraction.hang = TRUE;
297 }
298
299 void setup_action_movefromedge_south(ObAction **a, ObUserAction uact)
300 {
301 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
302 (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
303 (*a)->data.diraction.hang = TRUE;
304 }
305
306 void setup_action_movefromedge_east(ObAction **a, ObUserAction uact)
307 {
308 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
309 (*a)->data.diraction.direction = OB_DIRECTION_EAST;
310 (*a)->data.diraction.hang = TRUE;
311 }
312
313 void setup_action_movefromedge_west(ObAction **a, ObUserAction uact)
314 {
315 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
316 (*a)->data.diraction.direction = OB_DIRECTION_WEST;
317 (*a)->data.diraction.hang = TRUE;
318 }
319
320 void setup_action_movetoedge_north(ObAction **a, ObUserAction uact)
321 {
322 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
323 (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
324 (*a)->data.diraction.hang = FALSE;
325 }
326
327 void setup_action_movetoedge_south(ObAction **a, ObUserAction uact)
328 {
329 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
330 (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
331 (*a)->data.diraction.hang = FALSE;
332 }
333
334 void setup_action_movetoedge_east(ObAction **a, ObUserAction uact)
335 {
336 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
337 (*a)->data.diraction.direction = OB_DIRECTION_EAST;
338 (*a)->data.diraction.hang = FALSE;
339 }
340
341 void setup_action_movetoedge_west(ObAction **a, ObUserAction uact)
342 {
343 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
344 (*a)->data.diraction.direction = OB_DIRECTION_WEST;
345 (*a)->data.diraction.hang = FALSE;
346 }
347
348 void setup_action_growtoedge_north(ObAction **a, ObUserAction uact)
349 {
350 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
351 (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
352 }
353
354 void setup_action_growtoedge_south(ObAction **a, ObUserAction uact)
355 {
356 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
357 (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
358 }
359
360 void setup_action_growtoedge_east(ObAction **a, ObUserAction uact)
361 {
362 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
363 (*a)->data.diraction.direction = OB_DIRECTION_EAST;
364 }
365
366 void setup_action_growtoedge_west(ObAction **a, ObUserAction uact)
367 {
368 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
369 (*a)->data.diraction.direction = OB_DIRECTION_WEST;
370 }
371
372 void setup_action_top_layer(ObAction **a, ObUserAction uact)
373 {
374 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
375 (*a)->data.layer.layer = 1;
376 }
377
378 void setup_action_normal_layer(ObAction **a, ObUserAction uact)
379 {
380 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
381 (*a)->data.layer.layer = 0;
382 }
383
384 void setup_action_bottom_layer(ObAction **a, ObUserAction uact)
385 {
386 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
387 (*a)->data.layer.layer = -1;
388 }
389
390 void setup_action_resize(ObAction **a, ObUserAction uact)
391 {
392 (*a)->data.moveresize.any.client_action = OB_CLIENT_ACTION_ALWAYS;
393 (*a)->data.moveresize.keyboard =
394 (uact == OB_USER_ACTION_NONE ||
395 uact == OB_USER_ACTION_KEYBOARD_KEY ||
396 uact == OB_USER_ACTION_MENU_SELECTION);
397 (*a)->data.moveresize.corner = 0;
398 }
399
400 void setup_action_addremove_desktop_current(ObAction **a, ObUserAction uact)
401 {
402 (*a)->data.addremovedesktop.current = TRUE;
403 }
404
405 void setup_action_addremove_desktop_last(ObAction **a, ObUserAction uact)
406 {
407 (*a)->data.addremovedesktop.current = FALSE;
408 }
409
410 void setup_client_action(ObAction **a, ObUserAction uact)
411 {
412 (*a)->data.any.client_action = OB_CLIENT_ACTION_ALWAYS;
413 }
414
415 ActionString actionstrings[] =
416 {
417 {
418 "directionalfocusnorth",
419 action_directional_focus,
420 setup_action_directional_focus_north
421 },
422 {
423 "directionalfocuseast",
424 action_directional_focus,
425 setup_action_directional_focus_east
426 },
427 {
428 "directionalfocussouth",
429 action_directional_focus,
430 setup_action_directional_focus_south
431 },
432 {
433 "directionalfocuswest",
434 action_directional_focus,
435 setup_action_directional_focus_west
436 },
437 {
438 "directionalfocusnortheast",
439 action_directional_focus,
440 setup_action_directional_focus_northeast
441 },
442 {
443 "directionalfocussoutheast",
444 action_directional_focus,
445 setup_action_directional_focus_southeast
446 },
447 {
448 "directionalfocussouthwest",
449 action_directional_focus,
450 setup_action_directional_focus_southwest
451 },
452 {
453 "directionalfocusnorthwest",
454 action_directional_focus,
455 setup_action_directional_focus_northwest
456 },
457 {
458 "shadelower",
459 action_shadelower,
460 setup_client_action
461 },
462 {
463 "unshaderaise",
464 action_unshaderaise,
465 setup_client_action
466 },
467 {
468 "resizerelativevert",
469 action_resize_relative_vert,
470 setup_client_action
471 },
472 {
473 "resizerelative",
474 action_resize_relative,
475 setup_client_action
476 },
477 {
478 "sendtodesktop",
479 action_send_to_desktop,
480 setup_action_send_to_desktop
481 },
482 {
483 "sendtodesktopnext",
484 action_send_to_desktop_dir,
485 setup_action_send_to_desktop_next
486 },
487 {
488 "sendtodesktopprevious",
489 action_send_to_desktop_dir,
490 setup_action_send_to_desktop_prev
491 },
492 {
493 "sendtodesktopright",
494 action_send_to_desktop_dir,
495 setup_action_send_to_desktop_right
496 },
497 {
498 "sendtodesktopleft",
499 action_send_to_desktop_dir,
500 setup_action_send_to_desktop_left
501 },
502 {
503 "sendtodesktopup",
504 action_send_to_desktop_dir,
505 setup_action_send_to_desktop_up
506 },
507 {
508 "sendtodesktopdown",
509 action_send_to_desktop_dir,
510 setup_action_send_to_desktop_down
511 },
512 {
513 "desktop",
514 action_desktop,
515 setup_action_desktop
516 },
517 {
518 "desktopnext",
519 action_desktop_dir,
520 setup_action_desktop_next
521 },
522 {
523 "desktopprevious",
524 action_desktop_dir,
525 setup_action_desktop_prev
526 },
527 {
528 "desktopright",
529 action_desktop_dir,
530 setup_action_desktop_right
531 },
532 {
533 "desktopleft",
534 action_desktop_dir,
535 setup_action_desktop_left
536 },
537 {
538 "desktopup",
539 action_desktop_dir,
540 setup_action_desktop_up
541 },
542 {
543 "desktopdown",
544 action_desktop_dir,
545 setup_action_desktop_down
546 },
547 {
548 "toggledecorations",
549 action_toggle_decorations,
550 setup_client_action
551 },
552 {
553 "resize",
554 action_resize,
555 setup_action_resize
556 },
557 {
558 "toggledockautohide",
559 action_toggle_dockautohide,
560 NULL
561 },
562 {
563 "desktoplast",
564 action_desktop_last,
565 NULL
566 },
567 {
568 "sendtotoplayer",
569 action_send_to_layer,
570 setup_action_top_layer
571 },
572 {
573 "togglealwaysontop",
574 action_toggle_layer,
575 setup_action_top_layer
576 },
577 {
578 "sendtonormallayer",
579 action_send_to_layer,
580 setup_action_normal_layer
581 },
582 {
583 "sendtobottomlayer",
584 action_send_to_layer,
585 setup_action_bottom_layer
586 },
587 {
588 "togglealwaysonbottom",
589 action_toggle_layer,
590 setup_action_bottom_layer
591 },
592 {
593 "movefromedgenorth",
594 action_movetoedge,
595 setup_action_movefromedge_north
596 },
597 {
598 "movefromedgesouth",
599 action_movetoedge,
600 setup_action_movefromedge_south
601 },
602 {
603 "movefromedgewest",
604 action_movetoedge,
605 setup_action_movefromedge_west
606 },
607 {
608 "movefromedgeeast",
609 action_movetoedge,
610 setup_action_movefromedge_east
611 },
612 {
613 "movetoedgenorth",
614 action_movetoedge,
615 setup_action_movetoedge_north
616 },
617 {
618 "movetoedgesouth",
619 action_movetoedge,
620 setup_action_movetoedge_south
621 },
622 {
623 "movetoedgewest",
624 action_movetoedge,
625 setup_action_movetoedge_west
626 },
627 {
628 "movetoedgeeast",
629 action_movetoedge,
630 setup_action_movetoedge_east
631 },
632 {
633 "growtoedgenorth",
634 action_growtoedge,
635 setup_action_growtoedge_north
636 },
637 {
638 "growtoedgesouth",
639 action_growtoedge,
640 setup_action_growtoedge_south
641 },
642 {
643 "growtoedgewest",
644 action_growtoedge,
645 setup_action_growtoedge_west
646 },
647 {
648 "growtoedgeeast",
649 action_growtoedge,
650 setup_action_growtoedge_east
651 },
652 {
653 "adddesktoplast",
654 action_add_desktop,
655 setup_action_addremove_desktop_last
656 },
657 {
658 "removedesktoplast",
659 action_remove_desktop,
660 setup_action_addremove_desktop_last
661 },
662 {
663 "adddesktopcurrent",
664 action_add_desktop,
665 setup_action_addremove_desktop_current
666 },
667 {
668 "removedesktopcurrent",
669 action_remove_desktop,
670 setup_action_addremove_desktop_current
671 },
672 {
673 NULL,
674 NULL,
675 NULL
676 }
677 };
678
679 /* only key bindings can be interactive. thus saith the xor.
680 because of how the mouse is grabbed, mouse events dont even get
681 read during interactive events, so no dice! >:) */
682 #define INTERACTIVE_LIMIT(a, uact) \
683 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
684 a->data.any.interactive = FALSE;
685
686 ObAction *action_from_string(const gchar *name, ObUserAction uact)
687 {
688 ObAction *a = NULL;
689 gboolean exist = FALSE;
690 gint i;
691
692 for (i = 0; actionstrings[i].name; i++)
693 if (!g_ascii_strcasecmp(name, actionstrings[i].name)) {
694 exist = TRUE;
695 a = action_new(actionstrings[i].func);
696 if (actionstrings[i].setup)
697 actionstrings[i].setup(&a, uact);
698 if (a)
699 INTERACTIVE_LIMIT(a, uact);
700 break;
701 }
702 if (!exist)
703 g_message(_("Invalid action '%s' requested. No such action exists."),
704 name);
705 if (!a)
706 g_message(_("Invalid use of action '%s'. Action will be ignored."),
707 name);
708 return a;
709 }
710
711 ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
712 ObUserAction uact)
713 {
714 gchar *actname;
715 ObAction *act = NULL;
716 xmlNodePtr n;
717
718 if (parse_attr_string("name", node, &actname)) {
719 if ((act = action_from_string(actname, uact))) {
720 } else if (act->func == action_resize_relative) {
721 if ((n = parse_find_node("left", node->xmlChildrenNode)))
722 act->data.relative.deltaxl = parse_int(doc, n);
723 if ((n = parse_find_node("up", node->xmlChildrenNode)))
724 act->data.relative.deltayu = parse_int(doc, n);
725 if ((n = parse_find_node("right", node->xmlChildrenNode)))
726 act->data.relative.deltax = parse_int(doc, n);
727 if ((n = parse_find_node("down", node->xmlChildrenNode)))
728 act->data.relative.deltay = parse_int(doc, n);
729 } else if (act->func == action_desktop) {
730 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
731 act->data.desktop.desk = parse_int(doc, n);
732 if (act->data.desktop.desk > 0) act->data.desktop.desk--;
733 /*
734 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
735 act->data.desktop.inter.any.interactive =
736 parse_bool(doc, n);
737 */
738 } else if (act->func == action_send_to_desktop) {
739 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
740 act->data.sendto.desk = parse_int(doc, n);
741 if (act->data.sendto.desk > 0) act->data.sendto.desk--;
742 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
743 act->data.sendto.follow = parse_bool(doc, n);
744 } else if (act->func == action_desktop_dir) {
745 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
746 act->data.desktopdir.wrap = parse_bool(doc, n);
747 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
748 act->data.desktopdir.inter.any.interactive =
749 parse_bool(doc, n);
750 } else if (act->func == action_send_to_desktop_dir) {
751 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
752 act->data.sendtodir.wrap = parse_bool(doc, n);
753 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
754 act->data.sendtodir.follow = parse_bool(doc, n);
755 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
756 act->data.sendtodir.inter.any.interactive =
757 parse_bool(doc, n);
758 } else if (act->func == action_directional_focus) {
759 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
760 act->data.interdiraction.dialog = parse_bool(doc, n);
761 if ((n = parse_find_node("panels", node->xmlChildrenNode)))
762 act->data.interdiraction.dock_windows = parse_bool(doc, n);
763 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
764 act->data.interdiraction.desktop_windows =
765 parse_bool(doc, n);
766 } else if (act->func == action_resize) {
767 if ((n = parse_find_node("edge", node->xmlChildrenNode))) {
768 gchar *s = parse_string(doc, n);
769 if (!g_ascii_strcasecmp(s, "top"))
770 act->data.moveresize.corner =
771 prop_atoms.net_wm_moveresize_size_top;
772 else if (!g_ascii_strcasecmp(s, "bottom"))
773 act->data.moveresize.corner =
774 prop_atoms.net_wm_moveresize_size_bottom;
775 else if (!g_ascii_strcasecmp(s, "left"))
776 act->data.moveresize.corner =
777 prop_atoms.net_wm_moveresize_size_left;
778 else if (!g_ascii_strcasecmp(s, "right"))
779 act->data.moveresize.corner =
780 prop_atoms.net_wm_moveresize_size_right;
781 else if (!g_ascii_strcasecmp(s, "topleft"))
782 act->data.moveresize.corner =
783 prop_atoms.net_wm_moveresize_size_topleft;
784 else if (!g_ascii_strcasecmp(s, "topright"))
785 act->data.moveresize.corner =
786 prop_atoms.net_wm_moveresize_size_topright;
787 else if (!g_ascii_strcasecmp(s, "bottomleft"))
788 act->data.moveresize.corner =
789 prop_atoms.net_wm_moveresize_size_bottomleft;
790 else if (!g_ascii_strcasecmp(s, "bottomright"))
791 act->data.moveresize.corner =
792 prop_atoms.net_wm_moveresize_size_bottomright;
793 g_free(s);
794 }
795 INTERACTIVE_LIMIT(act, uact);
796 }
797 g_free(actname);
798 }
799 return act;
800 }
801
802 void action_run_list(GSList *acts, ObClient *c, ObFrameContext context,
803 guint state, guint button, gint x, gint y, Time time,
804 gboolean cancel, gboolean done)
805 {
806 GSList *it;
807 ObAction *a;
808
809 if (!acts)
810 return;
811
812 if (x < 0 && y < 0)
813 screen_pointer_pos(&x, &y);
814
815 for (it = acts; it; it = g_slist_next(it)) {
816 a = it->data;
817
818 if (!(a->data.any.client_action == OB_CLIENT_ACTION_ALWAYS && !c)) {
819 a->data.any.c = a->data.any.client_action ? c : NULL;
820 a->data.any.context = context;
821 a->data.any.x = x;
822 a->data.any.y = y;
823
824 a->data.any.button = button;
825
826 a->data.any.time = time;
827
828 if (a->data.any.interactive) {
829 a->data.inter.cancel = cancel;
830 a->data.inter.final = done;
831 if (!(cancel || done))
832 if (!keyboard_interactive_grab(state, a->data.any.c, a))
833 continue;
834 }
835
836 /* XXX UGLY HACK race with motion event starting a move and the
837 button release gettnig processed first. answer: don't queue
838 moveresize starts. UGLY HACK XXX
839
840 XXX ALSO don't queue showmenu events, because on button press
841 events we need to know if a mouse grab is going to take place,
842 and set the button to 0, so that later motion events don't think
843 that a drag is going on. since showmenu grabs the pointer..
844 */
845 if (a->data.any.interactive || a->func == action_move ||
846 a->func == action_resize || a->func == action_showmenu)
847 {
848 /* interactive actions are not queued */
849 a->func(&a->data);
850 } else if (a->func == action_focus ||
851 a->func == action_activate ||
852 a->func == action_showmenu)
853 {
854 /* XXX MORE UGLY HACK
855 actions from clicks on client windows are NOT queued.
856 this solves the mysterious click-and-drag-doesnt-work
857 problem. it was because the window gets focused and stuff
858 after the button event has already been passed through. i
859 dont really know why it should care but it does and it makes
860 a difference.
861
862 however this very bogus ! !
863 we want to send the button press to the window BEFORE
864 we do the action because the action might move the windows
865 (eg change desktops) and then the button press ends up on
866 the completely wrong window !
867 so, this is just for that bug, and it will only NOT queue it
868 if it is a focusing action that can be used with the mouse
869 pointer. ugh.
870
871 also with the menus, there is a race going on. if the
872 desktop wants to pop up a menu, and we do too, we send them
873 the button before we pop up the menu, so they pop up their
874 menu first. but not always. if we pop up our menu before
875 sending them the button press, then the result is
876 deterministic. yay.
877
878 XXX further more. focus actions are not queued at all,
879 because if you bind focus->showmenu, the menu will get
880 hidden to do the focusing
881 */
882 a->func(&a->data);
883 } else
884 ob_main_loop_queue_action(ob_main_loop, a);
885 }
886 }
887 }
888
889 void action_run_string(const gchar *name, struct _ObClient *c, Time time)
890 {
891 ObAction *a;
892 GSList *l;
893
894 a = action_from_string(name, OB_USER_ACTION_NONE);
895 g_assert(a);
896
897 l = g_slist_append(NULL, a);
898
899 action_run(l, c, 0, time);
900 }
901
902 void action_unshaderaise(union ActionData *data)
903 {
904 if (data->client.any.c->shaded)
905 action_unshade(data);
906 else
907 action_raise(data);
908 }
909
910 void action_shadelower(union ActionData *data)
911 {
912 if (data->client.any.c->shaded)
913 action_lower(data);
914 else
915 action_shade(data);
916 }
917
918 void action_resize_relative_horz(union ActionData *data)
919 {
920 ObClient *c = data->relative.any.c;
921 client_action_start(data);
922 client_resize(c,
923 c->area.width + data->relative.deltax * c->size_inc.width,
924 c->area.height);
925 client_action_end(data, FALSE);
926 }
927
928 void action_resize_relative_vert(union ActionData *data)
929 {
930 ObClient *c = data->relative.any.c;
931 if (!c->shaded) {
932 client_action_start(data);
933 client_resize(c, c->area.width, c->area.height +
934 data->relative.deltax * c->size_inc.height);
935 client_action_end(data, FALSE);
936 }
937 }
938
939 void action_resize_relative(union ActionData *data)
940 {
941 ObClient *c = data->relative.any.c;
942 gint x, y, ow, xoff, nw, oh, yoff, nh, lw, lh;
943
944 client_action_start(data);
945
946 x = c->area.x;
947 y = c->area.y;
948 ow = c->area.width;
949 xoff = -data->relative.deltaxl * c->size_inc.width;
950 nw = ow + data->relative.deltax * c->size_inc.width
951 + data->relative.deltaxl * c->size_inc.width;
952 oh = c->area.height;
953 yoff = -data->relative.deltayu * c->size_inc.height;
954 nh = oh + data->relative.deltay * c->size_inc.height
955 + data->relative.deltayu * c->size_inc.height;
956
957 g_print("deltax %d %d x %d ow %d xoff %d nw %d\n",
958 data->relative.deltax,
959 data->relative.deltaxl,
960 x, ow, xoff, nw);
961
962 client_try_configure(c, &x, &y, &nw, &nh, &lw, &lh, TRUE);
963 xoff = xoff == 0 ? 0 : (xoff < 0 ? MAX(xoff, ow-nw) : MIN(xoff, ow-nw));
964 yoff = yoff == 0 ? 0 : (yoff < 0 ? MAX(yoff, oh-nh) : MIN(yoff, oh-nh));
965 client_move_resize(c, x + xoff, y + yoff, nw, nh);
966 client_action_end(data, FALSE);
967 }
968
969 void action_send_to_desktop(union ActionData *data)
970 {
971 ObClient *c = data->sendto.any.c;
972
973 if (!client_normal(c)) return;
974
975 if (data->sendto.desk < screen_num_desktops ||
976 data->sendto.desk == DESKTOP_ALL) {
977 client_set_desktop(c, data->sendto.desk, data->sendto.follow, FALSE);
978 if (data->sendto.follow && data->sendto.desk != screen_desktop)
979 screen_set_desktop(data->sendto.desk, TRUE);
980 }
981 }
982
983 void action_desktop(union ActionData *data)
984 {
985 /* XXX add the interactive/dialog option back again once the dialog
986 has been made to not use grabs */
987 if (data->desktop.desk < screen_num_desktops ||
988 data->desktop.desk == DESKTOP_ALL)
989 {
990 screen_set_desktop(data->desktop.desk, TRUE);
991 if (data->inter.any.interactive)
992 screen_desktop_popup(data->desktop.desk, TRUE);
993 }
994 }
995
996 void action_desktop_dir(union ActionData *data)
997 {
998 guint d;
999
1000 d = screen_cycle_desktop(data->desktopdir.dir,
1001 data->desktopdir.wrap,
1002 data->desktopdir.linear,
1003 data->desktopdir.inter.any.interactive,
1004 data->desktopdir.inter.final,
1005 data->desktopdir.inter.cancel);
1006 /* only move the desktop when the action is complete. if we switch
1007 desktops during the interactive action, focus will move but with
1008 NotifyWhileGrabbed and applications don't like that. */
1009 if (!data->sendtodir.inter.any.interactive ||
1010 (data->sendtodir.inter.final && !data->sendtodir.inter.cancel))
1011 {
1012 if (d != screen_desktop)
1013 screen_set_desktop(d, TRUE);
1014 }
1015 }
1016
1017 void action_send_to_desktop_dir(union ActionData *data)
1018 {
1019 ObClient *c = data->sendtodir.inter.any.c;
1020 guint d;
1021
1022 if (!client_normal(c)) return;
1023
1024 d = screen_cycle_desktop(data->sendtodir.dir, data->sendtodir.wrap,
1025 data->sendtodir.linear,
1026 data->sendtodir.inter.any.interactive,
1027 data->sendtodir.inter.final,
1028 data->sendtodir.inter.cancel);
1029 /* only move the desktop when the action is complete. if we switch
1030 desktops during the interactive action, focus will move but with
1031 NotifyWhileGrabbed and applications don't like that. */
1032 if (!data->sendtodir.inter.any.interactive ||
1033 (data->sendtodir.inter.final && !data->sendtodir.inter.cancel))
1034 {
1035 client_set_desktop(c, d, data->sendtodir.follow, FALSE);
1036 if (data->sendtodir.follow && d != screen_desktop)
1037 screen_set_desktop(d, TRUE);
1038 }
1039 }
1040
1041 void action_desktop_last(union ActionData *data)
1042 {
1043 if (screen_last_desktop < screen_num_desktops)
1044 screen_set_desktop(screen_last_desktop, TRUE);
1045 }
1046
1047 void action_toggle_decorations(union ActionData *data)
1048 {
1049 ObClient *c = data->client.any.c;
1050
1051 client_action_start(data);
1052 client_set_undecorated(c, !c->undecorated);
1053 client_action_end(data, FALSE);
1054 }
1055
1056 static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch,
1057 gboolean shaded)
1058 {
1059 /* let's make x and y client relative instead of screen relative */
1060 x = x - cx;
1061 y = ch - (y - cy); /* y is inverted, 0 is at the bottom of the window */
1062
1063 #define X x*ch/cw
1064 #define A -4*X + 7*ch/3
1065 #define B 4*X -15*ch/9
1066 #define C -X/4 + 2*ch/3
1067 #define D X/4 + 5*ch/12
1068 #define E X/4 + ch/3
1069 #define F -X/4 + 7*ch/12
1070 #define G 4*X - 4*ch/3
1071 #define H -4*X + 8*ch/3
1072 #define a (y > 5*ch/9)
1073 #define b (x < 4*cw/9)
1074 #define c (x > 5*cw/9)
1075 #define d (y < 4*ch/9)
1076
1077 /*
1078 Each of these defines (except X which is just there for fun), represents
1079 the equation of a line. The lines they represent are shown in the diagram
1080 below. Checking y against these lines, we are able to choose a region
1081 of the window as shown.
1082
1083 +---------------------A-------|-------|-------B---------------------+
1084 | |A B| |
1085 | |A | | B| |
1086 | | A B | |
1087 | | A | | B | |
1088 | | A B | |
1089 | | A | | B | |
1090 | northwest | A north B | northeast |
1091 | | A | | B | |
1092 | | A B | |
1093 C---------------------+----A--+-------+--B----+---------------------D
1094 |CCCCCCC | A B | DDDDDDD|
1095 | CCCCCCCC | A | | B | DDDDDDDD |
1096 | CCCCCCC A B DDDDDDD |
1097 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
1098 | | b c | | sh
1099 | west | b move c | east | ad
1100 | | b c | | ed
1101 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
1102 | EEEEEEE G H FFFFFFF |
1103 | EEEEEEEE | G | | H | FFFFFFFF |
1104 |EEEEEEE | G H | FFFFFFF|
1105 E---------------------+----G--+-------+--H----+---------------------F
1106 | | G H | |
1107 | | G | | H | |
1108 | southwest | G south H | southeast |
1109 | | G | | H | |
1110 | | G H | |
1111 | | G | | H | |
1112 | | G H | |
1113 | |G | | H| |
1114 | |G H| |
1115 +---------------------G-------|-------|-------H---------------------+
1116 */
1117
1118 if (shaded) {
1119 /* for shaded windows, you can only resize west/east and move */
1120 if (b)
1121 return prop_atoms.net_wm_moveresize_size_left;
1122 if (c)
1123 return prop_atoms.net_wm_moveresize_size_right;
1124 return prop_atoms.net_wm_moveresize_move;
1125 }
1126
1127 if (y < A && y >= C)
1128 return prop_atoms.net_wm_moveresize_size_topleft;
1129 else if (y >= A && y >= B && a)
1130 return prop_atoms.net_wm_moveresize_size_top;
1131 else if (y < B && y >= D)
1132 return prop_atoms.net_wm_moveresize_size_topright;
1133 else if (y < C && y >= E && b)
1134 return prop_atoms.net_wm_moveresize_size_left;
1135 else if (y < D && y >= F && c)
1136 return prop_atoms.net_wm_moveresize_size_right;
1137 else if (y < E && y >= G)
1138 return prop_atoms.net_wm_moveresize_size_bottomleft;
1139 else if (y < G && y < H && d)
1140 return prop_atoms.net_wm_moveresize_size_bottom;
1141 else if (y >= H && y < F)
1142 return prop_atoms.net_wm_moveresize_size_bottomright;
1143 else
1144 return prop_atoms.net_wm_moveresize_move;
1145
1146 #undef X
1147 #undef A
1148 #undef B
1149 #undef C
1150 #undef D
1151 #undef E
1152 #undef F
1153 #undef G
1154 #undef H
1155 #undef a
1156 #undef b
1157 #undef c
1158 #undef d
1159 }
1160
1161 void action_resize(union ActionData *data)
1162 {
1163 ObClient *c = data->moveresize.any.c;
1164 guint32 corner;
1165
1166 if (data->moveresize.keyboard)
1167 corner = prop_atoms.net_wm_moveresize_size_keyboard;
1168 else if (data->moveresize.corner)
1169 corner = data->moveresize.corner; /* it was specified in the binding */
1170 else
1171 corner = pick_corner(data->any.x, data->any.y,
1172 c->frame->area.x, c->frame->area.y,
1173 /* use the client size because the frame
1174 can be differently sized (shaded
1175 windows) and we want this based on the
1176 clients size */
1177 c->area.width + c->frame->size.left +
1178 c->frame->size.right,
1179 c->area.height + c->frame->size.top +
1180 c->frame->size.bottom, c->shaded);
1181
1182 moveresize_start(c, data->any.x, data->any.y, data->any.button, corner);
1183 }
1184
1185 void action_directional_focus(union ActionData *data)
1186 {
1187 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1188 on us */
1189 event_halt_focus_delay();
1190
1191 focus_directional_cycle(data->interdiraction.direction,
1192 data->interdiraction.dock_windows,
1193 data->interdiraction.desktop_windows,
1194 data->any.interactive,
1195 data->interdiraction.dialog,
1196 data->interdiraction.inter.final,
1197 data->interdiraction.inter.cancel);
1198 }
1199
1200 void action_movetoedge(union ActionData *data)
1201 {
1202 gint x, y;
1203 ObClient *c = data->diraction.any.c;
1204
1205 x = c->frame->area.x;
1206 y = c->frame->area.y;
1207
1208 switch(data->diraction.direction) {
1209 case OB_DIRECTION_NORTH:
1210 y = client_directional_edge_search(c, OB_DIRECTION_NORTH,
1211 data->diraction.hang)
1212 - (data->diraction.hang ? c->frame->area.height : 0);
1213 break;
1214 case OB_DIRECTION_WEST:
1215 x = client_directional_edge_search(c, OB_DIRECTION_WEST,
1216 data->diraction.hang)
1217 - (data->diraction.hang ? c->frame->area.width : 0);
1218 break;
1219 case OB_DIRECTION_SOUTH:
1220 y = client_directional_edge_search(c, OB_DIRECTION_SOUTH,
1221 data->diraction.hang)
1222 - (data->diraction.hang ? 0 : c->frame->area.height);
1223 break;
1224 case OB_DIRECTION_EAST:
1225 x = client_directional_edge_search(c, OB_DIRECTION_EAST,
1226 data->diraction.hang)
1227 - (data->diraction.hang ? 0 : c->frame->area.width);
1228 break;
1229 default:
1230 g_assert_not_reached();
1231 }
1232 frame_frame_gravity(c->frame, &x, &y, c->area.width, c->area.height);
1233 client_action_start(data);
1234 client_move(c, x, y);
1235 client_action_end(data, FALSE);
1236 }
1237
1238 void action_growtoedge(union ActionData *data)
1239 {
1240 gint x, y, width, height, dest;
1241 ObClient *c = data->diraction.any.c;
1242 Rect *a;
1243
1244 a = screen_area(c->desktop, SCREEN_AREA_ALL_MONITORS, &c->frame->area);
1245 x = c->frame->area.x;
1246 y = c->frame->area.y;
1247 /* get the unshaded frame's dimensions..if it is shaded */
1248 width = c->area.width + c->frame->size.left + c->frame->size.right;
1249 height = c->area.height + c->frame->size.top + c->frame->size.bottom;
1250
1251 switch(data->diraction.direction) {
1252 case OB_DIRECTION_NORTH:
1253 if (c->shaded) break; /* don't allow vertical resize if shaded */
1254
1255 dest = client_directional_edge_search(c, OB_DIRECTION_NORTH, FALSE);
1256 if (a->y == y)
1257 height = height / 2;
1258 else {
1259 height = c->frame->area.y + height - dest;
1260 y = dest;
1261 }
1262 break;
1263 case OB_DIRECTION_WEST:
1264 dest = client_directional_edge_search(c, OB_DIRECTION_WEST, FALSE);
1265 if (a->x == x)
1266 width = width / 2;
1267 else {
1268 width = c->frame->area.x + width - dest;
1269 x = dest;
1270 }
1271 break;
1272 case OB_DIRECTION_SOUTH:
1273 if (c->shaded) break; /* don't allow vertical resize if shaded */
1274
1275 dest = client_directional_edge_search(c, OB_DIRECTION_SOUTH, FALSE);
1276 if (a->y + a->height == y + c->frame->area.height) {
1277 height = c->frame->area.height / 2;
1278 y = a->y + a->height - height;
1279 } else
1280 height = dest - c->frame->area.y;
1281 y += (height - c->frame->area.height) % c->size_inc.height;
1282 height -= (height - c->frame->area.height) % c->size_inc.height;
1283 break;
1284 case OB_DIRECTION_EAST:
1285 dest = client_directional_edge_search(c, OB_DIRECTION_EAST, FALSE);
1286 if (a->x + a->width == x + c->frame->area.width) {
1287 width = c->frame->area.width / 2;
1288 x = a->x + a->width - width;
1289 } else
1290 width = dest - c->frame->area.x;
1291 x += (width - c->frame->area.width) % c->size_inc.width;
1292 width -= (width - c->frame->area.width) % c->size_inc.width;
1293 break;
1294 default:
1295 g_assert_not_reached();
1296 }
1297 width -= c->frame->size.left + c->frame->size.right;
1298 height -= c->frame->size.top + c->frame->size.bottom;
1299 frame_frame_gravity(c->frame, &x, &y, width, height);
1300 client_action_start(data);
1301 client_move_resize(c, x, y, width, height);
1302 client_action_end(data, FALSE);
1303 g_free(a);
1304 }
1305
1306 void action_send_to_layer(union ActionData *data)
1307 {
1308 client_set_layer(data->layer.any.c, data->layer.layer);
1309 }
1310
1311 void action_toggle_layer(union ActionData *data)
1312 {
1313 ObClient *c = data->layer.any.c;
1314
1315 client_action_start(data);
1316 if (data->layer.layer < 0)
1317 client_set_layer(c, c->below ? 0 : -1);
1318 else if (data->layer.layer > 0)
1319 client_set_layer(c, c->above ? 0 : 1);
1320 client_action_end(data, config_focus_under_mouse);
1321 }
1322
1323 void action_toggle_dockautohide(union ActionData *data)
1324 {
1325 config_dock_hide = !config_dock_hide;
1326 dock_configure();
1327 }
1328
1329 void action_add_desktop(union ActionData *data)
1330 {
1331 client_action_start(data);
1332 screen_set_num_desktops(screen_num_desktops+1);
1333
1334 /* move all the clients over */
1335 if (data->addremovedesktop.current) {
1336 GList *it;
1337
1338 for (it = client_list; it; it = g_list_next(it)) {
1339 ObClient *c = it->data;
1340 if (c->desktop != DESKTOP_ALL && c->desktop >= screen_desktop)
1341 client_set_desktop(c, c->desktop+1, FALSE, TRUE);
1342 }
1343 }
1344
1345 client_action_end(data, config_focus_under_mouse);
1346 }
1347
1348 void action_remove_desktop(union ActionData *data)
1349 {
1350 guint rmdesktop, movedesktop;
1351 GList *it, *stacking_copy;
1352
1353 if (screen_num_desktops < 2) return;
1354
1355 client_action_start(data);
1356
1357 /* what desktop are we removing and moving to? */
1358 if (data->addremovedesktop.current)
1359 rmdesktop = screen_desktop;
1360 else
1361 rmdesktop = screen_num_desktops - 1;
1362 if (rmdesktop < screen_num_desktops - 1)
1363 movedesktop = rmdesktop + 1;
1364 else
1365 movedesktop = rmdesktop;
1366
1367 /* make a copy of the list cuz we're changing it */
1368 stacking_copy = g_list_copy(stacking_list);
1369 for (it = g_list_last(stacking_copy); it; it = g_list_previous(it)) {
1370 if (WINDOW_IS_CLIENT(it->data)) {
1371 ObClient *c = it->data;
1372 guint d = c->desktop;
1373 if (d != DESKTOP_ALL && d >= movedesktop) {
1374 client_set_desktop(c, c->desktop - 1, TRUE, TRUE);
1375 ob_debug("moving window %s\n", c->title);
1376 }
1377 /* raise all the windows that are on the current desktop which
1378 is being merged */
1379 if ((screen_desktop == rmdesktop - 1 ||
1380 screen_desktop == rmdesktop) &&
1381 (d == DESKTOP_ALL || d == screen_desktop))
1382 {
1383 stacking_raise(CLIENT_AS_WINDOW(c));
1384 ob_debug("raising window %s\n", c->title);
1385 }
1386 }
1387 }
1388
1389 /* act like we're changing desktops */
1390 if (screen_desktop < screen_num_desktops - 1) {
1391 gint d = screen_desktop;
1392 screen_desktop = screen_last_desktop;
1393 screen_set_desktop(d, TRUE);
1394 ob_debug("fake desktop change\n");
1395 }
1396
1397 screen_set_num_desktops(screen_num_desktops-1);
1398
1399 client_action_end(data, config_focus_under_mouse);
1400 }
This page took 0.09229 seconds and 3 git commands to generate.