Merge branch 'backport' into 3.4-working
[mikachu/openbox.git] / openbox / actions / desktop.c
1 #include "openbox/actions.h"
2 #include "openbox/screen.h"
3 #include "openbox/client.h"
4 #include <glib.h>
5
6 typedef enum {
7     LAST,
8     RELATIVE,
9     ABSOLUTE
10 } SwitchType;
11
12 typedef struct {
13     SwitchType type;
14     union {
15         struct {
16             guint desktop;
17         } abs;
18
19         struct {
20             gboolean linear;
21             gboolean wrap;
22             ObDirection dir;
23         } rel;
24     };
25     gboolean send;
26     gboolean follow;
27 } Options;
28
29 static gpointer setup_go_last_func(ObParseInst *i, xmlDocPtr doc,
30                                    xmlNodePtr node);
31 static gpointer setup_send_last_func(ObParseInst *i, xmlDocPtr doc,
32                                      xmlNodePtr node);
33 static gpointer setup_go_abs_func(ObParseInst *i, xmlDocPtr doc,
34                                    xmlNodePtr node);
35 static gpointer setup_send_abs_func(ObParseInst *i, xmlDocPtr doc,
36                                      xmlNodePtr node);
37 static gpointer setup_go_next_func(ObParseInst *i, xmlDocPtr doc,
38                                    xmlNodePtr node);
39 static gpointer setup_send_next_func(ObParseInst *i, xmlDocPtr doc,
40                                      xmlNodePtr node);
41 static gpointer setup_go_prev_func(ObParseInst *i, xmlDocPtr doc,
42                                    xmlNodePtr node);
43 static gpointer setup_send_prev_func(ObParseInst *i, xmlDocPtr doc,
44                                      xmlNodePtr node);
45 static gpointer setup_go_left_func(ObParseInst *i, xmlDocPtr doc,
46                                    xmlNodePtr node);
47 static gpointer setup_send_left_func(ObParseInst *i, xmlDocPtr doc,
48                                      xmlNodePtr node);
49 static gpointer setup_go_right_func(ObParseInst *i, xmlDocPtr doc,
50                                    xmlNodePtr node);
51 static gpointer setup_send_right_func(ObParseInst *i, xmlDocPtr doc,
52                                      xmlNodePtr node);
53 static gpointer setup_go_up_func(ObParseInst *i, xmlDocPtr doc,
54                                    xmlNodePtr node);
55 static gpointer setup_send_up_func(ObParseInst *i, xmlDocPtr doc,
56                                      xmlNodePtr node);
57 static gpointer setup_go_down_func(ObParseInst *i, xmlDocPtr doc,
58                                    xmlNodePtr node);
59 static gpointer setup_send_down_func(ObParseInst *i, xmlDocPtr doc,
60                                      xmlNodePtr node);
61 static gboolean run_func(ObActionsData *data, gpointer options);
62
63 void action_desktop_startup(void)
64 {
65     actions_register("DesktopLast", setup_go_last_func, g_free,
66                      run_func, NULL, NULL);
67     actions_register("SendToDesktopLast", setup_send_last_func, g_free,
68                      run_func, NULL, NULL);
69     actions_register("Desktop", setup_go_abs_func, g_free,
70                      run_func, NULL, NULL);
71     actions_register("SendToDesktop", setup_send_abs_func, g_free,
72                      run_func, NULL, NULL);
73     actions_register("DesktopNext", setup_go_next_func, g_free,
74                      run_func, NULL, NULL);
75     actions_register("SendToDesktopNext", setup_send_next_func, g_free,
76                      run_func, NULL, NULL);
77     actions_register("DesktopPrevious", setup_go_prev_func, g_free,
78                      run_func, NULL, NULL);
79     actions_register("SendToDesktopPrevious", setup_send_prev_func, g_free,
80                      run_func, NULL, NULL);
81     actions_register("DesktopLeft", setup_go_left_func, g_free,
82                      run_func, NULL, NULL);
83     actions_register("SendToDesktopLeft", setup_send_left_func, g_free,
84                      run_func, NULL, NULL);
85     actions_register("DesktopRight", setup_go_right_func, g_free,
86                      run_func, NULL, NULL);
87     actions_register("SendToDesktopRight", setup_send_right_func, g_free,
88                      run_func, NULL, NULL);
89     actions_register("DesktopUp", setup_go_up_func, g_free,
90                      run_func, NULL, NULL);
91     actions_register("SendToDesktopUp", setup_send_up_func, g_free,
92                      run_func, NULL, NULL);
93     actions_register("DesktopDown", setup_go_down_func, g_free,
94                      run_func, NULL, NULL);
95     actions_register("SendToDesktopDown", setup_send_down_func, g_free,
96                      run_func, NULL, NULL);
97 }
98
99 static gpointer setup_follow(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
100 {
101     xmlNodePtr n;
102     Options *o = g_new0(Options, 1);
103     o->send = TRUE;
104     o->follow = TRUE;
105     if ((n = parse_find_node("follow", node)))
106         o->follow = parse_bool(doc, n);
107     return o;
108 }
109
110 static gpointer setup_go_last_func(ObParseInst *i, xmlDocPtr doc,
111                                    xmlNodePtr node)
112 {
113     Options *o = g_new0(Options, 1);
114     o->type = LAST;
115     return o;
116 }
117
118 static gpointer setup_send_last_func(ObParseInst *i, xmlDocPtr doc,
119                                      xmlNodePtr node)
120 {
121     Options *o = setup_follow(i, doc, node);
122     o->type = LAST;
123     return o;
124 }
125
126 static gpointer setup_go_abs_func(ObParseInst *i, xmlDocPtr doc,
127                                    xmlNodePtr node)
128 {
129     xmlNodePtr n;
130     Options *o = g_new0(Options, 1);
131     o->type = ABSOLUTE;
132     if ((n = parse_find_node("desktop", node)))
133         o->abs.desktop = parse_int(doc, n) - 1;
134     else
135         o->abs.desktop = screen_desktop;
136     return o;
137 }
138
139 static gpointer setup_send_abs_func(ObParseInst *i, xmlDocPtr doc,
140                                      xmlNodePtr node)
141 {
142     xmlNodePtr n;
143     Options *o = setup_follow(i, doc, node);
144     o->type = ABSOLUTE;
145     if ((n = parse_find_node("desktop", node)))
146         o->abs.desktop = parse_int(doc, n) - 1;
147     else
148         o->abs.desktop = screen_desktop;
149     return o;
150 }
151
152 static void setup_rel(Options *o, ObParseInst *i, xmlDocPtr doc,
153                       xmlNodePtr node, gboolean lin, ObDirection dir)
154 {
155     xmlNodePtr n;
156
157     o->type = RELATIVE;
158     o->rel.linear = lin;
159     o->rel.dir = dir;
160     o->rel.wrap = TRUE;
161
162     if ((n = parse_find_node("wrap", node)))
163         o->rel.wrap = parse_bool(doc, n);
164 }
165
166 static gpointer setup_go_next_func(ObParseInst *i, xmlDocPtr doc,
167                                    xmlNodePtr node)
168 {
169     Options *o = g_new0(Options, 1);
170     setup_rel(o, i, doc, node, TRUE, OB_DIRECTION_EAST);
171     return o;
172 }
173
174 static gpointer setup_send_next_func(ObParseInst *i, xmlDocPtr doc,
175                                      xmlNodePtr node)
176 {
177     Options *o = setup_follow(i, doc, node);
178     setup_rel(o, i, doc, node, TRUE, OB_DIRECTION_EAST);
179     return o;
180 }
181
182 static gpointer setup_go_prev_func(ObParseInst *i, xmlDocPtr doc,
183                                    xmlNodePtr node)
184 {
185     Options *o = g_new0(Options, 1);
186     setup_rel(o, i, doc, node, TRUE, OB_DIRECTION_WEST);
187     return o;
188 }
189
190 static gpointer setup_send_prev_func(ObParseInst *i, xmlDocPtr doc,
191                                      xmlNodePtr node)
192 {
193     Options *o = setup_follow(i, doc, node);
194     setup_rel(o, i, doc, node, TRUE, OB_DIRECTION_WEST);
195     return o;
196 }
197
198 static gpointer setup_go_left_func(ObParseInst *i, xmlDocPtr doc,
199                                    xmlNodePtr node)
200 {
201     Options *o = g_new0(Options, 1);
202     setup_rel(o, i, doc, node, FALSE, OB_DIRECTION_WEST);
203     return o;
204 }
205
206 static gpointer setup_send_left_func(ObParseInst *i, xmlDocPtr doc,
207                                      xmlNodePtr node)
208 {
209     Options *o = setup_follow(i, doc, node);
210     setup_rel(o, i, doc, node, FALSE, OB_DIRECTION_WEST);
211     return o;
212 }
213
214 static gpointer setup_go_right_func(ObParseInst *i, xmlDocPtr doc,
215                                     xmlNodePtr node)
216 {
217     Options *o = g_new0(Options, 1);
218     setup_rel(o, i, doc, node, FALSE, OB_DIRECTION_EAST);
219     return o;
220 }
221
222 static gpointer setup_send_right_func(ObParseInst *i, xmlDocPtr doc,
223                                       xmlNodePtr node)
224 {
225     Options *o = setup_follow(i, doc, node);
226     setup_rel(o, i, doc, node, FALSE, OB_DIRECTION_EAST);
227     return o;
228 }
229
230 static gpointer setup_go_up_func(ObParseInst *i, xmlDocPtr doc,
231                                  xmlNodePtr node)
232 {
233     Options *o = g_new0(Options, 1);
234     setup_rel(o, i, doc, node, FALSE, OB_DIRECTION_NORTH);
235     return o;
236 }
237
238 static gpointer setup_send_up_func(ObParseInst *i, xmlDocPtr doc,
239                                    xmlNodePtr node)
240 {
241     Options *o = setup_follow(i, doc, node);
242     setup_rel(o, i, doc, node, FALSE, OB_DIRECTION_NORTH);
243     return o;
244 }
245
246 static gpointer setup_go_down_func(ObParseInst *i, xmlDocPtr doc,
247                                    xmlNodePtr node)
248 {
249     Options *o = g_new0(Options, 1);
250     setup_rel(o, i, doc, node, FALSE, OB_DIRECTION_SOUTH);
251     return o;
252 }
253
254 static gpointer setup_send_down_func(ObParseInst *i, xmlDocPtr doc,
255                                      xmlNodePtr node)
256 {
257     Options *o = setup_follow(i, doc, node);
258     setup_rel(o, i, doc, node, FALSE, OB_DIRECTION_SOUTH);
259     return o;
260 }
261
262 /* Always return FALSE because its not interactive */
263 static gboolean run_func(ObActionsData *data, gpointer options)
264 {
265     Options *o = options;
266     guint d;
267
268
269
270     switch (o->type) {
271     case LAST:
272         d = screen_last_desktop;
273         break;
274     case ABSOLUTE:
275         d = o->abs.desktop;
276         break;
277     case RELATIVE:
278         d = screen_find_desktop(screen_desktop,
279                                 o->rel.dir, o->rel.wrap, o->rel.linear);
280         break;
281     }
282
283     if (d < screen_num_desktops && d != screen_desktop) {
284         gboolean go = TRUE;
285
286         actions_client_move(data, TRUE);
287         if (o->send && data->client && client_normal(data->client)) {
288             client_set_desktop(data->client, d, o->follow, FALSE);
289             go = o->follow;
290         }
291
292         if (go) screen_set_desktop(d, TRUE);
293         actions_client_move(data, FALSE);
294     }
295     return FALSE;
296 }