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