]> icculus.org git repositories - mikachu/openbox.git/blob - openbox/action.c
add the 'raiselower' action for raising obscured windows and lowering fully visible...
[mikachu/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         "activate",
319         action_activate,
320         NULL,
321     },
322     {
323         "focus",
324         action_focus,
325         NULL,
326     },
327     {
328         "unfocus",
329         action_unfocus,
330         NULL
331     },
332     {
333         "iconify",
334         action_iconify,
335         NULL
336     },
337     {
338         "raiselower",
339         action_raiselower,
340         NULL
341     },
342     {
343         "raise",
344         action_raise,
345         NULL
346     },
347     {
348         "lower",
349         action_lower,
350         NULL
351     },
352     {
353         "close",
354         action_close,
355         NULL
356     },
357     {
358         "kill",
359         action_kill,
360         NULL
361     },
362     {
363         "shadelower",
364         action_shadelower,
365         NULL
366     },
367     {
368         "unshaderaise",
369         action_unshaderaise,
370         NULL
371     },
372     {
373         "shade",
374         action_shade,
375         NULL
376     },
377     {
378         "unshade",
379         action_unshade,
380         NULL
381     },
382     {
383         "toggleshade",
384         action_toggle_shade,
385         NULL
386     },
387     {
388         "toggleomnipresent",
389         action_toggle_omnipresent,
390         NULL
391     },
392     {
393         "moverelativehorz",
394         action_move_relative_horz,
395         NULL
396     },
397     {
398         "moverelativevert",
399         action_move_relative_vert,
400         NULL
401     },
402     {
403         "resizerelativehorz",
404         action_resize_relative_horz,
405         NULL
406     },
407     {
408         "resizerelativevert",
409         action_resize_relative_vert,
410         NULL
411     },
412     {
413         "maximizefull",
414         action_maximize_full,
415         NULL
416     },
417     {
418         "unmaximizefull",
419         action_unmaximize_full,
420         NULL
421     },
422     {
423         "togglemaximizefull",
424         action_toggle_maximize_full,
425         NULL
426     },
427     {
428         "maximizehorz",
429         action_maximize_horz,
430         NULL
431     },
432     {
433         "unmaximizehorz",
434         action_unmaximize_horz,
435         NULL
436     },
437     {
438         "togglemaximizehorz",
439         action_toggle_maximize_horz,
440         NULL
441     },
442     {
443         "maximizevert",
444         action_maximize_vert,
445         NULL
446     },
447     {
448         "unmaximizevert",
449         action_unmaximize_vert,
450         NULL
451     },
452     {
453         "togglemaximizevert",
454         action_toggle_maximize_vert,
455         NULL
456     },
457     {
458         "sendtodesktop",
459         action_send_to_desktop,
460         setup_action_send_to_desktop
461     },
462     {
463         "sendtodesktopnext",
464         action_send_to_desktop_dir,
465         setup_action_send_to_desktop_next
466     },
467     {
468         "sendtodesktopprevious",
469         action_send_to_desktop_dir,
470         setup_action_send_to_desktop_prev
471     },
472     {
473         "sendtodesktopright",
474         action_send_to_desktop_dir,
475         setup_action_send_to_desktop_right
476     },
477     {
478         "sendtodesktopleft",
479         action_send_to_desktop_dir,
480         setup_action_send_to_desktop_left
481     },
482     {
483         "sendtodesktopup",
484         action_send_to_desktop_dir,
485         setup_action_send_to_desktop_up
486     },
487     {
488         "sendtodesktopdown",
489         action_send_to_desktop_dir,
490         setup_action_send_to_desktop_down
491     },
492     {
493         "desktop",
494         action_desktop,
495         NULL
496     },
497     {
498         "desktopnext",
499         action_desktop_dir,
500         setup_action_desktop_next
501     },
502     {
503         "desktopprevious",
504         action_desktop_dir,
505         setup_action_desktop_prev
506     },
507     {
508         "desktopright",
509         action_desktop_dir,
510         setup_action_desktop_right
511     },
512     {
513         "desktopleft",
514         action_desktop_dir,
515         setup_action_desktop_left
516     },
517     {
518         "desktopup",
519         action_desktop_dir,
520         setup_action_desktop_up
521     },
522     {
523         "desktopdown",
524         action_desktop_dir,
525         setup_action_desktop_down
526     },
527     {
528         "toggledecorations",
529         action_toggle_decorations,
530         NULL
531     },
532     {
533         "keyboardmove", 
534         action_moveresize,
535         setup_action_move_keyboard
536     },
537     {
538         "move",
539         action_moveresize,
540         setup_action_move
541     },
542     {
543         "resize",
544         action_moveresize,
545         setup_action_resize
546     },
547     {
548         "keyboardresize",
549         action_moveresize,
550         setup_action_resize_keyboard
551     },
552     {
553         "toggleshowdesktop",
554         action_toggle_show_desktop,
555         NULL
556     },
557     {
558         "showdesktop",
559         action_show_desktop,
560         NULL
561     },
562     {
563         "unshowdesktop",
564         action_unshow_desktop,
565         NULL
566     },
567     {
568         "restart",
569         action_restart,
570         NULL
571     },
572     {
573         "exit",
574         action_exit,
575         NULL
576     },
577     {
578         "showmenu",
579         action_showmenu,
580         NULL
581     },
582     {
583         "sendtotoplayer",
584         action_send_to_layer,
585         setup_action_top_layer
586     },
587     {
588         "togglealwaysontop",
589         action_toggle_layer,
590         setup_action_top_layer
591     },
592     {
593         "sendtonormallayer",
594         action_send_to_layer,
595         setup_action_normal_layer
596     },
597     {
598         "sendtobottomlayer",
599         action_send_to_layer,
600         setup_action_bottom_layer
601     },
602     {
603         "togglealwaysonbottom",
604         action_toggle_layer,
605         setup_action_bottom_layer
606     },
607     {
608         "nextwindowlinear",
609         action_cycle_windows,
610         setup_action_cycle_windows_linear_next
611     },
612     {
613         "previouswindowlinear",
614         action_cycle_windows,
615         setup_action_cycle_windows_linear_previous
616     },
617     {
618         "nextwindow",
619         action_cycle_windows,
620         setup_action_cycle_windows_next
621     },
622     {
623         "previouswindow",
624         action_cycle_windows,
625         setup_action_cycle_windows_previous
626     },
627     {
628         "movetoedgenorth",
629         action_movetoedge,
630         setup_action_movetoedge_north
631     },
632     {
633         "movetoedgesouth",
634         action_movetoedge,
635         setup_action_movetoedge_south
636     },
637     {
638         "movetoedgewest",
639         action_movetoedge,
640         setup_action_movetoedge_west
641     },
642     {
643         "movetoedgeeast",
644         action_movetoedge,
645         setup_action_movetoedge_east
646     },
647     {
648         "growtoedgenorth",
649         action_growtoedge,
650         setup_action_growtoedge_north
651     },
652     {
653         "growtoedgesouth",
654         action_growtoedge,
655         setup_action_growtoedge_south
656     },
657     {
658         "growtoedgewest",
659         action_growtoedge,
660         setup_action_growtoedge_west
661     },
662     {
663         "growtoedgeeast",
664         action_growtoedge,
665         setup_action_growtoedge_east
666     },
667     {
668         NULL,
669         NULL,
670         NULL
671     }
672 };
673
674 ObAction *action_from_string(char *name)
675 {
676     ObAction *a = NULL;
677     int i;
678
679     for (i = 0; actionstrings[i].name; i++)
680         if (!g_ascii_strcasecmp(name, actionstrings[i].name)) {
681             a = action_new(actionstrings[i].func);
682             if (actionstrings[i].setup)
683                 actionstrings[i].setup(a);
684             break;
685         }
686     return a;
687 }
688
689 ObAction *action_parse(xmlDocPtr doc, xmlNodePtr node)
690 {
691     char *actname;
692     ObAction *act = NULL;
693     xmlNodePtr n;
694
695     if (parse_attr_string("name", node, &actname)) {
696         if ((act = action_from_string(actname))) {
697             if (act->func == action_execute || act->func == action_restart) {
698                 if ((n = parse_find_node("execute", node->xmlChildrenNode)))
699                     act->data.execute.path = parse_string(doc, n);
700             } else if (act->func == action_showmenu) {
701                 if ((n = parse_find_node("menu", node->xmlChildrenNode)))
702                     act->data.showmenu.name = parse_string(doc, n);
703             } else if (act->func == action_desktop) {
704                 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
705                     act->data.desktop.desk = parse_int(doc, n);
706                 if (act->data.desktop.desk > 0) act->data.desktop.desk--;
707             } else if (act->func == action_send_to_desktop) {
708                 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
709                     act->data.sendto.desk = parse_int(doc, n);
710                 if (act->data.sendto.desk > 0) act->data.sendto.desk--;
711             } else if (act->func == action_move_relative_horz ||
712                        act->func == action_move_relative_vert ||
713                        act->func == action_resize_relative_horz ||
714                        act->func == action_resize_relative_vert) {
715                 if ((n = parse_find_node("delta", node->xmlChildrenNode)))
716                     act->data.relative.delta = parse_int(doc, n);
717             } else if (act->func == action_desktop_dir) {
718                 if ((n = parse_find_node("wrap", node->xmlChildrenNode))) {
719                     act->data.desktopdir.wrap = parse_bool(doc, n);
720                 }
721             } else if (act->func == action_send_to_desktop_dir) {
722                 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
723                     act->data.sendtodir.wrap = parse_bool(doc, n);
724             } else if (act->func == action_activate) {
725                 if ((n = parse_find_node("here", node->xmlChildrenNode)))
726                     act->data.activate.here = parse_bool(doc, n);
727             }
728         }
729         g_free(actname);
730     }
731     return act;
732 }
733
734 void action_execute(union ActionData *data)
735 {
736     GError *e = NULL;
737     char *cmd;
738     if (data->execute.path) {
739         cmd = g_filename_from_utf8(data->execute.path, -1, NULL, NULL, NULL);
740         if (cmd) {
741             if (!g_spawn_command_line_async(cmd, &e)) {
742                 g_warning("failed to execute '%s': %s",
743                           cmd, e->message);
744             }
745         } else {
746             g_warning("failed to convert '%s' from utf8", data->execute.path);
747         }
748     }
749 }
750
751 void action_activate(union ActionData *data)
752 {
753     if (data->activate.c)
754         client_activate(data->activate.c, data->activate.here);
755 }
756
757 void action_focus(union ActionData *data)
758 {
759     if (data->client.c)
760         client_focus(data->client.c);
761 }
762
763 void action_unfocus (union ActionData *data)
764 {
765     if (data->client.c)
766         client_unfocus(data->client.c);
767 }
768
769 void action_iconify(union ActionData *data)
770 {
771     if (data->client.c)
772         client_iconify(data->client.c, TRUE, TRUE);
773 }
774
775 void action_raiselower(union ActionData *data)
776 {
777     if (data->client.c) {
778         if (data->client.c->frame->obscured)
779             stacking_raise(CLIENT_AS_WINDOW(data->client.c));
780         else
781             stacking_lower(CLIENT_AS_WINDOW(data->client.c));
782     }
783 }
784
785 void action_raise(union ActionData *data)
786 {
787     if (data->client.c)
788         stacking_raise(CLIENT_AS_WINDOW(data->client.c));
789 }
790
791 void action_unshaderaise(union ActionData *data)
792 {
793     if (data->client.c) {
794         if (data->client.c->shaded)
795             client_shade(data->client.c, FALSE);
796         else
797             stacking_raise(CLIENT_AS_WINDOW(data->client.c));
798     }
799 }
800
801 void action_shadelower(union ActionData *data)
802 {
803     if (data->client.c) {
804         if (data->client.c->shaded)
805             stacking_lower(CLIENT_AS_WINDOW(data->client.c));
806         else
807             client_shade(data->client.c, TRUE);
808     }
809 }
810
811 void action_lower(union ActionData *data)
812 {
813     if (data->client.c)
814         stacking_lower(CLIENT_AS_WINDOW(data->client.c));
815 }
816
817 void action_close(union ActionData *data)
818 {
819     if (data->client.c)
820         client_close(data->client.c);
821 }
822
823 void action_kill(union ActionData *data)
824 {
825     if (data->client.c)
826         client_kill(data->client.c);
827 }
828
829 void action_shade(union ActionData *data)
830 {
831     if (data->client.c)
832         client_shade(data->client.c, TRUE);
833 }
834
835 void action_unshade(union ActionData *data)
836 {
837     if (data->client.c)
838         client_shade(data->client.c, FALSE);
839 }
840
841 void action_toggle_shade(union ActionData *data)
842 {
843     if (data->client.c)
844         client_shade(data->client.c, !data->client.c->shaded);
845 }
846
847 void action_toggle_omnipresent(union ActionData *data)
848
849     if (data->client.c)
850         client_set_desktop(data->client.c,
851                            data->client.c->desktop == DESKTOP_ALL ?
852                            screen_desktop : DESKTOP_ALL, FALSE);
853 }
854
855 void action_move_relative_horz(union ActionData *data)
856 {
857     ObClient *c = data->relative.c;
858     if (c)
859         client_configure(c, OB_CORNER_TOPLEFT,
860                          c->area.x + data->relative.delta, c->area.y,
861                          c->area.width, c->area.height, TRUE, TRUE);
862 }
863
864 void action_move_relative_vert(union ActionData *data)
865 {
866     ObClient *c = data->relative.c;
867     if (c)
868         client_configure(c, OB_CORNER_TOPLEFT,
869                          c->area.x, c->area.y + data->relative.delta,
870                          c->area.width, c->area.height, TRUE, TRUE);
871 }
872
873 void action_resize_relative_horz(union ActionData *data)
874 {
875     ObClient *c = data->relative.c;
876     if (c)
877         client_configure(c, OB_CORNER_TOPLEFT, c->area.x, c->area.y,
878                          c->area.width +
879                          data->relative.delta * c->size_inc.width,
880                          c->area.height, TRUE, TRUE);
881 }
882
883 void action_resize_relative_vert(union ActionData *data)
884 {
885     ObClient *c = data->relative.c;
886     if (c && !c->shaded)
887         client_configure(c, OB_CORNER_TOPLEFT, c->area.x, c->area.y,
888                          c->area.width, c->area.height +
889                          data->relative.delta * c->size_inc.height,
890                          TRUE, TRUE);
891 }
892
893 void action_maximize_full(union ActionData *data)
894 {
895     if (data->client.c)
896         client_maximize(data->client.c, TRUE, 0, TRUE);
897 }
898
899 void action_unmaximize_full(union ActionData *data)
900 {
901     if (data->client.c)
902         client_maximize(data->client.c, FALSE, 0, TRUE);
903 }
904
905 void action_toggle_maximize_full(union ActionData *data)
906 {
907     if (data->client.c)
908         client_maximize(data->client.c,
909                         !(data->client.c->max_horz ||
910                           data->client.c->max_vert),
911                         0, TRUE);
912 }
913
914 void action_maximize_horz(union ActionData *data)
915 {
916     if (data->client.c)
917         client_maximize(data->client.c, TRUE, 1, TRUE);
918 }
919
920 void action_unmaximize_horz(union ActionData *data)
921 {
922     if (data->client.c)
923         client_maximize(data->client.c, FALSE, 1, TRUE);
924 }
925
926 void action_toggle_maximize_horz(union ActionData *data)
927 {
928     if (data->client.c)
929         client_maximize(data->client.c, !data->client.c->max_horz, 1, TRUE);
930 }
931
932 void action_maximize_vert(union ActionData *data)
933 {
934     if (data->client.c)
935         client_maximize(data->client.c, TRUE, 2, TRUE);
936 }
937
938 void action_unmaximize_vert(union ActionData *data)
939 {
940     if (data->client.c)
941         client_maximize(data->client.c, FALSE, 2, TRUE);
942 }
943
944 void action_toggle_maximize_vert(union ActionData *data)
945 {
946     if (data->client.c)
947         client_maximize(data->client.c, !data->client.c->max_vert, 2, TRUE);
948 }
949
950 void action_send_to_desktop(union ActionData *data)
951 {
952     ObClient *c = data->sendto.c;
953
954     if (!c || !client_normal(c)) return;
955
956     if (data->sendto.desk < screen_num_desktops ||
957         data->sendto.desk == DESKTOP_ALL) {
958         client_set_desktop(c, data->sendto.desk, TRUE);
959         screen_set_desktop(data->sendto.desk);
960     }
961 }
962
963 void action_desktop(union ActionData *data)
964 {
965     if (data->desktop.desk < screen_num_desktops ||
966         data->desktop.desk == DESKTOP_ALL)
967         screen_set_desktop(data->desktop.desk);
968 }
969
970 void action_desktop_dir(union ActionData *data)
971 {
972     guint d;
973
974     d = screen_cycle_desktop(data->desktopdir.dir, data->desktopdir.wrap,
975                              data->sendtodir.linear,
976                              data->desktopdir.final, data->desktopdir.cancel);
977     screen_set_desktop(d);
978 }
979
980 void action_send_to_desktop_dir(union ActionData *data)
981 {
982     ObClient *c = data->sendtodir.c;
983     guint d;
984
985     if (!c || !client_normal(c)) return;
986
987     d = screen_cycle_desktop(data->sendtodir.dir, data->sendtodir.wrap,
988                              data->sendtodir.linear,
989                              data->sendtodir.final, data->sendtodir.cancel);
990     client_set_desktop(c, d, TRUE);
991     screen_set_desktop(d);
992 }
993
994 #if 0
995 void action_desktop_right(union ActionData *data)
996 {
997     guint r, c, d;
998
999     cur_row_col(&r, &c);
1000     ++c;
1001     if (c >= screen_desktop_layout.columns) {
1002         if (!data->desktopdir.wrap) return;
1003         c = 0;
1004     }
1005     d = translate_row_col(r, c);
1006     if (d >= screen_num_desktops) {
1007         if (!data->desktopdir.wrap) return;
1008         ++c;
1009     }
1010     d = translate_row_col(r, c);
1011     if (d < screen_num_desktops)
1012         screen_cycle_desktop(d, data->desktopdir.final,
1013                              data->desktopdir.cancel);
1014 }
1015
1016 void action_send_to_desktop_right(union ActionData *data)
1017 {
1018     ObClient *cl = data->sendto.c;
1019     guint r, c, d;
1020
1021     if (!cl || !client_normal(cl)) return;
1022
1023     cur_row_col(&r, &c);
1024     ++c;
1025     if (c >= screen_desktop_layout.columns) {
1026         if (!data->sendtodir.wrap) return;
1027         c = 0;
1028     }
1029     d = translate_row_col(r, c);
1030     if (d >= screen_num_desktops) {
1031         if (!data->sendtodir.wrap) return;
1032         ++c;
1033     }
1034     d = translate_row_col(r, c);
1035     if (d < screen_num_desktops) {
1036         client_set_desktop(cl, d, data->sendtodir.follow);
1037         if (data->sendtodir.follow)
1038             screen_cycle_desktop(d, data->desktopdir.final,
1039                                  data->desktopdir.cancel);
1040     }
1041 }
1042
1043 void action_desktop_left(union ActionData *data)
1044 {
1045     guint r, c, d;
1046
1047     cur_row_col(&r, &c);
1048     --c;
1049     if (c >= screen_desktop_layout.columns) {
1050         if (!data->desktopdir.wrap) return;
1051         c = screen_desktop_layout.columns - 1;
1052     }
1053     d = translate_row_col(r, c);
1054     if (d >= screen_num_desktops) {
1055         if (!data->desktopdir.wrap) return;
1056         --c;
1057     }
1058     d = translate_row_col(r, c);
1059     if (d < screen_num_desktops)
1060         screen_cycle_desktop(d, data->desktopdir.final,
1061                              data->desktopdir.cancel);
1062 }
1063
1064 void action_send_to_desktop_left(union ActionData *data)
1065 {
1066     ObClient *cl = data->sendto.c;
1067     guint r, c, d;
1068
1069     if (!cl || !client_normal(cl)) return;
1070
1071     cur_row_col(&r, &c);
1072     --c;
1073     if (c >= screen_desktop_layout.columns) {
1074         if (!data->sendtodir.wrap) return;
1075         c = screen_desktop_layout.columns - 1;
1076     }
1077     d = translate_row_col(r, c);
1078     if (d >= screen_num_desktops) {
1079         if (!data->sendtodir.wrap) return;
1080         --c;
1081     }
1082     d = translate_row_col(r, c);
1083     if (d < screen_num_desktops) {
1084         client_set_desktop(cl, d, data->sendtodir.follow);
1085         if (data->sendtodir.follow)
1086             screen_cycle_desktop(d, data->desktopdir.final,
1087                                  data->desktopdir.cancel);
1088     }
1089 }
1090
1091 void action_desktop_down(union ActionData *data)
1092 {
1093     guint r, c, d;
1094
1095     cur_row_col(&r, &c);
1096     ++r;
1097     if (r >= screen_desktop_layout.rows) {
1098         if (!data->desktopdir.wrap) return;
1099         r = 0;
1100     }
1101     d = translate_row_col(r, c);
1102     if (d >= screen_num_desktops) {
1103         if (!data->desktopdir.wrap) return;
1104         ++r;
1105     }
1106     d = translate_row_col(r, c);
1107     if (d < screen_num_desktops)
1108         screen_cycle_desktop(d, data->desktopdir.final,
1109                              data->desktopdir.cancel);
1110 }
1111
1112 void action_send_to_desktop_down(union ActionData *data)
1113 {
1114     guint r, c, d;
1115
1116     if (data->sendtodir.c) {
1117         cur_row_col(&r, &c);
1118         ++r;
1119         if (r >= screen_desktop_layout.rows) {
1120             if (!data->sendtodir.wrap) return;
1121             r = 0;
1122         }
1123         d = translate_row_col(r, c);
1124         if (d >= screen_num_desktops) {
1125             if (!data->sendtodir.wrap) return;
1126             ++r;
1127         }
1128         d = translate_row_col(r, c);
1129         if (d < screen_num_desktops) {
1130             client_set_desktop(data->sendtodir.c, d, data->sendtodir.follow);
1131             if (data->sendtodir.follow)
1132                 screen_cycle_desktop(d, data->desktopdir.final,
1133                                      data->desktopdir.cancel);
1134         }
1135     }
1136 }
1137
1138 void action_desktop_up(union ActionData *data)
1139 {
1140     guint r, c, d;
1141
1142     cur_row_col(&r, &c);
1143     --r;
1144     if (r >= screen_desktop_layout.rows) {
1145         if (!data->desktopdir.wrap) return;
1146         r = screen_desktop_layout.rows - 1;
1147     }
1148     d = translate_row_col(r, c);
1149     if (d >= screen_num_desktops) {
1150         if (!data->desktopdir.wrap) return;
1151         --r;
1152     }
1153     d = translate_row_col(r, c);
1154     if (d < screen_num_desktops)
1155         screen_cycle_desktop(d, data->desktopdir.final,
1156                              data->desktopdir.cancel);
1157 }
1158
1159 void action_send_to_desktop_up(union ActionData *data)
1160 {
1161     guint r, c, d;
1162
1163     if (data->sendtodir.c) {
1164         cur_row_col(&r, &c);
1165         --r;
1166         if (r >= screen_desktop_layout.rows) {
1167             if (!data->sendtodir.wrap) return;
1168             r = screen_desktop_layout.rows - 1;
1169         }
1170         d = translate_row_col(r, c);
1171         if (d >= screen_num_desktops) {
1172             if (!data->sendtodir.wrap) return;
1173             --r;
1174         }
1175         d = translate_row_col(r, c);
1176         if (d < screen_num_desktops) {
1177             client_set_desktop(data->sendtodir.c, d, data->sendtodir.follow);
1178             if (data->sendtodir.follow)
1179                 screen_cycle_desktop(d, data->desktopdir.final,
1180                                      data->desktopdir.cancel);
1181         }
1182     }
1183 }
1184 #endif
1185
1186 void action_toggle_decorations(union ActionData *data)
1187 {
1188     ObClient *c = data->client.c;;
1189
1190     if (!c) return;
1191
1192     c->decorate = !c->decorate;
1193     client_setup_decor_and_functions(c);
1194 }
1195
1196 void action_moveresize(union ActionData *data)
1197 {
1198     ObClient *c = data->moveresize.c;
1199
1200     if (!c || !client_normal(c)) return;
1201
1202     moveresize_start(c, data->moveresize.x, data->moveresize.y,
1203                      data->moveresize.button, data->moveresize.corner);
1204 }
1205
1206 void action_restart(union ActionData *data)
1207 {
1208     ob_restart_other(data->execute.path);
1209 }
1210
1211 void action_exit(union ActionData *data)
1212 {
1213     ob_exit();
1214 }
1215
1216 void action_showmenu(union ActionData *data)
1217 {
1218     if (data->showmenu.name) {
1219         menu_show(data->showmenu.name, data->showmenu.x, data->showmenu.y,
1220                   data->showmenu.c);
1221     }
1222 }
1223
1224 void action_cycle_windows(union ActionData *data)
1225 {
1226     ObClient *c;
1227     
1228     c = focus_cycle(data->cycle.forward, data->cycle.linear, data->cycle.final,
1229                     data->cycle.cancel);
1230 }
1231
1232 void action_directional_focus(union ActionData *data)
1233 {
1234     ObClient *nf;
1235
1236     if (!data->diraction.c)
1237         return;
1238     if ((nf = client_find_directional(data->diraction.c,
1239                                       data->diraction.direction)))
1240         client_activate(nf, FALSE);
1241 }
1242
1243 void action_movetoedge(union ActionData *data)
1244 {
1245     int x, y;
1246     ObClient *c = data->diraction.c;
1247
1248     if (!c)
1249         return;
1250     x = c->frame->area.x;
1251     y = c->frame->area.y;
1252     
1253     switch(data->diraction.direction) {
1254     case OB_DIRECTION_NORTH:
1255         y = client_directional_edge_search(c, OB_DIRECTION_NORTH);
1256         break;
1257     case OB_DIRECTION_WEST:
1258         x = client_directional_edge_search(c, OB_DIRECTION_WEST);
1259         break;
1260     case OB_DIRECTION_SOUTH:
1261         y = client_directional_edge_search(c, OB_DIRECTION_SOUTH) -
1262             c->frame->area.height;
1263         break;
1264     case OB_DIRECTION_EAST:
1265         x = client_directional_edge_search(c, OB_DIRECTION_EAST) -
1266             c->frame->area.width;
1267         break;
1268     default:
1269         g_assert_not_reached();
1270     }
1271     frame_frame_gravity(c->frame, &x, &y);
1272     client_configure(c, OB_CORNER_TOPLEFT,
1273                      x, y, c->area.width, c->area.height, TRUE, TRUE);
1274
1275 }
1276
1277 void action_growtoedge(union ActionData *data)
1278 {
1279     int x, y, width, height, dest;
1280     ObClient *c = data->diraction.c;
1281     Rect *a = screen_area(c->desktop);
1282
1283     if (!c)
1284         return;
1285     
1286     x = c->frame->area.x;
1287     y = c->frame->area.y;
1288     width = c->frame->area.width;
1289     height = c->frame->area.height;
1290
1291     switch(data->diraction.direction) {
1292     case OB_DIRECTION_NORTH:
1293         dest = client_directional_edge_search(c, OB_DIRECTION_NORTH);
1294         if (a->y == y)
1295             height = c->frame->area.height / 2;
1296         else {
1297             height = c->frame->area.y + c->frame->area.height - dest;
1298             y = dest;
1299         }
1300         break;
1301     case OB_DIRECTION_WEST:
1302         dest = client_directional_edge_search(c, OB_DIRECTION_WEST);
1303         if (a->x == x)
1304             width = c->frame->area.width / 2;
1305         else {
1306             width = c->frame->area.x + c->frame->area.width - dest;
1307             x = dest;
1308         }
1309         break;
1310     case OB_DIRECTION_SOUTH:
1311         dest = client_directional_edge_search(c, OB_DIRECTION_SOUTH);
1312         if (a->y + a->height == y + c->frame->area.height) {
1313             height = c->frame->area.height / 2;
1314             y = a->y + a->height - height;
1315         } else
1316             height = dest - c->frame->area.y;
1317         y += (height - c->frame->area.height) % c->size_inc.height;
1318         height -= (height - c->frame->area.height) % c->size_inc.height;
1319         break;
1320     case OB_DIRECTION_EAST:
1321         dest = client_directional_edge_search(c, OB_DIRECTION_EAST);
1322         if (a->x + a->width == x + c->frame->area.width) {
1323             width = c->frame->area.width / 2;
1324             x = a->x + a->width - width;
1325         } else
1326             width = dest - c->frame->area.x;
1327         x += (width - c->frame->area.width) % c->size_inc.width;
1328         width -= (width - c->frame->area.width) % c->size_inc.width;
1329         break;
1330     default:
1331         g_assert_not_reached();
1332     }
1333     frame_frame_gravity(c->frame, &x, &y);
1334     width -= c->frame->size.left + c->frame->size.right;
1335     height -= c->frame->size.top + c->frame->size.bottom;
1336     client_configure(c, OB_CORNER_TOPLEFT, x, y, width, height, TRUE, TRUE);
1337 }
1338
1339 void action_send_to_layer(union ActionData *data)
1340 {
1341     if (data->layer.c)
1342         client_set_layer(data->layer.c, data->layer.layer);
1343 }
1344
1345 void action_toggle_layer(union ActionData *data)
1346 {
1347     ObClient *c = data->layer.c;
1348
1349     if (c) {
1350         if (data->layer.layer < 0)
1351             client_set_layer(c, c->below ? 0 : -1);
1352         else if (data->layer.layer > 0)
1353             client_set_layer(c, c->above ? 0 : 1);
1354     }
1355 }
1356
1357 void action_toggle_show_desktop(union ActionData *data)
1358 {
1359     screen_show_desktop(!screen_showing_desktop);
1360 }
1361
1362 void action_show_desktop(union ActionData *data)
1363 {
1364     screen_show_desktop(TRUE);
1365 }
1366
1367 void action_unshow_desktop(union ActionData *data)
1368 {
1369     screen_show_desktop(FALSE);
1370 }