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