add helper functions for manipulating the focus_order list.
[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 Action *action_new(void (*func)(union ActionData *data))
16 {
17     Action *a = g_new0(Action, 1);
18     a->func = func;
19
20     return a;
21 }
22
23 void action_free(Action *a)
24 {
25     if (a == NULL) return;
26
27     /* deal with pointers */
28     if (a->func == action_execute || a->func == action_restart)
29         g_free(a->data.execute.path);
30     else if (a->func == action_showmenu)
31         g_free(a->data.showmenu.name);
32
33     g_free(a);
34 }
35
36 Action *action_from_string(char *name)
37 {
38     Action *a = NULL;
39     if (!g_ascii_strcasecmp(name, "execute")) {
40         a = action_new(action_execute);
41     } else if (!g_ascii_strcasecmp(name, "focus")) {
42         a = action_new(action_focus);
43     } else if (!g_ascii_strcasecmp(name, "unfocus")) {
44         a = action_new(action_unfocus);
45     } else if (!g_ascii_strcasecmp(name, "iconify")) {
46         a = action_new(action_iconify);
47     } else if (!g_ascii_strcasecmp(name, "raise")) {
48         a = action_new(action_raise);
49     } else if (!g_ascii_strcasecmp(name, "lower")) {
50         a = action_new(action_lower);
51     } else if (!g_ascii_strcasecmp(name, "focusraise")) {
52         a = action_new(action_focusraise);
53     } else if (!g_ascii_strcasecmp(name, "close")) {
54         a = action_new(action_close);
55     } else if (!g_ascii_strcasecmp(name, "kill")) {
56         a = action_new(action_kill);
57     } else if (!g_ascii_strcasecmp(name, "shadelower")) {
58         a = action_new(action_shadelower);
59     } else if (!g_ascii_strcasecmp(name, "unshaderaise")) {
60         a = action_new(action_unshaderaise);
61     } else if (!g_ascii_strcasecmp(name, "shade")) {
62         a = action_new(action_shade);
63     } else if (!g_ascii_strcasecmp(name, "unshade")) {
64         a = action_new(action_unshade);
65     } else if (!g_ascii_strcasecmp(name, "toggleshade")) {
66         a = action_new(action_toggle_shade);
67     } else if (!g_ascii_strcasecmp(name, "toggleomnipresent")) {
68         a = action_new(action_toggle_omnipresent);
69     } else if (!g_ascii_strcasecmp(name, "moverelativehorz")) {
70         a = action_new(action_move_relative_horz);
71     } else if (!g_ascii_strcasecmp(name, "moverelativevert")) {
72         a = action_new(action_move_relative_vert);
73     } else if (!g_ascii_strcasecmp(name, "resizerelativehorz")) {
74         a = action_new(action_resize_relative_horz);
75     } else if (!g_ascii_strcasecmp(name, "resizerelativevert")) {
76         a = action_new(action_resize_relative_vert);
77     } else if (!g_ascii_strcasecmp(name, "maximizefull")) {
78         a = action_new(action_maximize_full);
79     } else if (!g_ascii_strcasecmp(name, "unmaximizefull")) {
80         a = action_new(action_unmaximize_full);
81     } else if (!g_ascii_strcasecmp(name, "togglemaximizefull")) {
82         a = action_new(action_toggle_maximize_full);
83     } else if (!g_ascii_strcasecmp(name, "maximizehorz")) {
84         a = action_new(action_maximize_horz);
85     } else if (!g_ascii_strcasecmp(name, "unmaximizehorz")) {
86         a = action_new(action_unmaximize_horz);
87     } else if (!g_ascii_strcasecmp(name, "togglemaximizehorz")) {
88         a = action_new(action_toggle_maximize_horz);
89     } else if (!g_ascii_strcasecmp(name, "maximizevert")) {
90         a = action_new(action_maximize_vert);
91     } else if (!g_ascii_strcasecmp(name, "unmaximizevert")) {
92         a = action_new(action_unmaximize_vert);
93     } else if (!g_ascii_strcasecmp(name, "togglemaximizevert")) {
94         a = action_new(action_toggle_maximize_vert);
95     } else if (!g_ascii_strcasecmp(name, "sendtodesktop")) {
96         a = action_new(action_send_to_desktop);
97         a->data.sendto.follow = TRUE;
98     } else if (!g_ascii_strcasecmp(name, "sendtonextdesktop")) {
99         a = action_new(action_send_to_next_desktop);
100         a->data.sendtonextprev.wrap = FALSE;
101         a->data.sendtonextprev.follow = TRUE;
102     } else if (!g_ascii_strcasecmp(name, "sendtonextdesktopwrap")) {
103         a = action_new(action_send_to_next_desktop);
104         a->data.sendtonextprev.wrap = TRUE;
105         a->data.sendtonextprev.follow = TRUE;
106     } else if (!g_ascii_strcasecmp(name, "sendtopreviousdesktop")) {
107         a = action_new(action_send_to_previous_desktop);
108         a->data.sendtonextprev.wrap = FALSE;
109         a->data.sendtonextprev.follow = TRUE;
110     } else if (!g_ascii_strcasecmp(name, "sendtopreviousdesktopwrap")) {
111         a = action_new(action_send_to_previous_desktop);
112         a->data.sendtonextprev.wrap = TRUE;
113         a->data.sendtonextprev.follow = TRUE;
114     } else if (!g_ascii_strcasecmp(name, "desktop")) {
115         a = action_new(action_desktop);
116     } else if (!g_ascii_strcasecmp(name, "nextdesktop")) {
117         a = action_new(action_next_desktop);
118         a->data.nextprevdesktop.wrap = FALSE;
119     } else if (!g_ascii_strcasecmp(name, "nextdesktopwrap")) {
120         a = action_new(action_next_desktop);
121         a->data.nextprevdesktop.wrap = TRUE;
122     } else if (!g_ascii_strcasecmp(name, "previousdesktop")) {
123         a = action_new(action_previous_desktop);
124         a->data.nextprevdesktop.wrap = FALSE;
125     } else if (!g_ascii_strcasecmp(name, "previousdesktopwrap")) {
126         a = action_new(action_previous_desktop);
127         a->data.nextprevdesktop.wrap = TRUE;
128     } else if (!g_ascii_strcasecmp(name, "nextdesktopcolumn")) {
129         a = action_new(action_next_desktop_column);
130         a->data.nextprevdesktop.wrap = FALSE;
131     } else if (!g_ascii_strcasecmp(name, "nextdesktopcolumnwrap")) {
132         a = action_new(action_next_desktop_column);
133         a->data.nextprevdesktop.wrap = TRUE;
134     } else if (!g_ascii_strcasecmp(name, "previousdesktopcolumn")) {
135         a = action_new(action_previous_desktop_column);
136         a->data.nextprevdesktop.wrap = FALSE;
137     } else if (!g_ascii_strcasecmp(name, "previousdesktopcolumnwrap")) {
138         a = action_new(action_previous_desktop_column);
139         a->data.nextprevdesktop.wrap = TRUE;
140     } else if (!g_ascii_strcasecmp(name, "nextdesktoprow")) {
141         a = action_new(action_next_desktop_row);
142         a->data.nextprevdesktop.wrap = FALSE;
143     } else if (!g_ascii_strcasecmp(name, "nextdesktoprowwrap")) {
144         a = action_new(action_next_desktop_row);
145         a->data.nextprevdesktop.wrap = TRUE;
146     } else if (!g_ascii_strcasecmp(name, "previousdesktoprow")) {
147         a = action_new(action_previous_desktop_row);
148         a->data.nextprevdesktop.wrap = FALSE;
149     } else if (!g_ascii_strcasecmp(name, "previousdesktoprowwrap")) {
150         a = action_new(action_previous_desktop_row);
151         a->data.nextprevdesktop.wrap = TRUE;
152     } else if (!g_ascii_strcasecmp(name, "toggledecorations")) {
153         a = action_new(action_toggle_decorations);
154     } else if (!g_ascii_strcasecmp(name, "keyboardmove")) {
155         a = action_new(action_moveresize);
156         a->data.moveresize.corner = prop_atoms.net_wm_moveresize_move_keyboard;
157     } else if (!g_ascii_strcasecmp(name, "move")) {
158         a = action_new(action_moveresize);
159         a->data.moveresize.corner = prop_atoms.net_wm_moveresize_move;
160     } else if (!g_ascii_strcasecmp(name, "resize")) {
161         a = action_new(action_moveresize);
162         a->data.moveresize.corner = prop_atoms.net_wm_moveresize_size_topleft;
163     } else if (!g_ascii_strcasecmp(name, "keyboardresize")) {
164         a = action_new(action_moveresize);
165         a->data.moveresize.corner = prop_atoms.net_wm_moveresize_size_keyboard;
166     } else if (!g_ascii_strcasecmp(name, "restart")) {
167         a = action_new(action_restart);
168     } else if (!g_ascii_strcasecmp(name, "exit")) {
169         a = action_new(action_exit);
170     } else if (!g_ascii_strcasecmp(name, "showmenu")) {
171         a = action_new(action_showmenu);
172     } else if (!g_ascii_strcasecmp(name, "nextwindowlinear")) {
173         a = action_new(action_cycle_windows);
174         a->data.cycle.linear = TRUE;
175         a->data.cycle.forward = TRUE;
176     } else if (!g_ascii_strcasecmp(name, "previouswindowlinear")) {
177         a = action_new(action_cycle_windows);
178         a->data.cycle.linear = TRUE;
179         a->data.cycle.forward = FALSE;
180     } else if (!g_ascii_strcasecmp(name, "nextwindow")) {
181         a = action_new(action_cycle_windows);
182         a->data.cycle.linear = FALSE;
183         a->data.cycle.forward = TRUE;
184     } else if (!g_ascii_strcasecmp(name, "previouswindow")) {
185         a = action_new(action_cycle_windows);
186         a->data.cycle.linear = FALSE;
187         a->data.cycle.forward = FALSE;
188     }
189     
190     return a;
191 }
192
193 void action_execute(union ActionData *data)
194 {
195     GError *e = NULL;
196     if (data->execute.path)
197         if (!g_spawn_command_line_async(data->execute.path, &e)) {
198             g_warning("failed to execute '%s': %s",
199                       data->execute.path, e->message);
200         }
201 }
202
203 void action_focus(union ActionData *data)
204 {
205     if (data->client.c)
206         client_focus(data->client.c);
207 }
208
209 void action_unfocus (union ActionData *data)
210 {
211     if (data->client.c)
212         client_unfocus(data->client.c);
213 }
214
215 void action_iconify(union ActionData *data)
216 {
217     if (data->client.c)
218         client_iconify(data->client.c, TRUE, TRUE);
219 }
220
221 void action_focusraise(union ActionData *data)
222 {
223     if (data->client.c) {
224         client_focus(data->client.c);
225         stacking_raise(data->client.c);
226     }
227 }
228
229 void action_raise(union ActionData *data)
230 {
231     if (data->client.c)
232         stacking_raise(data->client.c);
233 }
234
235 void action_unshaderaise(union ActionData *data)
236 {
237     if (data->client.c) {
238         if (data->client.c->shaded)
239             client_shade(data->client.c, FALSE);
240         else
241             stacking_raise(data->client.c);
242     }
243 }
244
245 void action_shadelower(union ActionData *data)
246 {
247     if (data->client.c) {
248         if (data->client.c->shaded)
249             stacking_lower(data->client.c);
250         else
251             client_shade(data->client.c, TRUE);
252     }
253 }
254
255 void action_lower(union ActionData *data)
256 {
257     if (data->client.c)
258         stacking_lower(data->client.c);
259 }
260
261 void action_close(union ActionData *data)
262 {
263     if (data->client.c)
264         client_close(data->client.c);
265 }
266
267 void action_kill(union ActionData *data)
268 {
269     if (data->client.c)
270         client_kill(data->client.c);
271 }
272
273 void action_shade(union ActionData *data)
274 {
275     if (data->client.c)
276         client_shade(data->client.c, TRUE);
277 }
278
279 void action_unshade(union ActionData *data)
280 {
281     if (data->client.c)
282         client_shade(data->client.c, FALSE);
283 }
284
285 void action_toggle_shade(union ActionData *data)
286 {
287     if (data->client.c)
288         client_shade(data->client.c, !data->client.c->shaded);
289 }
290
291 void action_toggle_omnipresent(union ActionData *data)
292
293     if (data->client.c)
294         client_set_desktop(data->client.c,
295                            data->client.c->desktop == DESKTOP_ALL ?
296                            screen_desktop : DESKTOP_ALL, FALSE);
297 }
298
299 void action_move_relative_horz(union ActionData *data)
300 {
301     Client *c = data->relative.c;
302     if (c)
303         client_configure(c, Corner_TopLeft,
304                          c->area.x + data->relative.delta, c->area.y,
305                          c->area.width, c->area.height, TRUE, TRUE);
306 }
307
308 void action_move_relative_vert(union ActionData *data)
309 {
310     Client *c = data->relative.c;
311     if (c)
312         client_configure(c, Corner_TopLeft,
313                          c->area.x, c->area.y + data->relative.delta,
314                          c->area.width, c->area.height, TRUE, TRUE);
315 }
316
317 void action_resize_relative_horz(union ActionData *data)
318 {
319     Client *c = data->relative.c;
320     if (c)
321         client_configure(c, Corner_TopLeft, c->area.x, c->area.y,
322                          c->area.width + data->relative.delta,
323                          c->area.height, TRUE, TRUE);
324 }
325
326 void action_resize_relative_vert(union ActionData *data)
327 {
328     Client *c = data->relative.c;
329     if (c && !c->shaded)
330         client_configure(c, Corner_TopLeft, c->area.x, c->area.y,
331                          c->area.width, c->area.height + data->relative.delta,
332                          TRUE, TRUE);
333 }
334
335 void action_maximize_full(union ActionData *data)
336 {
337     if (data->client.c)
338         client_maximize(data->client.c, TRUE, 0, TRUE);
339 }
340
341 void action_unmaximize_full(union ActionData *data)
342 {
343     if (data->client.c)
344         client_maximize(data->client.c, FALSE, 0, TRUE);
345 }
346
347 void action_toggle_maximize_full(union ActionData *data)
348 {
349     if (data->client.c)
350         client_maximize(data->client.c,
351                         !(data->client.c->max_horz ||
352                           data->client.c->max_vert),
353                         0, TRUE);
354 }
355
356 void action_maximize_horz(union ActionData *data)
357 {
358     if (data->client.c)
359         client_maximize(data->client.c, TRUE, 1, TRUE);
360 }
361
362 void action_unmaximize_horz(union ActionData *data)
363 {
364     if (data->client.c)
365         client_maximize(data->client.c, FALSE, 1, TRUE);
366 }
367
368 void action_toggle_maximize_horz(union ActionData *data)
369 {
370     if (data->client.c)
371         client_maximize(data->client.c, !data->client.c->max_horz, 1, TRUE);
372 }
373
374 void action_maximize_vert(union ActionData *data)
375 {
376     if (data->client.c)
377         client_maximize(data->client.c, TRUE, 2, TRUE);
378 }
379
380 void action_unmaximize_vert(union ActionData *data)
381 {
382     if (data->client.c)
383         client_maximize(data->client.c, FALSE, 2, TRUE);
384 }
385
386 void action_toggle_maximize_vert(union ActionData *data)
387 {
388     if (data->client.c)
389         client_maximize(data->client.c, !data->client.c->max_vert, 2, TRUE);
390 }
391
392 void action_send_to_desktop(union ActionData *data)
393 {
394     if (data->sendto.c) {
395         if (data->sendto.desk < screen_num_desktops ||
396             data->sendto.desk == DESKTOP_ALL) {
397             client_set_desktop(data->desktop.c,
398                                data->sendto.desk, data->sendto.follow);
399             if (data->sendto.follow) screen_set_desktop(data->sendto.desk);
400         }
401     }
402 }
403
404 void action_send_to_next_desktop(union ActionData *data)
405 {
406     guint d;
407
408     if (!data->sendtonextprev.c) return;
409
410     d = screen_desktop + 1;
411     if (d >= screen_num_desktops) {
412         if (!data->sendtonextprev.wrap) return;
413         d = 0;
414     }
415     client_set_desktop(data->sendtonextprev.c, d, data->sendtonextprev.follow);
416     if (data->sendtonextprev.follow) screen_set_desktop(d);
417 }
418
419 void action_send_to_previous_desktop(union ActionData *data)
420 {
421     guint d;
422
423     if (!data->sendtonextprev.c) return;
424
425     d = screen_desktop - 1;
426     if (d >= screen_num_desktops) {
427         if (!data->sendtonextprev.wrap) return;
428         d = screen_num_desktops - 1;
429     }
430     client_set_desktop(data->sendtonextprev.c, d, data->sendtonextprev.follow);
431     if (data->sendtonextprev.follow) screen_set_desktop(d);
432 }
433
434 void action_desktop(union ActionData *data)
435 {
436     if (data->desktop.desk < screen_num_desktops ||
437         data->desktop.desk == DESKTOP_ALL)
438         screen_set_desktop(data->desktop.desk);
439 }
440
441 void action_next_desktop(union ActionData *data)
442 {
443     guint d;
444
445     d = screen_desktop + 1;
446     if (d >= screen_num_desktops) {
447         if (!data->nextprevdesktop.wrap) return;
448         d = 0;
449     }
450     screen_set_desktop(d);
451 }
452
453 void action_previous_desktop(union ActionData *data)
454 {
455     guint d;
456
457     d = screen_desktop - 1;
458     if (d >= screen_num_desktops) {
459         if (!data->nextprevdesktop.wrap) return;
460         d = screen_num_desktops - 1;
461     }
462     screen_set_desktop(d);
463 }
464
465 static void cur_row_col(guint *r, guint *c)
466 {
467     switch (screen_desktop_layout.orientation) {
468     case Orientation_Horz:
469         switch (screen_desktop_layout.start_corner) {
470         case Corner_TopLeft:
471             *r = screen_desktop / screen_desktop_layout.columns;
472             *c = screen_desktop % screen_desktop_layout.columns;
473             break;
474         case Corner_BottomLeft:
475             *r = screen_desktop_layout.rows - 1 -
476                 screen_desktop / screen_desktop_layout.columns;
477             *c = screen_desktop % screen_desktop_layout.columns;
478             break;
479         case Corner_TopRight:
480             *r = screen_desktop / screen_desktop_layout.columns;
481             *c = screen_desktop_layout.columns - 1 -
482                 screen_desktop % screen_desktop_layout.columns;
483             break;
484         case Corner_BottomRight:
485             *r = screen_desktop_layout.rows - 1 -
486                 screen_desktop / screen_desktop_layout.columns;
487             *c = screen_desktop_layout.columns - 1 -
488                 screen_desktop % screen_desktop_layout.columns;
489             break;
490         }
491         break;
492     case Orientation_Vert:
493         switch (screen_desktop_layout.start_corner) {
494         case Corner_TopLeft:
495             *r = screen_desktop % screen_desktop_layout.rows;
496             *c = screen_desktop / screen_desktop_layout.rows;
497             break;
498         case Corner_BottomLeft:
499             *r = screen_desktop_layout.rows - 1 -
500                 screen_desktop % screen_desktop_layout.rows;
501             *c = screen_desktop / screen_desktop_layout.rows;
502             break;
503         case Corner_TopRight:
504             *r = screen_desktop % screen_desktop_layout.rows;
505             *c = screen_desktop_layout.columns - 1 -
506                 screen_desktop / screen_desktop_layout.rows;
507             break;
508         case Corner_BottomRight:
509             *r = screen_desktop_layout.rows - 1 -
510                 screen_desktop % screen_desktop_layout.rows;
511             *c = screen_desktop_layout.columns - 1 -
512                 screen_desktop / screen_desktop_layout.rows;
513             break;
514         }
515         break;
516     }
517 }
518
519 static guint translate_row_col(guint r, guint c)
520 {
521     switch (screen_desktop_layout.orientation) {
522     case Orientation_Horz:
523         switch (screen_desktop_layout.start_corner) {
524         case Corner_TopLeft:
525             return r % screen_desktop_layout.rows *
526                 screen_desktop_layout.columns +
527                 c % screen_desktop_layout.columns;
528         case Corner_BottomLeft:
529             return (screen_desktop_layout.rows - 1 -
530                     r % screen_desktop_layout.rows) *
531                 screen_desktop_layout.columns +
532                 c % screen_desktop_layout.columns;
533         case Corner_TopRight:
534             return r % screen_desktop_layout.rows *
535                 screen_desktop_layout.columns +
536                 (screen_desktop_layout.columns - 1 -
537                  c % screen_desktop_layout.columns);
538         case Corner_BottomRight:
539             return (screen_desktop_layout.rows - 1 -
540                     r % screen_desktop_layout.rows) *
541                 screen_desktop_layout.columns +
542                 (screen_desktop_layout.columns - 1 -
543                  c % screen_desktop_layout.columns);
544         }
545     case Orientation_Vert:
546         switch (screen_desktop_layout.start_corner) {
547         case Corner_TopLeft:
548             return c % screen_desktop_layout.columns *
549                 screen_desktop_layout.rows +
550                 r % screen_desktop_layout.rows;
551         case Corner_BottomLeft:
552             return c % screen_desktop_layout.columns *
553                 screen_desktop_layout.rows +
554                 (screen_desktop_layout.rows - 1 -
555                  r % screen_desktop_layout.rows);
556         case Corner_TopRight:
557             return (screen_desktop_layout.columns - 1 -
558                     c % screen_desktop_layout.columns) *
559                 screen_desktop_layout.rows +
560                 r % screen_desktop_layout.rows;
561         case Corner_BottomRight:
562             return (screen_desktop_layout.columns - 1 -
563                     c % screen_desktop_layout.columns) *
564                 screen_desktop_layout.rows +
565                 (screen_desktop_layout.rows - 1 -
566                  r % screen_desktop_layout.rows);
567         }
568     }
569     g_assert_not_reached();
570     return 0;
571 }
572
573 void action_next_desktop_column(union ActionData *data)
574 {
575     guint r, c, d;
576
577     cur_row_col(&r, &c);
578     ++c;
579     if (c >= screen_desktop_layout.columns)
580         c = 0;
581     d = translate_row_col(r, c);
582     if (d >= screen_num_desktops) {
583         if (!data->nextprevdesktop.wrap) return;
584         ++c;
585     }
586     d = translate_row_col(r, c);
587     if (d < screen_num_desktops)
588         screen_set_desktop(d);
589 }
590
591 void action_previous_desktop_column(union ActionData *data)
592 {
593     guint r, c, d;
594
595     cur_row_col(&r, &c);
596     --c;
597     if (c >= screen_desktop_layout.columns)
598         c = screen_desktop_layout.columns - 1;
599     d = translate_row_col(r, c);
600     if (d >= screen_num_desktops) {
601         if (!data->nextprevdesktop.wrap) return;
602         --c;
603     }
604     d = translate_row_col(r, c);
605     if (d < screen_num_desktops)
606         screen_set_desktop(d);
607 }
608
609 void action_next_desktop_row(union ActionData *data)
610 {
611     guint r, c, d;
612
613     cur_row_col(&r, &c);
614     ++r;
615     if (r >= screen_desktop_layout.rows)
616         r = 0;
617     d = translate_row_col(r, c);
618     if (d >= screen_num_desktops) {
619         if (!data->nextprevdesktop.wrap) return;
620         ++r;
621     }
622     d = translate_row_col(r, c);
623     if (d < screen_num_desktops)
624         screen_set_desktop(d);
625 }
626
627 void action_previous_desktop_row(union ActionData *data)
628 {
629     guint r, c, d;
630
631     cur_row_col(&r, &c);
632     --r;
633     if (r >= screen_desktop_layout.rows)
634         r = screen_desktop_layout.rows - 1;
635     d = translate_row_col(r, c);
636     if (d >= screen_num_desktops) {
637         if (!data->nextprevdesktop.wrap) return;
638         --r;
639     }
640     d = translate_row_col(r, c);
641     if (d < screen_num_desktops)
642         screen_set_desktop(d);
643 }
644
645 void action_toggle_decorations(union ActionData *data)
646 {
647     Client *c = data->client.c;;
648
649     if (!c) return;
650
651     c->disabled_decorations = c->disabled_decorations ? 0 : ~0;
652     client_setup_decor_and_functions(c);
653 }
654
655 void action_moveresize(union ActionData *data)
656 {
657     Client *c = data->moveresize.c;
658
659     if (!c || !client_normal(c)) return;
660
661     moveresize_start(c, data->moveresize.x, data->moveresize.y,
662                      data->moveresize.button, data->moveresize.corner);
663 }
664
665 void action_restart(union ActionData *data)
666 {
667     ob_restart_path = data->execute.path;
668     ob_shutdown = ob_restart = TRUE;
669 }
670
671 void action_exit(union ActionData *data)
672 {
673     ob_shutdown = TRUE;
674 }
675
676 void action_showmenu(union ActionData *data)
677 {
678     if (data->showmenu.name) {
679         menu_show(data->showmenu.name, data->showmenu.x, data->showmenu.y,
680                   data->showmenu.c);
681     }
682 }
683
684 void action_cycle_windows(union ActionData *data)
685 {
686     Client *c;
687     
688     c = focus_cycle(data->cycle.forward, data->cycle.linear, data->cycle.final,
689                     data->cycle.cancel);
690 }
691