]> Dogcows Code - chaz/openbox/blob - openbox/action.c
add directionaldesktop action
[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(ObAction **a, ObUserAction uact)
100 {
101 (*a)->data.sendto.any.client_action = OB_CLIENT_ACTION_ALWAYS;
102 (*a)->data.sendto.follow = TRUE;
103 }
104
105 void setup_action_send_to_desktop_prev(ObAction **a, ObUserAction uact)
106 {
107 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
108 (*a)->data.sendtodir.inter.any.interactive = TRUE;
109 (*a)->data.sendtodir.dir = OB_DIRECTION_WEST;
110 (*a)->data.sendtodir.linear = TRUE;
111 (*a)->data.sendtodir.wrap = TRUE;
112 (*a)->data.sendtodir.follow = TRUE;
113 }
114
115 void setup_action_send_to_desktop_next(ObAction **a, ObUserAction uact)
116 {
117 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
118 (*a)->data.sendtodir.inter.any.interactive = TRUE;
119 (*a)->data.sendtodir.dir = OB_DIRECTION_EAST;
120 (*a)->data.sendtodir.linear = TRUE;
121 (*a)->data.sendtodir.wrap = TRUE;
122 (*a)->data.sendtodir.follow = TRUE;
123 }
124
125 void setup_action_send_to_desktop_left(ObAction **a, ObUserAction uact)
126 {
127 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
128 (*a)->data.sendtodir.inter.any.interactive = TRUE;
129 (*a)->data.sendtodir.dir = OB_DIRECTION_WEST;
130 (*a)->data.sendtodir.linear = FALSE;
131 (*a)->data.sendtodir.wrap = TRUE;
132 (*a)->data.sendtodir.follow = TRUE;
133 }
134
135 void setup_action_send_to_desktop_right(ObAction **a, ObUserAction uact)
136 {
137 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
138 (*a)->data.sendtodir.inter.any.interactive = TRUE;
139 (*a)->data.sendtodir.dir = OB_DIRECTION_EAST;
140 (*a)->data.sendtodir.linear = FALSE;
141 (*a)->data.sendtodir.wrap = TRUE;
142 (*a)->data.sendtodir.follow = TRUE;
143 }
144
145 void setup_action_send_to_desktop_up(ObAction **a, ObUserAction uact)
146 {
147 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
148 (*a)->data.sendtodir.inter.any.interactive = TRUE;
149 (*a)->data.sendtodir.dir = OB_DIRECTION_NORTH;
150 (*a)->data.sendtodir.linear = FALSE;
151 (*a)->data.sendtodir.wrap = TRUE;
152 (*a)->data.sendtodir.follow = TRUE;
153 }
154
155 void setup_action_send_to_desktop_down(ObAction **a, ObUserAction uact)
156 {
157 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
158 (*a)->data.sendtodir.inter.any.interactive = TRUE;
159 (*a)->data.sendtodir.dir = OB_DIRECTION_SOUTH;
160 (*a)->data.sendtodir.linear = FALSE;
161 (*a)->data.sendtodir.wrap = TRUE;
162 (*a)->data.sendtodir.follow = TRUE;
163 }
164
165 void setup_action_desktop_prev(ObAction **a, ObUserAction uact)
166 {
167 (*a)->data.desktopdir.inter.any.interactive = TRUE;
168 (*a)->data.desktopdir.dir = OB_DIRECTION_WEST;
169 (*a)->data.desktopdir.linear = TRUE;
170 (*a)->data.desktopdir.wrap = TRUE;
171 }
172
173 void setup_action_desktop_next(ObAction **a, ObUserAction uact)
174 {
175 (*a)->data.desktopdir.inter.any.interactive = TRUE;
176 (*a)->data.desktopdir.dir = OB_DIRECTION_EAST;
177 (*a)->data.desktopdir.linear = TRUE;
178 (*a)->data.desktopdir.wrap = TRUE;
179 }
180
181 void setup_action_desktop_left(ObAction **a, ObUserAction uact)
182 {
183 (*a)->data.desktopdir.inter.any.interactive = TRUE;
184 (*a)->data.desktopdir.dir = OB_DIRECTION_WEST;
185 (*a)->data.desktopdir.linear = FALSE;
186 (*a)->data.desktopdir.wrap = TRUE;
187 }
188
189 void setup_action_desktop_right(ObAction **a, ObUserAction uact)
190 {
191 (*a)->data.desktopdir.inter.any.interactive = TRUE;
192 (*a)->data.desktopdir.dir = OB_DIRECTION_EAST;
193 (*a)->data.desktopdir.linear = FALSE;
194 (*a)->data.desktopdir.wrap = TRUE;
195 }
196
197 void setup_action_desktop_up(ObAction **a, ObUserAction uact)
198 {
199 (*a)->data.desktopdir.inter.any.interactive = TRUE;
200 (*a)->data.desktopdir.dir = OB_DIRECTION_NORTH;
201 (*a)->data.desktopdir.linear = FALSE;
202 (*a)->data.desktopdir.wrap = TRUE;
203 }
204
205 void setup_action_desktop_down(ObAction **a, ObUserAction uact)
206 {
207 (*a)->data.desktopdir.inter.any.interactive = TRUE;
208 (*a)->data.desktopdir.dir = OB_DIRECTION_SOUTH;
209 (*a)->data.desktopdir.linear = FALSE;
210 (*a)->data.desktopdir.wrap = TRUE;
211 }
212
213 void setup_action_movefromedge_north(ObAction **a, ObUserAction uact)
214 {
215 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
216 (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
217 (*a)->data.diraction.hang = TRUE;
218 }
219
220 void setup_action_movefromedge_south(ObAction **a, ObUserAction uact)
221 {
222 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
223 (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
224 (*a)->data.diraction.hang = TRUE;
225 }
226
227 void setup_action_movefromedge_east(ObAction **a, ObUserAction uact)
228 {
229 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
230 (*a)->data.diraction.direction = OB_DIRECTION_EAST;
231 (*a)->data.diraction.hang = TRUE;
232 }
233
234 void setup_action_movefromedge_west(ObAction **a, ObUserAction uact)
235 {
236 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
237 (*a)->data.diraction.direction = OB_DIRECTION_WEST;
238 (*a)->data.diraction.hang = TRUE;
239 }
240
241 void setup_action_movetoedge_north(ObAction **a, ObUserAction uact)
242 {
243 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
244 (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
245 (*a)->data.diraction.hang = FALSE;
246 }
247
248 void setup_action_movetoedge_south(ObAction **a, ObUserAction uact)
249 {
250 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
251 (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
252 (*a)->data.diraction.hang = FALSE;
253 }
254
255 void setup_action_movetoedge_east(ObAction **a, ObUserAction uact)
256 {
257 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
258 (*a)->data.diraction.direction = OB_DIRECTION_EAST;
259 (*a)->data.diraction.hang = FALSE;
260 }
261
262 void setup_action_movetoedge_west(ObAction **a, ObUserAction uact)
263 {
264 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
265 (*a)->data.diraction.direction = OB_DIRECTION_WEST;
266 (*a)->data.diraction.hang = FALSE;
267 }
268
269 void setup_action_growtoedge_north(ObAction **a, ObUserAction uact)
270 {
271 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
272 (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
273 }
274
275 void setup_action_growtoedge_south(ObAction **a, ObUserAction uact)
276 {
277 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
278 (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
279 }
280
281 void setup_action_growtoedge_east(ObAction **a, ObUserAction uact)
282 {
283 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
284 (*a)->data.diraction.direction = OB_DIRECTION_EAST;
285 }
286
287 void setup_action_growtoedge_west(ObAction **a, ObUserAction uact)
288 {
289 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
290 (*a)->data.diraction.direction = OB_DIRECTION_WEST;
291 }
292
293 void setup_action_top_layer(ObAction **a, ObUserAction uact)
294 {
295 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
296 (*a)->data.layer.layer = 1;
297 }
298
299 void setup_action_normal_layer(ObAction **a, ObUserAction uact)
300 {
301 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
302 (*a)->data.layer.layer = 0;
303 }
304
305 void setup_action_bottom_layer(ObAction **a, ObUserAction uact)
306 {
307 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
308 (*a)->data.layer.layer = -1;
309 }
310
311 void setup_action_resize(ObAction **a, ObUserAction uact)
312 {
313 (*a)->data.moveresize.any.client_action = OB_CLIENT_ACTION_ALWAYS;
314 (*a)->data.moveresize.keyboard =
315 (uact == OB_USER_ACTION_NONE ||
316 uact == OB_USER_ACTION_KEYBOARD_KEY ||
317 uact == OB_USER_ACTION_MENU_SELECTION);
318 (*a)->data.moveresize.corner = 0;
319 }
320
321 void setup_action_addremove_desktop_current(ObAction **a, ObUserAction uact)
322 {
323 (*a)->data.addremovedesktop.current = TRUE;
324 }
325
326 void setup_action_addremove_desktop_last(ObAction **a, ObUserAction uact)
327 {
328 (*a)->data.addremovedesktop.current = FALSE;
329 }
330
331 void setup_client_action(ObAction **a, ObUserAction uact)
332 {
333 (*a)->data.any.client_action = OB_CLIENT_ACTION_ALWAYS;
334 }
335
336 ActionString actionstrings[] =
337 {
338 {
339 "shadelower",
340 action_shadelower,
341 setup_client_action
342 },
343 {
344 "unshaderaise",
345 action_unshaderaise,
346 setup_client_action
347 },
348 {
349 "resizerelativevert",
350 action_resize_relative_vert,
351 setup_client_action
352 },
353 {
354 "resizerelative",
355 action_resize_relative,
356 setup_client_action
357 },
358 {
359 "sendtodesktop",
360 action_send_to_desktop,
361 setup_action_send_to_desktop
362 },
363 {
364 "sendtodesktopnext",
365 action_send_to_desktop_dir,
366 setup_action_send_to_desktop_next
367 },
368 {
369 "sendtodesktopprevious",
370 action_send_to_desktop_dir,
371 setup_action_send_to_desktop_prev
372 },
373 {
374 "sendtodesktopright",
375 action_send_to_desktop_dir,
376 setup_action_send_to_desktop_right
377 },
378 {
379 "sendtodesktopleft",
380 action_send_to_desktop_dir,
381 setup_action_send_to_desktop_left
382 },
383 {
384 "sendtodesktopup",
385 action_send_to_desktop_dir,
386 setup_action_send_to_desktop_up
387 },
388 {
389 "sendtodesktopdown",
390 action_send_to_desktop_dir,
391 setup_action_send_to_desktop_down
392 },
393 {
394 "toggledockautohide",
395 action_toggle_dockautohide,
396 NULL
397 },
398 {
399 "desktoplast",
400 action_desktop_last,
401 NULL
402 },
403 {
404 "sendtotoplayer",
405 action_send_to_layer,
406 setup_action_top_layer
407 },
408 {
409 "togglealwaysontop",
410 action_toggle_layer,
411 setup_action_top_layer
412 },
413 {
414 "sendtonormallayer",
415 action_send_to_layer,
416 setup_action_normal_layer
417 },
418 {
419 "sendtobottomlayer",
420 action_send_to_layer,
421 setup_action_bottom_layer
422 },
423 {
424 "togglealwaysonbottom",
425 action_toggle_layer,
426 setup_action_bottom_layer
427 },
428 {
429 "movefromedgenorth",
430 action_movetoedge,
431 setup_action_movefromedge_north
432 },
433 {
434 "movefromedgesouth",
435 action_movetoedge,
436 setup_action_movefromedge_south
437 },
438 {
439 "movefromedgewest",
440 action_movetoedge,
441 setup_action_movefromedge_west
442 },
443 {
444 "movefromedgeeast",
445 action_movetoedge,
446 setup_action_movefromedge_east
447 },
448 {
449 "movetoedgenorth",
450 action_movetoedge,
451 setup_action_movetoedge_north
452 },
453 {
454 "movetoedgesouth",
455 action_movetoedge,
456 setup_action_movetoedge_south
457 },
458 {
459 "movetoedgewest",
460 action_movetoedge,
461 setup_action_movetoedge_west
462 },
463 {
464 "movetoedgeeast",
465 action_movetoedge,
466 setup_action_movetoedge_east
467 },
468 {
469 "growtoedgenorth",
470 action_growtoedge,
471 setup_action_growtoedge_north
472 },
473 {
474 "growtoedgesouth",
475 action_growtoedge,
476 setup_action_growtoedge_south
477 },
478 {
479 "growtoedgewest",
480 action_growtoedge,
481 setup_action_growtoedge_west
482 },
483 {
484 "growtoedgeeast",
485 action_growtoedge,
486 setup_action_growtoedge_east
487 },
488 {
489 "adddesktoplast",
490 action_add_desktop,
491 setup_action_addremove_desktop_last
492 },
493 {
494 "removedesktoplast",
495 action_remove_desktop,
496 setup_action_addremove_desktop_last
497 },
498 {
499 "adddesktopcurrent",
500 action_add_desktop,
501 setup_action_addremove_desktop_current
502 },
503 {
504 "removedesktopcurrent",
505 action_remove_desktop,
506 setup_action_addremove_desktop_current
507 },
508 {
509 NULL,
510 NULL,
511 NULL
512 }
513 };
514
515 /* only key bindings can be interactive. thus saith the xor.
516 because of how the mouse is grabbed, mouse events dont even get
517 read during interactive events, so no dice! >:) */
518 #define INTERACTIVE_LIMIT(a, uact) \
519 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
520 a->data.any.interactive = FALSE;
521
522 ObAction *action_from_string(const gchar *name, ObUserAction uact)
523 {
524 ObAction *a = NULL;
525 gboolean exist = FALSE;
526 gint i;
527
528 for (i = 0; actionstrings[i].name; i++)
529 if (!g_ascii_strcasecmp(name, actionstrings[i].name)) {
530 exist = TRUE;
531 a = action_new(actionstrings[i].func);
532 if (actionstrings[i].setup)
533 actionstrings[i].setup(&a, uact);
534 if (a)
535 INTERACTIVE_LIMIT(a, uact);
536 break;
537 }
538 if (!exist)
539 g_message(_("Invalid action '%s' requested. No such action exists."),
540 name);
541 if (!a)
542 g_message(_("Invalid use of action '%s'. Action will be ignored."),
543 name);
544 return a;
545 }
546
547 ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
548 ObUserAction uact)
549 {
550 gchar *actname;
551 ObAction *act = NULL;
552 xmlNodePtr n;
553
554 if (parse_attr_string("name", node, &actname)) {
555 if ((act = action_from_string(actname, uact))) {
556 } else if (act->func == action_resize_relative) {
557 if ((n = parse_find_node("left", node->xmlChildrenNode)))
558 act->data.relative.deltaxl = parse_int(doc, n);
559 if ((n = parse_find_node("up", node->xmlChildrenNode)))
560 act->data.relative.deltayu = parse_int(doc, n);
561 if ((n = parse_find_node("right", node->xmlChildrenNode)))
562 act->data.relative.deltax = parse_int(doc, n);
563 if ((n = parse_find_node("down", node->xmlChildrenNode)))
564 act->data.relative.deltay = parse_int(doc, n);
565 } else if (act->func == action_desktop) {
566 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
567 act->data.desktop.desk = parse_int(doc, n);
568 if (act->data.desktop.desk > 0) act->data.desktop.desk--;
569 /*
570 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
571 act->data.desktop.inter.any.interactive =
572 parse_bool(doc, n);
573 */
574 } else if (act->func == action_send_to_desktop) {
575 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
576 act->data.sendto.desk = parse_int(doc, n);
577 if (act->data.sendto.desk > 0) act->data.sendto.desk--;
578 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
579 act->data.sendto.follow = parse_bool(doc, n);
580 } else if (act->func == action_send_to_desktop_dir) {
581 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
582 act->data.sendtodir.wrap = parse_bool(doc, n);
583 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
584 act->data.sendtodir.follow = parse_bool(doc, n);
585 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
586 act->data.sendtodir.inter.any.interactive =
587 parse_bool(doc, n);
588 INTERACTIVE_LIMIT(act, uact);
589 }
590 g_free(actname);
591 }
592 return act;
593 }
594
595 void action_run_list(GSList *acts, ObClient *c, ObFrameContext context,
596 guint state, guint button, gint x, gint y, Time time,
597 gboolean cancel, gboolean done)
598 {
599 GSList *it;
600 ObAction *a;
601
602 if (!acts)
603 return;
604
605 if (x < 0 && y < 0)
606 screen_pointer_pos(&x, &y);
607
608 for (it = acts; it; it = g_slist_next(it)) {
609 a = it->data;
610
611 if (!(a->data.any.client_action == OB_CLIENT_ACTION_ALWAYS && !c)) {
612 a->data.any.c = a->data.any.client_action ? c : NULL;
613 a->data.any.context = context;
614 a->data.any.x = x;
615 a->data.any.y = y;
616
617 a->data.any.button = button;
618
619 a->data.any.time = time;
620
621 if (a->data.any.interactive) {
622 a->data.inter.cancel = cancel;
623 a->data.inter.final = done;
624 if (!(cancel || done))
625 if (!keyboard_interactive_grab(state, a->data.any.c, a))
626 continue;
627 }
628
629 /* XXX UGLY HACK race with motion event starting a move and the
630 button release gettnig processed first. answer: don't queue
631 moveresize starts. UGLY HACK XXX
632
633 XXX ALSO don't queue showmenu events, because on button press
634 events we need to know if a mouse grab is going to take place,
635 and set the button to 0, so that later motion events don't think
636 that a drag is going on. since showmenu grabs the pointer..
637 */
638 if (a->data.any.interactive || a->func == action_move ||
639 a->func == action_resize || a->func == action_showmenu)
640 {
641 /* interactive actions are not queued */
642 a->func(&a->data);
643 } else if (a->func == action_focus ||
644 a->func == action_activate ||
645 a->func == action_showmenu)
646 {
647 /* XXX MORE UGLY HACK
648 actions from clicks on client windows are NOT queued.
649 this solves the mysterious click-and-drag-doesnt-work
650 problem. it was because the window gets focused and stuff
651 after the button event has already been passed through. i
652 dont really know why it should care but it does and it makes
653 a difference.
654
655 however this very bogus ! !
656 we want to send the button press to the window BEFORE
657 we do the action because the action might move the windows
658 (eg change desktops) and then the button press ends up on
659 the completely wrong window !
660 so, this is just for that bug, and it will only NOT queue it
661 if it is a focusing action that can be used with the mouse
662 pointer. ugh.
663
664 also with the menus, there is a race going on. if the
665 desktop wants to pop up a menu, and we do too, we send them
666 the button before we pop up the menu, so they pop up their
667 menu first. but not always. if we pop up our menu before
668 sending them the button press, then the result is
669 deterministic. yay.
670
671 XXX further more. focus actions are not queued at all,
672 because if you bind focus->showmenu, the menu will get
673 hidden to do the focusing
674 */
675 a->func(&a->data);
676 } else
677 ob_main_loop_queue_action(ob_main_loop, a);
678 }
679 }
680 }
681
682 void action_run_string(const gchar *name, struct _ObClient *c, Time time)
683 {
684 ObAction *a;
685 GSList *l;
686
687 a = action_from_string(name, OB_USER_ACTION_NONE);
688 g_assert(a);
689
690 l = g_slist_append(NULL, a);
691
692 action_run(l, c, 0, time);
693 }
694
695 void action_unshaderaise(union ActionData *data)
696 {
697 if (data->client.any.c->shaded)
698 action_unshade(data);
699 else
700 action_raise(data);
701 }
702
703 void action_shadelower(union ActionData *data)
704 {
705 if (data->client.any.c->shaded)
706 action_lower(data);
707 else
708 action_shade(data);
709 }
710
711 void action_resize_relative_horz(union ActionData *data)
712 {
713 ObClient *c = data->relative.any.c;
714 client_action_start(data);
715 client_resize(c,
716 c->area.width + data->relative.deltax * c->size_inc.width,
717 c->area.height);
718 client_action_end(data, FALSE);
719 }
720
721 void action_resize_relative_vert(union ActionData *data)
722 {
723 ObClient *c = data->relative.any.c;
724 if (!c->shaded) {
725 client_action_start(data);
726 client_resize(c, c->area.width, c->area.height +
727 data->relative.deltax * c->size_inc.height);
728 client_action_end(data, FALSE);
729 }
730 }
731
732 void action_resize_relative(union ActionData *data)
733 {
734 ObClient *c = data->relative.any.c;
735 gint x, y, ow, xoff, nw, oh, yoff, nh, lw, lh;
736
737 client_action_start(data);
738
739 x = c->area.x;
740 y = c->area.y;
741 ow = c->area.width;
742 xoff = -data->relative.deltaxl * c->size_inc.width;
743 nw = ow + data->relative.deltax * c->size_inc.width
744 + data->relative.deltaxl * c->size_inc.width;
745 oh = c->area.height;
746 yoff = -data->relative.deltayu * c->size_inc.height;
747 nh = oh + data->relative.deltay * c->size_inc.height
748 + data->relative.deltayu * c->size_inc.height;
749
750 g_print("deltax %d %d x %d ow %d xoff %d nw %d\n",
751 data->relative.deltax,
752 data->relative.deltaxl,
753 x, ow, xoff, nw);
754
755 client_try_configure(c, &x, &y, &nw, &nh, &lw, &lh, TRUE);
756 xoff = xoff == 0 ? 0 : (xoff < 0 ? MAX(xoff, ow-nw) : MIN(xoff, ow-nw));
757 yoff = yoff == 0 ? 0 : (yoff < 0 ? MAX(yoff, oh-nh) : MIN(yoff, oh-nh));
758 client_move_resize(c, x + xoff, y + yoff, nw, nh);
759 client_action_end(data, FALSE);
760 }
761
762 void action_send_to_desktop(union ActionData *data)
763 {
764 ObClient *c = data->sendto.any.c;
765
766 if (!client_normal(c)) return;
767
768 if (data->sendto.desk < screen_num_desktops ||
769 data->sendto.desk == DESKTOP_ALL) {
770 client_set_desktop(c, data->sendto.desk, data->sendto.follow, FALSE);
771 if (data->sendto.follow && data->sendto.desk != screen_desktop)
772 screen_set_desktop(data->sendto.desk, TRUE);
773 }
774 }
775
776 void action_desktop_dir(union ActionData *data)
777 {
778 guint d;
779
780 d = screen_cycle_desktop(data->desktopdir.dir,
781 data->desktopdir.wrap,
782 data->desktopdir.linear,
783 data->desktopdir.inter.any.interactive,
784 data->desktopdir.inter.final,
785 data->desktopdir.inter.cancel);
786 /* only move the desktop when the action is complete. if we switch
787 desktops during the interactive action, focus will move but with
788 NotifyWhileGrabbed and applications don't like that. */
789 if (!data->sendtodir.inter.any.interactive ||
790 (data->sendtodir.inter.final && !data->sendtodir.inter.cancel))
791 {
792 if (d != screen_desktop)
793 screen_set_desktop(d, TRUE);
794 }
795 }
796
797 void action_send_to_desktop_dir(union ActionData *data)
798 {
799 ObClient *c = data->sendtodir.inter.any.c;
800 guint d;
801
802 if (!client_normal(c)) return;
803
804 d = screen_cycle_desktop(data->sendtodir.dir, data->sendtodir.wrap,
805 data->sendtodir.linear,
806 data->sendtodir.inter.any.interactive,
807 data->sendtodir.inter.final,
808 data->sendtodir.inter.cancel);
809 /* only move the desktop when the action is complete. if we switch
810 desktops during the interactive action, focus will move but with
811 NotifyWhileGrabbed and applications don't like that. */
812 if (!data->sendtodir.inter.any.interactive ||
813 (data->sendtodir.inter.final && !data->sendtodir.inter.cancel))
814 {
815 client_set_desktop(c, d, data->sendtodir.follow, FALSE);
816 if (data->sendtodir.follow && d != screen_desktop)
817 screen_set_desktop(d, TRUE);
818 }
819 }
820
821 void action_desktop_last(union ActionData *data)
822 {
823 if (screen_last_desktop < screen_num_desktops)
824 screen_set_desktop(screen_last_desktop, TRUE);
825 }
826
827 void action_directional_focus(union ActionData *data)
828 {
829 /* if using focus_delay, stop the timer now so that focus doesn't go moving
830 on us */
831 event_halt_focus_delay();
832
833 focus_directional_cycle(data->interdiraction.direction,
834 data->interdiraction.dock_windows,
835 data->interdiraction.desktop_windows,
836 data->any.interactive,
837 data->interdiraction.dialog,
838 data->interdiraction.inter.final,
839 data->interdiraction.inter.cancel);
840 }
841
842 void action_movetoedge(union ActionData *data)
843 {
844 gint x, y;
845 ObClient *c = data->diraction.any.c;
846
847 x = c->frame->area.x;
848 y = c->frame->area.y;
849
850 switch(data->diraction.direction) {
851 case OB_DIRECTION_NORTH:
852 y = client_directional_edge_search(c, OB_DIRECTION_NORTH,
853 data->diraction.hang)
854 - (data->diraction.hang ? c->frame->area.height : 0);
855 break;
856 case OB_DIRECTION_WEST:
857 x = client_directional_edge_search(c, OB_DIRECTION_WEST,
858 data->diraction.hang)
859 - (data->diraction.hang ? c->frame->area.width : 0);
860 break;
861 case OB_DIRECTION_SOUTH:
862 y = client_directional_edge_search(c, OB_DIRECTION_SOUTH,
863 data->diraction.hang)
864 - (data->diraction.hang ? 0 : c->frame->area.height);
865 break;
866 case OB_DIRECTION_EAST:
867 x = client_directional_edge_search(c, OB_DIRECTION_EAST,
868 data->diraction.hang)
869 - (data->diraction.hang ? 0 : c->frame->area.width);
870 break;
871 default:
872 g_assert_not_reached();
873 }
874 frame_frame_gravity(c->frame, &x, &y, c->area.width, c->area.height);
875 client_action_start(data);
876 client_move(c, x, y);
877 client_action_end(data, FALSE);
878 }
879
880 void action_growtoedge(union ActionData *data)
881 {
882 gint x, y, width, height, dest;
883 ObClient *c = data->diraction.any.c;
884 Rect *a;
885
886 a = screen_area(c->desktop, SCREEN_AREA_ALL_MONITORS, &c->frame->area);
887 x = c->frame->area.x;
888 y = c->frame->area.y;
889 /* get the unshaded frame's dimensions..if it is shaded */
890 width = c->area.width + c->frame->size.left + c->frame->size.right;
891 height = c->area.height + c->frame->size.top + c->frame->size.bottom;
892
893 switch(data->diraction.direction) {
894 case OB_DIRECTION_NORTH:
895 if (c->shaded) break; /* don't allow vertical resize if shaded */
896
897 dest = client_directional_edge_search(c, OB_DIRECTION_NORTH, FALSE);
898 if (a->y == y)
899 height = height / 2;
900 else {
901 height = c->frame->area.y + height - dest;
902 y = dest;
903 }
904 break;
905 case OB_DIRECTION_WEST:
906 dest = client_directional_edge_search(c, OB_DIRECTION_WEST, FALSE);
907 if (a->x == x)
908 width = width / 2;
909 else {
910 width = c->frame->area.x + width - dest;
911 x = dest;
912 }
913 break;
914 case OB_DIRECTION_SOUTH:
915 if (c->shaded) break; /* don't allow vertical resize if shaded */
916
917 dest = client_directional_edge_search(c, OB_DIRECTION_SOUTH, FALSE);
918 if (a->y + a->height == y + c->frame->area.height) {
919 height = c->frame->area.height / 2;
920 y = a->y + a->height - height;
921 } else
922 height = dest - c->frame->area.y;
923 y += (height - c->frame->area.height) % c->size_inc.height;
924 height -= (height - c->frame->area.height) % c->size_inc.height;
925 break;
926 case OB_DIRECTION_EAST:
927 dest = client_directional_edge_search(c, OB_DIRECTION_EAST, FALSE);
928 if (a->x + a->width == x + c->frame->area.width) {
929 width = c->frame->area.width / 2;
930 x = a->x + a->width - width;
931 } else
932 width = dest - c->frame->area.x;
933 x += (width - c->frame->area.width) % c->size_inc.width;
934 width -= (width - c->frame->area.width) % c->size_inc.width;
935 break;
936 default:
937 g_assert_not_reached();
938 }
939 width -= c->frame->size.left + c->frame->size.right;
940 height -= c->frame->size.top + c->frame->size.bottom;
941 frame_frame_gravity(c->frame, &x, &y, width, height);
942 client_action_start(data);
943 client_move_resize(c, x, y, width, height);
944 client_action_end(data, FALSE);
945 g_free(a);
946 }
947
948 void action_send_to_layer(union ActionData *data)
949 {
950 client_set_layer(data->layer.any.c, data->layer.layer);
951 }
952
953 void action_toggle_layer(union ActionData *data)
954 {
955 ObClient *c = data->layer.any.c;
956
957 client_action_start(data);
958 if (data->layer.layer < 0)
959 client_set_layer(c, c->below ? 0 : -1);
960 else if (data->layer.layer > 0)
961 client_set_layer(c, c->above ? 0 : 1);
962 client_action_end(data, config_focus_under_mouse);
963 }
964
965 void action_toggle_dockautohide(union ActionData *data)
966 {
967 config_dock_hide = !config_dock_hide;
968 dock_configure();
969 }
970
971 void action_add_desktop(union ActionData *data)
972 {
973 client_action_start(data);
974 screen_set_num_desktops(screen_num_desktops+1);
975
976 /* move all the clients over */
977 if (data->addremovedesktop.current) {
978 GList *it;
979
980 for (it = client_list; it; it = g_list_next(it)) {
981 ObClient *c = it->data;
982 if (c->desktop != DESKTOP_ALL && c->desktop >= screen_desktop)
983 client_set_desktop(c, c->desktop+1, FALSE, TRUE);
984 }
985 }
986
987 client_action_end(data, config_focus_under_mouse);
988 }
989
990 void action_remove_desktop(union ActionData *data)
991 {
992 guint rmdesktop, movedesktop;
993 GList *it, *stacking_copy;
994
995 if (screen_num_desktops < 2) return;
996
997 client_action_start(data);
998
999 /* what desktop are we removing and moving to? */
1000 if (data->addremovedesktop.current)
1001 rmdesktop = screen_desktop;
1002 else
1003 rmdesktop = screen_num_desktops - 1;
1004 if (rmdesktop < screen_num_desktops - 1)
1005 movedesktop = rmdesktop + 1;
1006 else
1007 movedesktop = rmdesktop;
1008
1009 /* make a copy of the list cuz we're changing it */
1010 stacking_copy = g_list_copy(stacking_list);
1011 for (it = g_list_last(stacking_copy); it; it = g_list_previous(it)) {
1012 if (WINDOW_IS_CLIENT(it->data)) {
1013 ObClient *c = it->data;
1014 guint d = c->desktop;
1015 if (d != DESKTOP_ALL && d >= movedesktop) {
1016 client_set_desktop(c, c->desktop - 1, TRUE, TRUE);
1017 ob_debug("moving window %s\n", c->title);
1018 }
1019 /* raise all the windows that are on the current desktop which
1020 is being merged */
1021 if ((screen_desktop == rmdesktop - 1 ||
1022 screen_desktop == rmdesktop) &&
1023 (d == DESKTOP_ALL || d == screen_desktop))
1024 {
1025 stacking_raise(CLIENT_AS_WINDOW(c));
1026 ob_debug("raising window %s\n", c->title);
1027 }
1028 }
1029 }
1030
1031 /* act like we're changing desktops */
1032 if (screen_desktop < screen_num_desktops - 1) {
1033 gint d = screen_desktop;
1034 screen_desktop = screen_last_desktop;
1035 screen_set_desktop(d, TRUE);
1036 ob_debug("fake desktop change\n");
1037 }
1038
1039 screen_set_num_desktops(screen_num_desktops-1);
1040
1041 client_action_end(data, config_focus_under_mouse);
1042 }
This page took 0.081576 seconds and 4 git commands to generate.