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