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