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