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