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