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