]> Dogcows Code - chaz/openbox/blob - openbox/actions/desktop.c
more using g_slice_new() instead of g_new()
[chaz/openbox] / 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 RELATIVE,
10 ABSOLUTE
11 } SwitchType;
12
13 typedef struct {
14 SwitchType type;
15 union {
16 struct {
17 guint desktop;
18 } abs;
19
20 struct {
21 gboolean linear;
22 gboolean wrap;
23 ObDirection dir;
24 } rel;
25 } u;
26 gboolean send;
27 gboolean follow;
28 gboolean interactive;
29 } Options;
30
31 static gpointer setup_go_func(xmlNodePtr node,
32 ObActionsIPreFunc *pre,
33 ObActionsIInputFunc *input,
34 ObActionsICancelFunc *cancel,
35 ObActionsIPostFunc *post);
36 static gpointer setup_send_func(xmlNodePtr node,
37 ObActionsIPreFunc *pre,
38 ObActionsIInputFunc *input,
39 ObActionsICancelFunc *cancel,
40 ObActionsIPostFunc *post);
41 static void free_func(gpointer o);
42 static gboolean run_func(ObActionsData *data, gpointer options);
43
44 static gboolean i_pre_func(guint state, gpointer options);
45 static gboolean i_input_func(guint initial_state,
46 XEvent *e,
47 ObtIC *ic,
48 gpointer options,
49 gboolean *used);
50 static void i_post_func(gpointer options);
51
52 /* 3.4-compatibility */
53 static gpointer setup_go_last_func(xmlNodePtr node);
54 static gpointer setup_send_last_func(xmlNodePtr node);
55 static gpointer setup_go_abs_func(xmlNodePtr node);
56 static gpointer setup_send_abs_func(xmlNodePtr node);
57 static gpointer setup_go_next_func(xmlNodePtr node,
58 ObActionsIPreFunc *pre,
59 ObActionsIInputFunc *input,
60 ObActionsICancelFunc *cancel,
61 ObActionsIPostFunc *post);
62 static gpointer setup_send_next_func(xmlNodePtr node,
63 ObActionsIPreFunc *pre,
64 ObActionsIInputFunc *input,
65 ObActionsICancelFunc *cancel,
66 ObActionsIPostFunc *post);
67 static gpointer setup_go_prev_func(xmlNodePtr node,
68 ObActionsIPreFunc *pre,
69 ObActionsIInputFunc *input,
70 ObActionsICancelFunc *cancel,
71 ObActionsIPostFunc *post);
72 static gpointer setup_send_prev_func(xmlNodePtr node,
73 ObActionsIPreFunc *pre,
74 ObActionsIInputFunc *input,
75 ObActionsICancelFunc *cancel,
76 ObActionsIPostFunc *post);
77 static gpointer setup_go_left_func(xmlNodePtr node,
78 ObActionsIPreFunc *pre,
79 ObActionsIInputFunc *input,
80 ObActionsICancelFunc *cancel,
81 ObActionsIPostFunc *post);
82 static gpointer setup_send_left_func(xmlNodePtr node,
83 ObActionsIPreFunc *pre,
84 ObActionsIInputFunc *input,
85 ObActionsICancelFunc *cancel,
86 ObActionsIPostFunc *post);
87 static gpointer setup_go_right_func(xmlNodePtr node,
88 ObActionsIPreFunc *pre,
89 ObActionsIInputFunc *input,
90 ObActionsICancelFunc *cancel,
91 ObActionsIPostFunc *post);
92 static gpointer setup_send_right_func(xmlNodePtr node,
93 ObActionsIPreFunc *pre,
94 ObActionsIInputFunc *input,
95 ObActionsICancelFunc *cancel,
96 ObActionsIPostFunc *post);
97 static gpointer setup_go_up_func(xmlNodePtr node,
98 ObActionsIPreFunc *pre,
99 ObActionsIInputFunc *input,
100 ObActionsICancelFunc *cancel,
101 ObActionsIPostFunc *post);
102 static gpointer setup_send_up_func(xmlNodePtr node,
103 ObActionsIPreFunc *pre,
104 ObActionsIInputFunc *input,
105 ObActionsICancelFunc *cancel,
106 ObActionsIPostFunc *post);
107 static gpointer setup_go_down_func(xmlNodePtr node,
108 ObActionsIPreFunc *pre,
109 ObActionsIInputFunc *input,
110 ObActionsICancelFunc *cancel,
111 ObActionsIPostFunc *post);
112 static gpointer setup_send_down_func(xmlNodePtr node,
113 ObActionsIPreFunc *pre,
114 ObActionsIInputFunc *input,
115 ObActionsICancelFunc *cancel,
116 ObActionsIPostFunc *post);
117
118 void action_desktop_startup(void)
119 {
120 actions_register_i("GoToDesktop", setup_go_func, free_func, run_func);
121 actions_register_i("SendToDesktop", setup_send_func, free_func, run_func);
122 /* 3.4-compatibility */
123 actions_register("DesktopLast", setup_go_last_func, free_func, run_func);
124 actions_register("SendToDesktopLast", setup_send_last_func,
125 free_func, run_func);
126 actions_register("Desktop", setup_go_abs_func, free_func, run_func);
127 actions_register("SendToDesktop", setup_send_abs_func,
128 free_func, run_func);
129 actions_register_i("DesktopNext", setup_go_next_func, free_func, run_func);
130 actions_register_i("SendToDesktopNext", setup_send_next_func,
131 free_func, run_func);
132 actions_register_i("DesktopPrevious", setup_go_prev_func,
133 free_func, run_func);
134 actions_register_i("SendToDesktopPrevious", setup_send_prev_func,
135 free_func, run_func);
136 actions_register_i("DesktopLeft", setup_go_left_func, free_func, run_func);
137 actions_register_i("SendToDesktopLeft", setup_send_left_func,
138 free_func, run_func);
139 actions_register_i("DesktopRight", setup_go_right_func,
140 free_func, run_func);
141 actions_register_i("SendToDesktopRight", setup_send_right_func,
142 free_func, run_func);
143 actions_register_i("DesktopUp", setup_go_up_func, free_func, run_func);
144 actions_register_i("SendToDesktopUp", setup_send_up_func,
145 free_func, run_func);
146 actions_register_i("DesktopDown", setup_go_down_func, free_func, run_func);
147 actions_register_i("SendToDesktopDown", setup_send_down_func,
148 free_func, run_func);
149 }
150
151 static gpointer setup_func(xmlNodePtr node,
152 ObActionsIPreFunc *pre,
153 ObActionsIInputFunc *input,
154 ObActionsICancelFunc *cancel,
155 ObActionsIPostFunc *post)
156 {
157 xmlNodePtr n;
158 Options *o;
159
160 o = g_slice_new0(Options);
161 /* don't go anywhere if there are no options given */
162 o->type = ABSOLUTE;
163 o->u.abs.desktop = screen_desktop;
164 /* wrap by default - it's handy! */
165 o->u.rel.wrap = TRUE;
166
167 if ((n = obt_xml_find_node(node, "to"))) {
168 gchar *s = obt_xml_node_string(n);
169 if (!g_ascii_strcasecmp(s, "last"))
170 o->type = LAST;
171 else if (!g_ascii_strcasecmp(s, "next")) {
172 o->type = RELATIVE;
173 o->u.rel.linear = TRUE;
174 o->u.rel.dir = OB_DIRECTION_EAST;
175 }
176 else if (!g_ascii_strcasecmp(s, "previous")) {
177 o->type = RELATIVE;
178 o->u.rel.linear = TRUE;
179 o->u.rel.dir = OB_DIRECTION_WEST;
180 }
181 else if (!g_ascii_strcasecmp(s, "north") ||
182 !g_ascii_strcasecmp(s, "up")) {
183 o->type = RELATIVE;
184 o->u.rel.dir = OB_DIRECTION_NORTH;
185 }
186 else if (!g_ascii_strcasecmp(s, "south") ||
187 !g_ascii_strcasecmp(s, "down")) {
188 o->type = RELATIVE;
189 o->u.rel.dir = OB_DIRECTION_SOUTH;
190 }
191 else if (!g_ascii_strcasecmp(s, "west") ||
192 !g_ascii_strcasecmp(s, "left")) {
193 o->type = RELATIVE;
194 o->u.rel.dir = OB_DIRECTION_WEST;
195 }
196 else if (!g_ascii_strcasecmp(s, "east") ||
197 !g_ascii_strcasecmp(s, "right")) {
198 o->type = RELATIVE;
199 o->u.rel.dir = OB_DIRECTION_EAST;
200 }
201 else {
202 o->type = ABSOLUTE;
203 o->u.abs.desktop = atoi(s) - 1;
204 }
205 g_free(s);
206 }
207
208 if ((n = obt_xml_find_node(node, "wrap")))
209 o->u.rel.wrap = obt_xml_node_bool(n);
210
211 return o;
212 }
213
214
215 static gpointer setup_go_func(xmlNodePtr node,
216 ObActionsIPreFunc *pre,
217 ObActionsIInputFunc *input,
218 ObActionsICancelFunc *cancel,
219 ObActionsIPostFunc *post)
220 {
221 Options *o;
222
223 o = setup_func(node, pre, input, cancel, post);
224 if (o->type == RELATIVE) {
225 o->interactive = TRUE;
226 *pre = i_pre_func;
227 *input = i_input_func;
228 *post = i_post_func;
229 }
230
231 return o;
232 }
233
234 static gpointer setup_send_func(xmlNodePtr node,
235 ObActionsIPreFunc *pre,
236 ObActionsIInputFunc *input,
237 ObActionsICancelFunc *cancel,
238 ObActionsIPostFunc *post)
239 {
240 xmlNodePtr n;
241 Options *o;
242
243 o = setup_func(node, pre, input, cancel, post);
244 o->send = TRUE;
245 o->follow = TRUE;
246
247 if ((n = obt_xml_find_node(node, "follow")))
248 o->follow = obt_xml_node_bool(n);
249
250 if (o->type == RELATIVE && o->follow) {
251 o->interactive = TRUE;
252 *pre = i_pre_func;
253 *input = i_input_func;
254 *post = i_post_func;
255 }
256
257 return o;
258 }
259
260 static void free_func(gpointer o)
261 {
262 g_slice_free(Options, o);
263 }
264
265 /* Always return FALSE because its not interactive */
266 static gboolean run_func(ObActionsData *data, gpointer options)
267 {
268 Options *o = options;
269 guint d;
270
271 switch (o->type) {
272 case LAST:
273 d = screen_last_desktop;
274 break;
275 case ABSOLUTE:
276 d = o->u.abs.desktop;
277 break;
278 case RELATIVE:
279 d = screen_find_desktop(screen_desktop,
280 o->u.rel.dir, o->u.rel.wrap, o->u.rel.linear);
281 break;
282 default:
283 g_assert_not_reached();
284 }
285
286 if (d < screen_num_desktops && d != screen_desktop) {
287 gboolean go = TRUE;
288
289 actions_client_move(data, TRUE);
290 if (o->send && data->client && client_normal(data->client)) {
291 client_set_desktop(data->client, d, o->follow, FALSE);
292 go = o->follow;
293 }
294
295 if (go) {
296 screen_set_desktop(d, TRUE);
297 if (data->client)
298 client_bring_helper_windows(data->client);
299 }
300
301 actions_client_move(data, FALSE);
302 }
303
304 return o->interactive;
305 }
306
307 static gboolean i_input_func(guint initial_state,
308 XEvent *e,
309 ObtIC *ic,
310 gpointer options,
311 gboolean *used)
312 {
313 guint mods;
314
315 mods = obt_keyboard_only_modmasks(e->xkey.state);
316 if (e->type == KeyRelease) {
317 /* remove from the state the mask of the modifier key being
318 released, if it is a modifier key being released that is */
319 mods &= ~obt_keyboard_keycode_to_modmask(e->xkey.keycode);
320 }
321
322 if (e->type == KeyPress) {
323 KeySym sym = obt_keyboard_keypress_to_keysym(e);
324
325 /* Escape cancels no matter what */
326 if (sym == XK_Escape)
327 return FALSE;
328
329 /* There were no modifiers and they pressed enter */
330 else if (sym == XK_Return && !initial_state)
331 return FALSE;
332 }
333 /* They released the modifiers */
334 else if (e->type == KeyRelease && initial_state && !(mods & initial_state))
335 {
336 return FALSE;
337 }
338
339 return TRUE;
340 }
341
342 static gboolean i_pre_func(guint initial_state, gpointer options)
343 {
344 if (!initial_state) {
345 Options *o = options;
346 o->interactive = FALSE;
347 return FALSE;
348 }
349 else {
350 screen_show_desktop_popup(screen_desktop, TRUE);
351 return TRUE;
352 }
353 }
354
355 static void i_post_func(gpointer options)
356 {
357 screen_hide_desktop_popup();
358 }
359
360 /* 3.4-compatilibity */
361 static gpointer setup_follow(xmlNodePtr node)
362 {
363 xmlNodePtr n;
364 Options *o = g_slice_new0(Options);
365 o->send = TRUE;
366 o->follow = TRUE;
367 if ((n = obt_xml_find_node(node, "follow")))
368 o->follow = obt_xml_node_bool(n);
369 return o;
370 }
371
372 static gpointer setup_go_last_func(xmlNodePtr node)
373 {
374 Options *o = g_slice_new0(Options);
375 o->type = LAST;
376 return o;
377 }
378
379 static gpointer setup_send_last_func(xmlNodePtr node)
380 {
381 Options *o = setup_follow(node);
382 o->type = LAST;
383 return o;
384 }
385
386 static gpointer setup_go_abs_func(xmlNodePtr node)
387 {
388 xmlNodePtr n;
389 Options *o = g_slice_new0(Options);
390 o->type = ABSOLUTE;
391 if ((n = obt_xml_find_node(node, "desktop")))
392 o->u.abs.desktop = obt_xml_node_int(n) - 1;
393 else
394 o->u.abs.desktop = screen_desktop;
395 return o;
396 }
397
398 static gpointer setup_send_abs_func(xmlNodePtr node)
399 {
400 xmlNodePtr n;
401 Options *o = setup_follow(node);
402 o->type = ABSOLUTE;
403 if ((n = obt_xml_find_node(node, "desktop")))
404 o->u.abs.desktop = obt_xml_node_int(n) - 1;
405 else
406 o->u.abs.desktop = screen_desktop;
407 return o;
408 }
409
410 static void setup_rel(Options *o, xmlNodePtr node, gboolean lin,
411 ObDirection dir,
412 ObActionsIPreFunc *pre,
413 ObActionsIInputFunc *input,
414 ObActionsIPostFunc *post)
415 {
416 xmlNodePtr n;
417
418 o->type = RELATIVE;
419 o->u.rel.linear = lin;
420 o->u.rel.dir = dir;
421 o->u.rel.wrap = TRUE;
422
423 if ((n = obt_xml_find_node(node, "wrap")))
424 o->u.rel.wrap = obt_xml_node_bool(n);
425
426 if (input) {
427 o->interactive = TRUE;
428 *pre = i_pre_func;
429 *input = i_input_func;
430 *post = i_post_func;
431 }
432 }
433
434 static gpointer setup_go_next_func(xmlNodePtr node,
435 ObActionsIPreFunc *pre,
436 ObActionsIInputFunc *input,
437 ObActionsICancelFunc *cancel,
438 ObActionsIPostFunc *post)
439 {
440 Options *o = g_slice_new0(Options);
441 setup_rel(o, node, TRUE, OB_DIRECTION_EAST, pre, input, post);
442 return o;
443 }
444
445 static gpointer setup_send_next_func(xmlNodePtr node,
446 ObActionsIPreFunc *pre,
447 ObActionsIInputFunc *input,
448 ObActionsICancelFunc *cancel,
449 ObActionsIPostFunc *post)
450 {
451 Options *o = setup_follow(node);
452 setup_rel(o, node, TRUE, OB_DIRECTION_EAST,
453 pre, (o->follow ? input : NULL), post);
454 return o;
455 }
456
457 static gpointer setup_go_prev_func(xmlNodePtr node,
458 ObActionsIPreFunc *pre,
459 ObActionsIInputFunc *input,
460 ObActionsICancelFunc *cancel,
461 ObActionsIPostFunc *post)
462 {
463 Options *o = g_slice_new0(Options);
464 setup_rel(o, node, TRUE, OB_DIRECTION_WEST, pre, input, post);
465 return o;
466 }
467
468 static gpointer setup_send_prev_func(xmlNodePtr node,
469 ObActionsIPreFunc *pre,
470 ObActionsIInputFunc *input,
471 ObActionsICancelFunc *cancel,
472 ObActionsIPostFunc *post)
473 {
474 Options *o = setup_follow(node);
475 setup_rel(o, node, TRUE, OB_DIRECTION_WEST,
476 pre, (o->follow ? input : NULL), post);
477 return o;
478 }
479
480 static gpointer setup_go_left_func(xmlNodePtr node,
481 ObActionsIPreFunc *pre,
482 ObActionsIInputFunc *input,
483 ObActionsICancelFunc *cancel,
484 ObActionsIPostFunc *post)
485 {
486 Options *o = g_slice_new0(Options);
487 setup_rel(o, node, FALSE, OB_DIRECTION_WEST, pre, input, post);
488 return o;
489 }
490
491 static gpointer setup_send_left_func(xmlNodePtr node,
492 ObActionsIPreFunc *pre,
493 ObActionsIInputFunc *input,
494 ObActionsICancelFunc *cancel,
495 ObActionsIPostFunc *post)
496 {
497 Options *o = setup_follow(node);
498 setup_rel(o, node, FALSE, OB_DIRECTION_WEST,
499 pre, (o->follow ? input : NULL), post);
500 return o;
501 }
502
503 static gpointer setup_go_right_func(xmlNodePtr node,
504 ObActionsIPreFunc *pre,
505 ObActionsIInputFunc *input,
506 ObActionsICancelFunc *cancel,
507 ObActionsIPostFunc *post)
508 {
509 Options *o = g_slice_new0(Options);
510 setup_rel(o, node, FALSE, OB_DIRECTION_EAST, pre, input, post);
511 return o;
512 }
513
514 static gpointer setup_send_right_func(xmlNodePtr node,
515 ObActionsIPreFunc *pre,
516 ObActionsIInputFunc *input,
517 ObActionsICancelFunc *cancel,
518 ObActionsIPostFunc *post)
519 {
520 Options *o = setup_follow(node);
521 setup_rel(o, node, FALSE, OB_DIRECTION_EAST,
522 pre, (o->follow ? input : NULL), post);
523 return o;
524 }
525
526 static gpointer setup_go_up_func(xmlNodePtr node,
527 ObActionsIPreFunc *pre,
528 ObActionsIInputFunc *input,
529 ObActionsICancelFunc *cancel,
530 ObActionsIPostFunc *post)
531 {
532 Options *o = g_slice_new0(Options);
533 setup_rel(o, node, FALSE, OB_DIRECTION_NORTH, pre, input, post);
534 return o;
535 }
536
537 static gpointer setup_send_up_func(xmlNodePtr node,
538 ObActionsIPreFunc *pre,
539 ObActionsIInputFunc *input,
540 ObActionsICancelFunc *cancel,
541 ObActionsIPostFunc *post)
542 {
543 Options *o = setup_follow(node);
544 setup_rel(o, node, FALSE, OB_DIRECTION_NORTH,
545 pre, (o->follow ? input : NULL), post);
546 return o;
547 }
548
549 static gpointer setup_go_down_func(xmlNodePtr node,
550 ObActionsIPreFunc *pre,
551 ObActionsIInputFunc *input,
552 ObActionsICancelFunc *cancel,
553 ObActionsIPostFunc *post)
554 {
555 Options *o = g_slice_new0(Options);
556 setup_rel(o, node, FALSE, OB_DIRECTION_SOUTH, pre, input, post);
557 return o;
558 }
559
560 static gpointer setup_send_down_func(xmlNodePtr node,
561 ObActionsIPreFunc *pre,
562 ObActionsIInputFunc *input,
563 ObActionsICancelFunc *cancel,
564 ObActionsIPostFunc *post)
565 {
566 Options *o = setup_follow(node);
567 setup_rel(o, node, FALSE, OB_DIRECTION_SOUTH,
568 pre, (o->follow ? input : NULL), post);
569 return o;
570 }
This page took 0.054137 seconds and 4 git commands to generate.