]> Dogcows Code - chaz/openbox/blob - openbox/action.c
add the resize action
[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 "toggledecorations",
437 action_toggle_decorations,
438 setup_client_action
439 },
440 {
441 "toggledockautohide",
442 action_toggle_dockautohide,
443 NULL
444 },
445 {
446 "desktoplast",
447 action_desktop_last,
448 NULL
449 },
450 {
451 "sendtotoplayer",
452 action_send_to_layer,
453 setup_action_top_layer
454 },
455 {
456 "togglealwaysontop",
457 action_toggle_layer,
458 setup_action_top_layer
459 },
460 {
461 "sendtonormallayer",
462 action_send_to_layer,
463 setup_action_normal_layer
464 },
465 {
466 "sendtobottomlayer",
467 action_send_to_layer,
468 setup_action_bottom_layer
469 },
470 {
471 "togglealwaysonbottom",
472 action_toggle_layer,
473 setup_action_bottom_layer
474 },
475 {
476 "movefromedgenorth",
477 action_movetoedge,
478 setup_action_movefromedge_north
479 },
480 {
481 "movefromedgesouth",
482 action_movetoedge,
483 setup_action_movefromedge_south
484 },
485 {
486 "movefromedgewest",
487 action_movetoedge,
488 setup_action_movefromedge_west
489 },
490 {
491 "movefromedgeeast",
492 action_movetoedge,
493 setup_action_movefromedge_east
494 },
495 {
496 "movetoedgenorth",
497 action_movetoedge,
498 setup_action_movetoedge_north
499 },
500 {
501 "movetoedgesouth",
502 action_movetoedge,
503 setup_action_movetoedge_south
504 },
505 {
506 "movetoedgewest",
507 action_movetoedge,
508 setup_action_movetoedge_west
509 },
510 {
511 "movetoedgeeast",
512 action_movetoedge,
513 setup_action_movetoedge_east
514 },
515 {
516 "growtoedgenorth",
517 action_growtoedge,
518 setup_action_growtoedge_north
519 },
520 {
521 "growtoedgesouth",
522 action_growtoedge,
523 setup_action_growtoedge_south
524 },
525 {
526 "growtoedgewest",
527 action_growtoedge,
528 setup_action_growtoedge_west
529 },
530 {
531 "growtoedgeeast",
532 action_growtoedge,
533 setup_action_growtoedge_east
534 },
535 {
536 "adddesktoplast",
537 action_add_desktop,
538 setup_action_addremove_desktop_last
539 },
540 {
541 "removedesktoplast",
542 action_remove_desktop,
543 setup_action_addremove_desktop_last
544 },
545 {
546 "adddesktopcurrent",
547 action_add_desktop,
548 setup_action_addremove_desktop_current
549 },
550 {
551 "removedesktopcurrent",
552 action_remove_desktop,
553 setup_action_addremove_desktop_current
554 },
555 {
556 NULL,
557 NULL,
558 NULL
559 }
560 };
561
562 /* only key bindings can be interactive. thus saith the xor.
563 because of how the mouse is grabbed, mouse events dont even get
564 read during interactive events, so no dice! >:) */
565 #define INTERACTIVE_LIMIT(a, uact) \
566 if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
567 a->data.any.interactive = FALSE;
568
569 ObAction *action_from_string(const gchar *name, ObUserAction uact)
570 {
571 ObAction *a = NULL;
572 gboolean exist = FALSE;
573 gint i;
574
575 for (i = 0; actionstrings[i].name; i++)
576 if (!g_ascii_strcasecmp(name, actionstrings[i].name)) {
577 exist = TRUE;
578 a = action_new(actionstrings[i].func);
579 if (actionstrings[i].setup)
580 actionstrings[i].setup(&a, uact);
581 if (a)
582 INTERACTIVE_LIMIT(a, uact);
583 break;
584 }
585 if (!exist)
586 g_message(_("Invalid action '%s' requested. No such action exists."),
587 name);
588 if (!a)
589 g_message(_("Invalid use of action '%s'. Action will be ignored."),
590 name);
591 return a;
592 }
593
594 ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
595 ObUserAction uact)
596 {
597 gchar *actname;
598 ObAction *act = NULL;
599 xmlNodePtr n;
600
601 if (parse_attr_string("name", node, &actname)) {
602 if ((act = action_from_string(actname, uact))) {
603 } else if (act->func == action_resize_relative) {
604 if ((n = parse_find_node("left", node->xmlChildrenNode)))
605 act->data.relative.deltaxl = parse_int(doc, n);
606 if ((n = parse_find_node("up", node->xmlChildrenNode)))
607 act->data.relative.deltayu = parse_int(doc, n);
608 if ((n = parse_find_node("right", node->xmlChildrenNode)))
609 act->data.relative.deltax = parse_int(doc, n);
610 if ((n = parse_find_node("down", node->xmlChildrenNode)))
611 act->data.relative.deltay = parse_int(doc, n);
612 } else if (act->func == action_desktop) {
613 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
614 act->data.desktop.desk = parse_int(doc, n);
615 if (act->data.desktop.desk > 0) act->data.desktop.desk--;
616 /*
617 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
618 act->data.desktop.inter.any.interactive =
619 parse_bool(doc, n);
620 */
621 } else if (act->func == action_send_to_desktop) {
622 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
623 act->data.sendto.desk = parse_int(doc, n);
624 if (act->data.sendto.desk > 0) act->data.sendto.desk--;
625 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
626 act->data.sendto.follow = parse_bool(doc, n);
627 } else if (act->func == action_desktop_dir) {
628 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
629 act->data.desktopdir.wrap = parse_bool(doc, n);
630 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
631 act->data.desktopdir.inter.any.interactive =
632 parse_bool(doc, n);
633 } else if (act->func == action_send_to_desktop_dir) {
634 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
635 act->data.sendtodir.wrap = parse_bool(doc, n);
636 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
637 act->data.sendtodir.follow = parse_bool(doc, n);
638 if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
639 act->data.sendtodir.inter.any.interactive =
640 parse_bool(doc, n);
641 INTERACTIVE_LIMIT(act, uact);
642 }
643 g_free(actname);
644 }
645 return act;
646 }
647
648 void action_run_list(GSList *acts, ObClient *c, ObFrameContext context,
649 guint state, guint button, gint x, gint y, Time time,
650 gboolean cancel, gboolean done)
651 {
652 GSList *it;
653 ObAction *a;
654
655 if (!acts)
656 return;
657
658 if (x < 0 && y < 0)
659 screen_pointer_pos(&x, &y);
660
661 for (it = acts; it; it = g_slist_next(it)) {
662 a = it->data;
663
664 if (!(a->data.any.client_action == OB_CLIENT_ACTION_ALWAYS && !c)) {
665 a->data.any.c = a->data.any.client_action ? c : NULL;
666 a->data.any.context = context;
667 a->data.any.x = x;
668 a->data.any.y = y;
669
670 a->data.any.button = button;
671
672 a->data.any.time = time;
673
674 if (a->data.any.interactive) {
675 a->data.inter.cancel = cancel;
676 a->data.inter.final = done;
677 if (!(cancel || done))
678 if (!keyboard_interactive_grab(state, a->data.any.c, a))
679 continue;
680 }
681
682 /* XXX UGLY HACK race with motion event starting a move and the
683 button release gettnig processed first. answer: don't queue
684 moveresize starts. UGLY HACK XXX
685
686 XXX ALSO don't queue showmenu events, because on button press
687 events we need to know if a mouse grab is going to take place,
688 and set the button to 0, so that later motion events don't think
689 that a drag is going on. since showmenu grabs the pointer..
690 */
691 if (a->data.any.interactive || a->func == action_move ||
692 a->func == action_resize || a->func == action_showmenu)
693 {
694 /* interactive actions are not queued */
695 a->func(&a->data);
696 } else if (a->func == action_focus ||
697 a->func == action_activate ||
698 a->func == action_showmenu)
699 {
700 /* XXX MORE UGLY HACK
701 actions from clicks on client windows are NOT queued.
702 this solves the mysterious click-and-drag-doesnt-work
703 problem. it was because the window gets focused and stuff
704 after the button event has already been passed through. i
705 dont really know why it should care but it does and it makes
706 a difference.
707
708 however this very bogus ! !
709 we want to send the button press to the window BEFORE
710 we do the action because the action might move the windows
711 (eg change desktops) and then the button press ends up on
712 the completely wrong window !
713 so, this is just for that bug, and it will only NOT queue it
714 if it is a focusing action that can be used with the mouse
715 pointer. ugh.
716
717 also with the menus, there is a race going on. if the
718 desktop wants to pop up a menu, and we do too, we send them
719 the button before we pop up the menu, so they pop up their
720 menu first. but not always. if we pop up our menu before
721 sending them the button press, then the result is
722 deterministic. yay.
723
724 XXX further more. focus actions are not queued at all,
725 because if you bind focus->showmenu, the menu will get
726 hidden to do the focusing
727 */
728 a->func(&a->data);
729 } else
730 ob_main_loop_queue_action(ob_main_loop, a);
731 }
732 }
733 }
734
735 void action_run_string(const gchar *name, struct _ObClient *c, Time time)
736 {
737 ObAction *a;
738 GSList *l;
739
740 a = action_from_string(name, OB_USER_ACTION_NONE);
741 g_assert(a);
742
743 l = g_slist_append(NULL, a);
744
745 action_run(l, c, 0, time);
746 }
747
748 void action_unshaderaise(union ActionData *data)
749 {
750 if (data->client.any.c->shaded)
751 action_unshade(data);
752 else
753 action_raise(data);
754 }
755
756 void action_shadelower(union ActionData *data)
757 {
758 if (data->client.any.c->shaded)
759 action_lower(data);
760 else
761 action_shade(data);
762 }
763
764 void action_resize_relative_horz(union ActionData *data)
765 {
766 ObClient *c = data->relative.any.c;
767 client_action_start(data);
768 client_resize(c,
769 c->area.width + data->relative.deltax * c->size_inc.width,
770 c->area.height);
771 client_action_end(data, FALSE);
772 }
773
774 void action_resize_relative_vert(union ActionData *data)
775 {
776 ObClient *c = data->relative.any.c;
777 if (!c->shaded) {
778 client_action_start(data);
779 client_resize(c, c->area.width, c->area.height +
780 data->relative.deltax * c->size_inc.height);
781 client_action_end(data, FALSE);
782 }
783 }
784
785 void action_resize_relative(union ActionData *data)
786 {
787 ObClient *c = data->relative.any.c;
788 gint x, y, ow, xoff, nw, oh, yoff, nh, lw, lh;
789
790 client_action_start(data);
791
792 x = c->area.x;
793 y = c->area.y;
794 ow = c->area.width;
795 xoff = -data->relative.deltaxl * c->size_inc.width;
796 nw = ow + data->relative.deltax * c->size_inc.width
797 + data->relative.deltaxl * c->size_inc.width;
798 oh = c->area.height;
799 yoff = -data->relative.deltayu * c->size_inc.height;
800 nh = oh + data->relative.deltay * c->size_inc.height
801 + data->relative.deltayu * c->size_inc.height;
802
803 g_print("deltax %d %d x %d ow %d xoff %d nw %d\n",
804 data->relative.deltax,
805 data->relative.deltaxl,
806 x, ow, xoff, nw);
807
808 client_try_configure(c, &x, &y, &nw, &nh, &lw, &lh, TRUE);
809 xoff = xoff == 0 ? 0 : (xoff < 0 ? MAX(xoff, ow-nw) : MIN(xoff, ow-nw));
810 yoff = yoff == 0 ? 0 : (yoff < 0 ? MAX(yoff, oh-nh) : MIN(yoff, oh-nh));
811 client_move_resize(c, x + xoff, y + yoff, nw, nh);
812 client_action_end(data, FALSE);
813 }
814
815 void action_send_to_desktop(union ActionData *data)
816 {
817 ObClient *c = data->sendto.any.c;
818
819 if (!client_normal(c)) return;
820
821 if (data->sendto.desk < screen_num_desktops ||
822 data->sendto.desk == DESKTOP_ALL) {
823 client_set_desktop(c, data->sendto.desk, data->sendto.follow, FALSE);
824 if (data->sendto.follow && data->sendto.desk != screen_desktop)
825 screen_set_desktop(data->sendto.desk, TRUE);
826 }
827 }
828
829 void action_desktop(union ActionData *data)
830 {
831 /* XXX add the interactive/dialog option back again once the dialog
832 has been made to not use grabs */
833 if (data->desktop.desk < screen_num_desktops ||
834 data->desktop.desk == DESKTOP_ALL)
835 {
836 screen_set_desktop(data->desktop.desk, TRUE);
837 if (data->inter.any.interactive)
838 screen_desktop_popup(data->desktop.desk, TRUE);
839 }
840 }
841
842 void action_desktop_dir(union ActionData *data)
843 {
844 guint d;
845
846 d = screen_cycle_desktop(data->desktopdir.dir,
847 data->desktopdir.wrap,
848 data->desktopdir.linear,
849 data->desktopdir.inter.any.interactive,
850 data->desktopdir.inter.final,
851 data->desktopdir.inter.cancel);
852 /* only move the desktop when the action is complete. if we switch
853 desktops during the interactive action, focus will move but with
854 NotifyWhileGrabbed and applications don't like that. */
855 if (!data->sendtodir.inter.any.interactive ||
856 (data->sendtodir.inter.final && !data->sendtodir.inter.cancel))
857 {
858 if (d != screen_desktop)
859 screen_set_desktop(d, TRUE);
860 }
861 }
862
863 void action_send_to_desktop_dir(union ActionData *data)
864 {
865 ObClient *c = data->sendtodir.inter.any.c;
866 guint d;
867
868 if (!client_normal(c)) return;
869
870 d = screen_cycle_desktop(data->sendtodir.dir, data->sendtodir.wrap,
871 data->sendtodir.linear,
872 data->sendtodir.inter.any.interactive,
873 data->sendtodir.inter.final,
874 data->sendtodir.inter.cancel);
875 /* only move the desktop when the action is complete. if we switch
876 desktops during the interactive action, focus will move but with
877 NotifyWhileGrabbed and applications don't like that. */
878 if (!data->sendtodir.inter.any.interactive ||
879 (data->sendtodir.inter.final && !data->sendtodir.inter.cancel))
880 {
881 client_set_desktop(c, d, data->sendtodir.follow, FALSE);
882 if (data->sendtodir.follow && d != screen_desktop)
883 screen_set_desktop(d, TRUE);
884 }
885 }
886
887 void action_desktop_last(union ActionData *data)
888 {
889 if (screen_last_desktop < screen_num_desktops)
890 screen_set_desktop(screen_last_desktop, TRUE);
891 }
892
893 void action_toggle_decorations(union ActionData *data)
894 {
895 ObClient *c = data->client.any.c;
896
897 client_action_start(data);
898 client_set_undecorated(c, !c->undecorated);
899 client_action_end(data, FALSE);
900 }
901
902
903 void action_directional_focus(union ActionData *data)
904 {
905 /* if using focus_delay, stop the timer now so that focus doesn't go moving
906 on us */
907 event_halt_focus_delay();
908
909 focus_directional_cycle(data->interdiraction.direction,
910 data->interdiraction.dock_windows,
911 data->interdiraction.desktop_windows,
912 data->any.interactive,
913 data->interdiraction.dialog,
914 data->interdiraction.inter.final,
915 data->interdiraction.inter.cancel);
916 }
917
918 void action_movetoedge(union ActionData *data)
919 {
920 gint x, y;
921 ObClient *c = data->diraction.any.c;
922
923 x = c->frame->area.x;
924 y = c->frame->area.y;
925
926 switch(data->diraction.direction) {
927 case OB_DIRECTION_NORTH:
928 y = client_directional_edge_search(c, OB_DIRECTION_NORTH,
929 data->diraction.hang)
930 - (data->diraction.hang ? c->frame->area.height : 0);
931 break;
932 case OB_DIRECTION_WEST:
933 x = client_directional_edge_search(c, OB_DIRECTION_WEST,
934 data->diraction.hang)
935 - (data->diraction.hang ? c->frame->area.width : 0);
936 break;
937 case OB_DIRECTION_SOUTH:
938 y = client_directional_edge_search(c, OB_DIRECTION_SOUTH,
939 data->diraction.hang)
940 - (data->diraction.hang ? 0 : c->frame->area.height);
941 break;
942 case OB_DIRECTION_EAST:
943 x = client_directional_edge_search(c, OB_DIRECTION_EAST,
944 data->diraction.hang)
945 - (data->diraction.hang ? 0 : c->frame->area.width);
946 break;
947 default:
948 g_assert_not_reached();
949 }
950 frame_frame_gravity(c->frame, &x, &y, c->area.width, c->area.height);
951 client_action_start(data);
952 client_move(c, x, y);
953 client_action_end(data, FALSE);
954 }
955
956 void action_growtoedge(union ActionData *data)
957 {
958 gint x, y, width, height, dest;
959 ObClient *c = data->diraction.any.c;
960 Rect *a;
961
962 a = screen_area(c->desktop, SCREEN_AREA_ALL_MONITORS, &c->frame->area);
963 x = c->frame->area.x;
964 y = c->frame->area.y;
965 /* get the unshaded frame's dimensions..if it is shaded */
966 width = c->area.width + c->frame->size.left + c->frame->size.right;
967 height = c->area.height + c->frame->size.top + c->frame->size.bottom;
968
969 switch(data->diraction.direction) {
970 case OB_DIRECTION_NORTH:
971 if (c->shaded) break; /* don't allow vertical resize if shaded */
972
973 dest = client_directional_edge_search(c, OB_DIRECTION_NORTH, FALSE);
974 if (a->y == y)
975 height = height / 2;
976 else {
977 height = c->frame->area.y + height - dest;
978 y = dest;
979 }
980 break;
981 case OB_DIRECTION_WEST:
982 dest = client_directional_edge_search(c, OB_DIRECTION_WEST, FALSE);
983 if (a->x == x)
984 width = width / 2;
985 else {
986 width = c->frame->area.x + width - dest;
987 x = dest;
988 }
989 break;
990 case OB_DIRECTION_SOUTH:
991 if (c->shaded) break; /* don't allow vertical resize if shaded */
992
993 dest = client_directional_edge_search(c, OB_DIRECTION_SOUTH, FALSE);
994 if (a->y + a->height == y + c->frame->area.height) {
995 height = c->frame->area.height / 2;
996 y = a->y + a->height - height;
997 } else
998 height = dest - c->frame->area.y;
999 y += (height - c->frame->area.height) % c->size_inc.height;
1000 height -= (height - c->frame->area.height) % c->size_inc.height;
1001 break;
1002 case OB_DIRECTION_EAST:
1003 dest = client_directional_edge_search(c, OB_DIRECTION_EAST, FALSE);
1004 if (a->x + a->width == x + c->frame->area.width) {
1005 width = c->frame->area.width / 2;
1006 x = a->x + a->width - width;
1007 } else
1008 width = dest - c->frame->area.x;
1009 x += (width - c->frame->area.width) % c->size_inc.width;
1010 width -= (width - c->frame->area.width) % c->size_inc.width;
1011 break;
1012 default:
1013 g_assert_not_reached();
1014 }
1015 width -= c->frame->size.left + c->frame->size.right;
1016 height -= c->frame->size.top + c->frame->size.bottom;
1017 frame_frame_gravity(c->frame, &x, &y, width, height);
1018 client_action_start(data);
1019 client_move_resize(c, x, y, width, height);
1020 client_action_end(data, FALSE);
1021 g_free(a);
1022 }
1023
1024 void action_send_to_layer(union ActionData *data)
1025 {
1026 client_set_layer(data->layer.any.c, data->layer.layer);
1027 }
1028
1029 void action_toggle_layer(union ActionData *data)
1030 {
1031 ObClient *c = data->layer.any.c;
1032
1033 client_action_start(data);
1034 if (data->layer.layer < 0)
1035 client_set_layer(c, c->below ? 0 : -1);
1036 else if (data->layer.layer > 0)
1037 client_set_layer(c, c->above ? 0 : 1);
1038 client_action_end(data, config_focus_under_mouse);
1039 }
1040
1041 void action_toggle_dockautohide(union ActionData *data)
1042 {
1043 config_dock_hide = !config_dock_hide;
1044 dock_configure();
1045 }
1046
1047 void action_add_desktop(union ActionData *data)
1048 {
1049 client_action_start(data);
1050 screen_set_num_desktops(screen_num_desktops+1);
1051
1052 /* move all the clients over */
1053 if (data->addremovedesktop.current) {
1054 GList *it;
1055
1056 for (it = client_list; it; it = g_list_next(it)) {
1057 ObClient *c = it->data;
1058 if (c->desktop != DESKTOP_ALL && c->desktop >= screen_desktop)
1059 client_set_desktop(c, c->desktop+1, FALSE, TRUE);
1060 }
1061 }
1062
1063 client_action_end(data, config_focus_under_mouse);
1064 }
1065
1066 void action_remove_desktop(union ActionData *data)
1067 {
1068 guint rmdesktop, movedesktop;
1069 GList *it, *stacking_copy;
1070
1071 if (screen_num_desktops < 2) return;
1072
1073 client_action_start(data);
1074
1075 /* what desktop are we removing and moving to? */
1076 if (data->addremovedesktop.current)
1077 rmdesktop = screen_desktop;
1078 else
1079 rmdesktop = screen_num_desktops - 1;
1080 if (rmdesktop < screen_num_desktops - 1)
1081 movedesktop = rmdesktop + 1;
1082 else
1083 movedesktop = rmdesktop;
1084
1085 /* make a copy of the list cuz we're changing it */
1086 stacking_copy = g_list_copy(stacking_list);
1087 for (it = g_list_last(stacking_copy); it; it = g_list_previous(it)) {
1088 if (WINDOW_IS_CLIENT(it->data)) {
1089 ObClient *c = it->data;
1090 guint d = c->desktop;
1091 if (d != DESKTOP_ALL && d >= movedesktop) {
1092 client_set_desktop(c, c->desktop - 1, TRUE, TRUE);
1093 ob_debug("moving window %s\n", c->title);
1094 }
1095 /* raise all the windows that are on the current desktop which
1096 is being merged */
1097 if ((screen_desktop == rmdesktop - 1 ||
1098 screen_desktop == rmdesktop) &&
1099 (d == DESKTOP_ALL || d == screen_desktop))
1100 {
1101 stacking_raise(CLIENT_AS_WINDOW(c));
1102 ob_debug("raising window %s\n", c->title);
1103 }
1104 }
1105 }
1106
1107 /* act like we're changing desktops */
1108 if (screen_desktop < screen_num_desktops - 1) {
1109 gint d = screen_desktop;
1110 screen_desktop = screen_last_desktop;
1111 screen_set_desktop(d, TRUE);
1112 ob_debug("fake desktop change\n");
1113 }
1114
1115 screen_set_num_desktops(screen_num_desktops-1);
1116
1117 client_action_end(data, config_focus_under_mouse);
1118 }
This page took 0.082717 seconds and 4 git commands to generate.