]> Dogcows Code - chaz/openbox/blob - openbox/action.c
58a0e61ffc7a97efd2659a4c79300230c7cd4aee
[chaz/openbox] / openbox / action.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3 action.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include "debug.h"
21 #include "client.h"
22 #include "focus.h"
23 #include "focus_cycle.h"
24 #include "moveresize.h"
25 #include "menu.h"
26 #include "prop.h"
27 #include "stacking.h"
28 #include "screen.h"
29 #include "action.h"
30 #include "openbox.h"
31 #include "grab.h"
32 #include "keyboard.h"
33 #include "event.h"
34 #include "dock.h"
35 #include "config.h"
36 #include "mainloop.h"
37 #include "startupnotify.h"
38 #include "gettext.h"
39
40 #include <glib.h>
41
42
43
44 typedef struct
45 {
46 const gchar *name;
47 void (*func)(union ActionData *);
48 void (*setup)(ObAction **, ObUserAction uact);
49 } ActionString;
50
51 static ObAction *action_new(void (*func)(union ActionData *data))
52 {
53 ObAction *a = g_new0(ObAction, 1);
54 a->ref = 1;
55 a->func = func;
56
57 return a;
58 }
59
60 void action_ref(ObAction *a)
61 {
62 ++a->ref;
63 }
64
65 void action_unref(ObAction *a)
66 {
67 if (a == NULL) return;
68
69 if (--a->ref > 0) return;
70
71 /* deal with pointers */
72 if (a->func == action_execute || a->func == action_restart)
73 g_free(a->data.execute.path);
74 else if (a->func == action_debug)
75 g_free(a->data.debug.string);
76 else if (a->func == action_showmenu)
77 g_free(a->data.showmenu.name);
78
79 g_free(a);
80 }
81
82 ObAction* action_copy(const ObAction *src)
83 {
84 ObAction *a = action_new(src->func);
85
86 a->data = src->data;
87
88 /* deal with pointers */
89 if (a->func == action_execute || a->func == action_restart)
90 a->data.execute.path = g_strdup(a->data.execute.path);
91 else if (a->func == action_debug)
92 a->data.debug.string = g_strdup(a->data.debug.string);
93 else if (a->func == action_showmenu)
94 a->data.showmenu.name = g_strdup(a->data.showmenu.name);
95
96 return a;
97 }
98
99 void setup_action_send_to_desktop(ObAction **a, ObUserAction uact)
100 {
101 (*a)->data.sendto.any.client_action = OB_CLIENT_ACTION_ALWAYS;
102 (*a)->data.sendto.follow = TRUE;
103 }
104
105 void setup_action_send_to_desktop_prev(ObAction **a, ObUserAction uact)
106 {
107 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
108 (*a)->data.sendtodir.inter.any.interactive = TRUE;
109 (*a)->data.sendtodir.dir = OB_DIRECTION_WEST;
110 (*a)->data.sendtodir.linear = TRUE;
111 (*a)->data.sendtodir.wrap = TRUE;
112 (*a)->data.sendtodir.follow = TRUE;
113 }
114
115 void setup_action_send_to_desktop_next(ObAction **a, ObUserAction uact)
116 {
117 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
118 (*a)->data.sendtodir.inter.any.interactive = TRUE;
119 (*a)->data.sendtodir.dir = OB_DIRECTION_EAST;
120 (*a)->data.sendtodir.linear = TRUE;
121 (*a)->data.sendtodir.wrap = TRUE;
122 (*a)->data.sendtodir.follow = TRUE;
123 }
124
125 void setup_action_send_to_desktop_left(ObAction **a, ObUserAction uact)
126 {
127 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
128 (*a)->data.sendtodir.inter.any.interactive = TRUE;
129 (*a)->data.sendtodir.dir = OB_DIRECTION_WEST;
130 (*a)->data.sendtodir.linear = FALSE;
131 (*a)->data.sendtodir.wrap = TRUE;
132 (*a)->data.sendtodir.follow = TRUE;
133 }
134
135 void setup_action_send_to_desktop_right(ObAction **a, ObUserAction uact)
136 {
137 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
138 (*a)->data.sendtodir.inter.any.interactive = TRUE;
139 (*a)->data.sendtodir.dir = OB_DIRECTION_EAST;
140 (*a)->data.sendtodir.linear = FALSE;
141 (*a)->data.sendtodir.wrap = TRUE;
142 (*a)->data.sendtodir.follow = TRUE;
143 }
144
145 void setup_action_send_to_desktop_up(ObAction **a, ObUserAction uact)
146 {
147 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
148 (*a)->data.sendtodir.inter.any.interactive = TRUE;
149 (*a)->data.sendtodir.dir = OB_DIRECTION_NORTH;
150 (*a)->data.sendtodir.linear = FALSE;
151 (*a)->data.sendtodir.wrap = TRUE;
152 (*a)->data.sendtodir.follow = TRUE;
153 }
154
155 void setup_action_send_to_desktop_down(ObAction **a, ObUserAction uact)
156 {
157 (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS;
158 (*a)->data.sendtodir.inter.any.interactive = TRUE;
159 (*a)->data.sendtodir.dir = OB_DIRECTION_SOUTH;
160 (*a)->data.sendtodir.linear = FALSE;
161 (*a)->data.sendtodir.wrap = TRUE;
162 (*a)->data.sendtodir.follow = TRUE;
163 }
164
165 void setup_action_desktop_prev(ObAction **a, ObUserAction uact)
166 {
167 (*a)->data.desktopdir.inter.any.interactive = TRUE;
168 (*a)->data.desktopdir.dir = OB_DIRECTION_WEST;
169 (*a)->data.desktopdir.linear = TRUE;
170 (*a)->data.desktopdir.wrap = TRUE;
171 }
172
173 void setup_action_desktop_next(ObAction **a, ObUserAction uact)
174 {
175 (*a)->data.desktopdir.inter.any.interactive = TRUE;
176 (*a)->data.desktopdir.dir = OB_DIRECTION_EAST;
177 (*a)->data.desktopdir.linear = TRUE;
178 (*a)->data.desktopdir.wrap = TRUE;
179 }
180
181 void setup_action_desktop_left(ObAction **a, ObUserAction uact)
182 {
183 (*a)->data.desktopdir.inter.any.interactive = TRUE;
184 (*a)->data.desktopdir.dir = OB_DIRECTION_WEST;
185 (*a)->data.desktopdir.linear = FALSE;
186 (*a)->data.desktopdir.wrap = TRUE;
187 }
188
189 void setup_action_desktop_right(ObAction **a, ObUserAction uact)
190 {
191 (*a)->data.desktopdir.inter.any.interactive = TRUE;
192 (*a)->data.desktopdir.dir = OB_DIRECTION_EAST;
193 (*a)->data.desktopdir.linear = FALSE;
194 (*a)->data.desktopdir.wrap = TRUE;
195 }
196
197 void setup_action_desktop_up(ObAction **a, ObUserAction uact)
198 {
199 (*a)->data.desktopdir.inter.any.interactive = TRUE;
200 (*a)->data.desktopdir.dir = OB_DIRECTION_NORTH;
201 (*a)->data.desktopdir.linear = FALSE;
202 (*a)->data.desktopdir.wrap = TRUE;
203 }
204
205 void setup_action_desktop_down(ObAction **a, ObUserAction uact)
206 {
207 (*a)->data.desktopdir.inter.any.interactive = TRUE;
208 (*a)->data.desktopdir.dir = OB_DIRECTION_SOUTH;
209 (*a)->data.desktopdir.linear = FALSE;
210 (*a)->data.desktopdir.wrap = TRUE;
211 }
212
213 void setup_action_movefromedge_north(ObAction **a, ObUserAction uact)
214 {
215 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
216 (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
217 (*a)->data.diraction.hang = TRUE;
218 }
219
220 void setup_action_movefromedge_south(ObAction **a, ObUserAction uact)
221 {
222 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
223 (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
224 (*a)->data.diraction.hang = TRUE;
225 }
226
227 void setup_action_movefromedge_east(ObAction **a, ObUserAction uact)
228 {
229 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
230 (*a)->data.diraction.direction = OB_DIRECTION_EAST;
231 (*a)->data.diraction.hang = TRUE;
232 }
233
234 void setup_action_movefromedge_west(ObAction **a, ObUserAction uact)
235 {
236 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
237 (*a)->data.diraction.direction = OB_DIRECTION_WEST;
238 (*a)->data.diraction.hang = TRUE;
239 }
240
241 void setup_action_movetoedge_north(ObAction **a, ObUserAction uact)
242 {
243 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
244 (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
245 (*a)->data.diraction.hang = FALSE;
246 }
247
248 void setup_action_movetoedge_south(ObAction **a, ObUserAction uact)
249 {
250 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
251 (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
252 (*a)->data.diraction.hang = FALSE;
253 }
254
255 void setup_action_movetoedge_east(ObAction **a, ObUserAction uact)
256 {
257 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
258 (*a)->data.diraction.direction = OB_DIRECTION_EAST;
259 (*a)->data.diraction.hang = FALSE;
260 }
261
262 void setup_action_movetoedge_west(ObAction **a, ObUserAction uact)
263 {
264 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
265 (*a)->data.diraction.direction = OB_DIRECTION_WEST;
266 (*a)->data.diraction.hang = FALSE;
267 }
268
269 void setup_action_growtoedge_north(ObAction **a, ObUserAction uact)
270 {
271 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
272 (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
273 }
274
275 void setup_action_growtoedge_south(ObAction **a, ObUserAction uact)
276 {
277 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
278 (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
279 }
280
281 void setup_action_growtoedge_east(ObAction **a, ObUserAction uact)
282 {
283 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
284 (*a)->data.diraction.direction = OB_DIRECTION_EAST;
285 }
286
287 void setup_action_growtoedge_west(ObAction **a, ObUserAction uact)
288 {
289 (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
290 (*a)->data.diraction.direction = OB_DIRECTION_WEST;
291 }
292
293 void setup_action_top_layer(ObAction **a, ObUserAction uact)
294 {
295 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
296 (*a)->data.layer.layer = 1;
297 }
298
299 void setup_action_normal_layer(ObAction **a, ObUserAction uact)
300 {
301 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
302 (*a)->data.layer.layer = 0;
303 }
304
305 void setup_action_bottom_layer(ObAction **a, ObUserAction uact)
306 {
307 (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
308 (*a)->data.layer.layer = -1;
309 }
310
311 void setup_action_resize(ObAction **a, ObUserAction uact)
312 {
313 (*a)->data.moveresize.any.client_action = OB_CLIENT_ACTION_ALWAYS;
314 (*a)->data.moveresize.keyboard =
315 (uact == OB_USER_ACTION_NONE ||
316 uact == OB_USER_ACTION_KEYBOARD_KEY ||
317 uact == OB_USER_ACTION_MENU_SELECTION);
318 (*a)->data.moveresize.corner = 0;
319 }
320
321 void setup_action_addremove_desktop_current(ObAction **a, ObUserAction uact)
322 {
323 (*a)->data.addremovedesktop.current = TRUE;
324 }
325
326 void setup_action_addremove_desktop_last(ObAction **a, ObUserAction uact)
327 {
328 (*a)->data.addremovedesktop.current = FALSE;
329 }
330
331 void setup_client_action(ObAction **a, ObUserAction uact)
332 {
333 (*a)->data.any.client_action = OB_CLIENT_ACTION_ALWAYS;
334 }
335
336 ActionString actionstrings[] =
337 {
338 {
339 "shadelower",
340 action_shadelower,
341 setup_client_action
342 },
343 {
344 "unshaderaise",
345 action_unshaderaise,
346 setup_client_action
347 },
348 {
349 "resizerelativevert",
350 action_resize_relative_vert,
351 setup_client_action
352 },
353 {
354 "resizerelative",
355 action_resize_relative,
356 setup_client_action
357 },
358 {
359 "sendtodesktop",
360 action_send_to_desktop,
361 setup_action_send_to_desktop
362 },
363 {
364 "sendtodesktopnext",
365 action_send_to_desktop_dir,
366 setup_action_send_to_desktop_next
367 },
368 {
369 "sendtodesktopprevious",
370 action_send_to_desktop_dir,
371 setup_action_send_to_desktop_prev
372 },
373 {
374 "sendtodesktopright",
375 action_send_to_desktop_dir,
376 setup_action_send_to_desktop_right
377 },
378 {
379 "sendtodesktopleft",
380 action_send_to_desktop_dir,
381 setup_action_send_to_desktop_left
382 },
383 {
384 "sendtodesktopup",
385 action_send_to_desktop_dir,
386 setup_action_send_to_desktop_up
387 },
388 {
389 "sendtodesktopdown",
390 action_send_to_desktop_dir,
391 setup_action_send_to_desktop_down
392 },
393 {
394 "desktopnext",
395 action_desktop_dir,
396 setup_action_desktop_next
397 },
398 {
399 "desktopprevious",
400 action_desktop_dir,
401 setup_action_desktop_prev
402 },
403 {
404 "desktopright",
405 action_desktop_dir,
406 setup_action_desktop_right
407 },
408 {
409 "desktopleft",
410 action_desktop_dir,
411 setup_action_desktop_left
412 },
413 {
414 "desktopup",
415 action_desktop_dir,
416 setup_action_desktop_up
417 },
418 {
419 "desktopdown",
420 action_desktop_dir,
421 setup_action_desktop_down
422 },
423 {
424 "toggledockautohide",
425 action_toggle_dockautohide,
426 NULL
427 },
428 {
429 "desktoplast",
430 action_desktop_last,
431 NULL
432 },
433 {
434 "sendtotoplayer",
435 action_send_to_layer,
436 setup_action_top_layer
437 },
438 {
439 "togglealwaysontop",
440 action_toggle_layer,
441 setup_action_top_layer
442 },
443 {
444 "sendtonormallayer",
445 action_send_to_layer,
446 setup_action_normal_layer
447 },
448 {
449 "sendtobottomlayer",
450 action_send_to_layer,
451 setup_action_bottom_layer
452 },
453 {
454 "togglealwaysonbottom",
455 action_toggle_layer,
456 setup_action_bottom_layer
457 },
458 {
459 "movefromedgenorth",
460 action_movetoedge,
461 setup_action_movefromedge_north
462 },
463 {
464 "movefromedgesouth",
465 action_movetoedge,
466 setup_action_movefromedge_south
467 },
468 {
469 "movefromedgewest",
470 action_movetoedge,
471 setup_action_movefromedge_west
472 },
473 {
474 "movefromedgeeast",
475 action_movetoedge,
476 setup_action_movefromedge_east
477 },
478 {
479 "movetoedgenorth",
480 action_movetoedge,
481 setup_action_movetoedge_north
482 },
483 {
484 "movetoedgesouth",
485 action_movetoedge,
486 setup_action_movetoedge_south
487 },
488 {
489 "movetoedgewest",
490 action_movetoedge,
491 setup_action_movetoedge_west
492 },
493 {
494 "movetoedgeeast",
495 action_movetoedge,
496 setup_action_movetoedge_east
497 },
498 {
499 "growtoedgenorth",
500 action_growtoedge,
501 setup_action_growtoedge_north
502 },
503 {
504 "growtoedgesouth",
505 action_growtoedge,
506 setup_action_growtoedge_south
507 },
508 {
509 "growtoedgewest",
510 action_growtoedge,
511 setup_action_growtoedge_west
512 },
513 {
514 "growtoedgeeast",
515 action_growtoedge,
516 setup_action_growtoedge_east
517 },
518 {
519 "adddesktoplast",
520 action_add_desktop,
521 setup_action_addremove_desktop_last
522 },
523 {
524 "removedesktoplast",
525 action_remove_desktop,
526 setup_action_addremove_desktop_last
527 },
528 {
529 "adddesktopcurrent",
530 action_add_desktop,
531 setup_action_addremove_desktop_current
532 },
533 {
534 "removedesktopcurrent",
535 action_remove_desktop,
536 setup_action_addremove_desktop_current
537 },
538 {
539 NULL,
540 NULL,
541 NULL
542 }
543 };
544
545 /* only key bindings can be interactive. thus saith the xor.
546 because of how the mouse is grabbed, mouse events dont even get
547 read during interactive events, so no dice! >:) */
548 #define INTERACTIVE_LIMIT(a, uact) \
549 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
550 a->data.any.interactive = FALSE;
551
552 ObAction *action_from_string(const gchar *name, ObUserAction uact)
553 {
554 ObAction *a = NULL;
555 gboolean exist = FALSE;
556 gint i;
557
558 for (i = 0; actionstrings[i].name; i++)
559 if (!g_ascii_strcasecmp(name, actionstrings[i].name)) {
560 exist = TRUE;
561 a = action_new(actionstrings[i].func);
562 if (actionstrings[i].setup)
563 actionstrings[i].setup(&a, uact);
564 if (a)
565 INTERACTIVE_LIMIT(a, uact);
566 break;
567 }
568 if (!exist)
569 g_message(_("Invalid action '%s' requested. No such action exists."),
570 name);
571 if (!a)
572 g_message(_("Invalid use of action '%s'. Action will be ignored."),
573 name);
574 return a;
575 }
576
577 ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
578 ObUserAction uact)
579 {
580 gchar *actname;
581 ObAction *act = NULL;
582 xmlNodePtr n;
583
584 if (parse_attr_string("name", node, &actname)) {
585 if ((act = action_from_string(actname, uact))) {
586 } else if (act->func == action_resize_relative) {
587 if ((n = parse_find_node("left", node->xmlChildrenNode)))
588 act->data.relative.deltaxl = parse_int(doc, n);
589 if ((n = parse_find_node("up", node->xmlChildrenNode)))
590 act->data.relative.deltayu = parse_int(doc, n);
591 if ((n = parse_find_node("right", node->xmlChildrenNode)))
592 act->data.relative.deltax = parse_int(doc, n);
593 if ((n = parse_find_node("down", node->xmlChildrenNode)))
594 act->data.relative.deltay = parse_int(doc, n);
595 } else if (act->func == action_desktop) {
596 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
597 act->data.desktop.desk = parse_int(doc, n);
598 if (act->data.desktop.desk > 0) act->data.desktop.desk--;
599 /*
600 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
601 act->data.desktop.inter.any.interactive =
602 parse_bool(doc, n);
603 */
604 } else if (act->func == action_send_to_desktop) {
605 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
606 act->data.sendto.desk = parse_int(doc, n);
607 if (act->data.sendto.desk > 0) act->data.sendto.desk--;
608 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
609 act->data.sendto.follow = parse_bool(doc, n);
610 } else if (act->func == action_desktop_dir) {
611 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
612 act->data.desktopdir.wrap = parse_bool(doc, n);
613 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
614 act->data.desktopdir.inter.any.interactive =
615 parse_bool(doc, n);
616 } else if (act->func == action_send_to_desktop_dir) {
617 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
618 act->data.sendtodir.wrap = parse_bool(doc, n);
619 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
620 act->data.sendtodir.follow = parse_bool(doc, n);
621 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
622 act->data.sendtodir.inter.any.interactive =
623 parse_bool(doc, n);
624 INTERACTIVE_LIMIT(act, uact);
625 }
626 g_free(actname);
627 }
628 return act;
629 }
630
631 void action_run_list(GSList *acts, ObClient *c, ObFrameContext context,
632 guint state, guint button, gint x, gint y, Time time,
633 gboolean cancel, gboolean done)
634 {
635 GSList *it;
636 ObAction *a;
637
638 if (!acts)
639 return;
640
641 if (x < 0 && y < 0)
642 screen_pointer_pos(&x, &y);
643
644 for (it = acts; it; it = g_slist_next(it)) {
645 a = it->data;
646
647 if (!(a->data.any.client_action == OB_CLIENT_ACTION_ALWAYS && !c)) {
648 a->data.any.c = a->data.any.client_action ? c : NULL;
649 a->data.any.context = context;
650 a->data.any.x = x;
651 a->data.any.y = y;
652
653 a->data.any.button = button;
654
655 a->data.any.time = time;
656
657 if (a->data.any.interactive) {
658 a->data.inter.cancel = cancel;
659 a->data.inter.final = done;
660 if (!(cancel || done))
661 if (!keyboard_interactive_grab(state, a->data.any.c, a))
662 continue;
663 }
664
665 /* XXX UGLY HACK race with motion event starting a move and the
666 button release gettnig processed first. answer: don't queue
667 moveresize starts. UGLY HACK XXX
668
669 XXX ALSO don't queue showmenu events, because on button press
670 events we need to know if a mouse grab is going to take place,
671 and set the button to 0, so that later motion events don't think
672 that a drag is going on. since showmenu grabs the pointer..
673 */
674 if (a->data.any.interactive || a->func == action_move ||
675 a->func == action_resize || a->func == action_showmenu)
676 {
677 /* interactive actions are not queued */
678 a->func(&a->data);
679 } else if (a->func == action_focus ||
680 a->func == action_activate ||
681 a->func == action_showmenu)
682 {
683 /* XXX MORE UGLY HACK
684 actions from clicks on client windows are NOT queued.
685 this solves the mysterious click-and-drag-doesnt-work
686 problem. it was because the window gets focused and stuff
687 after the button event has already been passed through. i
688 dont really know why it should care but it does and it makes
689 a difference.
690
691 however this very bogus ! !
692 we want to send the button press to the window BEFORE
693 we do the action because the action might move the windows
694 (eg change desktops) and then the button press ends up on
695 the completely wrong window !
696 so, this is just for that bug, and it will only NOT queue it
697 if it is a focusing action that can be used with the mouse
698 pointer. ugh.
699
700 also with the menus, there is a race going on. if the
701 desktop wants to pop up a menu, and we do too, we send them
702 the button before we pop up the menu, so they pop up their
703 menu first. but not always. if we pop up our menu before
704 sending them the button press, then the result is
705 deterministic. yay.
706
707 XXX further more. focus actions are not queued at all,
708 because if you bind focus->showmenu, the menu will get
709 hidden to do the focusing
710 */
711 a->func(&a->data);
712 } else
713 ob_main_loop_queue_action(ob_main_loop, a);
714 }
715 }
716 }
717
718 void action_run_string(const gchar *name, struct _ObClient *c, Time time)
719 {
720 ObAction *a;
721 GSList *l;
722
723 a = action_from_string(name, OB_USER_ACTION_NONE);
724 g_assert(a);
725
726 l = g_slist_append(NULL, a);
727
728 action_run(l, c, 0, time);
729 }
730
731 void action_unshaderaise(union ActionData *data)
732 {
733 if (data->client.any.c->shaded)
734 action_unshade(data);
735 else
736 action_raise(data);
737 }
738
739 void action_shadelower(union ActionData *data)
740 {
741 if (data->client.any.c->shaded)
742 action_lower(data);
743 else
744 action_shade(data);
745 }
746
747 void action_resize_relative_horz(union ActionData *data)
748 {
749 ObClient *c = data->relative.any.c;
750 client_action_start(data);
751 client_resize(c,
752 c->area.width + data->relative.deltax * c->size_inc.width,
753 c->area.height);
754 client_action_end(data, FALSE);
755 }
756
757 void action_resize_relative_vert(union ActionData *data)
758 {
759 ObClient *c = data->relative.any.c;
760 if (!c->shaded) {
761 client_action_start(data);
762 client_resize(c, c->area.width, c->area.height +
763 data->relative.deltax * c->size_inc.height);
764 client_action_end(data, FALSE);
765 }
766 }
767
768 void action_resize_relative(union ActionData *data)
769 {
770 ObClient *c = data->relative.any.c;
771 gint x, y, ow, xoff, nw, oh, yoff, nh, lw, lh;
772
773 client_action_start(data);
774
775 x = c->area.x;
776 y = c->area.y;
777 ow = c->area.width;
778 xoff = -data->relative.deltaxl * c->size_inc.width;
779 nw = ow + data->relative.deltax * c->size_inc.width
780 + data->relative.deltaxl * c->size_inc.width;
781 oh = c->area.height;
782 yoff = -data->relative.deltayu * c->size_inc.height;
783 nh = oh + data->relative.deltay * c->size_inc.height
784 + data->relative.deltayu * c->size_inc.height;
785
786 g_print("deltax %d %d x %d ow %d xoff %d nw %d\n",
787 data->relative.deltax,
788 data->relative.deltaxl,
789 x, ow, xoff, nw);
790
791 client_try_configure(c, &x, &y, &nw, &nh, &lw, &lh, TRUE);
792 xoff = xoff == 0 ? 0 : (xoff < 0 ? MAX(xoff, ow-nw) : MIN(xoff, ow-nw));
793 yoff = yoff == 0 ? 0 : (yoff < 0 ? MAX(yoff, oh-nh) : MIN(yoff, oh-nh));
794 client_move_resize(c, x + xoff, y + yoff, nw, nh);
795 client_action_end(data, FALSE);
796 }
797
798 void action_send_to_desktop(union ActionData *data)
799 {
800 ObClient *c = data->sendto.any.c;
801
802 if (!client_normal(c)) return;
803
804 if (data->sendto.desk < screen_num_desktops ||
805 data->sendto.desk == DESKTOP_ALL) {
806 client_set_desktop(c, data->sendto.desk, data->sendto.follow, FALSE);
807 if (data->sendto.follow && data->sendto.desk != screen_desktop)
808 screen_set_desktop(data->sendto.desk, TRUE);
809 }
810 }
811
812 void action_desktop_dir(union ActionData *data)
813 {
814 guint d;
815
816 d = screen_cycle_desktop(data->desktopdir.dir,
817 data->desktopdir.wrap,
818 data->desktopdir.linear,
819 data->desktopdir.inter.any.interactive,
820 data->desktopdir.inter.final,
821 data->desktopdir.inter.cancel);
822 /* only move the desktop when the action is complete. if we switch
823 desktops during the interactive action, focus will move but with
824 NotifyWhileGrabbed and applications don't like that. */
825 if (!data->sendtodir.inter.any.interactive ||
826 (data->sendtodir.inter.final && !data->sendtodir.inter.cancel))
827 {
828 if (d != screen_desktop)
829 screen_set_desktop(d, TRUE);
830 }
831 }
832
833 void action_send_to_desktop_dir(union ActionData *data)
834 {
835 ObClient *c = data->sendtodir.inter.any.c;
836 guint d;
837
838 if (!client_normal(c)) return;
839
840 d = screen_cycle_desktop(data->sendtodir.dir, data->sendtodir.wrap,
841 data->sendtodir.linear,
842 data->sendtodir.inter.any.interactive,
843 data->sendtodir.inter.final,
844 data->sendtodir.inter.cancel);
845 /* only move the desktop when the action is complete. if we switch
846 desktops during the interactive action, focus will move but with
847 NotifyWhileGrabbed and applications don't like that. */
848 if (!data->sendtodir.inter.any.interactive ||
849 (data->sendtodir.inter.final && !data->sendtodir.inter.cancel))
850 {
851 client_set_desktop(c, d, data->sendtodir.follow, FALSE);
852 if (data->sendtodir.follow && d != screen_desktop)
853 screen_set_desktop(d, TRUE);
854 }
855 }
856
857 void action_desktop_last(union ActionData *data)
858 {
859 if (screen_last_desktop < screen_num_desktops)
860 screen_set_desktop(screen_last_desktop, TRUE);
861 }
862
863 void action_directional_focus(union ActionData *data)
864 {
865 /* if using focus_delay, stop the timer now so that focus doesn't go moving
866 on us */
867 event_halt_focus_delay();
868
869 focus_directional_cycle(data->interdiraction.direction,
870 data->interdiraction.dock_windows,
871 data->interdiraction.desktop_windows,
872 data->any.interactive,
873 data->interdiraction.dialog,
874 data->interdiraction.inter.final,
875 data->interdiraction.inter.cancel);
876 }
877
878 void action_movetoedge(union ActionData *data)
879 {
880 gint x, y;
881 ObClient *c = data->diraction.any.c;
882
883 x = c->frame->area.x;
884 y = c->frame->area.y;
885
886 switch(data->diraction.direction) {
887 case OB_DIRECTION_NORTH:
888 y = client_directional_edge_search(c, OB_DIRECTION_NORTH,
889 data->diraction.hang)
890 - (data->diraction.hang ? c->frame->area.height : 0);
891 break;
892 case OB_DIRECTION_WEST:
893 x = client_directional_edge_search(c, OB_DIRECTION_WEST,
894 data->diraction.hang)
895 - (data->diraction.hang ? c->frame->area.width : 0);
896 break;
897 case OB_DIRECTION_SOUTH:
898 y = client_directional_edge_search(c, OB_DIRECTION_SOUTH,
899 data->diraction.hang)
900 - (data->diraction.hang ? 0 : c->frame->area.height);
901 break;
902 case OB_DIRECTION_EAST:
903 x = client_directional_edge_search(c, OB_DIRECTION_EAST,
904 data->diraction.hang)
905 - (data->diraction.hang ? 0 : c->frame->area.width);
906 break;
907 default:
908 g_assert_not_reached();
909 }
910 frame_frame_gravity(c->frame, &x, &y, c->area.width, c->area.height);
911 client_action_start(data);
912 client_move(c, x, y);
913 client_action_end(data, FALSE);
914 }
915
916 void action_growtoedge(union ActionData *data)
917 {
918 gint x, y, width, height, dest;
919 ObClient *c = data->diraction.any.c;
920 Rect *a;
921
922 a = screen_area(c->desktop, SCREEN_AREA_ALL_MONITORS, &c->frame->area);
923 x = c->frame->area.x;
924 y = c->frame->area.y;
925 /* get the unshaded frame's dimensions..if it is shaded */
926 width = c->area.width + c->frame->size.left + c->frame->size.right;
927 height = c->area.height + c->frame->size.top + c->frame->size.bottom;
928
929 switch(data->diraction.direction) {
930 case OB_DIRECTION_NORTH:
931 if (c->shaded) break; /* don't allow vertical resize if shaded */
932
933 dest = client_directional_edge_search(c, OB_DIRECTION_NORTH, FALSE);
934 if (a->y == y)
935 height = height / 2;
936 else {
937 height = c->frame->area.y + height - dest;
938 y = dest;
939 }
940 break;
941 case OB_DIRECTION_WEST:
942 dest = client_directional_edge_search(c, OB_DIRECTION_WEST, FALSE);
943 if (a->x == x)
944 width = width / 2;
945 else {
946 width = c->frame->area.x + width - dest;
947 x = dest;
948 }
949 break;
950 case OB_DIRECTION_SOUTH:
951 if (c->shaded) break; /* don't allow vertical resize if shaded */
952
953 dest = client_directional_edge_search(c, OB_DIRECTION_SOUTH, FALSE);
954 if (a->y + a->height == y + c->frame->area.height) {
955 height = c->frame->area.height / 2;
956 y = a->y + a->height - height;
957 } else
958 height = dest - c->frame->area.y;
959 y += (height - c->frame->area.height) % c->size_inc.height;
960 height -= (height - c->frame->area.height) % c->size_inc.height;
961 break;
962 case OB_DIRECTION_EAST:
963 dest = client_directional_edge_search(c, OB_DIRECTION_EAST, FALSE);
964 if (a->x + a->width == x + c->frame->area.width) {
965 width = c->frame->area.width / 2;
966 x = a->x + a->width - width;
967 } else
968 width = dest - c->frame->area.x;
969 x += (width - c->frame->area.width) % c->size_inc.width;
970 width -= (width - c->frame->area.width) % c->size_inc.width;
971 break;
972 default:
973 g_assert_not_reached();
974 }
975 width -= c->frame->size.left + c->frame->size.right;
976 height -= c->frame->size.top + c->frame->size.bottom;
977 frame_frame_gravity(c->frame, &x, &y, width, height);
978 client_action_start(data);
979 client_move_resize(c, x, y, width, height);
980 client_action_end(data, FALSE);
981 g_free(a);
982 }
983
984 void action_send_to_layer(union ActionData *data)
985 {
986 client_set_layer(data->layer.any.c, data->layer.layer);
987 }
988
989 void action_toggle_layer(union ActionData *data)
990 {
991 ObClient *c = data->layer.any.c;
992
993 client_action_start(data);
994 if (data->layer.layer < 0)
995 client_set_layer(c, c->below ? 0 : -1);
996 else if (data->layer.layer > 0)
997 client_set_layer(c, c->above ? 0 : 1);
998 client_action_end(data, config_focus_under_mouse);
999 }
1000
1001 void action_toggle_dockautohide(union ActionData *data)
1002 {
1003 config_dock_hide = !config_dock_hide;
1004 dock_configure();
1005 }
1006
1007 void action_add_desktop(union ActionData *data)
1008 {
1009 client_action_start(data);
1010 screen_set_num_desktops(screen_num_desktops+1);
1011
1012 /* move all the clients over */
1013 if (data->addremovedesktop.current) {
1014 GList *it;
1015
1016 for (it = client_list; it; it = g_list_next(it)) {
1017 ObClient *c = it->data;
1018 if (c->desktop != DESKTOP_ALL && c->desktop >= screen_desktop)
1019 client_set_desktop(c, c->desktop+1, FALSE, TRUE);
1020 }
1021 }
1022
1023 client_action_end(data, config_focus_under_mouse);
1024 }
1025
1026 void action_remove_desktop(union ActionData *data)
1027 {
1028 guint rmdesktop, movedesktop;
1029 GList *it, *stacking_copy;
1030
1031 if (screen_num_desktops < 2) return;
1032
1033 client_action_start(data);
1034
1035 /* what desktop are we removing and moving to? */
1036 if (data->addremovedesktop.current)
1037 rmdesktop = screen_desktop;
1038 else
1039 rmdesktop = screen_num_desktops - 1;
1040 if (rmdesktop < screen_num_desktops - 1)
1041 movedesktop = rmdesktop + 1;
1042 else
1043 movedesktop = rmdesktop;
1044
1045 /* make a copy of the list cuz we're changing it */
1046 stacking_copy = g_list_copy(stacking_list);
1047 for (it = g_list_last(stacking_copy); it; it = g_list_previous(it)) {
1048 if (WINDOW_IS_CLIENT(it->data)) {
1049 ObClient *c = it->data;
1050 guint d = c->desktop;
1051 if (d != DESKTOP_ALL && d >= movedesktop) {
1052 client_set_desktop(c, c->desktop - 1, TRUE, TRUE);
1053 ob_debug("moving window %s\n", c->title);
1054 }
1055 /* raise all the windows that are on the current desktop which
1056 is being merged */
1057 if ((screen_desktop == rmdesktop - 1 ||
1058 screen_desktop == rmdesktop) &&
1059 (d == DESKTOP_ALL || d == screen_desktop))
1060 {
1061 stacking_raise(CLIENT_AS_WINDOW(c));
1062 ob_debug("raising window %s\n", c->title);
1063 }
1064 }
1065 }
1066
1067 /* act like we're changing desktops */
1068 if (screen_desktop < screen_num_desktops - 1) {
1069 gint d = screen_desktop;
1070 screen_desktop = screen_last_desktop;
1071 screen_set_desktop(d, TRUE);
1072 ob_debug("fake desktop change\n");
1073 }
1074
1075 screen_set_num_desktops(screen_num_desktops-1);
1076
1077 client_action_end(data, config_focus_under_mouse);
1078 }
This page took 0.079504 seconds and 3 git commands to generate.