]> icculus.org git repositories - dana/openbox.git/blob - openbox/action.c
bug fixes for growtoedge from tore. props to tore for all the growtoedge and movetoed...
[dana/openbox.git] / openbox / action.c
1 #include "debug.h"
2 #include "client.h"
3 #include "focus.h"
4 #include "moveresize.h"
5 #include "menu.h"
6 #include "prop.h"
7 #include "stacking.h"
8 #include "frame.h"
9 #include "screen.h"
10 #include "action.h"
11 #include "dispatch.h"
12 #include "openbox.h"
13
14 #include <glib.h>
15
16 typedef struct ActionString {
17     char *name;
18     void (*func)(union ActionData *);
19     void (*setup)(ObAction *);
20 } ActionString;
21
22 ObAction *action_new(void (*func)(union ActionData *data))
23 {
24     ObAction *a = g_new0(ObAction, 1);
25     a->func = func;
26
27     return a;
28 }
29
30 void action_free(ObAction *a)
31 {
32     if (a == NULL) return;
33
34     /* deal with pointers */
35     if (a->func == action_execute || a->func == action_restart)
36         g_free(a->data.execute.path);
37     else if (a->func == action_showmenu)
38         g_free(a->data.showmenu.name);
39
40     g_free(a);
41 }
42
43 void setup_action_directional_focus_north(ObAction *a)
44 {
45     a->data.diraction.direction = OB_DIRECTION_NORTH;
46 }
47
48 void setup_action_directional_focus_east(ObAction *a)
49 {
50     a->data.diraction.direction = OB_DIRECTION_EAST;
51 }
52
53 void setup_action_directional_focus_south(ObAction *a)
54 {
55     a->data.diraction.direction = OB_DIRECTION_SOUTH;
56 }
57
58 void setup_action_directional_focus_west(ObAction *a)
59 {
60     a->data.diraction.direction = OB_DIRECTION_WEST;
61 }
62
63 void setup_action_directional_focus_northeast(ObAction *a)
64 {
65     a->data.diraction.direction = OB_DIRECTION_NORTHEAST;
66 }
67
68 void setup_action_directional_focus_southeast(ObAction *a)
69 {
70     a->data.diraction.direction = OB_DIRECTION_SOUTHEAST;
71 }
72
73 void setup_action_directional_focus_southwest(ObAction *a)
74 {
75     a->data.diraction.direction = OB_DIRECTION_SOUTHWEST;
76 }
77
78 void setup_action_directional_focus_northwest(ObAction *a)
79 {
80     a->data.diraction.direction = OB_DIRECTION_NORTHWEST;
81 }
82
83 void setup_action_send_to_desktop(ObAction *a)
84 {
85 }
86
87 void setup_action_send_to_desktop_prev(ObAction *a)
88 {
89     a->data.sendtodir.dir = OB_DIRECTION_WEST;
90     a->data.sendtodir.linear = TRUE;
91     a->data.sendtodir.wrap = TRUE;
92 }
93
94 void setup_action_send_to_desktop_next(ObAction *a)
95 {
96     a->data.sendtodir.dir = OB_DIRECTION_EAST;
97     a->data.sendtodir.linear = TRUE;
98     a->data.sendtodir.wrap = TRUE;
99 }
100
101 void setup_action_send_to_desktop_left(ObAction *a)
102 {
103     a->data.sendtodir.dir = OB_DIRECTION_WEST;
104     a->data.sendtodir.linear = FALSE;
105     a->data.sendtodir.wrap = TRUE;
106 }
107
108 void setup_action_send_to_desktop_right(ObAction *a)
109 {
110     a->data.sendtodir.dir = OB_DIRECTION_EAST;
111     a->data.sendtodir.linear = FALSE;
112     a->data.sendtodir.wrap = TRUE;
113 }
114
115 void setup_action_send_to_desktop_up(ObAction *a)
116 {
117     a->data.sendtodir.dir = OB_DIRECTION_NORTH;
118     a->data.sendtodir.linear = FALSE;
119     a->data.sendtodir.wrap = TRUE;
120 }
121
122 void setup_action_send_to_desktop_down(ObAction *a)
123 {
124     a->data.sendtodir.dir = OB_DIRECTION_SOUTH;
125     a->data.sendtodir.linear = FALSE;
126     a->data.sendtodir.wrap = TRUE;
127 }
128
129 void setup_action_desktop_prev(ObAction *a)
130 {
131     a->data.desktopdir.dir = OB_DIRECTION_WEST;
132     a->data.desktopdir.linear = TRUE;
133     a->data.desktopdir.wrap = TRUE;
134 }
135
136 void setup_action_desktop_next(ObAction *a)
137 {
138     a->data.desktopdir.dir = OB_DIRECTION_EAST;
139     a->data.desktopdir.linear = TRUE;
140     a->data.desktopdir.wrap = TRUE;
141 }
142
143 void setup_action_desktop_left(ObAction *a)
144 {
145     a->data.desktopdir.dir = OB_DIRECTION_WEST;
146     a->data.desktopdir.linear = FALSE;
147     a->data.desktopdir.wrap = TRUE;
148 }
149
150 void setup_action_desktop_right(ObAction *a)
151 {
152     a->data.desktopdir.dir = OB_DIRECTION_EAST;
153     a->data.desktopdir.linear = FALSE;
154     a->data.desktopdir.wrap = TRUE;
155 }
156
157 void setup_action_desktop_up(ObAction *a)
158 {
159     a->data.desktopdir.dir = OB_DIRECTION_NORTH;
160     a->data.desktopdir.linear = FALSE;
161     a->data.desktopdir.wrap = TRUE;
162 }
163
164 void setup_action_desktop_down(ObAction *a)
165 {
166     a->data.desktopdir.dir = OB_DIRECTION_SOUTH;
167     a->data.desktopdir.linear = FALSE;
168     a->data.desktopdir.wrap = TRUE;
169 }
170
171 void setup_action_move_keyboard(ObAction *a)
172 {
173     a->data.moveresize.corner = prop_atoms.net_wm_moveresize_move_keyboard;
174 }
175
176 void setup_action_move(ObAction *a)
177 {
178     a->data.moveresize.corner = prop_atoms.net_wm_moveresize_move;
179 }
180
181 void setup_action_resize(ObAction *a)
182 {
183     a->data.moveresize.corner = prop_atoms.net_wm_moveresize_size_topleft;
184 }
185
186 void setup_action_resize_keyboard(ObAction *a)
187 {
188     a->data.moveresize.corner = prop_atoms.net_wm_moveresize_size_keyboard;
189 }
190
191 void setup_action_cycle_windows_linear_next(ObAction *a)
192 {
193     a->data.cycle.linear = TRUE;
194     a->data.cycle.forward = TRUE;
195 }
196
197 void setup_action_cycle_windows_linear_previous(ObAction *a)
198 {
199     a->data.cycle.linear = TRUE;
200     a->data.cycle.forward = FALSE;
201 }
202
203 void setup_action_cycle_windows_next(ObAction *a)
204 {
205     a->data.cycle.linear = FALSE;
206     a->data.cycle.forward = TRUE;
207 }
208
209 void setup_action_cycle_windows_previous(ObAction *a)
210 {
211     a->data.cycle.linear = FALSE;
212     a->data.cycle.forward = FALSE;
213 }
214
215 void setup_action_movetoedge_north(ObAction *a)
216 {
217     a->data.diraction.direction = OB_DIRECTION_NORTH;
218 }
219
220 void setup_action_movetoedge_south(ObAction *a)
221 {
222     a->data.diraction.direction = OB_DIRECTION_SOUTH;
223 }
224
225 void setup_action_movetoedge_east(ObAction *a)
226 {
227     a->data.diraction.direction = OB_DIRECTION_EAST;
228 }
229
230 void setup_action_movetoedge_west(ObAction *a)
231 {
232     a->data.diraction.direction = OB_DIRECTION_WEST;
233 }
234
235 void setup_action_growtoedge_north(ObAction *a)
236 {
237     a->data.diraction.direction = OB_DIRECTION_NORTH;
238 }
239
240 void setup_action_growtoedge_south(ObAction *a)
241 {
242     a->data.diraction.direction = OB_DIRECTION_SOUTH;
243 }
244
245 void setup_action_growtoedge_east(ObAction *a)
246 {
247     a->data.diraction.direction = OB_DIRECTION_EAST;
248 }
249
250 void setup_action_growtoedge_west(ObAction *a)
251 {
252     a->data.diraction.direction = OB_DIRECTION_WEST;
253 }
254
255 void setup_action_top_layer(ObAction *a)
256 {
257     a->data.layer.layer = 1;
258 }
259
260 void setup_action_normal_layer(ObAction *a)
261 {
262     a->data.layer.layer = 0;
263 }
264
265 void setup_action_bottom_layer(ObAction *a)
266 {
267     a->data.layer.layer = -1;
268 }
269
270 ActionString actionstrings[] =
271 {
272     {
273         "execute", 
274         action_execute, 
275         NULL
276     },
277     {
278         "directionalfocusnorth", 
279         action_directional_focus, 
280         setup_action_directional_focus_north
281     },
282     {
283         "directionalfocuseast", 
284         action_directional_focus, 
285         setup_action_directional_focus_east
286     },
287     {
288         "directionalfocussouth", 
289         action_directional_focus, 
290         setup_action_directional_focus_south
291     },
292     {
293         "directionalfocuswest",
294         action_directional_focus,
295         setup_action_directional_focus_west
296     },
297     {
298         "directionalfocusnortheast",
299         action_directional_focus,
300         setup_action_directional_focus_northeast
301     },
302     {
303         "directionalfocussoutheast",
304         action_directional_focus,
305         setup_action_directional_focus_southeast
306     },
307     {
308         "directionalfocussouthwest",
309         action_directional_focus,
310         setup_action_directional_focus_southwest
311     },
312     {
313         "directionalfocusnorthwest",
314         action_directional_focus,
315         setup_action_directional_focus_northwest
316     },
317     {
318         "focus",
319         action_focus,
320         NULL,
321     },
322     {
323         "unfocus",
324         action_unfocus,
325         NULL
326     },
327     {
328         "iconify",
329         action_iconify,
330         NULL
331     },
332     {
333         "raise",
334         action_raise,
335         NULL
336     },
337     {
338         "lower",
339         action_lower,
340         NULL
341     },
342     {
343         "close",
344         action_close,
345         NULL
346     },
347     {
348         "kill",
349         action_kill,
350         NULL
351     },
352     {
353         "shadelower",
354         action_shadelower,
355         NULL
356     },
357     {
358         "unshaderaise",
359         action_unshaderaise,
360         NULL
361     },
362     {
363         "shade",
364         action_shade,
365         NULL
366     },
367     {
368         "unshade",
369         action_unshade,
370         NULL
371     },
372     {
373         "toggleshade",
374         action_toggle_shade,
375         NULL
376     },
377     {
378         "toggleomnipresent",
379         action_toggle_omnipresent,
380         NULL
381     },
382     {
383         "moverelativehorz",
384         action_move_relative_horz,
385         NULL
386     },
387     {
388         "moverelativevert",
389         action_move_relative_vert,
390         NULL
391     },
392     {
393         "resizerelativehorz",
394         action_resize_relative_horz,
395         NULL
396     },
397     {
398         "resizerelativevert",
399         action_resize_relative_vert,
400         NULL
401     },
402     {
403         "maximizefull",
404         action_maximize_full,
405         NULL
406     },
407     {
408         "unmaximizefull",
409         action_unmaximize_full,
410         NULL
411     },
412     {
413         "togglemaximizefull",
414         action_toggle_maximize_full,
415         NULL
416     },
417     {
418         "maximizehorz",
419         action_maximize_horz,
420         NULL
421     },
422     {
423         "unmaximizehorz",
424         action_unmaximize_horz,
425         NULL
426     },
427     {
428         "togglemaximizehorz",
429         action_toggle_maximize_horz,
430         NULL
431     },
432     {
433         "maximizevert",
434         action_maximize_vert,
435         NULL
436     },
437     {
438         "unmaximizevert",
439         action_unmaximize_vert,
440         NULL
441     },
442     {
443         "togglemaximizevert",
444         action_toggle_maximize_vert,
445         NULL
446     },
447     {
448         "sendtodesktop",
449         action_send_to_desktop,
450         setup_action_send_to_desktop
451     },
452     {
453         "sendtodesktopnext",
454         action_send_to_desktop_dir,
455         setup_action_send_to_desktop_next
456     },
457     {
458         "sendtodesktopprevious",
459         action_send_to_desktop_dir,
460         setup_action_send_to_desktop_prev
461     },
462     {
463         "sendtodesktopright",
464         action_send_to_desktop_dir,
465         setup_action_send_to_desktop_right
466     },
467     {
468         "sendtodesktopleft",
469         action_send_to_desktop_dir,
470         setup_action_send_to_desktop_left
471     },
472     {
473         "sendtodesktopup",
474         action_send_to_desktop_dir,
475         setup_action_send_to_desktop_up
476     },
477     {
478         "sendtodesktopdown",
479         action_send_to_desktop_dir,
480         setup_action_send_to_desktop_down
481     },
482     {
483         "desktop",
484         action_desktop,
485         NULL
486     },
487     {
488         "desktopnext",
489         action_desktop_dir,
490         setup_action_desktop_next
491     },
492     {
493         "desktopprevious",
494         action_desktop_dir,
495         setup_action_desktop_prev
496     },
497     {
498         "desktopright",
499         action_desktop_dir,
500         setup_action_desktop_right
501     },
502     {
503         "desktopleft",
504         action_desktop_dir,
505         setup_action_desktop_left
506     },
507     {
508         "desktopup",
509         action_desktop_dir,
510         setup_action_desktop_up
511     },
512     {
513         "desktopdown",
514         action_desktop_dir,
515         setup_action_desktop_down
516     },
517     {
518         "toggledecorations",
519         action_toggle_decorations,
520         NULL
521     },
522     {
523         "keyboardmove", 
524         action_moveresize,
525         setup_action_move_keyboard
526     },
527     {
528         "move",
529         action_moveresize,
530         setup_action_move
531     },
532     {
533         "resize",
534         action_moveresize,
535         setup_action_resize
536     },
537     {
538         "keyboardresize",
539         action_moveresize,
540         setup_action_resize_keyboard
541     },
542     {
543         "toggleshowdesktop",
544         action_toggle_show_desktop,
545         NULL
546     },
547     {
548         "showdesktop",
549         action_show_desktop,
550         NULL
551     },
552     {
553         "unshowdesktop",
554         action_unshow_desktop,
555         NULL
556     },
557     {
558         "restart",
559         action_restart,
560         NULL
561     },
562     {
563         "exit",
564         action_exit,
565         NULL
566     },
567     {
568         "showmenu",
569         action_showmenu,
570         NULL
571     },
572     {
573         "sendtotoplayer",
574         action_send_to_layer,
575         setup_action_top_layer
576     },
577     {
578         "togglealwaysontop",
579         action_toggle_layer,
580         setup_action_top_layer
581     },
582     {
583         "sendtonormallayer",
584         action_send_to_layer,
585         setup_action_normal_layer
586     },
587     {
588         "sendtobottomlayer",
589         action_send_to_layer,
590         setup_action_bottom_layer
591     },
592     {
593         "togglealwaysonbottom",
594         action_toggle_layer,
595         setup_action_bottom_layer
596     },
597     {
598         "nextwindowlinear",
599         action_cycle_windows,
600         setup_action_cycle_windows_linear_next
601     },
602     {
603         "previouswindowlinear",
604         action_cycle_windows,
605         setup_action_cycle_windows_linear_previous
606     },
607     {
608         "nextwindow",
609         action_cycle_windows,
610         setup_action_cycle_windows_next
611     },
612     {
613         "previouswindow",
614         action_cycle_windows,
615         setup_action_cycle_windows_previous
616     },
617     {
618         "movetoedgenorth",
619         action_movetoedge,
620         setup_action_movetoedge_north
621     },
622     {
623         "movetoedgesouth",
624         action_movetoedge,
625         setup_action_movetoedge_south
626     },
627     {
628         "movetoedgewest",
629         action_movetoedge,
630         setup_action_movetoedge_west
631     },
632     {
633         "movetoedgeeast",
634         action_movetoedge,
635         setup_action_movetoedge_east
636     },
637     {
638         "growtoedgenorth",
639         action_growtoedge,
640         setup_action_growtoedge_north
641     },
642     {
643         "growtoedgesouth",
644         action_growtoedge,
645         setup_action_growtoedge_south
646     },
647     {
648         "growtoedgewest",
649         action_growtoedge,
650         setup_action_growtoedge_west
651     },
652     {
653         "growtoedgeeast",
654         action_growtoedge,
655         setup_action_growtoedge_east
656     },
657     {
658         NULL,
659         NULL,
660         NULL
661     }
662 };
663
664 ObAction *action_from_string(char *name)
665 {
666     ObAction *a = NULL;
667     int i;
668
669     for (i = 0; actionstrings[i].name; i++)
670         if (!g_ascii_strcasecmp(name, actionstrings[i].name)) {
671             a = action_new(actionstrings[i].func);
672             if (actionstrings[i].setup)
673                 actionstrings[i].setup(a);
674             break;
675         }
676     return a;
677 }
678
679 ObAction *action_parse(xmlDocPtr doc, xmlNodePtr node)
680 {
681     char *actname;
682     ObAction *act = NULL;
683     xmlNodePtr n;
684
685     if (parse_attr_string("name", node, &actname)) {
686         if ((act = action_from_string(actname))) {
687             if (act->func == action_execute || act->func == action_restart) {
688                 if ((n = parse_find_node("execute", node->xmlChildrenNode)))
689                     act->data.execute.path = parse_string(doc, n);
690             } else if (act->func == action_showmenu) {
691                 if ((n = parse_find_node("menu", node->xmlChildrenNode)))
692                     act->data.showmenu.name = parse_string(doc, n);
693             } else if (act->func == action_desktop) {
694                 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
695                     act->data.desktop.desk = parse_int(doc, n);
696                 if (act->data.desktop.desk > 0) act->data.desktop.desk--;
697             } else if (act->func == action_send_to_desktop) {
698                 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
699                     act->data.sendto.desk = parse_int(doc, n);
700                 if (act->data.sendto.desk > 0) act->data.sendto.desk--;
701             } else if (act->func == action_move_relative_horz ||
702                        act->func == action_move_relative_vert ||
703                        act->func == action_resize_relative_horz ||
704                        act->func == action_resize_relative_vert) {
705                 if ((n = parse_find_node("delta", node->xmlChildrenNode)))
706                     act->data.relative.delta = parse_int(doc, n);
707             } else if (act->func == action_desktop_dir) {
708                 if ((n = parse_find_node("wrap", node->xmlChildrenNode))) {
709                     act->data.desktopdir.wrap = parse_bool(doc, n);
710                 }
711             } else if (act->func == action_send_to_desktop_dir) {
712                 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
713                     act->data.sendtodir.wrap = parse_bool(doc, n);
714             }
715         }
716         g_free(actname);
717     }
718     return act;
719 }
720
721 void action_execute(union ActionData *data)
722 {
723     GError *e = NULL;
724     char *cmd;
725     if (data->execute.path) {
726         cmd = g_filename_from_utf8(data->execute.path, -1, NULL, NULL, NULL);
727         if (cmd) {
728             if (!g_spawn_command_line_async(cmd, &e)) {
729                 g_warning("failed to execute '%s': %s",
730                           cmd, e->message);
731             }
732         } else {
733             g_warning("failed to convert '%s' from utf8", data->execute.path);
734         }
735     }
736 }
737
738 void action_focus(union ActionData *data)
739 {
740     if (data->client.c)
741         client_focus(data->client.c);
742 }
743
744 void action_unfocus (union ActionData *data)
745 {
746     if (data->client.c)
747         client_unfocus(data->client.c);
748 }
749
750 void action_iconify(union ActionData *data)
751 {
752     if (data->client.c)
753         client_iconify(data->client.c, TRUE, TRUE);
754 }
755
756 void action_raise(union ActionData *data)
757 {
758     if (data->client.c)
759         stacking_raise(CLIENT_AS_WINDOW(data->client.c));
760 }
761
762 void action_unshaderaise(union ActionData *data)
763 {
764     if (data->client.c) {
765         if (data->client.c->shaded)
766             client_shade(data->client.c, FALSE);
767         else
768             stacking_raise(CLIENT_AS_WINDOW(data->client.c));
769     }
770 }
771
772 void action_shadelower(union ActionData *data)
773 {
774     if (data->client.c) {
775         if (data->client.c->shaded)
776             stacking_lower(CLIENT_AS_WINDOW(data->client.c));
777         else
778             client_shade(data->client.c, TRUE);
779     }
780 }
781
782 void action_lower(union ActionData *data)
783 {
784     if (data->client.c)
785         stacking_lower(CLIENT_AS_WINDOW(data->client.c));
786 }
787
788 void action_close(union ActionData *data)
789 {
790     if (data->client.c)
791         client_close(data->client.c);
792 }
793
794 void action_kill(union ActionData *data)
795 {
796     if (data->client.c)
797         client_kill(data->client.c);
798 }
799
800 void action_shade(union ActionData *data)
801 {
802     if (data->client.c)
803         client_shade(data->client.c, TRUE);
804 }
805
806 void action_unshade(union ActionData *data)
807 {
808     if (data->client.c)
809         client_shade(data->client.c, FALSE);
810 }
811
812 void action_toggle_shade(union ActionData *data)
813 {
814     if (data->client.c)
815         client_shade(data->client.c, !data->client.c->shaded);
816 }
817
818 void action_toggle_omnipresent(union ActionData *data)
819
820     if (data->client.c)
821         client_set_desktop(data->client.c,
822                            data->client.c->desktop == DESKTOP_ALL ?
823                            screen_desktop : DESKTOP_ALL, FALSE);
824 }
825
826 void action_move_relative_horz(union ActionData *data)
827 {
828     ObClient *c = data->relative.c;
829     if (c)
830         client_configure(c, OB_CORNER_TOPLEFT,
831                          c->area.x + data->relative.delta, c->area.y,
832                          c->area.width, c->area.height, TRUE, TRUE);
833 }
834
835 void action_move_relative_vert(union ActionData *data)
836 {
837     ObClient *c = data->relative.c;
838     if (c)
839         client_configure(c, OB_CORNER_TOPLEFT,
840                          c->area.x, c->area.y + data->relative.delta,
841                          c->area.width, c->area.height, TRUE, TRUE);
842 }
843
844 void action_resize_relative_horz(union ActionData *data)
845 {
846     ObClient *c = data->relative.c;
847     if (c)
848         client_configure(c, OB_CORNER_TOPLEFT, c->area.x, c->area.y,
849                          c->area.width +
850                          data->relative.delta * c->size_inc.width,
851                          c->area.height, TRUE, TRUE);
852 }
853
854 void action_resize_relative_vert(union ActionData *data)
855 {
856     ObClient *c = data->relative.c;
857     if (c && !c->shaded)
858         client_configure(c, OB_CORNER_TOPLEFT, c->area.x, c->area.y,
859                          c->area.width, c->area.height +
860                          data->relative.delta * c->size_inc.height,
861                          TRUE, TRUE);
862 }
863
864 void action_maximize_full(union ActionData *data)
865 {
866     if (data->client.c)
867         client_maximize(data->client.c, TRUE, 0, TRUE);
868 }
869
870 void action_unmaximize_full(union ActionData *data)
871 {
872     if (data->client.c)
873         client_maximize(data->client.c, FALSE, 0, TRUE);
874 }
875
876 void action_toggle_maximize_full(union ActionData *data)
877 {
878     if (data->client.c)
879         client_maximize(data->client.c,
880                         !(data->client.c->max_horz ||
881                           data->client.c->max_vert),
882                         0, TRUE);
883 }
884
885 void action_maximize_horz(union ActionData *data)
886 {
887     if (data->client.c)
888         client_maximize(data->client.c, TRUE, 1, TRUE);
889 }
890
891 void action_unmaximize_horz(union ActionData *data)
892 {
893     if (data->client.c)
894         client_maximize(data->client.c, FALSE, 1, TRUE);
895 }
896
897 void action_toggle_maximize_horz(union ActionData *data)
898 {
899     if (data->client.c)
900         client_maximize(data->client.c, !data->client.c->max_horz, 1, TRUE);
901 }
902
903 void action_maximize_vert(union ActionData *data)
904 {
905     if (data->client.c)
906         client_maximize(data->client.c, TRUE, 2, TRUE);
907 }
908
909 void action_unmaximize_vert(union ActionData *data)
910 {
911     if (data->client.c)
912         client_maximize(data->client.c, FALSE, 2, TRUE);
913 }
914
915 void action_toggle_maximize_vert(union ActionData *data)
916 {
917     if (data->client.c)
918         client_maximize(data->client.c, !data->client.c->max_vert, 2, TRUE);
919 }
920
921 void action_send_to_desktop(union ActionData *data)
922 {
923     ObClient *c = data->sendto.c;
924
925     if (!c || !client_normal(c)) return;
926
927     if (data->sendto.desk < screen_num_desktops ||
928         data->sendto.desk == DESKTOP_ALL) {
929         client_set_desktop(c, data->sendto.desk, TRUE);
930         screen_set_desktop(data->sendto.desk);
931     }
932 }
933
934 void action_desktop(union ActionData *data)
935 {
936     if (data->desktop.desk < screen_num_desktops ||
937         data->desktop.desk == DESKTOP_ALL)
938         screen_set_desktop(data->desktop.desk);
939 }
940
941 void action_desktop_dir(union ActionData *data)
942 {
943     guint d;
944
945     d = screen_cycle_desktop(data->desktopdir.dir, data->desktopdir.wrap,
946                              data->sendtodir.linear,
947                              data->desktopdir.final, data->desktopdir.cancel);
948     screen_set_desktop(d);
949 }
950
951 void action_send_to_desktop_dir(union ActionData *data)
952 {
953     ObClient *c = data->sendtodir.c;
954     guint d;
955
956     if (!c || !client_normal(c)) return;
957
958     d = screen_cycle_desktop(data->sendtodir.dir, data->sendtodir.wrap,
959                              data->sendtodir.linear,
960                              data->sendtodir.final, data->sendtodir.cancel);
961     client_set_desktop(c, d, TRUE);
962     screen_set_desktop(d);
963 }
964
965 #if 0
966 void action_desktop_right(union ActionData *data)
967 {
968     guint r, c, d;
969
970     cur_row_col(&r, &c);
971     ++c;
972     if (c >= screen_desktop_layout.columns) {
973         if (!data->desktopdir.wrap) return;
974         c = 0;
975     }
976     d = translate_row_col(r, c);
977     if (d >= screen_num_desktops) {
978         if (!data->desktopdir.wrap) return;
979         ++c;
980     }
981     d = translate_row_col(r, c);
982     if (d < screen_num_desktops)
983         screen_cycle_desktop(d, data->desktopdir.final,
984                              data->desktopdir.cancel);
985 }
986
987 void action_send_to_desktop_right(union ActionData *data)
988 {
989     ObClient *cl = data->sendto.c;
990     guint r, c, d;
991
992     if (!cl || !client_normal(cl)) return;
993
994     cur_row_col(&r, &c);
995     ++c;
996     if (c >= screen_desktop_layout.columns) {
997         if (!data->sendtodir.wrap) return;
998         c = 0;
999     }
1000     d = translate_row_col(r, c);
1001     if (d >= screen_num_desktops) {
1002         if (!data->sendtodir.wrap) return;
1003         ++c;
1004     }
1005     d = translate_row_col(r, c);
1006     if (d < screen_num_desktops) {
1007         client_set_desktop(cl, d, data->sendtodir.follow);
1008         if (data->sendtodir.follow)
1009             screen_cycle_desktop(d, data->desktopdir.final,
1010                                  data->desktopdir.cancel);
1011     }
1012 }
1013
1014 void action_desktop_left(union ActionData *data)
1015 {
1016     guint r, c, d;
1017
1018     cur_row_col(&r, &c);
1019     --c;
1020     if (c >= screen_desktop_layout.columns) {
1021         if (!data->desktopdir.wrap) return;
1022         c = screen_desktop_layout.columns - 1;
1023     }
1024     d = translate_row_col(r, c);
1025     if (d >= screen_num_desktops) {
1026         if (!data->desktopdir.wrap) return;
1027         --c;
1028     }
1029     d = translate_row_col(r, c);
1030     if (d < screen_num_desktops)
1031         screen_cycle_desktop(d, data->desktopdir.final,
1032                              data->desktopdir.cancel);
1033 }
1034
1035 void action_send_to_desktop_left(union ActionData *data)
1036 {
1037     ObClient *cl = data->sendto.c;
1038     guint r, c, d;
1039
1040     if (!cl || !client_normal(cl)) return;
1041
1042     cur_row_col(&r, &c);
1043     --c;
1044     if (c >= screen_desktop_layout.columns) {
1045         if (!data->sendtodir.wrap) return;
1046         c = screen_desktop_layout.columns - 1;
1047     }
1048     d = translate_row_col(r, c);
1049     if (d >= screen_num_desktops) {
1050         if (!data->sendtodir.wrap) return;
1051         --c;
1052     }
1053     d = translate_row_col(r, c);
1054     if (d < screen_num_desktops) {
1055         client_set_desktop(cl, d, data->sendtodir.follow);
1056         if (data->sendtodir.follow)
1057             screen_cycle_desktop(d, data->desktopdir.final,
1058                                  data->desktopdir.cancel);
1059     }
1060 }
1061
1062 void action_desktop_down(union ActionData *data)
1063 {
1064     guint r, c, d;
1065
1066     cur_row_col(&r, &c);
1067     ++r;
1068     if (r >= screen_desktop_layout.rows) {
1069         if (!data->desktopdir.wrap) return;
1070         r = 0;
1071     }
1072     d = translate_row_col(r, c);
1073     if (d >= screen_num_desktops) {
1074         if (!data->desktopdir.wrap) return;
1075         ++r;
1076     }
1077     d = translate_row_col(r, c);
1078     if (d < screen_num_desktops)
1079         screen_cycle_desktop(d, data->desktopdir.final,
1080                              data->desktopdir.cancel);
1081 }
1082
1083 void action_send_to_desktop_down(union ActionData *data)
1084 {
1085     guint r, c, d;
1086
1087     if (data->sendtodir.c) {
1088         cur_row_col(&r, &c);
1089         ++r;
1090         if (r >= screen_desktop_layout.rows) {
1091             if (!data->sendtodir.wrap) return;
1092             r = 0;
1093         }
1094         d = translate_row_col(r, c);
1095         if (d >= screen_num_desktops) {
1096             if (!data->sendtodir.wrap) return;
1097             ++r;
1098         }
1099         d = translate_row_col(r, c);
1100         if (d < screen_num_desktops) {
1101             client_set_desktop(data->sendtodir.c, d, data->sendtodir.follow);
1102             if (data->sendtodir.follow)
1103                 screen_cycle_desktop(d, data->desktopdir.final,
1104                                      data->desktopdir.cancel);
1105         }
1106     }
1107 }
1108
1109 void action_desktop_up(union ActionData *data)
1110 {
1111     guint r, c, d;
1112
1113     cur_row_col(&r, &c);
1114     --r;
1115     if (r >= screen_desktop_layout.rows) {
1116         if (!data->desktopdir.wrap) return;
1117         r = screen_desktop_layout.rows - 1;
1118     }
1119     d = translate_row_col(r, c);
1120     if (d >= screen_num_desktops) {
1121         if (!data->desktopdir.wrap) return;
1122         --r;
1123     }
1124     d = translate_row_col(r, c);
1125     if (d < screen_num_desktops)
1126         screen_cycle_desktop(d, data->desktopdir.final,
1127                              data->desktopdir.cancel);
1128 }
1129
1130 void action_send_to_desktop_up(union ActionData *data)
1131 {
1132     guint r, c, d;
1133
1134     if (data->sendtodir.c) {
1135         cur_row_col(&r, &c);
1136         --r;
1137         if (r >= screen_desktop_layout.rows) {
1138             if (!data->sendtodir.wrap) return;
1139             r = screen_desktop_layout.rows - 1;
1140         }
1141         d = translate_row_col(r, c);
1142         if (d >= screen_num_desktops) {
1143             if (!data->sendtodir.wrap) return;
1144             --r;
1145         }
1146         d = translate_row_col(r, c);
1147         if (d < screen_num_desktops) {
1148             client_set_desktop(data->sendtodir.c, d, data->sendtodir.follow);
1149             if (data->sendtodir.follow)
1150                 screen_cycle_desktop(d, data->desktopdir.final,
1151                                      data->desktopdir.cancel);
1152         }
1153     }
1154 }
1155 #endif
1156
1157 void action_toggle_decorations(union ActionData *data)
1158 {
1159     ObClient *c = data->client.c;;
1160
1161     if (!c) return;
1162
1163     c->decorate = !c->decorate;
1164     client_setup_decor_and_functions(c);
1165 }
1166
1167 void action_moveresize(union ActionData *data)
1168 {
1169     ObClient *c = data->moveresize.c;
1170
1171     if (!c || !client_normal(c)) return;
1172
1173     moveresize_start(c, data->moveresize.x, data->moveresize.y,
1174                      data->moveresize.button, data->moveresize.corner);
1175 }
1176
1177 void action_restart(union ActionData *data)
1178 {
1179     ob_restart_other(data->execute.path);
1180 }
1181
1182 void action_exit(union ActionData *data)
1183 {
1184     ob_exit();
1185 }
1186
1187 void action_showmenu(union ActionData *data)
1188 {
1189     if (data->showmenu.name) {
1190         menu_show(data->showmenu.name, data->showmenu.x, data->showmenu.y,
1191                   data->showmenu.c);
1192     }
1193 }
1194
1195 void action_cycle_windows(union ActionData *data)
1196 {
1197     ObClient *c;
1198     
1199     c = focus_cycle(data->cycle.forward, data->cycle.linear, data->cycle.final,
1200                     data->cycle.cancel);
1201 }
1202
1203 void action_directional_focus(union ActionData *data)
1204 {
1205     ObClient *nf;
1206
1207     if (!data->diraction.c)
1208         return;
1209     if ((nf = client_find_directional(data->diraction.c,
1210                                       data->diraction.direction)))
1211         client_activate(nf);
1212 }
1213
1214 void action_movetoedge(union ActionData *data)
1215 {
1216     int x, y;
1217     ObClient *c = data->diraction.c;
1218
1219     if (!c)
1220         return;
1221     x = c->frame->area.x;
1222     y = c->frame->area.y;
1223     
1224     switch(data->diraction.direction) {
1225     case OB_DIRECTION_NORTH:
1226         y = client_directional_edge_search(c, OB_DIRECTION_NORTH);
1227         break;
1228     case OB_DIRECTION_WEST:
1229         x = client_directional_edge_search(c, OB_DIRECTION_WEST);
1230         break;
1231     case OB_DIRECTION_SOUTH:
1232         y = client_directional_edge_search(c, OB_DIRECTION_SOUTH) -
1233             c->frame->area.height;
1234         break;
1235     case OB_DIRECTION_EAST:
1236         x = client_directional_edge_search(c, OB_DIRECTION_EAST) -
1237             c->frame->area.width;
1238         break;
1239     default:
1240         g_assert_not_reached();
1241     }
1242     frame_frame_gravity(c->frame, &x, &y);
1243     client_configure(c, OB_CORNER_TOPLEFT,
1244                      x, y, c->area.width, c->area.height, TRUE, TRUE);
1245
1246 }
1247
1248 void action_growtoedge(union ActionData *data)
1249 {
1250     int x, y, width, height, dest;
1251     ObClient *c = data->diraction.c;
1252     Rect *a = screen_area(c->desktop);
1253
1254     if (!c)
1255         return;
1256     
1257     x = c->frame->area.x;
1258     y = c->frame->area.y;
1259     width = c->frame->area.width;
1260     height = c->frame->area.height;
1261
1262     switch(data->diraction.direction) {
1263     case OB_DIRECTION_NORTH:
1264         dest = client_directional_edge_search(c, OB_DIRECTION_NORTH);
1265         if (a->y == y)
1266             height = c->frame->area.height / 2;
1267         else {
1268             height = c->frame->area.y + c->frame->area.height - dest;
1269             y = dest;
1270         }
1271         break;
1272     case OB_DIRECTION_WEST:
1273         dest = client_directional_edge_search(c, OB_DIRECTION_WEST);
1274         if (a->x == x)
1275             width = c->frame->area.width / 2;
1276         else {
1277             width = c->frame->area.x + c->frame->area.width - dest;
1278             x = dest;
1279         }
1280         break;
1281     case OB_DIRECTION_SOUTH:
1282         dest = client_directional_edge_search(c, OB_DIRECTION_SOUTH);
1283         if (a->y + a->height == y + c->frame->area.height) {
1284             height = c->frame->area.height / 2;
1285             y = a->y + a->height - height;
1286         } else
1287             height = dest - c->frame->area.y;
1288         y += (height - c->frame->area.height) % c->size_inc.height;
1289         height -= (height - c->frame->area.height) % c->size_inc.height;
1290         break;
1291     case OB_DIRECTION_EAST:
1292         dest = client_directional_edge_search(c, OB_DIRECTION_EAST);
1293         if (a->x + a->width == x + c->frame->area.width) {
1294             width = c->frame->area.width / 2;
1295             x = a->x + a->width - width;
1296         } else
1297             width = dest - c->frame->area.x;
1298         x += (width - c->frame->area.width) % c->size_inc.width;
1299         width -= (width - c->frame->area.width) % c->size_inc.width;
1300         break;
1301     default:
1302         g_assert_not_reached();
1303     }
1304     frame_frame_gravity(c->frame, &x, &y);
1305     width -= c->frame->size.left + c->frame->size.right;
1306     height -= c->frame->size.top + c->frame->size.bottom;
1307     client_configure(c, OB_CORNER_TOPLEFT, x, y, width, height, TRUE, TRUE);
1308 }
1309
1310 void action_send_to_layer(union ActionData *data)
1311 {
1312     if (data->layer.c)
1313         client_set_layer(data->layer.c, data->layer.layer);
1314 }
1315
1316 void action_toggle_layer(union ActionData *data)
1317 {
1318     ObClient *c = data->layer.c;
1319
1320     if (c) {
1321         if (data->layer.layer < 0)
1322             client_set_layer(c, c->below ? 0 : -1);
1323         else if (data->layer.layer > 0)
1324             client_set_layer(c, c->above ? 0 : 1);
1325     }
1326 }
1327
1328 void action_toggle_show_desktop(union ActionData *data)
1329 {
1330     screen_show_desktop(!screen_showing_desktop);
1331 }
1332
1333 void action_show_desktop(union ActionData *data)
1334 {
1335     screen_show_desktop(TRUE);
1336 }
1337
1338 void action_unshow_desktop(union ActionData *data)
1339 {
1340     screen_show_desktop(FALSE);
1341 }