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"
32 static gpointer setup_go_func(xmlNodePtr node,
33 ObActionsIPreFunc *pre,
34 ObActionsIInputFunc *input,
35 ObActionsICancelFunc *cancel,
36 ObActionsIPostFunc *post);
37 static gpointer setup_send_func(xmlNodePtr node,
38 ObActionsIPreFunc *pre,
39 ObActionsIInputFunc *input,
40 ObActionsICancelFunc *cancel,
41 ObActionsIPostFunc *post);
42 static void free_func(gpointer o);
43 static gboolean run_func(ObActionsData *data, gpointer options);
45 static gboolean i_pre_func(guint state, gpointer options);
46 static gboolean i_input_func(guint initial_state,
51 static void i_post_func(gpointer options);
53 /* 3.4-compatibility */
54 static gpointer setup_go_last_func(xmlNodePtr node);
55 static gpointer setup_send_last_func(xmlNodePtr node);
56 static gpointer setup_go_abs_func(xmlNodePtr node);
57 static gpointer setup_send_abs_func(xmlNodePtr node);
58 static gpointer setup_go_next_func(xmlNodePtr node,
59 ObActionsIPreFunc *pre,
60 ObActionsIInputFunc *input,
61 ObActionsICancelFunc *cancel,
62 ObActionsIPostFunc *post);
63 static gpointer setup_send_next_func(xmlNodePtr node,
64 ObActionsIPreFunc *pre,
65 ObActionsIInputFunc *input,
66 ObActionsICancelFunc *cancel,
67 ObActionsIPostFunc *post);
68 static gpointer setup_go_prev_func(xmlNodePtr node,
69 ObActionsIPreFunc *pre,
70 ObActionsIInputFunc *input,
71 ObActionsICancelFunc *cancel,
72 ObActionsIPostFunc *post);
73 static gpointer setup_send_prev_func(xmlNodePtr node,
74 ObActionsIPreFunc *pre,
75 ObActionsIInputFunc *input,
76 ObActionsICancelFunc *cancel,
77 ObActionsIPostFunc *post);
78 static gpointer setup_go_left_func(xmlNodePtr node,
79 ObActionsIPreFunc *pre,
80 ObActionsIInputFunc *input,
81 ObActionsICancelFunc *cancel,
82 ObActionsIPostFunc *post);
83 static gpointer setup_send_left_func(xmlNodePtr node,
84 ObActionsIPreFunc *pre,
85 ObActionsIInputFunc *input,
86 ObActionsICancelFunc *cancel,
87 ObActionsIPostFunc *post);
88 static gpointer setup_go_right_func(xmlNodePtr node,
89 ObActionsIPreFunc *pre,
90 ObActionsIInputFunc *input,
91 ObActionsICancelFunc *cancel,
92 ObActionsIPostFunc *post);
93 static gpointer setup_send_right_func(xmlNodePtr node,
94 ObActionsIPreFunc *pre,
95 ObActionsIInputFunc *input,
96 ObActionsICancelFunc *cancel,
97 ObActionsIPostFunc *post);
98 static gpointer setup_go_up_func(xmlNodePtr node,
99 ObActionsIPreFunc *pre,
100 ObActionsIInputFunc *input,
101 ObActionsICancelFunc *cancel,
102 ObActionsIPostFunc *post);
103 static gpointer setup_send_up_func(xmlNodePtr node,
104 ObActionsIPreFunc *pre,
105 ObActionsIInputFunc *input,
106 ObActionsICancelFunc *cancel,
107 ObActionsIPostFunc *post);
108 static gpointer setup_go_down_func(xmlNodePtr node,
109 ObActionsIPreFunc *pre,
110 ObActionsIInputFunc *input,
111 ObActionsICancelFunc *cancel,
112 ObActionsIPostFunc *post);
113 static gpointer setup_send_down_func(xmlNodePtr node,
114 ObActionsIPreFunc *pre,
115 ObActionsIInputFunc *input,
116 ObActionsICancelFunc *cancel,
117 ObActionsIPostFunc *post);
119 void action_desktop_startup(void)
121 actions_register_i("GoToDesktop", setup_go_func, free_func, run_func);
122 actions_register_i("SendToDesktop", setup_send_func, free_func, run_func);
123 /* 3.4-compatibility */
124 actions_register("DesktopLast", setup_go_last_func, free_func, run_func);
125 actions_register("SendToDesktopLast", setup_send_last_func,
126 free_func, run_func);
127 actions_register("Desktop", setup_go_abs_func, free_func, run_func);
128 actions_register("SendToDesktop", setup_send_abs_func,
129 free_func, run_func);
130 actions_register_i("DesktopNext", setup_go_next_func, free_func, run_func);
131 actions_register_i("SendToDesktopNext", setup_send_next_func,
132 free_func, run_func);
133 actions_register_i("DesktopPrevious", setup_go_prev_func,
134 free_func, run_func);
135 actions_register_i("SendToDesktopPrevious", setup_send_prev_func,
136 free_func, run_func);
137 actions_register_i("DesktopLeft", setup_go_left_func, free_func, run_func);
138 actions_register_i("SendToDesktopLeft", setup_send_left_func,
139 free_func, run_func);
140 actions_register_i("DesktopRight", setup_go_right_func,
141 free_func, run_func);
142 actions_register_i("SendToDesktopRight", setup_send_right_func,
143 free_func, run_func);
144 actions_register_i("DesktopUp", setup_go_up_func, free_func, run_func);
145 actions_register_i("SendToDesktopUp", setup_send_up_func,
146 free_func, run_func);
147 actions_register_i("DesktopDown", setup_go_down_func, free_func, run_func);
148 actions_register_i("SendToDesktopDown", setup_send_down_func,
149 free_func, run_func);
152 static gpointer setup_func(xmlNodePtr node,
153 ObActionsIPreFunc *pre,
154 ObActionsIInputFunc *input,
155 ObActionsICancelFunc *cancel,
156 ObActionsIPostFunc *post)
161 o = g_slice_new0(Options);
162 /* don't go anywhere if there are no options given */
164 o->u.abs.desktop = screen_desktop;
165 /* wrap by default - it's handy! */
166 o->u.rel.wrap = TRUE;
168 if ((n = obt_xml_find_node(node, "to"))) {
169 gchar *s = obt_xml_node_string(n);
170 if (!g_ascii_strcasecmp(s, "last"))
172 else if (!g_ascii_strcasecmp(s, "current"))
174 else if (!g_ascii_strcasecmp(s, "next")) {
176 o->u.rel.linear = TRUE;
177 o->u.rel.dir = OB_DIRECTION_EAST;
179 else if (!g_ascii_strcasecmp(s, "previous")) {
181 o->u.rel.linear = TRUE;
182 o->u.rel.dir = OB_DIRECTION_WEST;
184 else if (!g_ascii_strcasecmp(s, "north") ||
185 !g_ascii_strcasecmp(s, "up")) {
187 o->u.rel.dir = OB_DIRECTION_NORTH;
189 else if (!g_ascii_strcasecmp(s, "south") ||
190 !g_ascii_strcasecmp(s, "down")) {
192 o->u.rel.dir = OB_DIRECTION_SOUTH;
194 else if (!g_ascii_strcasecmp(s, "west") ||
195 !g_ascii_strcasecmp(s, "left")) {
197 o->u.rel.dir = OB_DIRECTION_WEST;
199 else if (!g_ascii_strcasecmp(s, "east") ||
200 !g_ascii_strcasecmp(s, "right")) {
202 o->u.rel.dir = OB_DIRECTION_EAST;
206 o->u.abs.desktop = atoi(s) - 1;
211 if ((n = obt_xml_find_node(node, "wrap")))
212 o->u.rel.wrap = obt_xml_node_bool(n);
218 static gpointer setup_go_func(xmlNodePtr node,
219 ObActionsIPreFunc *pre,
220 ObActionsIInputFunc *input,
221 ObActionsICancelFunc *cancel,
222 ObActionsIPostFunc *post)
226 o = setup_func(node, pre, input, cancel, post);
227 if (o->type == RELATIVE) {
228 o->interactive = TRUE;
230 *input = i_input_func;
237 static gpointer setup_send_func(xmlNodePtr node,
238 ObActionsIPreFunc *pre,
239 ObActionsIInputFunc *input,
240 ObActionsICancelFunc *cancel,
241 ObActionsIPostFunc *post)
246 o = setup_func(node, pre, input, cancel, post);
250 if ((n = obt_xml_find_node(node, "follow")))
251 o->follow = obt_xml_node_bool(n);
253 if (o->type == RELATIVE && o->follow) {
254 o->interactive = TRUE;
256 *input = i_input_func;
263 static void free_func(gpointer o)
265 g_slice_free(Options, o);
268 /* Always return FALSE because its not interactive */
269 static gboolean run_func(ObActionsData *data, gpointer options)
271 Options *o = options;
276 d = screen_last_desktop;
282 d = o->u.abs.desktop;
285 d = screen_find_desktop(screen_desktop,
286 o->u.rel.dir, o->u.rel.wrap, o->u.rel.linear);
289 g_assert_not_reached();
292 if (d < screen_num_desktops &&
293 (d != screen_desktop ||
294 (data->client && data->client->desktop != screen_desktop))) {
297 actions_client_move(data, TRUE);
298 if (o->send && data->client && client_normal(data->client)) {
299 client_set_desktop(data->client, d, o->follow, FALSE);
304 screen_set_desktop(d, TRUE);
306 client_bring_helper_windows(data->client);
309 actions_client_move(data, FALSE);
312 return o->interactive;
315 static gboolean i_input_func(guint initial_state,
323 mods = obt_keyboard_only_modmasks(e->xkey.state);
324 if (e->type == KeyRelease) {
325 /* remove from the state the mask of the modifier key being
326 released, if it is a modifier key being released that is */
327 mods &= ~obt_keyboard_keyevent_to_modmask(e);
330 if (e->type == KeyPress) {
331 KeySym sym = obt_keyboard_keypress_to_keysym(e);
333 /* Escape cancels no matter what */
334 if (sym == XK_Escape)
337 /* There were no modifiers and they pressed enter */
338 else if ((sym == XK_Return || sym == XK_KP_Enter) && !initial_state)
341 /* They released the modifiers */
342 else if (e->type == KeyRelease && initial_state && !(mods & initial_state))
350 static gboolean i_pre_func(guint initial_state, gpointer options)
352 if (!initial_state) {
353 Options *o = options;
354 o->interactive = FALSE;
358 screen_show_desktop_popup(screen_desktop, TRUE);
363 static void i_post_func(gpointer options)
365 screen_hide_desktop_popup();
368 /* 3.4-compatilibity */
369 static gpointer setup_follow(xmlNodePtr node)
372 Options *o = g_slice_new0(Options);
375 if ((n = obt_xml_find_node(node, "follow")))
376 o->follow = obt_xml_node_bool(n);
380 static gpointer setup_go_last_func(xmlNodePtr node)
382 Options *o = g_slice_new0(Options);
387 static gpointer setup_send_last_func(xmlNodePtr node)
389 Options *o = setup_follow(node);
394 static gpointer setup_go_abs_func(xmlNodePtr node)
397 Options *o = g_slice_new0(Options);
399 if ((n = obt_xml_find_node(node, "desktop")))
400 o->u.abs.desktop = obt_xml_node_int(n) - 1;
402 o->u.abs.desktop = screen_desktop;
406 static gpointer setup_send_abs_func(xmlNodePtr node)
409 Options *o = setup_follow(node);
411 if ((n = obt_xml_find_node(node, "desktop")))
412 o->u.abs.desktop = obt_xml_node_int(n) - 1;
414 o->u.abs.desktop = screen_desktop;
418 static void setup_rel(Options *o, xmlNodePtr node, gboolean lin,
420 ObActionsIPreFunc *pre,
421 ObActionsIInputFunc *input,
422 ObActionsIPostFunc *post)
427 o->u.rel.linear = lin;
429 o->u.rel.wrap = TRUE;
431 if ((n = obt_xml_find_node(node, "wrap")))
432 o->u.rel.wrap = obt_xml_node_bool(n);
435 o->interactive = TRUE;
437 *input = i_input_func;
442 static gpointer setup_go_next_func(xmlNodePtr node,
443 ObActionsIPreFunc *pre,
444 ObActionsIInputFunc *input,
445 ObActionsICancelFunc *cancel,
446 ObActionsIPostFunc *post)
448 Options *o = g_slice_new0(Options);
449 setup_rel(o, node, TRUE, OB_DIRECTION_EAST, pre, input, post);
453 static gpointer setup_send_next_func(xmlNodePtr node,
454 ObActionsIPreFunc *pre,
455 ObActionsIInputFunc *input,
456 ObActionsICancelFunc *cancel,
457 ObActionsIPostFunc *post)
459 Options *o = setup_follow(node);
460 setup_rel(o, node, TRUE, OB_DIRECTION_EAST,
461 pre, (o->follow ? input : NULL), post);
465 static gpointer setup_go_prev_func(xmlNodePtr node,
466 ObActionsIPreFunc *pre,
467 ObActionsIInputFunc *input,
468 ObActionsICancelFunc *cancel,
469 ObActionsIPostFunc *post)
471 Options *o = g_slice_new0(Options);
472 setup_rel(o, node, TRUE, OB_DIRECTION_WEST, pre, input, post);
476 static gpointer setup_send_prev_func(xmlNodePtr node,
477 ObActionsIPreFunc *pre,
478 ObActionsIInputFunc *input,
479 ObActionsICancelFunc *cancel,
480 ObActionsIPostFunc *post)
482 Options *o = setup_follow(node);
483 setup_rel(o, node, TRUE, OB_DIRECTION_WEST,
484 pre, (o->follow ? input : NULL), post);
488 static gpointer setup_go_left_func(xmlNodePtr node,
489 ObActionsIPreFunc *pre,
490 ObActionsIInputFunc *input,
491 ObActionsICancelFunc *cancel,
492 ObActionsIPostFunc *post)
494 Options *o = g_slice_new0(Options);
495 setup_rel(o, node, FALSE, OB_DIRECTION_WEST, pre, input, post);
499 static gpointer setup_send_left_func(xmlNodePtr node,
500 ObActionsIPreFunc *pre,
501 ObActionsIInputFunc *input,
502 ObActionsICancelFunc *cancel,
503 ObActionsIPostFunc *post)
505 Options *o = setup_follow(node);
506 setup_rel(o, node, FALSE, OB_DIRECTION_WEST,
507 pre, (o->follow ? input : NULL), post);
511 static gpointer setup_go_right_func(xmlNodePtr node,
512 ObActionsIPreFunc *pre,
513 ObActionsIInputFunc *input,
514 ObActionsICancelFunc *cancel,
515 ObActionsIPostFunc *post)
517 Options *o = g_slice_new0(Options);
518 setup_rel(o, node, FALSE, OB_DIRECTION_EAST, pre, input, post);
522 static gpointer setup_send_right_func(xmlNodePtr node,
523 ObActionsIPreFunc *pre,
524 ObActionsIInputFunc *input,
525 ObActionsICancelFunc *cancel,
526 ObActionsIPostFunc *post)
528 Options *o = setup_follow(node);
529 setup_rel(o, node, FALSE, OB_DIRECTION_EAST,
530 pre, (o->follow ? input : NULL), post);
534 static gpointer setup_go_up_func(xmlNodePtr node,
535 ObActionsIPreFunc *pre,
536 ObActionsIInputFunc *input,
537 ObActionsICancelFunc *cancel,
538 ObActionsIPostFunc *post)
540 Options *o = g_slice_new0(Options);
541 setup_rel(o, node, FALSE, OB_DIRECTION_NORTH, pre, input, post);
545 static gpointer setup_send_up_func(xmlNodePtr node,
546 ObActionsIPreFunc *pre,
547 ObActionsIInputFunc *input,
548 ObActionsICancelFunc *cancel,
549 ObActionsIPostFunc *post)
551 Options *o = setup_follow(node);
552 setup_rel(o, node, FALSE, OB_DIRECTION_NORTH,
553 pre, (o->follow ? input : NULL), post);
557 static gpointer setup_go_down_func(xmlNodePtr node,
558 ObActionsIPreFunc *pre,
559 ObActionsIInputFunc *input,
560 ObActionsICancelFunc *cancel,
561 ObActionsIPostFunc *post)
563 Options *o = g_slice_new0(Options);
564 setup_rel(o, node, FALSE, OB_DIRECTION_SOUTH, pre, input, post);
568 static gpointer setup_send_down_func(xmlNodePtr node,
569 ObActionsIPreFunc *pre,
570 ObActionsIInputFunc *input,
571 ObActionsICancelFunc *cancel,
572 ObActionsIPostFunc *post)
574 Options *o = setup_follow(node);
575 setup_rel(o, node, FALSE, OB_DIRECTION_SOUTH,
576 pre, (o->follow ? input : NULL), post);