mouse and key bindings plugins work. segfault somewhere still on shutdown
[mikachu/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
7 #include <glib.h>
8
9 Action *action_new(void (*func)(union ActionData *data))
10 {
11     Action *a = g_new(Action, 1);
12     a->func = func;
13
14     /* deal with pointers */
15     if (func == action_execute)
16         a->data.execute.path = NULL;
17
18     return a;
19 }
20
21 void action_free(Action *a)
22 {
23     /* deal with pointers */
24     if (a->func == action_execute)
25         g_free(a->data.execute.path);
26
27     g_free(a);
28 }
29
30 void action_execute(union ActionData *data)
31 {
32     GError *e;
33     if (!g_spawn_command_line_async(data->execute.path, &e)) {
34         g_warning("failed to execute '%s': %s",
35                   data->execute.path, e->message);
36     }
37 }
38
39 void action_iconify(union ActionData *data)
40 {
41     client_iconify(data->client.c, TRUE, TRUE);
42 }
43
44 void action_raise(union ActionData *data)
45 {
46     stacking_raise(data->client.c);
47 }
48
49 void action_lower(union ActionData *data)
50 {
51     stacking_lower(data->client.c);
52 }
53
54 void action_close(union ActionData *data)
55 {
56     client_close(data->client.c);
57 }
58
59 void action_shade(union ActionData *data)
60 {
61     client_shade(data->client.c, TRUE);
62 }
63
64 void action_unshade(union ActionData *data)
65 {
66     client_shade(data->client.c, FALSE);
67 }
68
69 void action_toggle_shade(union ActionData *data)
70 {
71     client_shade(data->client.c, !data->client.c->shaded);
72 }
73
74 void action_toggle_omnipresent(union ActionData *data)
75 {
76     client_set_desktop(data->client.c, data->client.c->desktop == DESKTOP_ALL ?
77                        screen_desktop : DESKTOP_ALL);
78 }
79
80 void action_move_relative(union ActionData *data)
81 {
82     Client *c = data->relative.c;
83     client_configure(c, Corner_TopLeft,
84                      c->area.x + data->relative.dx,
85                      c->area.y + data->relative.dy,
86                      c->area.width, c->area.height, TRUE, TRUE);
87 }
88
89 void action_resize_relative(union ActionData *data)
90 {
91     Client *c = data->relative.c;
92     client_configure(c, Corner_TopLeft, c->area.x, c->area.y,
93                      c->area.width + data->relative.dx,
94                      c->area.height + data->relative.dy, TRUE, TRUE);
95 }
96
97 void action_maximize_full(union ActionData *data)
98 {
99     client_maximize(data->client.c, TRUE, 0, TRUE);
100 }
101
102 void action_unmaximize_full(union ActionData *data)
103 {
104     client_maximize(data->client.c, FALSE, 0, TRUE);
105 }
106
107 void action_toggle_maximize_full(union ActionData *data)
108 {
109     client_maximize(data->client.c,
110                     !(data->client.c->max_horz || data->client.c->max_vert),
111                     0, TRUE);
112 }
113
114 void action_maximize_horz(union ActionData *data)
115 {
116     client_maximize(data->client.c, TRUE, 1, TRUE);
117 }
118
119 void action_unmaximize_horz(union ActionData *data)
120 {
121     client_maximize(data->client.c, FALSE, 1, TRUE);
122 }
123
124 void action_toggle_maximize_horz(union ActionData *data)
125 {
126     client_maximize(data->client.c, !data->client.c->max_horz, 1, TRUE);
127 }
128
129 void action_maximize_vert(union ActionData *data)
130 {
131     client_maximize(data->client.c, TRUE, 2, TRUE);
132 }
133
134 void action_unmaximize_vert(union ActionData *data)
135 {
136     client_maximize(data->client.c, FALSE, 2, TRUE);
137 }
138
139 void action_toggle_maximize_vert(union ActionData *data)
140 {
141     client_maximize(data->client.c, !data->client.c->max_vert, 2, TRUE);
142 }
143
144 void action_send_to_desktop(union ActionData *data)
145 {
146     if (data->sendto.desktop < screen_num_desktops ||
147         data->sendto.desktop == DESKTOP_ALL)
148         client_set_desktop(data->sendto.c, data->sendto.desktop);
149 }
150
151 void action_send_to_next_desktop(union ActionData *data)
152 {
153     guint d;
154
155     d = screen_desktop + 1;
156     if (d >= screen_num_desktops) {
157         if (!data->sendtonextprev.wrap) return;
158         d = 0;
159     }
160     client_set_desktop(data->sendtonextprev.c, d);
161     if (data->sendtonextprev.follow) screen_set_desktop(d);
162 }
163
164 void action_send_to_previous_desktop(union ActionData *data)
165 {
166     guint d;
167
168     d = screen_desktop - 1;
169     if (d >= screen_num_desktops) {
170         if (!data->sendtonextprev.wrap) return;
171         d = screen_num_desktops - 1;
172     }
173     client_set_desktop(data->sendtonextprev.c, d);
174     if (data->sendtonextprev.follow) screen_set_desktop(d);
175 }
176
177 void action_desktop(union ActionData *data)
178 {
179     if (data->desktop.desk < screen_num_desktops ||
180         data->desktop.desk == DESKTOP_ALL)
181         screen_set_desktop(data->desktop.desk);
182 }
183
184 void action_next_desktop(union ActionData *data)
185 {
186     guint d;
187
188     d = screen_desktop + 1;
189     if (d >= screen_num_desktops) {
190         if (!data->nextprevdesktop.wrap) return;
191         d = 0;
192     }
193     screen_set_desktop(d);
194 }
195
196 void action_previous_desktop(union ActionData *data)
197 {
198     guint d;
199
200     d = screen_desktop - 1;
201     if (d >= screen_num_desktops) {
202         if (!data->nextprevdesktop.wrap) return;
203         d = screen_num_desktops - 1;
204     }
205     screen_set_desktop(d);
206 }
207
208 static void cur_row_col(guint *r, guint *c)
209 {
210     switch (screen_desktop_layout.orientation) {
211     case Orientation_Horz:
212         switch (screen_desktop_layout.start_corner) {
213         case Corner_TopLeft:
214             *r = screen_desktop / screen_desktop_layout.columns;
215             *c = screen_desktop % screen_desktop_layout.columns;
216             break;
217         case Corner_BottomLeft:
218             *r = screen_desktop_layout.rows - 1 -
219                 screen_desktop / screen_desktop_layout.columns;
220             *c = screen_desktop % screen_desktop_layout.columns;
221             break;
222         break;
223         case Corner_TopRight:
224             *r = screen_desktop / screen_desktop_layout.columns;
225             *c = screen_desktop_layout.columns - 1 -
226                 screen_desktop % screen_desktop_layout.columns;
227             break;
228         case Corner_BottomRight:
229             *r = screen_desktop_layout.rows - 1 -
230                 screen_desktop / screen_desktop_layout.columns;
231             *c = screen_desktop_layout.columns - 1 -
232                 screen_desktop % screen_desktop_layout.columns;
233             break;
234         break;
235         }
236     case Orientation_Vert:
237         switch (screen_desktop_layout.start_corner) {
238         case Corner_TopLeft:
239             *r = screen_desktop % screen_desktop_layout.rows;
240             *c = screen_desktop / screen_desktop_layout.rows;
241             break;
242         case Corner_BottomLeft:
243             *r = screen_desktop_layout.rows - 1 -
244                 screen_desktop % screen_desktop_layout.rows;
245             *c = screen_desktop / screen_desktop_layout.rows;
246             break;
247         break;
248         case Corner_TopRight:
249             *r = screen_desktop % screen_desktop_layout.rows;
250             *c = screen_desktop_layout.columns - 1 -
251                 screen_desktop / screen_desktop_layout.rows;
252             break;
253         case Corner_BottomRight:
254             *r = screen_desktop_layout.rows - 1 -
255                 screen_desktop % screen_desktop_layout.rows;
256             *c = screen_desktop_layout.columns - 1 -
257                 screen_desktop / screen_desktop_layout.rows;
258             break;
259         break;
260         }
261         break;
262     }
263 }
264
265 static guint translate_row_col(guint r, guint c)
266 {
267     switch (screen_desktop_layout.orientation) {
268     case Orientation_Horz:
269         switch (screen_desktop_layout.start_corner) {
270         case Corner_TopLeft:
271             return r * screen_desktop_layout.columns + c;
272         case Corner_BottomLeft:
273             return (screen_desktop_layout.rows - 1 - r) *
274                 screen_desktop_layout.columns + c;
275         case Corner_TopRight:
276             return r * screen_desktop_layout.columns +
277                 (screen_desktop_layout.columns - 1 - c);
278         case Corner_BottomRight:
279             return (screen_desktop_layout.rows - 1 - r) *
280                 screen_desktop_layout.columns +
281                 (screen_desktop_layout.columns - 1 - c);
282         }
283     case Orientation_Vert:
284         switch (screen_desktop_layout.start_corner) {
285         case Corner_TopLeft:
286             return c * screen_desktop_layout.rows + r;
287         case Corner_BottomLeft:
288             return c * screen_desktop_layout.rows +
289                 (screen_desktop_layout.rows - 1 - r);
290         case Corner_TopRight:
291             return (screen_desktop_layout.columns - 1 - c) *
292                 screen_desktop_layout.rows + r;
293         case Corner_BottomRight:
294             return (screen_desktop_layout.columns - 1 - c) *
295                 screen_desktop_layout.rows +
296                 (screen_desktop_layout.rows - 1 - r);
297         }
298     }
299     g_assert_not_reached();
300     return 0;
301 }
302
303 void action_next_desktop_column(union ActionData *data)
304 {
305     guint r, c, d;
306
307     cur_row_col(&r, &c);
308     ++c;
309     d = translate_row_col(r, c);
310     if (d >= screen_num_desktops) {
311         if (!data->nextprevdesktop.wrap) return;
312         c = 0;
313     }
314     if (d >= screen_num_desktops)
315         ++c;
316     d = translate_row_col(r, c);
317     if (d < screen_num_desktops)
318         screen_set_desktop(d);
319 }
320
321 void action_previous_desktop_column(union ActionData *data)
322 {
323     guint r, c, d;
324
325     cur_row_col(&r, &c);
326     --c;
327     d = translate_row_col(r, c);
328     if (d >= screen_num_desktops) {
329         if (!data->nextprevdesktop.wrap) return;
330         c = screen_desktop_layout.columns - 1;
331     }
332     if (d >= screen_num_desktops)
333         --c;
334     d = translate_row_col(r, c);
335     if (d < screen_num_desktops)
336         screen_set_desktop(d);
337 }
338
339 void action_next_desktop_row(union ActionData *data)
340 {
341     guint r, c, d;
342
343     cur_row_col(&r, &c);
344     ++r;
345     d = translate_row_col(r, c);
346     if (d >= screen_num_desktops) {
347         if (!data->nextprevdesktop.wrap) return;
348         r = 0;
349     }
350     if (d >= screen_num_desktops)
351         ++r;
352     d = translate_row_col(r, c);
353     if (d < screen_num_desktops)
354         screen_set_desktop(d);
355 }
356
357 void action_previous_desktop_row(union ActionData *data)
358 {
359     guint r, c, d;
360
361     cur_row_col(&r, &c);
362     --r;
363     d = translate_row_col(r, c);
364     if (d >= screen_num_desktops) {
365         if (!data->nextprevdesktop.wrap) return;
366         c = screen_desktop_layout.rows - 1;
367     }
368     if (d >= screen_num_desktops)
369         --r;
370     d = translate_row_col(r, c);
371     if (d < screen_num_desktops)
372         screen_set_desktop(d);
373 }
374
375 void action_toggle_decorations(union ActionData *data)
376 {
377     Client *c = data->client.c;
378     c->disabled_decorations = c->disabled_decorations ? 0 : ~0;
379     client_setup_decor_and_functions(c);
380 }
381
382 void action_move(union ActionData *data)
383 {
384     Client *c = data->move.c;
385     int x = data->move.x;
386     int y = data->move.y;
387
388     client_configure(c, Corner_TopLeft, x, y, c->area.width, c->area.height,
389                      TRUE, data->move.final);
390 }
391
392 void action_resize(union ActionData *data)
393 {
394     Client *c = data->resize.c;
395     int w = data->resize.x - c->frame->size.left - c->frame->size.right;
396     int h = data->resize.y - c->frame->size.top - c->frame->size.bottom;
397
398     client_configure(c, data->resize.corner, c->area.x, c->area.y, w, h,
399                      TRUE, data->resize.final);
400 }