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