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