Add reminder to investigate recursive commands for 2.6
[fvwm.git] / fvwm / focus.c
blob6c14cd2cdf5b0f7473b43b1990e1754f291eaae8
1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * This module is all original code
19 * by Rob Nation
20 * Copyright 1993, Robert Nation
21 * You may use this code for any purpose, as long as the original
22 * copyright remains in the source code and all documentation
25 /* ---------------------------- included header files ---------------------- */
27 #include "config.h"
29 #include <stdio.h>
31 #include "libs/fvwmlib.h"
32 #include "libs/charmap.h"
33 #include "libs/wcontext.h"
34 #include "libs/ClientMsg.h"
35 #include "libs/Grab.h"
36 #include "libs/Parse.h"
37 #include "libs/Strings.h"
38 #include "fvwm.h"
39 #include "externs.h"
40 #include "execcontext.h"
41 #include "eventhandler.h"
42 #include "bindings.h"
43 #include "misc.h"
44 #include "screen.h"
45 #include "focus.h"
46 #include "borders.h"
47 #include "frame.h"
48 #include "virtual.h"
49 #include "stack.h"
50 #include "geometry.h"
51 #include "colormaps.h"
52 #include "add_window.h"
54 /* ---------------------------- local definitions -------------------------- */
56 /* ---------------------------- local macros ------------------------------- */
58 /* ---------------------------- imports ------------------------------------ */
60 /* ---------------------------- included code files ------------------------ */
62 /* ---------------------------- local types -------------------------------- */
64 typedef struct
66 unsigned do_allow_force_broadcast : 1;
67 unsigned do_forbid_warp : 1;
68 unsigned do_force : 1;
69 unsigned is_focus_by_flip_focus_cmd : 1;
70 unsigned client_entered : 1;
71 fpol_set_focus_by_t set_by;
72 } sftfwin_args_t;
74 /* ---------------------------- forward declarations ----------------------- */
76 /* ---------------------------- local variables ---------------------------- */
78 static Bool lastFocusType;
79 /* Last window which Fvwm gave the focus to NOT the window that really has the
80 * focus */
81 static FvwmWindow *ScreenFocus = NULL;
82 /* Window which had focus before the pointer moved to a different screen. */
83 static FvwmWindow *LastScreenFocus = NULL;
85 /* ---------------------------- exported variables (globals) --------------- */
87 /* ---------------------------- local functions ---------------------------- */
89 static Bool focus_get_fpol_context_flag(
90 fpol_context_t *fpol_context, int context)
92 int flag;
94 switch (context)
96 case C_WINDOW:
97 case C_EWMH_DESKTOP:
98 flag = fpol_context->client;
99 break;
100 case C_ICON:
101 flag = fpol_context->icon;
102 break;
103 default:
104 flag = fpol_context->decor;
105 break;
108 return (flag) ? True : False;
112 * Helper functions for setting the focus
114 static void __try_program_focus(Window w, const FvwmWindow *fw)
116 if (fw && WM_TAKES_FOCUS(fw) &&
117 FP_DO_FOCUS_BY_PROGRAM(FW_FOCUS_POLICY(fw)))
119 send_clientmessage(dpy, w, _XA_WM_TAKE_FOCUS, fev_get_evtime());
122 return;
125 static Bool __try_forbid_user_focus(
126 Window w, FvwmWindow *fw)
128 if (fw == NULL ||
129 fpol_query_allow_user_focus(&FW_FOCUS_POLICY(fw)) == True)
131 return False;
133 if (WM_TAKES_FOCUS(fw))
135 /* give it a chance to take the focus itself */
136 __try_program_focus(w, fw);
137 XFlush(dpy);
139 else
141 /* make sure the window is not hilighted */
142 border_draw_decorations(
143 fw, PART_ALL, False, False, CLEAR_ALL, NULL, NULL);
146 return True;
149 static Bool __check_allow_focus(
150 Window w, FvwmWindow *fw, fpol_set_focus_by_t set_by)
152 FvwmWindow *sf;
154 if (fw == NULL || set_by == FOCUS_SET_FORCE)
156 /* always allow to delete focus */
157 return True;
159 sf = get_focus_window();
160 if (!FP_IS_LENIENT(FW_FOCUS_POLICY(fw)) &&
161 !focus_does_accept_input_focus(fw) &&
162 sf != NULL && sf->Desk == Scr.CurrentDesk)
164 /* window does not want focus */
165 return False;
167 if (fpol_query_allow_set_focus(&FW_FOCUS_POLICY(fw), set_by))
169 return True;
172 return False;
175 static void __update_windowlist(
176 FvwmWindow *fw, fpol_set_focus_by_t set_by,
177 int is_focus_by_flip_focus_cmd)
179 lastFocusType = (is_focus_by_flip_focus_cmd) ? True : False;
180 if (fw == NULL || focus_is_focused(fw) || fw == &Scr.FvwmRoot ||
181 IS_SCHEDULED_FOR_DESTROY(fw))
183 return;
185 /* Watch out: fw may not be on the windowlist and the windowlist may be
186 * empty */
187 if (!is_focus_by_flip_focus_cmd &&
188 (FP_DO_SORT_WINDOWLIST_BY(FW_FOCUS_POLICY(fw)) ==
189 FPOL_SORT_WL_BY_OPEN ||
190 set_by == FOCUS_SET_BY_FUNCTION))
192 /* move the windowlist around so that fw is at the top */
193 FvwmWindow *fw2;
195 /* find the window on the windowlist */
196 for (fw2 = &Scr.FvwmRoot; fw2 && fw2 != fw; fw2 = fw2->next)
198 /* nothing */
200 if (fw2)
202 /* the window is on the (non-zero length) windowlist */
203 /* make fw2 point to the last window on the list */
204 while (fw2->next)
206 fw2 = fw2->next;
209 /* close the ends of the windowlist */
210 fw2->next = Scr.FvwmRoot.next;
211 Scr.FvwmRoot.next->prev = fw2;
213 /* make fw the new start of the list */
214 Scr.FvwmRoot.next = fw;
215 /* open the closed loop windowlist */
216 fw->prev->next = NULL;
217 fw->prev = &Scr.FvwmRoot;
220 else
222 /* pluck window from list and deposit at top */
223 /* remove fw from list */
224 if (fw->prev)
226 fw->prev->next = fw->next;
228 if (fw->next)
230 fw->next->prev = fw->prev;
232 /* insert fw at start */
233 fw->next = Scr.FvwmRoot.next;
234 if (Scr.FvwmRoot.next)
236 Scr.FvwmRoot.next->prev = fw;
238 Scr.FvwmRoot.next = fw;
239 fw->prev = &Scr.FvwmRoot;
242 return;
245 static Bool __try_other_screen_focus(const FvwmWindow *fw)
247 if (fw == NULL && !Scr.flags.is_pointer_on_this_screen)
249 FvwmWindow *sf;
251 sf = get_focus_window();
252 set_focus_window(NULL);
253 if (sf != NULL)
255 focus_grab_buttons(sf);
257 /* DV (25-Nov-2000): Don't give the Scr.NoFocusWin the focus
258 * here. This would steal the focus from the other screen's
259 * root window again. */
260 return True;
263 return False;
267 * Sets the input focus to the indicated window.
269 static void __set_focus_to_fwin(
270 Window w, FvwmWindow *fw, sftfwin_args_t *args)
272 FvwmWindow *sf;
274 if (__try_forbid_user_focus(w, fw) == True)
276 return;
278 __try_program_focus(w, fw);
279 if (__check_allow_focus(w, fw, args->set_by) == False)
281 return;
283 __update_windowlist(fw, args->set_by, args->is_focus_by_flip_focus_cmd);
284 if (__try_other_screen_focus(fw) == True)
286 return;
289 if (fw && !args->do_forbid_warp)
291 if (IS_ICONIFIED(fw))
293 rectangle r;
294 Bool rc;
296 rc = get_visible_icon_geometry(fw, &r);
297 if (!rc || !IsRectangleOnThisPage(&r, fw->Desk))
299 fw = NULL;
300 w = Scr.NoFocusWin;
303 else if (!IsRectangleOnThisPage(&(fw->g.frame), fw->Desk))
305 fw = NULL;
306 w = Scr.NoFocusWin;
310 sf = get_focus_window();
311 if (fw == NULL)
313 FOCUS_SET(Scr.NoFocusWin);
314 set_focus_window(NULL);
315 Scr.UnknownWinFocused = None;
316 XFlush(dpy);
317 return;
319 /* RBW - allow focus to go to a NoIconTitle icon window so
320 * auto-raise will work on it. */
321 if (IS_ICONIFIED(fw))
323 Bool is_window_selected = False;
325 if (FW_W_ICON_TITLE(fw))
327 w = FW_W_ICON_TITLE(fw);
328 is_window_selected = True;
330 if ((!is_window_selected || WAS_ICON_HINT_PROVIDED(fw)) &&
331 FW_W_ICON_PIXMAP(fw))
333 w = FW_W_ICON_PIXMAP(fw);
337 if (FP_IS_LENIENT(FW_FOCUS_POLICY(fw)))
339 FOCUS_SET(w);
340 set_focus_window(fw);
341 if (args->do_allow_force_broadcast)
343 SET_FOCUS_CHANGE_BROADCAST_PENDING(fw, 1);
345 Scr.UnknownWinFocused = None;
347 else if (focus_does_accept_input_focus(fw))
349 /* Window will accept input focus */
350 if (Scr.StolenFocusWin == w && Scr.UnknownWinFocused != None)
352 /* Without this FocusIn is not generated on the
353 * window if it was focuesed when the unmanaged
354 * window took focus. */
355 FOCUS_SET(Scr.NoFocusWin);
358 FOCUS_SET(w);
359 set_focus_window(fw);
360 if (fw)
362 if (args->do_allow_force_broadcast)
364 SET_FOCUS_CHANGE_BROADCAST_PENDING(fw, 1);
367 Scr.UnknownWinFocused = None;
369 else if (sf && sf->Desk == Scr.CurrentDesk)
371 /* Window doesn't want focus. Leave focus alone */
373 else
375 FOCUS_SET(Scr.NoFocusWin);
376 set_focus_window(NULL);
378 XFlush(dpy);
380 return;
383 static void set_focus_to_fwin(
384 Window w, FvwmWindow *fw, sftfwin_args_t *args)
386 FvwmWindow *sf;
388 sf = get_focus_window();
389 if (!args->do_force && fw == sf)
391 focus_grab_buttons(sf);
392 return;
394 __set_focus_to_fwin(w, fw, args);
395 /* Make sure the button grabs on the new and the old focused windows
396 * are up to date. */
397 if (args->client_entered)
399 focus_grab_buttons_client_entered(fw);
401 else
403 focus_grab_buttons(fw);
405 /* RBW -- don't call this twice for the same window! */
406 if (fw != get_focus_window())
408 if (args->client_entered)
410 focus_grab_buttons_client_entered(get_focus_window());
412 else
414 focus_grab_buttons(get_focus_window());
418 return;
423 * Moves pointer to specified window
426 static void warp_to_fvwm_window(
427 const exec_context_t *exc, int warp_x, int x_unit, int warp_y,
428 int y_unit)
430 int dx,dy;
431 int cx,cy;
432 int x,y;
433 FvwmWindow *t = exc->w.fw;
435 if (t == (FvwmWindow *)0 ||
436 (IS_ICONIFIED(t) && FW_W_ICON_TITLE(t) == None))
438 return;
440 if (t->Desk != Scr.CurrentDesk)
442 goto_desk(t->Desk);
444 if (IS_ICONIFIED(t))
446 rectangle g;
447 Bool rc;
449 rc = get_visible_icon_title_geometry(t, &g);
450 if (rc == False)
452 get_visible_icon_picture_geometry(t, &g);
454 cx = g.x + g.width / 2;
455 cy = g.y + g.height / 2;
457 else
459 cx = t->g.frame.x + t->g.frame.width/2;
460 cy = t->g.frame.y + t->g.frame.height/2;
462 dx = (cx + Scr.Vx) / Scr.MyDisplayWidth * Scr.MyDisplayWidth;
463 dy = (cy + Scr.Vy) / Scr.MyDisplayHeight * Scr.MyDisplayHeight;
464 if (dx != Scr.Vx || dy != Scr.Vy)
466 MoveViewport(dx, dy, True);
468 if (IS_ICONIFIED(t))
470 rectangle g;
471 Bool rc;
473 rc = get_visible_icon_title_geometry(t, &g);
474 if (rc == False)
476 get_visible_icon_picture_geometry(t, &g);
478 x = g.x + g.width / 2;
479 y = g.y + g.height / 2;
481 else
483 if (x_unit != Scr.MyDisplayWidth && warp_x >= 0)
485 x = t->g.frame.x + warp_x;
487 else if (x_unit != Scr.MyDisplayWidth)
489 x = t->g.frame.x + t->g.frame.width + warp_x;
491 else if (warp_x >= 0)
493 x = t->g.frame.x +
494 (t->g.frame.width - 1) * warp_x / 100;
496 else
498 x = t->g.frame.x +
499 (t->g.frame.width - 1) * (100 + warp_x) / 100;
502 if (y_unit != Scr.MyDisplayHeight && warp_y >= 0)
504 y = t->g.frame.y + warp_y;
506 else if (y_unit != Scr.MyDisplayHeight)
508 y = t->g.frame.y + t->g.frame.height + warp_y;
510 else if (warp_y >= 0)
512 y = t->g.frame.y +
513 (t->g.frame.height - 1) * warp_y / 100;
515 else
517 y = t->g.frame.y +
518 (t->g.frame.height - 1) * (100 + warp_y) / 100;
521 FWarpPointerUpdateEvpos(
522 exc->x.elast, dpy, None, Scr.Root, 0, 0, 0, 0, x, y);
523 RaiseWindow(t, False);
524 /* If the window is still not visible, make it visible! */
525 if (t->g.frame.x + t->g.frame.width < 0 ||
526 t->g.frame.y + t->g.frame.height < 0 ||
527 t->g.frame.x >= Scr.MyDisplayWidth ||
528 t->g.frame.y >= Scr.MyDisplayHeight)
530 frame_setup_window(
531 t, 0, 0, t->g.frame.width, t->g.frame.height, False);
532 FWarpPointerUpdateEvpos(
533 exc->x.elast, dpy, None, Scr.Root, 0, 0, 0, 0, 2, 2);
536 return;
539 static Bool focus_query_grab_buttons(FvwmWindow *fw, Bool client_entered)
541 Bool flag;
542 Bool is_focused;
544 if (fw->Desk != Scr.CurrentDesk || IS_ICONIFIED(fw))
546 return False;
548 is_focused = focus_is_focused(fw);
549 if (!is_focused && FP_DO_FOCUS_CLICK_CLIENT(FW_FOCUS_POLICY(fw)))
551 return True;
553 if (is_on_top_of_layer_and_above_unmanaged(fw))
555 return False;
557 if (is_focused)
559 flag = FP_DO_RAISE_FOCUSED_CLIENT_CLICK(FW_FOCUS_POLICY(fw));
561 else
563 flag = FP_DO_RAISE_UNFOCUSED_CLIENT_CLICK(FW_FOCUS_POLICY(fw));
566 return (flag) ? True : False;
569 static FvwmWindow *__restore_focus_after_unmap(
570 const FvwmWindow *fw, Bool do_skip_marked_transients)
572 FvwmWindow *t = NULL;
573 FvwmWindow *set_focus_to = NULL;
575 t = get_transientfor_fvwmwindow(fw);
576 if (t != NULL &&
577 FP_DO_RELEASE_FOCUS_TRANSIENT(FW_FOCUS_POLICY(fw)) &&
578 !FP_DO_OVERRIDE_RELEASE_FOCUS(FW_FOCUS_POLICY(t)) &&
579 t->Desk == fw->Desk &&
580 (!do_skip_marked_transients || !IS_IN_TRANSIENT_SUBTREE(t)))
582 set_focus_to = t;
584 else if (t == NULL && FP_DO_RELEASE_FOCUS(FW_FOCUS_POLICY(fw)))
586 for (t = fw->next; t != NULL && set_focus_to == NULL;
587 t = t->next)
589 if (!FP_DO_OVERRIDE_RELEASE_FOCUS(
590 FW_FOCUS_POLICY(t)) &&
591 t->Desk == fw->Desk && !DO_SKIP_CIRCULATE(t) &&
592 !(IS_ICONIFIED(t) && (DO_SKIP_ICON_CIRCULATE(t) ||
593 IS_ICON_SUPPRESSED(t))) &&
594 (!do_skip_marked_transients ||
595 !IS_IN_TRANSIENT_SUBTREE(t)))
597 /* If it is on a different desk we have to look
598 * for another window */
599 set_focus_to = t;
603 if (set_focus_to && set_focus_to != fw &&
604 set_focus_to->Desk == fw->Desk)
606 /* Don't transfer focus to windows on other desks */
607 SetFocusWindow(set_focus_to, True, FOCUS_SET_FORCE);
609 if (focus_is_focused(fw))
611 DeleteFocus(True);
614 return set_focus_to;
619 * Moves focus to specified window; only to be called bay Focus and FlipFocus
622 static void __activate_window_by_command(
623 F_CMD_ARGS, int is_focus_by_flip_focus_cmd)
625 int cx;
626 int cy;
627 Bool do_not_warp;
628 sftfwin_args_t sf_args;
629 FvwmWindow * const fw = exc->w.fw;
631 memset(&sf_args, 0, sizeof(sf_args));
632 sf_args.do_allow_force_broadcast = 1;
633 sf_args.is_focus_by_flip_focus_cmd = is_focus_by_flip_focus_cmd;
634 sf_args.set_by = FOCUS_SET_BY_FUNCTION;
635 sf_args.client_entered = 0;
636 if (fw == NULL || !FP_DO_FOCUS_BY_FUNCTION(FW_FOCUS_POLICY(fw)))
638 UngrabEm(GRAB_NORMAL);
639 if (fw)
641 /* give the window a chance to take the focus itself */
642 sf_args.do_forbid_warp = 1;
643 sf_args.do_force = 0;
644 set_focus_to_fwin(FW_W(fw), fw, &sf_args);
646 return;
649 do_not_warp = StrEquals(PeekToken(action, NULL), "NoWarp");
650 if (!do_not_warp)
652 if (fw->Desk != Scr.CurrentDesk)
654 goto_desk(fw->Desk);
656 if (IS_ICONIFIED(fw))
658 rectangle g;
659 Bool rc;
661 rc = get_visible_icon_title_geometry(fw, &g);
662 if (rc == False)
664 get_visible_icon_picture_geometry(fw, &g);
666 cx = g.x + g.width / 2;
667 cy = g.y + g.height / 2;
669 else
671 cx = fw->g.frame.x + fw->g.frame.width/2;
672 cy = fw->g.frame.y + fw->g.frame.height/2;
674 if (
675 cx < 0 || cx >= Scr.MyDisplayWidth ||
676 cy < 0 || cy >= Scr.MyDisplayHeight)
678 int dx;
679 int dy;
681 dx = ((cx + Scr.Vx) / Scr.MyDisplayWidth) *
682 Scr.MyDisplayWidth;
683 dy = ((cy + Scr.Vy) / Scr.MyDisplayHeight) *
684 Scr.MyDisplayHeight;
685 MoveViewport(dx, dy, True);
687 #if 0 /* can not happen */
688 /* If the window is still not visible, make it visible! */
689 if (fw->g.frame.x + fw->g.frame.width < 0 ||
690 fw->g.frame.y + fw->g.frame.height < 0 ||
691 fw->g.frame.x >= Scr.MyDisplayWidth ||
692 fw->g.frame.y >= Scr.MyDisplayHeight)
694 frame_setup_window(
695 fw, 0, 0, fw->g.frame.width,
696 fw->g.frame.height, False);
697 if (
698 FP_DO_WARP_POINTER_ON_FOCUS_FUNC(
699 FW_FOCUS_POLICY(fw)))
701 FWarpPointerUpdateEvpos(
702 exc->x.elast, dpy, None, Scr.Root, 0,
703 0, 0, 0, 2, 2);
706 #endif
708 UngrabEm(GRAB_NORMAL);
710 if (fw->Desk == Scr.CurrentDesk)
712 FvwmWindow *sf;
714 sf = get_focus_window();
715 sf_args.do_forbid_warp = !!do_not_warp;
716 sf_args.do_force = 0;
717 sf_args.client_entered = 0;
718 set_focus_to_fwin(FW_W(fw), fw, &sf_args);
719 if (sf != get_focus_window())
721 /* Ignore EnterNotify event while we are waiting for
722 * this window to be focused. */
723 Scr.focus_in_pending_window = sf;
727 return;
730 static void __focus_grab_one_button(
731 FvwmWindow *fw, int button, int grab_buttons)
733 Bool do_grab;
735 do_grab = (grab_buttons & (1 << button));
736 if ((do_grab & (1 << button)) == (fw->grabbed_buttons & (1 << button)))
738 return;
740 if (do_grab)
742 XGrabButton(
743 dpy, button + 1, AnyModifier, FW_W_PARENT(fw), True,
744 ButtonPressMask, GrabModeSync, GrabModeAsync, None,
745 None);
746 /* Set window flags accordingly as we grab or ungrab. */
747 fw->grabbed_buttons |= (1 << button);
749 else
751 XUngrabButton(dpy, button + 1, AnyModifier, FW_W_PARENT(fw));
752 fw->grabbed_buttons &= ~(1 << button);
755 return;
758 /* ---------------------------- interface functions ------------------------ */
760 Bool focus_does_accept_input_focus(const FvwmWindow *fw)
762 return (!fw || !fw->wmhints ||
763 !(fw->wmhints->flags & InputHint) || fw->wmhints->input);
766 Bool focus_is_focused(const FvwmWindow *fw)
768 return (fw && fw == ScreenFocus);
771 Bool focus_query_click_to_raise(
772 FvwmWindow *fw, Bool is_focused, int context)
774 fpol_context_t *c;
776 if (is_focused)
778 c = &FP_DO_RAISE_FOCUSED_CLICK(FW_FOCUS_POLICY(fw));
780 else
782 c = &FP_DO_RAISE_UNFOCUSED_CLICK(FW_FOCUS_POLICY(fw));
785 return focus_get_fpol_context_flag(c, context);
788 Bool focus_query_click_to_focus(
789 FvwmWindow *fw, int context)
791 fpol_context_t *c;
793 c = &FP_DO_FOCUS_CLICK(FW_FOCUS_POLICY(fw));
795 return focus_get_fpol_context_flag(c, context);
798 /* Takes as input the window that wants the focus and the one that currently
799 * has the focus and returns if the new window should get it. */
800 Bool focus_query_open_grab_focus(FvwmWindow *fw, FvwmWindow *focus_win)
802 if (fw == NULL)
804 return False;
806 focus_win = get_focus_window();
807 if (focus_win != NULL &&
808 FP_DO_OVERRIDE_GRAB_FOCUS(FW_FOCUS_POLICY(focus_win)))
810 /* Don't steal the focus from the current window */
811 return False;
813 validate_transientfor(fw);
814 if (IS_TRANSIENT(fw) && FW_W_TRANSIENTFOR(fw) != Scr.Root)
816 if (focus_win != NULL &&
817 FP_DO_GRAB_FOCUS_TRANSIENT(FW_FOCUS_POLICY(fw)) &&
818 FW_W(focus_win) == FW_W_TRANSIENTFOR(fw))
820 /* it's a transient and its transientfor currently has
821 * focus. */
822 return True;
825 else
827 if (FP_DO_GRAB_FOCUS(FW_FOCUS_POLICY(fw)) &&
828 (focus_win == NULL ||
829 !FP_DO_OVERRIDE_GRAB_FOCUS(FW_FOCUS_POLICY(focus_win))))
831 return True;
835 return False;
838 /* Returns true if the focus has to be restored to a different window after
839 * unmapping. */
840 Bool focus_query_close_release_focus(const FvwmWindow *fw)
842 if (fw == NULL || fw != get_focus_window())
844 return False;
846 if (!IS_TRANSIENT(fw) &&
847 (FW_W_TRANSIENTFOR(fw) == Scr.Root ||
848 FP_DO_GRAB_FOCUS(FW_FOCUS_POLICY(fw))))
850 return True;
852 else if (IS_TRANSIENT(fw) &&
853 FP_DO_GRAB_FOCUS_TRANSIENT(FW_FOCUS_POLICY(fw)))
855 return True;
858 return False;
861 static void __focus_grab_buttons(FvwmWindow *fw, Bool client_entered)
863 int i;
864 Bool do_grab_window = False;
865 int grab_buttons;
867 if (fw == NULL || IS_SCHEDULED_FOR_DESTROY(fw) || !IS_MAPPED(fw))
869 /* It is pointless to grab buttons on dieing windows. Buttons
870 * can not be grabbed when the window is unmapped. */
871 return;
873 grab_buttons = Scr.buttons2grab;
874 do_grab_window = focus_query_grab_buttons(fw, client_entered);
875 if (do_grab_window == True)
877 grab_buttons |= FP_USE_MOUSE_BUTTONS(FW_FOCUS_POLICY(fw));
879 if (grab_buttons != fw->grabbed_buttons)
881 MyXGrabServer(dpy);
882 for (i = 0; i < NUMBER_OF_EXTENDED_MOUSE_BUTTONS; i++)
884 __focus_grab_one_button(fw, i, grab_buttons);
886 MyXUngrabServer (dpy);
889 return;
892 void focus_grab_buttons(FvwmWindow *fw)
894 __focus_grab_buttons(fw, False);
897 void focus_grab_buttons_client_entered(FvwmWindow *fw)
899 __focus_grab_buttons(fw, True);
902 void focus_grab_buttons_on_layer(int layer)
904 FvwmWindow *fw;
906 for (
907 fw = Scr.FvwmRoot.stack_next;
908 fw != &Scr.FvwmRoot && fw->layer >= layer;
909 fw = fw->stack_next)
911 if (fw->layer == layer)
913 focus_grab_buttons(fw);
917 return;
920 void focus_grab_buttons_all(void)
922 FvwmWindow *fw;
924 for (fw = Scr.FvwmRoot.next; fw != NULL; fw = fw->next)
926 focus_grab_buttons(fw);
929 return;
932 void _SetFocusWindow(
933 FvwmWindow *fw, Bool do_allow_force_broadcast,
934 fpol_set_focus_by_t set_by, Bool client_entered)
936 sftfwin_args_t sf_args;
938 memset(&sf_args, 0, sizeof(sf_args));
939 sf_args.do_allow_force_broadcast = !!do_allow_force_broadcast;
940 sf_args.is_focus_by_flip_focus_cmd = 0;
941 sf_args.do_forbid_warp = 0;
942 sf_args.do_force = 1;
943 sf_args.set_by = set_by;
944 if (client_entered)
946 sf_args.client_entered = 1;
948 else
950 sf_args.client_entered = 0;
952 set_focus_to_fwin(FW_W(fw), fw, &sf_args);
954 return;
957 void _ReturnFocusWindow(FvwmWindow *fw)
959 sftfwin_args_t sf_args;
961 memset(&sf_args, 0, sizeof(sf_args));
962 sf_args.do_allow_force_broadcast = 1;
963 sf_args.is_focus_by_flip_focus_cmd = 0;
964 sf_args.do_forbid_warp = 1;
965 sf_args.client_entered = 0;
966 sf_args.do_force = 0;
967 sf_args.set_by = FOCUS_SET_FORCE;
968 set_focus_to_fwin(FW_W(fw), fw, &sf_args);
970 return;
973 void _DeleteFocus(Bool do_allow_force_broadcast)
975 sftfwin_args_t sf_args;
977 memset(&sf_args, 0, sizeof(sf_args));
978 sf_args.do_allow_force_broadcast = !!do_allow_force_broadcast;
979 sf_args.is_focus_by_flip_focus_cmd = 0;
980 sf_args.do_forbid_warp = 0;
981 sf_args.client_entered = 0;
982 sf_args.do_force = 0;
983 sf_args.set_by = FOCUS_SET_FORCE;
984 set_focus_to_fwin(Scr.NoFocusWin, NULL, &sf_args);
986 return;
989 void _ForceDeleteFocus(void)
991 sftfwin_args_t sf_args;
993 memset(&sf_args, 0, sizeof(sf_args));
994 sf_args.do_allow_force_broadcast = 1;
995 sf_args.is_focus_by_flip_focus_cmd = 0;
996 sf_args.do_forbid_warp = 0;
997 sf_args.client_entered = 0;
998 sf_args.do_force = 1;
999 sf_args.set_by = FOCUS_SET_FORCE;
1000 set_focus_to_fwin(Scr.NoFocusWin, NULL, &sf_args);
1002 return;
1005 /* When a window is unmapped (or destroyed) this function takes care of
1006 * adjusting the focus window appropriately. */
1007 void restore_focus_after_unmap(
1008 const FvwmWindow *fw, Bool do_skip_marked_transients)
1010 extern FvwmWindow *colormap_win;
1011 FvwmWindow *set_focus_to = NULL;
1013 if (focus_is_focused(fw))
1015 set_focus_to = __restore_focus_after_unmap(
1016 fw, do_skip_marked_transients);
1018 if (fw == Scr.pushed_window)
1020 Scr.pushed_window = NULL;
1022 if (fw == colormap_win)
1024 InstallWindowColormaps(set_focus_to);
1027 return;
1030 Bool IsLastFocusSetByMouse(void)
1032 return lastFocusType;
1036 /* same as above, but forces to regrab buttons on the window under the pointer
1037 * if necessary */
1038 void focus_grab_buttons_on_pointer_window(void)
1040 Window w;
1041 FvwmWindow *fw;
1043 if (!FQueryPointer(
1044 dpy, Scr.Root, &JunkRoot, &w, &JunkX, &JunkY, &JunkX,
1045 &JunkY, &JunkMask))
1047 /* pointer is not on this screen */
1048 return;
1050 if (XFindContext(dpy, w, FvwmContext, (caddr_t *) &fw) == XCNOENT)
1052 /* pointer is not over a window */
1053 return;
1055 focus_grab_buttons(fw);
1057 return;
1060 /* functions to access ScreenFocus, LastScreenFocus and PreviousFocus */
1061 FvwmWindow *get_focus_window(void)
1063 return ScreenFocus;
1066 void set_focus_window(FvwmWindow *fw)
1068 ScreenFocus = fw;
1070 return;
1073 FvwmWindow *get_last_screen_focus_window(void)
1075 return LastScreenFocus;
1078 void set_last_screen_focus_window(FvwmWindow *fw)
1080 LastScreenFocus = fw;
1082 return;
1085 void update_last_screen_focus_window(FvwmWindow *fw)
1087 if (fw == LastScreenFocus)
1089 LastScreenFocus = NULL;
1092 return;
1095 void set_focus_model(FvwmWindow *fw)
1097 if (!focus_does_accept_input_focus(fw))
1099 if (WM_TAKES_FOCUS(fw))
1101 fw->focus_model = FM_GLOBALLY_ACTIVE;
1103 else
1105 fw->focus_model = FM_NO_INPUT;
1108 else
1110 if (WM_TAKES_FOCUS(fw))
1112 fw->focus_model = FM_LOCALLY_ACTIVE;
1114 else
1116 fw->focus_model = FM_PASSIVE;
1120 return;
1123 /* This function is part of a hack to make focus handling work better with
1124 * applications that use the passive focus model but manage focus in their own
1125 * sub windows and should thus use the locally active focus model instead.
1126 * There are many examples like netscape or ddd. */
1127 void focus_force_refresh_focus(const FvwmWindow *fw)
1129 XWindowAttributes winattrs;
1131 MyXGrabServer(dpy);
1132 if (XGetWindowAttributes(dpy, FW_W(fw), &winattrs))
1134 XSelectInput(
1135 dpy, FW_W(fw),
1136 winattrs.your_event_mask & ~FocusChangeMask);
1137 FOCUS_SET(FW_W(fw));
1138 XSelectInput(dpy, FW_W(fw), winattrs.your_event_mask);
1140 MyXUngrabServer(dpy);
1142 return;
1145 void refresh_focus(const FvwmWindow *fw)
1147 Bool do_refresh = False;
1149 if (fw == NULL || !focus_is_focused(fw))
1151 /* only refresh the focus on the currently focused window */
1152 return;
1155 /* only refresh the focus for windows with the passive focus model so
1156 * that we don't disturb focus handling more than necessary */
1157 switch (fw->focus_model)
1159 case FM_PASSIVE:
1160 do_refresh = True;
1161 break;
1162 case FM_NO_INPUT:
1163 case FM_GLOBALLY_ACTIVE:
1164 case FM_LOCALLY_ACTIVE:
1165 default:
1166 do_refresh = False;
1167 break;
1169 if (do_refresh)
1171 focus_force_refresh_focus(fw);
1174 return;
1177 /* ---------------------------- builtin commands --------------------------- */
1179 void CMD_FlipFocus(F_CMD_ARGS)
1181 /* Reorder the window list */
1182 __activate_window_by_command(F_PASS_ARGS, 1);
1184 return;
1187 void CMD_Focus(F_CMD_ARGS)
1189 __activate_window_by_command(F_PASS_ARGS, 0);
1191 return;
1194 void CMD_WarpToWindow(F_CMD_ARGS)
1196 int val1_unit, val2_unit, n;
1197 int val1, val2;
1199 n = GetTwoArguments(action, &val1, &val2, &val1_unit, &val2_unit);
1200 if (exc->w.wcontext != C_UNMANAGED)
1202 if (n == 2)
1204 warp_to_fvwm_window(
1205 exc, val1, val1_unit, val2, val2_unit);
1207 else
1209 warp_to_fvwm_window(exc, 0, 0, 0, 0);
1212 else
1214 int x = 0;
1215 int y = 0;
1217 if (n == 2)
1219 int wx;
1220 int wy;
1221 int ww;
1222 int wh;
1224 if (!XGetGeometry(
1225 dpy, exc->w.w, &JunkRoot, &wx, &wy,
1226 (unsigned int*)&ww, (unsigned int*)&wh,
1227 (unsigned int*)&JunkBW,
1228 (unsigned int*)&JunkDepth))
1230 return;
1232 if (val1_unit != Scr.MyDisplayWidth)
1234 x = val1;
1236 else
1238 x = (ww - 1) * val1 / 100;
1240 if (val2_unit != Scr.MyDisplayHeight)
1242 y = val2;
1244 else
1246 y = (wh - 1) * val2 / 100;
1248 if (x < 0)
1250 x += ww;
1252 if (y < 0)
1254 y += wh;
1257 FWarpPointerUpdateEvpos(
1258 exc->x.elast, dpy, None, exc->w.w, 0, 0, 0, 0, x, y);
1261 return;