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