]> Dogcows Code - chaz/openbox/blob - openbox/action.c
61f346b1cad329aeedd75ce248f92890c1827a6a
[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 "kill",
459 action_kill,
460 setup_client_action
461 },
462 {
463 "shadelower",
464 action_shadelower,
465 setup_client_action
466 },
467 {
468 "unshaderaise",
469 action_unshaderaise,
470 setup_client_action
471 },
472 {
473 "shade",
474 action_shade,
475 setup_client_action
476 },
477 {
478 "unshade",
479 action_unshade,
480 setup_client_action
481 },
482 {
483 "toggleshade",
484 action_toggle_shade,
485 setup_client_action
486 },
487 {
488 "toggleomnipresent",
489 action_toggle_omnipresent,
490 setup_client_action
491 },
492 {
493 "moverelativehorz",
494 action_move_relative_horz,
495 setup_client_action
496 },
497 {
498 "moverelativevert",
499 action_move_relative_vert,
500 setup_client_action
501 },
502 {
503 "resizerelativehorz",
504 action_resize_relative_horz,
505 setup_client_action
506 },
507 {
508 "resizerelativevert",
509 action_resize_relative_vert,
510 setup_client_action
511 },
512 {
513 "moverelative",
514 action_move_relative,
515 setup_client_action
516 },
517 {
518 "resizerelative",
519 action_resize_relative,
520 setup_client_action
521 },
522 {
523 "sendtodesktop",
524 action_send_to_desktop,
525 setup_action_send_to_desktop
526 },
527 {
528 "sendtodesktopnext",
529 action_send_to_desktop_dir,
530 setup_action_send_to_desktop_next
531 },
532 {
533 "sendtodesktopprevious",
534 action_send_to_desktop_dir,
535 setup_action_send_to_desktop_prev
536 },
537 {
538 "sendtodesktopright",
539 action_send_to_desktop_dir,
540 setup_action_send_to_desktop_right
541 },
542 {
543 "sendtodesktopleft",
544 action_send_to_desktop_dir,
545 setup_action_send_to_desktop_left
546 },
547 {
548 "sendtodesktopup",
549 action_send_to_desktop_dir,
550 setup_action_send_to_desktop_up
551 },
552 {
553 "sendtodesktopdown",
554 action_send_to_desktop_dir,
555 setup_action_send_to_desktop_down
556 },
557 {
558 "desktop",
559 action_desktop,
560 setup_action_desktop
561 },
562 {
563 "desktopnext",
564 action_desktop_dir,
565 setup_action_desktop_next
566 },
567 {
568 "desktopprevious",
569 action_desktop_dir,
570 setup_action_desktop_prev
571 },
572 {
573 "desktopright",
574 action_desktop_dir,
575 setup_action_desktop_right
576 },
577 {
578 "desktopleft",
579 action_desktop_dir,
580 setup_action_desktop_left
581 },
582 {
583 "desktopup",
584 action_desktop_dir,
585 setup_action_desktop_up
586 },
587 {
588 "desktopdown",
589 action_desktop_dir,
590 setup_action_desktop_down
591 },
592 {
593 "toggledecorations",
594 action_toggle_decorations,
595 setup_client_action
596 },
597 {
598 "resize",
599 action_resize,
600 setup_action_resize
601 },
602 {
603 "toggledockautohide",
604 action_toggle_dockautohide,
605 NULL
606 },
607 {
608 "desktoplast",
609 action_desktop_last,
610 NULL
611 },
612 {
613 "sendtotoplayer",
614 action_send_to_layer,
615 setup_action_top_layer
616 },
617 {
618 "togglealwaysontop",
619 action_toggle_layer,
620 setup_action_top_layer
621 },
622 {
623 "sendtonormallayer",
624 action_send_to_layer,
625 setup_action_normal_layer
626 },
627 {
628 "sendtobottomlayer",
629 action_send_to_layer,
630 setup_action_bottom_layer
631 },
632 {
633 "togglealwaysonbottom",
634 action_toggle_layer,
635 setup_action_bottom_layer
636 },
637 {
638 "movefromedgenorth",
639 action_movetoedge,
640 setup_action_movefromedge_north
641 },
642 {
643 "movefromedgesouth",
644 action_movetoedge,
645 setup_action_movefromedge_south
646 },
647 {
648 "movefromedgewest",
649 action_movetoedge,
650 setup_action_movefromedge_west
651 },
652 {
653 "movefromedgeeast",
654 action_movetoedge,
655 setup_action_movefromedge_east
656 },
657 {
658 "movetoedgenorth",
659 action_movetoedge,
660 setup_action_movetoedge_north
661 },
662 {
663 "movetoedgesouth",
664 action_movetoedge,
665 setup_action_movetoedge_south
666 },
667 {
668 "movetoedgewest",
669 action_movetoedge,
670 setup_action_movetoedge_west
671 },
672 {
673 "movetoedgeeast",
674 action_movetoedge,
675 setup_action_movetoedge_east
676 },
677 {
678 "growtoedgenorth",
679 action_growtoedge,
680 setup_action_growtoedge_north
681 },
682 {
683 "growtoedgesouth",
684 action_growtoedge,
685 setup_action_growtoedge_south
686 },
687 {
688 "growtoedgewest",
689 action_growtoedge,
690 setup_action_growtoedge_west
691 },
692 {
693 "growtoedgeeast",
694 action_growtoedge,
695 setup_action_growtoedge_east
696 },
697 {
698 "adddesktoplast",
699 action_add_desktop,
700 setup_action_addremove_desktop_last
701 },
702 {
703 "removedesktoplast",
704 action_remove_desktop,
705 setup_action_addremove_desktop_last
706 },
707 {
708 "adddesktopcurrent",
709 action_add_desktop,
710 setup_action_addremove_desktop_current
711 },
712 {
713 "removedesktopcurrent",
714 action_remove_desktop,
715 setup_action_addremove_desktop_current
716 },
717 {
718 NULL,
719 NULL,
720 NULL
721 }
722 };
723
724 /* only key bindings can be interactive. thus saith the xor.
725 because of how the mouse is grabbed, mouse events dont even get
726 read during interactive events, so no dice! >:) */
727 #define INTERACTIVE_LIMIT(a, uact) \
728 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
729 a->data.any.interactive = FALSE;
730
731 ObAction *action_from_string(const gchar *name, ObUserAction uact)
732 {
733 ObAction *a = NULL;
734 gboolean exist = FALSE;
735 gint i;
736
737 for (i = 0; actionstrings[i].name; i++)
738 if (!g_ascii_strcasecmp(name, actionstrings[i].name)) {
739 exist = TRUE;
740 a = action_new(actionstrings[i].func);
741 if (actionstrings[i].setup)
742 actionstrings[i].setup(&a, uact);
743 if (a)
744 INTERACTIVE_LIMIT(a, uact);
745 break;
746 }
747 if (!exist)
748 g_message(_("Invalid action '%s' requested. No such action exists."),
749 name);
750 if (!a)
751 g_message(_("Invalid use of action '%s'. Action will be ignored."),
752 name);
753 return a;
754 }
755
756 ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
757 ObUserAction uact)
758 {
759 gchar *actname;
760 ObAction *act = NULL;
761 xmlNodePtr n;
762
763 if (parse_attr_string("name", node, &actname)) {
764 if ((act = action_from_string(actname, uact))) {
765 } else if (act->func == action_move_relative_horz ||
766 act->func == action_move_relative_vert ||
767 act->func == action_resize_relative_horz ||
768 act->func == action_resize_relative_vert) {
769 if ((n = parse_find_node("delta", node->xmlChildrenNode)))
770 act->data.relative.deltax = parse_int(doc, n);
771 } else if (act->func == action_move_relative) {
772 if ((n = parse_find_node("x", node->xmlChildrenNode)))
773 act->data.relative.deltax = parse_int(doc, n);
774 if ((n = parse_find_node("y", node->xmlChildrenNode)))
775 act->data.relative.deltay = parse_int(doc, n);
776 } else if (act->func == action_resize_relative) {
777 if ((n = parse_find_node("left", node->xmlChildrenNode)))
778 act->data.relative.deltaxl = parse_int(doc, n);
779 if ((n = parse_find_node("up", node->xmlChildrenNode)))
780 act->data.relative.deltayu = parse_int(doc, n);
781 if ((n = parse_find_node("right", node->xmlChildrenNode)))
782 act->data.relative.deltax = parse_int(doc, n);
783 if ((n = parse_find_node("down", node->xmlChildrenNode)))
784 act->data.relative.deltay = parse_int(doc, n);
785 } else if (act->func == action_desktop) {
786 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
787 act->data.desktop.desk = parse_int(doc, n);
788 if (act->data.desktop.desk > 0) act->data.desktop.desk--;
789 /*
790 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
791 act->data.desktop.inter.any.interactive =
792 parse_bool(doc, n);
793 */
794 } else if (act->func == action_send_to_desktop) {
795 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
796 act->data.sendto.desk = parse_int(doc, n);
797 if (act->data.sendto.desk > 0) act->data.sendto.desk--;
798 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
799 act->data.sendto.follow = parse_bool(doc, n);
800 } else if (act->func == action_desktop_dir) {
801 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
802 act->data.desktopdir.wrap = parse_bool(doc, n);
803 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
804 act->data.desktopdir.inter.any.interactive =
805 parse_bool(doc, n);
806 } else if (act->func == action_send_to_desktop_dir) {
807 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
808 act->data.sendtodir.wrap = parse_bool(doc, n);
809 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
810 act->data.sendtodir.follow = parse_bool(doc, n);
811 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
812 act->data.sendtodir.inter.any.interactive =
813 parse_bool(doc, n);
814 } else if (act->func == action_directional_focus) {
815 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
816 act->data.interdiraction.dialog = parse_bool(doc, n);
817 if ((n = parse_find_node("panels", node->xmlChildrenNode)))
818 act->data.interdiraction.dock_windows = parse_bool(doc, n);
819 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
820 act->data.interdiraction.desktop_windows =
821 parse_bool(doc, n);
822 } else if (act->func == action_resize) {
823 if ((n = parse_find_node("edge", node->xmlChildrenNode))) {
824 gchar *s = parse_string(doc, n);
825 if (!g_ascii_strcasecmp(s, "top"))
826 act->data.moveresize.corner =
827 prop_atoms.net_wm_moveresize_size_top;
828 else if (!g_ascii_strcasecmp(s, "bottom"))
829 act->data.moveresize.corner =
830 prop_atoms.net_wm_moveresize_size_bottom;
831 else if (!g_ascii_strcasecmp(s, "left"))
832 act->data.moveresize.corner =
833 prop_atoms.net_wm_moveresize_size_left;
834 else if (!g_ascii_strcasecmp(s, "right"))
835 act->data.moveresize.corner =
836 prop_atoms.net_wm_moveresize_size_right;
837 else if (!g_ascii_strcasecmp(s, "topleft"))
838 act->data.moveresize.corner =
839 prop_atoms.net_wm_moveresize_size_topleft;
840 else if (!g_ascii_strcasecmp(s, "topright"))
841 act->data.moveresize.corner =
842 prop_atoms.net_wm_moveresize_size_topright;
843 else if (!g_ascii_strcasecmp(s, "bottomleft"))
844 act->data.moveresize.corner =
845 prop_atoms.net_wm_moveresize_size_bottomleft;
846 else if (!g_ascii_strcasecmp(s, "bottomright"))
847 act->data.moveresize.corner =
848 prop_atoms.net_wm_moveresize_size_bottomright;
849 g_free(s);
850 }
851 INTERACTIVE_LIMIT(act, uact);
852 }
853 g_free(actname);
854 }
855 return act;
856 }
857
858 void action_run_list(GSList *acts, ObClient *c, ObFrameContext context,
859 guint state, guint button, gint x, gint y, Time time,
860 gboolean cancel, gboolean done)
861 {
862 GSList *it;
863 ObAction *a;
864
865 if (!acts)
866 return;
867
868 if (x < 0 && y < 0)
869 screen_pointer_pos(&x, &y);
870
871 for (it = acts; it; it = g_slist_next(it)) {
872 a = it->data;
873
874 if (!(a->data.any.client_action == OB_CLIENT_ACTION_ALWAYS && !c)) {
875 a->data.any.c = a->data.any.client_action ? c : NULL;
876 a->data.any.context = context;
877 a->data.any.x = x;
878 a->data.any.y = y;
879
880 a->data.any.button = button;
881
882 a->data.any.time = time;
883
884 if (a->data.any.interactive) {
885 a->data.inter.cancel = cancel;
886 a->data.inter.final = done;
887 if (!(cancel || done))
888 if (!keyboard_interactive_grab(state, a->data.any.c, a))
889 continue;
890 }
891
892 /* XXX UGLY HACK race with motion event starting a move and the
893 button release gettnig processed first. answer: don't queue
894 moveresize starts. UGLY HACK XXX
895
896 XXX ALSO don't queue showmenu events, because on button press
897 events we need to know if a mouse grab is going to take place,
898 and set the button to 0, so that later motion events don't think
899 that a drag is going on. since showmenu grabs the pointer..
900 */
901 if (a->data.any.interactive || a->func == action_move ||
902 a->func == action_resize || a->func == action_showmenu)
903 {
904 /* interactive actions are not queued */
905 a->func(&a->data);
906 } else if (a->func == action_focus ||
907 a->func == action_activate ||
908 a->func == action_showmenu)
909 {
910 /* XXX MORE UGLY HACK
911 actions from clicks on client windows are NOT queued.
912 this solves the mysterious click-and-drag-doesnt-work
913 problem. it was because the window gets focused and stuff
914 after the button event has already been passed through. i
915 dont really know why it should care but it does and it makes
916 a difference.
917
918 however this very bogus ! !
919 we want to send the button press to the window BEFORE
920 we do the action because the action might move the windows
921 (eg change desktops) and then the button press ends up on
922 the completely wrong window !
923 so, this is just for that bug, and it will only NOT queue it
924 if it is a focusing action that can be used with the mouse
925 pointer. ugh.
926
927 also with the menus, there is a race going on. if the
928 desktop wants to pop up a menu, and we do too, we send them
929 the button before we pop up the menu, so they pop up their
930 menu first. but not always. if we pop up our menu before
931 sending them the button press, then the result is
932 deterministic. yay.
933
934 XXX further more. focus actions are not queued at all,
935 because if you bind focus->showmenu, the menu will get
936 hidden to do the focusing
937 */
938 a->func(&a->data);
939 } else
940 ob_main_loop_queue_action(ob_main_loop, a);
941 }
942 }
943 }
944
945 void action_run_string(const gchar *name, struct _ObClient *c, Time time)
946 {
947 ObAction *a;
948 GSList *l;
949
950 a = action_from_string(name, OB_USER_ACTION_NONE);
951 g_assert(a);
952
953 l = g_slist_append(NULL, a);
954
955 action_run(l, c, 0, time);
956 }
957
958 void action_unshaderaise(union ActionData *data)
959 {
960 if (data->client.any.c->shaded)
961 action_unshade(data);
962 else
963 action_raise(data);
964 }
965
966 void action_shadelower(union ActionData *data)
967 {
968 if (data->client.any.c->shaded)
969 action_lower(data);
970 else
971 action_shade(data);
972 }
973
974 void action_kill(union ActionData *data)
975 {
976 client_kill(data->client.any.c);
977 }
978
979 void action_shade(union ActionData *data)
980 {
981 client_action_start(data);
982 client_shade(data->client.any.c, TRUE);
983 client_action_end(data, config_focus_under_mouse);
984 }
985
986 void action_unshade(union ActionData *data)
987 {
988 client_action_start(data);
989 client_shade(data->client.any.c, FALSE);
990 client_action_end(data, config_focus_under_mouse);
991 }
992
993 void action_toggle_shade(union ActionData *data)
994 {
995 client_action_start(data);
996 client_shade(data->client.any.c, !data->client.any.c->shaded);
997 client_action_end(data, config_focus_under_mouse);
998 }
999
1000 void action_toggle_omnipresent(union ActionData *data)
1001 {
1002 client_set_desktop(data->client.any.c,
1003 data->client.any.c->desktop == DESKTOP_ALL ?
1004 screen_desktop : DESKTOP_ALL, FALSE, TRUE);
1005 }
1006
1007 void action_move_relative_horz(union ActionData *data)
1008 {
1009 ObClient *c = data->relative.any.c;
1010 client_action_start(data);
1011 client_move(c, c->area.x + data->relative.deltax, c->area.y);
1012 client_action_end(data, FALSE);
1013 }
1014
1015 void action_move_relative_vert(union ActionData *data)
1016 {
1017 ObClient *c = data->relative.any.c;
1018 client_action_start(data);
1019 client_move(c, c->area.x, c->area.y + data->relative.deltax);
1020 client_action_end(data, FALSE);
1021 }
1022
1023 void action_resize_relative_horz(union ActionData *data)
1024 {
1025 ObClient *c = data->relative.any.c;
1026 client_action_start(data);
1027 client_resize(c,
1028 c->area.width + data->relative.deltax * c->size_inc.width,
1029 c->area.height);
1030 client_action_end(data, FALSE);
1031 }
1032
1033 void action_resize_relative_vert(union ActionData *data)
1034 {
1035 ObClient *c = data->relative.any.c;
1036 if (!c->shaded) {
1037 client_action_start(data);
1038 client_resize(c, c->area.width, c->area.height +
1039 data->relative.deltax * c->size_inc.height);
1040 client_action_end(data, FALSE);
1041 }
1042 }
1043
1044 void action_move_relative(union ActionData *data)
1045 {
1046 ObClient *c = data->relative.any.c;
1047 client_action_start(data);
1048 client_move(c, c->area.x + data->relative.deltax, c->area.y +
1049 data->relative.deltay);
1050 client_action_end(data, FALSE);
1051 }
1052
1053 void action_resize_relative(union ActionData *data)
1054 {
1055 ObClient *c = data->relative.any.c;
1056 gint x, y, ow, xoff, nw, oh, yoff, nh, lw, lh;
1057
1058 client_action_start(data);
1059
1060 x = c->area.x;
1061 y = c->area.y;
1062 ow = c->area.width;
1063 xoff = -data->relative.deltaxl * c->size_inc.width;
1064 nw = ow + data->relative.deltax * c->size_inc.width
1065 + data->relative.deltaxl * c->size_inc.width;
1066 oh = c->area.height;
1067 yoff = -data->relative.deltayu * c->size_inc.height;
1068 nh = oh + data->relative.deltay * c->size_inc.height
1069 + data->relative.deltayu * c->size_inc.height;
1070
1071 g_print("deltax %d %d x %d ow %d xoff %d nw %d\n",
1072 data->relative.deltax,
1073 data->relative.deltaxl,
1074 x, ow, xoff, nw);
1075
1076 client_try_configure(c, &x, &y, &nw, &nh, &lw, &lh, TRUE);
1077 xoff = xoff == 0 ? 0 : (xoff < 0 ? MAX(xoff, ow-nw) : MIN(xoff, ow-nw));
1078 yoff = yoff == 0 ? 0 : (yoff < 0 ? MAX(yoff, oh-nh) : MIN(yoff, oh-nh));
1079 client_move_resize(c, x + xoff, y + yoff, nw, nh);
1080 client_action_end(data, FALSE);
1081 }
1082
1083 void action_send_to_desktop(union ActionData *data)
1084 {
1085 ObClient *c = data->sendto.any.c;
1086
1087 if (!client_normal(c)) return;
1088
1089 if (data->sendto.desk < screen_num_desktops ||
1090 data->sendto.desk == DESKTOP_ALL) {
1091 client_set_desktop(c, data->sendto.desk, data->sendto.follow, FALSE);
1092 if (data->sendto.follow && data->sendto.desk != screen_desktop)
1093 screen_set_desktop(data->sendto.desk, TRUE);
1094 }
1095 }
1096
1097 void action_desktop(union ActionData *data)
1098 {
1099 /* XXX add the interactive/dialog option back again once the dialog
1100 has been made to not use grabs */
1101 if (data->desktop.desk < screen_num_desktops ||
1102 data->desktop.desk == DESKTOP_ALL)
1103 {
1104 screen_set_desktop(data->desktop.desk, TRUE);
1105 if (data->inter.any.interactive)
1106 screen_desktop_popup(data->desktop.desk, TRUE);
1107 }
1108 }
1109
1110 void action_desktop_dir(union ActionData *data)
1111 {
1112 guint d;
1113
1114 d = screen_cycle_desktop(data->desktopdir.dir,
1115 data->desktopdir.wrap,
1116 data->desktopdir.linear,
1117 data->desktopdir.inter.any.interactive,
1118 data->desktopdir.inter.final,
1119 data->desktopdir.inter.cancel);
1120 /* only move the desktop when the action is complete. if we switch
1121 desktops during the interactive action, focus will move but with
1122 NotifyWhileGrabbed and applications don't like that. */
1123 if (!data->sendtodir.inter.any.interactive ||
1124 (data->sendtodir.inter.final && !data->sendtodir.inter.cancel))
1125 {
1126 if (d != screen_desktop)
1127 screen_set_desktop(d, TRUE);
1128 }
1129 }
1130
1131 void action_send_to_desktop_dir(union ActionData *data)
1132 {
1133 ObClient *c = data->sendtodir.inter.any.c;
1134 guint d;
1135
1136 if (!client_normal(c)) return;
1137
1138 d = screen_cycle_desktop(data->sendtodir.dir, data->sendtodir.wrap,
1139 data->sendtodir.linear,
1140 data->sendtodir.inter.any.interactive,
1141 data->sendtodir.inter.final,
1142 data->sendtodir.inter.cancel);
1143 /* only move the desktop when the action is complete. if we switch
1144 desktops during the interactive action, focus will move but with
1145 NotifyWhileGrabbed and applications don't like that. */
1146 if (!data->sendtodir.inter.any.interactive ||
1147 (data->sendtodir.inter.final && !data->sendtodir.inter.cancel))
1148 {
1149 client_set_desktop(c, d, data->sendtodir.follow, FALSE);
1150 if (data->sendtodir.follow && d != screen_desktop)
1151 screen_set_desktop(d, TRUE);
1152 }
1153 }
1154
1155 void action_desktop_last(union ActionData *data)
1156 {
1157 if (screen_last_desktop < screen_num_desktops)
1158 screen_set_desktop(screen_last_desktop, TRUE);
1159 }
1160
1161 void action_toggle_decorations(union ActionData *data)
1162 {
1163 ObClient *c = data->client.any.c;
1164
1165 client_action_start(data);
1166 client_set_undecorated(c, !c->undecorated);
1167 client_action_end(data, FALSE);
1168 }
1169
1170 static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch,
1171 gboolean shaded)
1172 {
1173 /* let's make x and y client relative instead of screen relative */
1174 x = x - cx;
1175 y = ch - (y - cy); /* y is inverted, 0 is at the bottom of the window */
1176
1177 #define X x*ch/cw
1178 #define A -4*X + 7*ch/3
1179 #define B 4*X -15*ch/9
1180 #define C -X/4 + 2*ch/3
1181 #define D X/4 + 5*ch/12
1182 #define E X/4 + ch/3
1183 #define F -X/4 + 7*ch/12
1184 #define G 4*X - 4*ch/3
1185 #define H -4*X + 8*ch/3
1186 #define a (y > 5*ch/9)
1187 #define b (x < 4*cw/9)
1188 #define c (x > 5*cw/9)
1189 #define d (y < 4*ch/9)
1190
1191 /*
1192 Each of these defines (except X which is just there for fun), represents
1193 the equation of a line. The lines they represent are shown in the diagram
1194 below. Checking y against these lines, we are able to choose a region
1195 of the window as shown.
1196
1197 +---------------------A-------|-------|-------B---------------------+
1198 | |A B| |
1199 | |A | | B| |
1200 | | A B | |
1201 | | A | | B | |
1202 | | A B | |
1203 | | A | | B | |
1204 | northwest | A north B | northeast |
1205 | | A | | B | |
1206 | | A B | |
1207 C---------------------+----A--+-------+--B----+---------------------D
1208 |CCCCCCC | A B | DDDDDDD|
1209 | CCCCCCCC | A | | B | DDDDDDDD |
1210 | CCCCCCC A B DDDDDDD |
1211 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
1212 | | b c | | sh
1213 | west | b move c | east | ad
1214 | | b c | | ed
1215 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
1216 | EEEEEEE G H FFFFFFF |
1217 | EEEEEEEE | G | | H | FFFFFFFF |
1218 |EEEEEEE | G H | FFFFFFF|
1219 E---------------------+----G--+-------+--H----+---------------------F
1220 | | G H | |
1221 | | G | | H | |
1222 | southwest | G south H | southeast |
1223 | | G | | H | |
1224 | | G H | |
1225 | | G | | H | |
1226 | | G H | |
1227 | |G | | H| |
1228 | |G H| |
1229 +---------------------G-------|-------|-------H---------------------+
1230 */
1231
1232 if (shaded) {
1233 /* for shaded windows, you can only resize west/east and move */
1234 if (b)
1235 return prop_atoms.net_wm_moveresize_size_left;
1236 if (c)
1237 return prop_atoms.net_wm_moveresize_size_right;
1238 return prop_atoms.net_wm_moveresize_move;
1239 }
1240
1241 if (y < A && y >= C)
1242 return prop_atoms.net_wm_moveresize_size_topleft;
1243 else if (y >= A && y >= B && a)
1244 return prop_atoms.net_wm_moveresize_size_top;
1245 else if (y < B && y >= D)
1246 return prop_atoms.net_wm_moveresize_size_topright;
1247 else if (y < C && y >= E && b)
1248 return prop_atoms.net_wm_moveresize_size_left;
1249 else if (y < D && y >= F && c)
1250 return prop_atoms.net_wm_moveresize_size_right;
1251 else if (y < E && y >= G)
1252 return prop_atoms.net_wm_moveresize_size_bottomleft;
1253 else if (y < G && y < H && d)
1254 return prop_atoms.net_wm_moveresize_size_bottom;
1255 else if (y >= H && y < F)
1256 return prop_atoms.net_wm_moveresize_size_bottomright;
1257 else
1258 return prop_atoms.net_wm_moveresize_move;
1259
1260 #undef X
1261 #undef A
1262 #undef B
1263 #undef C
1264 #undef D
1265 #undef E
1266 #undef F
1267 #undef G
1268 #undef H
1269 #undef a
1270 #undef b
1271 #undef c
1272 #undef d
1273 }
1274
1275 void action_resize(union ActionData *data)
1276 {
1277 ObClient *c = data->moveresize.any.c;
1278 guint32 corner;
1279
1280 if (data->moveresize.keyboard)
1281 corner = prop_atoms.net_wm_moveresize_size_keyboard;
1282 else if (data->moveresize.corner)
1283 corner = data->moveresize.corner; /* it was specified in the binding */
1284 else
1285 corner = pick_corner(data->any.x, data->any.y,
1286 c->frame->area.x, c->frame->area.y,
1287 /* use the client size because the frame
1288 can be differently sized (shaded
1289 windows) and we want this based on the
1290 clients size */
1291 c->area.width + c->frame->size.left +
1292 c->frame->size.right,
1293 c->area.height + c->frame->size.top +
1294 c->frame->size.bottom, c->shaded);
1295
1296 moveresize_start(c, data->any.x, data->any.y, data->any.button, corner);
1297 }
1298
1299 void action_directional_focus(union ActionData *data)
1300 {
1301 /* if using focus_delay, stop the timer now so that focus doesn't go moving
1302 on us */
1303 event_halt_focus_delay();
1304
1305 focus_directional_cycle(data->interdiraction.direction,
1306 data->interdiraction.dock_windows,
1307 data->interdiraction.desktop_windows,
1308 data->any.interactive,
1309 data->interdiraction.dialog,
1310 data->interdiraction.inter.final,
1311 data->interdiraction.inter.cancel);
1312 }
1313
1314 void action_movetoedge(union ActionData *data)
1315 {
1316 gint x, y;
1317 ObClient *c = data->diraction.any.c;
1318
1319 x = c->frame->area.x;
1320 y = c->frame->area.y;
1321
1322 switch(data->diraction.direction) {
1323 case OB_DIRECTION_NORTH:
1324 y = client_directional_edge_search(c, OB_DIRECTION_NORTH,
1325 data->diraction.hang)
1326 - (data->diraction.hang ? c->frame->area.height : 0);
1327 break;
1328 case OB_DIRECTION_WEST:
1329 x = client_directional_edge_search(c, OB_DIRECTION_WEST,
1330 data->diraction.hang)
1331 - (data->diraction.hang ? c->frame->area.width : 0);
1332 break;
1333 case OB_DIRECTION_SOUTH:
1334 y = client_directional_edge_search(c, OB_DIRECTION_SOUTH,
1335 data->diraction.hang)
1336 - (data->diraction.hang ? 0 : c->frame->area.height);
1337 break;
1338 case OB_DIRECTION_EAST:
1339 x = client_directional_edge_search(c, OB_DIRECTION_EAST,
1340 data->diraction.hang)
1341 - (data->diraction.hang ? 0 : c->frame->area.width);
1342 break;
1343 default:
1344 g_assert_not_reached();
1345 }
1346 frame_frame_gravity(c->frame, &x, &y, c->area.width, c->area.height);
1347 client_action_start(data);
1348 client_move(c, x, y);
1349 client_action_end(data, FALSE);
1350 }
1351
1352 void action_growtoedge(union ActionData *data)
1353 {
1354 gint x, y, width, height, dest;
1355 ObClient *c = data->diraction.any.c;
1356 Rect *a;
1357
1358 a = screen_area(c->desktop, SCREEN_AREA_ALL_MONITORS, &c->frame->area);
1359 x = c->frame->area.x;
1360 y = c->frame->area.y;
1361 /* get the unshaded frame's dimensions..if it is shaded */
1362 width = c->area.width + c->frame->size.left + c->frame->size.right;
1363 height = c->area.height + c->frame->size.top + c->frame->size.bottom;
1364
1365 switch(data->diraction.direction) {
1366 case OB_DIRECTION_NORTH:
1367 if (c->shaded) break; /* don't allow vertical resize if shaded */
1368
1369 dest = client_directional_edge_search(c, OB_DIRECTION_NORTH, FALSE);
1370 if (a->y == y)
1371 height = height / 2;
1372 else {
1373 height = c->frame->area.y + height - dest;
1374 y = dest;
1375 }
1376 break;
1377 case OB_DIRECTION_WEST:
1378 dest = client_directional_edge_search(c, OB_DIRECTION_WEST, FALSE);
1379 if (a->x == x)
1380 width = width / 2;
1381 else {
1382 width = c->frame->area.x + width - dest;
1383 x = dest;
1384 }
1385 break;
1386 case OB_DIRECTION_SOUTH:
1387 if (c->shaded) break; /* don't allow vertical resize if shaded */
1388
1389 dest = client_directional_edge_search(c, OB_DIRECTION_SOUTH, FALSE);
1390 if (a->y + a->height == y + c->frame->area.height) {
1391 height = c->frame->area.height / 2;
1392 y = a->y + a->height - height;
1393 } else
1394 height = dest - c->frame->area.y;
1395 y += (height - c->frame->area.height) % c->size_inc.height;
1396 height -= (height - c->frame->area.height) % c->size_inc.height;
1397 break;
1398 case OB_DIRECTION_EAST:
1399 dest = client_directional_edge_search(c, OB_DIRECTION_EAST, FALSE);
1400 if (a->x + a->width == x + c->frame->area.width) {
1401 width = c->frame->area.width / 2;
1402 x = a->x + a->width - width;
1403 } else
1404 width = dest - c->frame->area.x;
1405 x += (width - c->frame->area.width) % c->size_inc.width;
1406 width -= (width - c->frame->area.width) % c->size_inc.width;
1407 break;
1408 default:
1409 g_assert_not_reached();
1410 }
1411 width -= c->frame->size.left + c->frame->size.right;
1412 height -= c->frame->size.top + c->frame->size.bottom;
1413 frame_frame_gravity(c->frame, &x, &y, width, height);
1414 client_action_start(data);
1415 client_move_resize(c, x, y, width, height);
1416 client_action_end(data, FALSE);
1417 g_free(a);
1418 }
1419
1420 void action_send_to_layer(union ActionData *data)
1421 {
1422 client_set_layer(data->layer.any.c, data->layer.layer);
1423 }
1424
1425 void action_toggle_layer(union ActionData *data)
1426 {
1427 ObClient *c = data->layer.any.c;
1428
1429 client_action_start(data);
1430 if (data->layer.layer < 0)
1431 client_set_layer(c, c->below ? 0 : -1);
1432 else if (data->layer.layer > 0)
1433 client_set_layer(c, c->above ? 0 : 1);
1434 client_action_end(data, config_focus_under_mouse);
1435 }
1436
1437 void action_toggle_dockautohide(union ActionData *data)
1438 {
1439 config_dock_hide = !config_dock_hide;
1440 dock_configure();
1441 }
1442
1443 void action_add_desktop(union ActionData *data)
1444 {
1445 client_action_start(data);
1446 screen_set_num_desktops(screen_num_desktops+1);
1447
1448 /* move all the clients over */
1449 if (data->addremovedesktop.current) {
1450 GList *it;
1451
1452 for (it = client_list; it; it = g_list_next(it)) {
1453 ObClient *c = it->data;
1454 if (c->desktop != DESKTOP_ALL && c->desktop >= screen_desktop)
1455 client_set_desktop(c, c->desktop+1, FALSE, TRUE);
1456 }
1457 }
1458
1459 client_action_end(data, config_focus_under_mouse);
1460 }
1461
1462 void action_remove_desktop(union ActionData *data)
1463 {
1464 guint rmdesktop, movedesktop;
1465 GList *it, *stacking_copy;
1466
1467 if (screen_num_desktops < 2) return;
1468
1469 client_action_start(data);
1470
1471 /* what desktop are we removing and moving to? */
1472 if (data->addremovedesktop.current)
1473 rmdesktop = screen_desktop;
1474 else
1475 rmdesktop = screen_num_desktops - 1;
1476 if (rmdesktop < screen_num_desktops - 1)
1477 movedesktop = rmdesktop + 1;
1478 else
1479 movedesktop = rmdesktop;
1480
1481 /* make a copy of the list cuz we're changing it */
1482 stacking_copy = g_list_copy(stacking_list);
1483 for (it = g_list_last(stacking_copy); it; it = g_list_previous(it)) {
1484 if (WINDOW_IS_CLIENT(it->data)) {
1485 ObClient *c = it->data;
1486 guint d = c->desktop;
1487 if (d != DESKTOP_ALL && d >= movedesktop) {
1488 client_set_desktop(c, c->desktop - 1, TRUE, TRUE);
1489 ob_debug("moving window %s\n", c->title);
1490 }
1491 /* raise all the windows that are on the current desktop which
1492 is being merged */
1493 if ((screen_desktop == rmdesktop - 1 ||
1494 screen_desktop == rmdesktop) &&
1495 (d == DESKTOP_ALL || d == screen_desktop))
1496 {
1497 stacking_raise(CLIENT_AS_WINDOW(c));
1498 ob_debug("raising window %s\n", c->title);
1499 }
1500 }
1501 }
1502
1503 /* act like we're changing desktops */
1504 if (screen_desktop < screen_num_desktops - 1) {
1505 gint d = screen_desktop;
1506 screen_desktop = screen_last_desktop;
1507 screen_set_desktop(d, TRUE);
1508 ob_debug("fake desktop change\n");
1509 }
1510
1511 screen_set_num_desktops(screen_num_desktops-1);
1512
1513 client_action_end(data, config_focus_under_mouse);
1514 }
This page took 0.099403 seconds and 3 git commands to generate.