Merge branch 'master' of git://git.openbox.org/dana/openbox
[mikachu/openbox.git] / openbox / actions / desktop.c
1 #include "openbox/actions.h"
2 #include "openbox/screen.h"
3 #include "openbox/client.h"
4 #include "openbox/openbox.h"
5 #include "obt/keyboard.h"
6
7 typedef enum {
8     LAST,
9     CURRENT,
10     RELATIVE,
11     ABSOLUTE
12 } SwitchType;
13
14 typedef struct {
15     SwitchType type;
16     union {
17         struct {
18             guint desktop;
19         } abs;
20
21         struct {
22             gboolean linear;
23             gboolean wrap;
24             ObDirection dir;
25         } rel;
26     } u;
27     gboolean send;
28     gboolean follow;
29 } Options;
30
31 static gpointer setup_func(xmlNodePtr node);
32 static gpointer setup_send_func(xmlNodePtr node);
33 static void free_func(gpointer o);
34 static gboolean run_func(ObActionsData *data, gpointer options);
35
36 /* 3.4-compatibility */
37 static gpointer setup_go_last_func(xmlNodePtr node);
38 static gpointer setup_send_last_func(xmlNodePtr node);
39 static gpointer setup_go_abs_func(xmlNodePtr node);
40 static gpointer setup_go_next_func(xmlNodePtr node);
41 static gpointer setup_send_next_func(xmlNodePtr node);
42 static gpointer setup_go_prev_func(xmlNodePtr node);
43 static gpointer setup_send_prev_func(xmlNodePtr node);
44 static gpointer setup_go_left_func(xmlNodePtr node);
45 static gpointer setup_send_left_func(xmlNodePtr node);
46 static gpointer setup_go_right_func(xmlNodePtr node);
47 static gpointer setup_send_right_func(xmlNodePtr node);
48 static gpointer setup_go_up_func(xmlNodePtr node);
49 static gpointer setup_send_up_func(xmlNodePtr node);
50 static gpointer setup_go_down_func(xmlNodePtr node);
51 static gpointer setup_send_down_func(xmlNodePtr node);
52
53 void action_desktop_startup(void)
54 {
55     actions_register("GoToDesktop", setup_func, free_func, run_func);
56     actions_register("SendToDesktop", setup_send_func, free_func, run_func);
57     /* 3.4-compatibility */
58     actions_register("DesktopLast", setup_go_last_func, free_func, run_func);
59     actions_register("SendToDesktopLast", setup_send_last_func,
60                      free_func, run_func);
61     actions_register("Desktop", setup_go_abs_func, free_func, run_func);
62     actions_register("DesktopNext", setup_go_next_func, free_func, run_func);
63     actions_register("SendToDesktopNext", setup_send_next_func,
64                      free_func, run_func);
65     actions_register("DesktopPrevious", setup_go_prev_func,
66                      free_func, run_func);
67     actions_register("SendToDesktopPrevious", setup_send_prev_func,
68                      free_func, run_func);
69     actions_register("DesktopLeft", setup_go_left_func, free_func, run_func);
70     actions_register("SendToDesktopLeft", setup_send_left_func,
71                      free_func, run_func);
72     actions_register("DesktopRight", setup_go_right_func,
73                      free_func, run_func);
74     actions_register("SendToDesktopRight", setup_send_right_func,
75                      free_func, run_func);
76     actions_register("DesktopUp", setup_go_up_func, free_func, run_func);
77     actions_register("SendToDesktopUp", setup_send_up_func,
78                      free_func, run_func);
79     actions_register("DesktopDown", setup_go_down_func, free_func, run_func);
80     actions_register("SendToDesktopDown", setup_send_down_func,
81                      free_func, run_func);
82 }
83
84 static gpointer setup_func(xmlNodePtr node)
85 {
86     xmlNodePtr n;
87     Options *o;
88
89     o = g_slice_new0(Options);
90     /* don't go anywhere if there are no options given */
91     o->type = ABSOLUTE;
92     o->u.abs.desktop = screen_desktop;
93     /* wrap by default - it's handy! */
94     o->u.rel.wrap = TRUE;
95
96     if ((n = obt_xml_find_node(node, "to"))) {
97         gchar *s = obt_xml_node_string(n);
98         if (!g_ascii_strcasecmp(s, "last"))
99             o->type = LAST;
100         else if (!g_ascii_strcasecmp(s, "current"))
101             o->type = CURRENT;
102         else if (!g_ascii_strcasecmp(s, "next")) {
103             o->type = RELATIVE;
104             o->u.rel.linear = TRUE;
105             o->u.rel.dir = OB_DIRECTION_EAST;
106         }
107         else if (!g_ascii_strcasecmp(s, "previous")) {
108             o->type = RELATIVE;
109             o->u.rel.linear = TRUE;
110             o->u.rel.dir = OB_DIRECTION_WEST;
111         }
112         else if (!g_ascii_strcasecmp(s, "north") ||
113                  !g_ascii_strcasecmp(s, "up")) {
114             o->type = RELATIVE;
115             o->u.rel.dir = OB_DIRECTION_NORTH;
116         }
117         else if (!g_ascii_strcasecmp(s, "south") ||
118                  !g_ascii_strcasecmp(s, "down")) {
119             o->type = RELATIVE;
120             o->u.rel.dir = OB_DIRECTION_SOUTH;
121         }
122         else if (!g_ascii_strcasecmp(s, "west") ||
123                  !g_ascii_strcasecmp(s, "left")) {
124             o->type = RELATIVE;
125             o->u.rel.dir = OB_DIRECTION_WEST;
126         }
127         else if (!g_ascii_strcasecmp(s, "east") ||
128                  !g_ascii_strcasecmp(s, "right")) {
129             o->type = RELATIVE;
130             o->u.rel.dir = OB_DIRECTION_EAST;
131         }
132         else {
133             o->type = ABSOLUTE;
134             o->u.abs.desktop = atoi(s) - 1;
135         }
136         g_free(s);
137     }
138
139     if ((n = obt_xml_find_node(node, "wrap")))
140         o->u.rel.wrap = obt_xml_node_bool(n);
141
142     return o;
143 }
144
145 static gpointer setup_send_func(xmlNodePtr node)
146 {
147     xmlNodePtr n;
148     Options *o;
149
150     o = setup_func(node);
151     if ((n = obt_xml_find_node(node, "desktop"))) {
152         /* 3.4 compatibility */
153         o->u.abs.desktop = obt_xml_node_int(n) - 1;
154         o->type = ABSOLUTE;
155     }
156     o->send = TRUE;
157     o->follow = TRUE;
158
159     if ((n = obt_xml_find_node(node, "follow")))
160         o->follow = obt_xml_node_bool(n);
161
162     return o;
163 }
164
165 static void free_func(gpointer o)
166 {
167     g_slice_free(Options, o);
168 }
169
170 static gboolean run_func(ObActionsData *data, gpointer options)
171 {
172     Options *o = options;
173     guint d;
174
175     switch (o->type) {
176     case LAST:
177         d = screen_last_desktop;
178         break;
179     case CURRENT:
180         d = screen_desktop;
181         break;
182     case ABSOLUTE:
183         d = o->u.abs.desktop;
184         break;
185     case RELATIVE:
186         d = screen_find_desktop(screen_desktop,
187                                 o->u.rel.dir, o->u.rel.wrap, o->u.rel.linear);
188         break;
189     default:
190         g_assert_not_reached();
191     }
192
193     if (d < screen_num_desktops &&
194         (d != screen_desktop ||
195          (data->client && data->client->desktop != screen_desktop))) {
196         gboolean go = TRUE;
197
198         actions_client_move(data, TRUE);
199         if (o->send && data->client && client_normal(data->client)) {
200             client_set_desktop(data->client, d, o->follow, FALSE);
201             go = o->follow;
202         }
203
204         if (go) {
205             screen_set_desktop(d, TRUE);
206             if (data->client)
207                 client_bring_helper_windows(data->client);
208         }
209
210         actions_client_move(data, FALSE);
211     }
212
213     return FALSE;
214 }
215
216 /* 3.4-compatilibity */
217 static gpointer setup_follow(xmlNodePtr node)
218 {
219     xmlNodePtr n;
220     Options *o = g_slice_new0(Options);
221     o->send = TRUE;
222     o->follow = TRUE;
223     if ((n = obt_xml_find_node(node, "follow")))
224         o->follow = obt_xml_node_bool(n);
225     return o;
226 }
227
228 static gpointer setup_go_last_func(xmlNodePtr node)
229 {
230     Options *o = g_slice_new0(Options);
231     o->type = LAST;
232     return o;
233 }
234
235 static gpointer setup_send_last_func(xmlNodePtr node)
236 {
237     Options *o = setup_follow(node);
238     o->type = LAST;
239     return o;
240 }
241
242 static gpointer setup_go_abs_func(xmlNodePtr node)
243 {
244     xmlNodePtr n;
245     Options *o = g_slice_new0(Options);
246     o->type = ABSOLUTE;
247     if ((n = obt_xml_find_node(node, "desktop")))
248         o->u.abs.desktop = obt_xml_node_int(n) - 1;
249     else
250         o->u.abs.desktop = screen_desktop;
251     return o;
252 }
253
254 static void setup_rel(Options *o, xmlNodePtr node, gboolean lin,
255                       ObDirection dir)
256 {
257     xmlNodePtr n;
258
259     o->type = RELATIVE;
260     o->u.rel.linear = lin;
261     o->u.rel.dir = dir;
262     o->u.rel.wrap = TRUE;
263
264     if ((n = obt_xml_find_node(node, "wrap")))
265         o->u.rel.wrap = obt_xml_node_bool(n);
266 }
267
268 static gpointer setup_go_next_func(xmlNodePtr node)
269 {
270     Options *o = g_slice_new0(Options);
271     setup_rel(o, node, TRUE, OB_DIRECTION_EAST);
272     return o;
273 }
274
275 static gpointer setup_send_next_func(xmlNodePtr node)
276 {
277     Options *o = setup_follow(node);
278     setup_rel(o, node, TRUE, OB_DIRECTION_EAST);
279     return o;
280 }
281
282 static gpointer setup_go_prev_func(xmlNodePtr node)
283 {
284     Options *o = g_slice_new0(Options);
285     setup_rel(o, node, TRUE, OB_DIRECTION_WEST);
286     return o;
287 }
288
289 static gpointer setup_send_prev_func(xmlNodePtr node)
290 {
291     Options *o = setup_follow(node);
292     setup_rel(o, node, TRUE, OB_DIRECTION_WEST);
293     return o;
294 }
295
296 static gpointer setup_go_left_func(xmlNodePtr node)
297 {
298     Options *o = g_slice_new0(Options);
299     setup_rel(o, node, FALSE, OB_DIRECTION_WEST);
300     return o;
301 }
302
303 static gpointer setup_send_left_func(xmlNodePtr node)
304 {
305     Options *o = setup_follow(node);
306     setup_rel(o, node, FALSE, OB_DIRECTION_WEST);
307     return o;
308 }
309
310 static gpointer setup_go_right_func(xmlNodePtr node)
311 {
312     Options *o = g_slice_new0(Options);
313     setup_rel(o, node, FALSE, OB_DIRECTION_EAST);
314     return o;
315 }
316
317 static gpointer setup_send_right_func(xmlNodePtr node)
318 {
319     Options *o = setup_follow(node);
320     setup_rel(o, node, FALSE, OB_DIRECTION_EAST);
321     return o;
322 }
323
324 static gpointer setup_go_up_func(xmlNodePtr node)
325 {
326     Options *o = g_slice_new0(Options);
327     setup_rel(o, node, FALSE, OB_DIRECTION_NORTH);
328     return o;
329 }
330
331 static gpointer setup_send_up_func(xmlNodePtr node)
332 {
333     Options *o = setup_follow(node);
334     setup_rel(o, node, FALSE, OB_DIRECTION_NORTH);
335     return o;
336 }
337
338 static gpointer setup_go_down_func(xmlNodePtr node)
339 {
340     Options *o = g_slice_new0(Options);
341     setup_rel(o, node, FALSE, OB_DIRECTION_SOUTH);
342     return o;
343 }
344
345 static gpointer setup_send_down_func(xmlNodePtr node)
346 {
347     Options *o = setup_follow(node);
348     setup_rel(o, node, FALSE, OB_DIRECTION_SOUTH);
349     return o;
350 }