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