]> icculus.org git repositories - dana/openbox.git/blob - openbox/action.c
translate sendtodesktop actions
[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     } else if (!g_ascii_strcasecmp(name, "sendtonextdesktop")) {
96         a = action_new(action_send_to_next_desktop);
97         a->data.sendtonextprev.wrap = FALSE;
98         a->data.sendtonextprev.follow = TRUE;
99     } else if (!g_ascii_strcasecmp(name, "sendtonextdesktopwrap")) {
100         a = action_new(action_send_to_next_desktop);
101         a->data.sendtonextprev.wrap = TRUE;
102         a->data.sendtonextprev.follow = TRUE;
103     } else if (!g_ascii_strcasecmp(name, "sendtopreviousdesktop")) {
104         a = action_new(action_send_to_previous_desktop);
105         a->data.sendtonextprev.wrap = FALSE;
106         a->data.sendtonextprev.follow = TRUE;
107     } else if (!g_ascii_strcasecmp(name, "sendtopreviousdesktopwrap")) {
108         a = action_new(action_send_to_previous_desktop);
109         a->data.sendtonextprev.wrap = TRUE;
110         a->data.sendtonextprev.follow = TRUE;
111     } else if (!g_ascii_strcasecmp(name, "desktop")) {
112         a = action_new(action_desktop);
113     } else if (!g_ascii_strcasecmp(name, "nextdesktop")) {
114         a = action_new(action_next_desktop);
115         a->data.nextprevdesktop.wrap = FALSE;
116     } else if (!g_ascii_strcasecmp(name, "nextdesktopwrap")) {
117         a = action_new(action_next_desktop);
118         a->data.nextprevdesktop.wrap = TRUE;
119     } else if (!g_ascii_strcasecmp(name, "previousdesktop")) {
120         a = action_new(action_previous_desktop);
121         a->data.nextprevdesktop.wrap = FALSE;
122     } else if (!g_ascii_strcasecmp(name, "previousdesktopwrap")) {
123         a = action_new(action_previous_desktop);
124         a->data.nextprevdesktop.wrap = TRUE;
125     } else if (!g_ascii_strcasecmp(name, "nextdesktopcolumn")) {
126         a = action_new(action_next_desktop_column);
127         a->data.nextprevdesktop.wrap = FALSE;
128     } else if (!g_ascii_strcasecmp(name, "nextdesktopcolumnwrap")) {
129         a = action_new(action_next_desktop_column);
130         a->data.nextprevdesktop.wrap = TRUE;
131     } else if (!g_ascii_strcasecmp(name, "previousdesktopcolumn")) {
132         a = action_new(action_previous_desktop_column);
133         a->data.nextprevdesktop.wrap = FALSE;
134     } else if (!g_ascii_strcasecmp(name, "previousdesktopcolumnwrap")) {
135         a = action_new(action_previous_desktop_column);
136         a->data.nextprevdesktop.wrap = TRUE;
137     } else if (!g_ascii_strcasecmp(name, "nextdesktoprow")) {
138         a = action_new(action_next_desktop_row);
139         a->data.nextprevdesktop.wrap = FALSE;
140     } else if (!g_ascii_strcasecmp(name, "nextdesktoprowwrap")) {
141         a = action_new(action_next_desktop_row);
142         a->data.nextprevdesktop.wrap = TRUE;
143     } else if (!g_ascii_strcasecmp(name, "previousdesktoprow")) {
144         a = action_new(action_previous_desktop_row);
145         a->data.nextprevdesktop.wrap = FALSE;
146     } else if (!g_ascii_strcasecmp(name, "previousdesktoprowwrap")) {
147         a = action_new(action_previous_desktop_row);
148         a->data.nextprevdesktop.wrap = TRUE;
149     } else if (!g_ascii_strcasecmp(name, "toggledecorations")) {
150         a = action_new(action_toggle_decorations);
151     } else if (!g_ascii_strcasecmp(name, "move")) {
152         a = action_new(action_move);
153     } else if (!g_ascii_strcasecmp(name, "resize")) {
154         a = action_new(action_resize);
155     } else if (!g_ascii_strcasecmp(name, "restart")) {
156         a = action_new(action_restart);
157     } else if (!g_ascii_strcasecmp(name, "exit")) {
158         a = action_new(action_exit);
159     }
160     else if (!g_ascii_strcasecmp(name, "showmenu")) {
161         a = action_new(action_showmenu);
162     }
163     
164     return a;
165 }
166
167 void action_execute(union ActionData *data)
168 {
169     GError *e = NULL;
170     if (data->execute.path)
171         if (!g_spawn_command_line_async(data->execute.path, &e)) {
172             g_warning("failed to execute '%s': %s",
173                       data->execute.path, e->message);
174         }
175 }
176
177 void action_focus(union ActionData *data)
178 {
179     if (data->client.c)
180         client_focus(data->client.c);
181 }
182
183 void action_unfocus (union ActionData *data)
184 {
185     if (data->client.c)
186         client_unfocus(data->client.c);
187 }
188
189 void action_iconify(union ActionData *data)
190 {
191     if (data->client.c)
192         client_iconify(data->client.c, TRUE, TRUE);
193 }
194
195 void action_focusraise(union ActionData *data)
196 {
197     if (data->client.c) {
198         client_focus(data->client.c);
199         stacking_raise(data->client.c);
200     }
201 }
202
203 void action_raise(union ActionData *data)
204 {
205     if (data->client.c)
206         stacking_raise(data->client.c);
207 }
208
209 void action_unshaderaise(union ActionData *data)
210 {
211     if (data->client.c) {
212         if (data->client.c->shaded)
213             client_shade(data->client.c, FALSE);
214         else
215             stacking_raise(data->client.c);
216     }
217 }
218
219 void action_shadelower(union ActionData *data)
220 {
221     if (data->client.c) {
222         if (data->client.c->shaded)
223             stacking_lower(data->client.c);
224         else
225             client_shade(data->client.c, TRUE);
226     }
227 }
228
229 void action_lower(union ActionData *data)
230 {
231     if (data->client.c)
232         stacking_lower(data->client.c);
233 }
234
235 void action_close(union ActionData *data)
236 {
237     if (data->client.c)
238         client_close(data->client.c);
239 }
240
241 void action_kill(union ActionData *data)
242 {
243     if (data->client.c)
244         client_kill(data->client.c);
245 }
246
247 void action_shade(union ActionData *data)
248 {
249     if (data->client.c)
250         client_shade(data->client.c, TRUE);
251 }
252
253 void action_unshade(union ActionData *data)
254 {
255     if (data->client.c)
256         client_shade(data->client.c, FALSE);
257 }
258
259 void action_toggle_shade(union ActionData *data)
260 {
261     if (data->client.c)
262         client_shade(data->client.c, !data->client.c->shaded);
263 }
264
265 void action_toggle_omnipresent(union ActionData *data)
266
267     if (data->client.c)
268         client_set_desktop(data->client.c,
269                            data->client.c->desktop == DESKTOP_ALL ?
270                            screen_desktop : DESKTOP_ALL, FALSE);
271 }
272
273 void action_move_relative_horz(union ActionData *data)
274 {
275     Client *c = data->relative.c;
276     if (c)
277         client_configure(c, Corner_TopLeft,
278                          c->area.x + data->relative.delta, c->area.y,
279                          c->area.width, c->area.height, TRUE, TRUE);
280 }
281
282 void action_move_relative_vert(union ActionData *data)
283 {
284     Client *c = data->relative.c;
285     if (c)
286         client_configure(c, Corner_TopLeft,
287                          c->area.x, c->area.y + data->relative.delta,
288                          c->area.width, c->area.height, TRUE, TRUE);
289 }
290
291 void action_resize_relative_horz(union ActionData *data)
292 {
293     Client *c = data->relative.c;
294     if (c)
295         client_configure(c, Corner_TopLeft, c->area.x, c->area.y,
296                          c->area.width + data->relative.delta,
297                          c->area.height, TRUE, TRUE);
298 }
299
300 void action_resize_relative_vert(union ActionData *data)
301 {
302     Client *c = data->relative.c;
303     if (c)
304         client_configure(c, Corner_TopLeft, c->area.x, c->area.y,
305                          c->area.width, c->area.height + data->relative.delta,
306                          TRUE, TRUE);
307 }
308
309 void action_maximize_full(union ActionData *data)
310 {
311     if (data->client.c)
312         client_maximize(data->client.c, TRUE, 0, TRUE);
313 }
314
315 void action_unmaximize_full(union ActionData *data)
316 {
317     if (data->client.c)
318         client_maximize(data->client.c, FALSE, 0, TRUE);
319 }
320
321 void action_toggle_maximize_full(union ActionData *data)
322 {
323     if (data->client.c)
324         client_maximize(data->client.c,
325                         !(data->client.c->max_horz ||
326                           data->client.c->max_vert),
327                         0, TRUE);
328 }
329
330 void action_maximize_horz(union ActionData *data)
331 {
332     if (data->client.c)
333         client_maximize(data->client.c, TRUE, 1, TRUE);
334 }
335
336 void action_unmaximize_horz(union ActionData *data)
337 {
338     if (data->client.c)
339         client_maximize(data->client.c, FALSE, 1, TRUE);
340 }
341
342 void action_toggle_maximize_horz(union ActionData *data)
343 {
344     if (data->client.c)
345         client_maximize(data->client.c, !data->client.c->max_horz, 1, TRUE);
346 }
347
348 void action_maximize_vert(union ActionData *data)
349 {
350     if (data->client.c)
351         client_maximize(data->client.c, TRUE, 2, TRUE);
352 }
353
354 void action_unmaximize_vert(union ActionData *data)
355 {
356     if (data->client.c)
357         client_maximize(data->client.c, FALSE, 2, TRUE);
358 }
359
360 void action_toggle_maximize_vert(union ActionData *data)
361 {
362     if (data->client.c)
363         client_maximize(data->client.c, !data->client.c->max_vert, 2, TRUE);
364 }
365
366 void action_send_to_desktop(union ActionData *data)
367 {
368     if (data->sendto.c)
369         if (data->sendto.desktop < screen_num_desktops ||
370             data->sendto.desktop == DESKTOP_ALL)
371             client_set_desktop(data->sendto.c, data->sendto.desktop, TRUE);
372 }
373
374 void action_send_to_next_desktop(union ActionData *data)
375 {
376     guint d;
377
378     if (!data->sendto.c) return;
379
380     d = screen_desktop + 1;
381     if (d >= screen_num_desktops) {
382         if (!data->sendtonextprev.wrap) return;
383         d = 0;
384     }
385     client_set_desktop(data->sendtonextprev.c, d, data->sendtonextprev.follow);
386     if (data->sendtonextprev.follow) screen_set_desktop(d);
387 }
388
389 void action_send_to_previous_desktop(union ActionData *data)
390 {
391     guint d;
392
393     if (!data->sendto.c) return;
394
395     d = screen_desktop - 1;
396     if (d >= screen_num_desktops) {
397         if (!data->sendtonextprev.wrap) return;
398         d = screen_num_desktops - 1;
399     }
400     client_set_desktop(data->sendtonextprev.c, d, data->sendtonextprev.follow);
401     if (data->sendtonextprev.follow) screen_set_desktop(d);
402 }
403
404 void action_desktop(union ActionData *data)
405 {
406     if (data->desktop.desk < screen_num_desktops ||
407         data->desktop.desk == DESKTOP_ALL)
408         screen_set_desktop(data->desktop.desk);
409 }
410
411 void action_next_desktop(union ActionData *data)
412 {
413     guint d;
414
415     d = screen_desktop + 1;
416     if (d >= screen_num_desktops) {
417         if (!data->nextprevdesktop.wrap) return;
418         d = 0;
419     }
420     screen_set_desktop(d);
421 }
422
423 void action_previous_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 = screen_num_desktops - 1;
431     }
432     screen_set_desktop(d);
433 }
434
435 static void cur_row_col(guint *r, guint *c)
436 {
437     switch (screen_desktop_layout.orientation) {
438     case Orientation_Horz:
439         switch (screen_desktop_layout.start_corner) {
440         case Corner_TopLeft:
441             *r = screen_desktop / screen_desktop_layout.columns;
442             *c = screen_desktop % screen_desktop_layout.columns;
443             break;
444         case Corner_BottomLeft:
445             *r = screen_desktop_layout.rows - 1 -
446                 screen_desktop / screen_desktop_layout.columns;
447             *c = screen_desktop % screen_desktop_layout.columns;
448             break;
449         break;
450         case Corner_TopRight:
451             *r = screen_desktop / screen_desktop_layout.columns;
452             *c = screen_desktop_layout.columns - 1 -
453                 screen_desktop % screen_desktop_layout.columns;
454             break;
455         case Corner_BottomRight:
456             *r = screen_desktop_layout.rows - 1 -
457                 screen_desktop / screen_desktop_layout.columns;
458             *c = screen_desktop_layout.columns - 1 -
459                 screen_desktop % screen_desktop_layout.columns;
460             break;
461         break;
462         }
463     case Orientation_Vert:
464         switch (screen_desktop_layout.start_corner) {
465         case Corner_TopLeft:
466             *r = screen_desktop % screen_desktop_layout.rows;
467             *c = screen_desktop / screen_desktop_layout.rows;
468             break;
469         case Corner_BottomLeft:
470             *r = screen_desktop_layout.rows - 1 -
471                 screen_desktop % screen_desktop_layout.rows;
472             *c = screen_desktop / screen_desktop_layout.rows;
473             break;
474         break;
475         case Corner_TopRight:
476             *r = screen_desktop % screen_desktop_layout.rows;
477             *c = screen_desktop_layout.columns - 1 -
478                 screen_desktop / screen_desktop_layout.rows;
479             break;
480         case Corner_BottomRight:
481             *r = screen_desktop_layout.rows - 1 -
482                 screen_desktop % screen_desktop_layout.rows;
483             *c = screen_desktop_layout.columns - 1 -
484                 screen_desktop / screen_desktop_layout.rows;
485             break;
486         break;
487         }
488         break;
489     }
490 }
491
492 static guint translate_row_col(guint r, guint c)
493 {
494     switch (screen_desktop_layout.orientation) {
495     case Orientation_Horz:
496         switch (screen_desktop_layout.start_corner) {
497         case Corner_TopLeft:
498             return r * screen_desktop_layout.columns + c;
499         case Corner_BottomLeft:
500             return (screen_desktop_layout.rows - 1 - r) *
501                 screen_desktop_layout.columns + c;
502         case Corner_TopRight:
503             return r * screen_desktop_layout.columns +
504                 (screen_desktop_layout.columns - 1 - c);
505         case Corner_BottomRight:
506             return (screen_desktop_layout.rows - 1 - r) *
507                 screen_desktop_layout.columns +
508                 (screen_desktop_layout.columns - 1 - c);
509         }
510     case Orientation_Vert:
511         switch (screen_desktop_layout.start_corner) {
512         case Corner_TopLeft:
513             return c * screen_desktop_layout.rows + r;
514         case Corner_BottomLeft:
515             return c * screen_desktop_layout.rows +
516                 (screen_desktop_layout.rows - 1 - r);
517         case Corner_TopRight:
518             return (screen_desktop_layout.columns - 1 - c) *
519                 screen_desktop_layout.rows + r;
520         case Corner_BottomRight:
521             return (screen_desktop_layout.columns - 1 - c) *
522                 screen_desktop_layout.rows +
523                 (screen_desktop_layout.rows - 1 - r);
524         }
525     }
526     g_assert_not_reached();
527     return 0;
528 }
529
530 void action_next_desktop_column(union ActionData *data)
531 {
532     guint r, c, d;
533
534     cur_row_col(&r, &c);
535     ++c;
536     d = translate_row_col(r, c);
537     if (d >= screen_num_desktops) {
538         if (!data->nextprevdesktop.wrap) return;
539         c = 0;
540     }
541     if (d >= screen_num_desktops)
542         ++c;
543     d = translate_row_col(r, c);
544     if (d < screen_num_desktops)
545         screen_set_desktop(d);
546 }
547
548 void action_previous_desktop_column(union ActionData *data)
549 {
550     guint r, c, d;
551
552     cur_row_col(&r, &c);
553     --c;
554     d = translate_row_col(r, c);
555     if (d >= screen_num_desktops) {
556         if (!data->nextprevdesktop.wrap) return;
557         c = screen_desktop_layout.columns - 1;
558     }
559     if (d >= screen_num_desktops)
560         --c;
561     d = translate_row_col(r, c);
562     if (d < screen_num_desktops)
563         screen_set_desktop(d);
564 }
565
566 void action_next_desktop_row(union ActionData *data)
567 {
568     guint r, c, d;
569
570     cur_row_col(&r, &c);
571     ++r;
572     d = translate_row_col(r, c);
573     if (d >= screen_num_desktops) {
574         if (!data->nextprevdesktop.wrap) return;
575         r = 0;
576     }
577     if (d >= screen_num_desktops)
578         ++r;
579     d = translate_row_col(r, c);
580     if (d < screen_num_desktops)
581         screen_set_desktop(d);
582 }
583
584 void action_previous_desktop_row(union ActionData *data)
585 {
586     guint r, c, d;
587
588     cur_row_col(&r, &c);
589     --r;
590     d = translate_row_col(r, c);
591     if (d >= screen_num_desktops) {
592         if (!data->nextprevdesktop.wrap) return;
593         c = screen_desktop_layout.rows - 1;
594     }
595     if (d >= screen_num_desktops)
596         --r;
597     d = translate_row_col(r, c);
598     if (d < screen_num_desktops)
599         screen_set_desktop(d);
600 }
601
602 void action_toggle_decorations(union ActionData *data)
603 {
604     Client *c = data->client.c;
605     c->disabled_decorations = c->disabled_decorations ? 0 : ~0;
606     client_setup_decor_and_functions(c);
607 }
608
609 void action_move(union ActionData *data)
610 {
611     Client *c = data->move.c;
612     int x = data->move.x;
613     int y = data->move.y;
614
615     if (!c || !client_normal(c)) return;
616
617     dispatch_move(c, &x, &y);
618
619     frame_frame_gravity(c->frame, &x, &y); /* get where the client should be */
620     client_configure(c, Corner_TopLeft, x, y, c->area.width, c->area.height,
621                      TRUE, data->move.final);
622 }
623
624 void action_resize(union ActionData *data)
625 {
626     Client *c = data->resize.c;
627     int w = data->resize.x;
628     int h = data->resize.y;
629  
630     if (!c || !client_normal(c)) return;
631
632     /* XXX window snapping/struts */
633     
634     dispatch_resize(c, &w, &h, data->resize.corner);
635     
636     w -= c->frame->size.left + c->frame->size.right;
637     h -= c->frame->size.top + c->frame->size.bottom;
638     
639     client_configure(c, data->resize.corner, c->area.x, c->area.y, w, h,
640                      TRUE, data->resize.final);
641 }
642
643 void action_restart(union ActionData *data)
644 {
645     ob_restart_path = data->execute.path;
646     ob_shutdown = ob_restart = TRUE;
647 }
648
649 void action_exit(union ActionData *data)
650 {
651     ob_shutdown = TRUE;
652 }
653
654 void action_showmenu(union ActionData *data)
655 {
656     g_message(__FUNCTION__);
657 }