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
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 ---------------------- */
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"
40 #include "execcontext.h"
41 #include "eventhandler.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 -------------------------------- */
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
;
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
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
)
98 flag
= fpol_context
->client
;
101 flag
= fpol_context
->icon
;
104 flag
= fpol_context
->decor
;
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());
125 static Bool
__try_forbid_user_focus(
126 Window w
, FvwmWindow
*fw
)
129 fpol_query_allow_user_focus(&FW_FOCUS_POLICY(fw
)) == True
)
133 if (WM_TAKES_FOCUS(fw
))
135 /* give it a chance to take the focus itself */
136 __try_program_focus(w
, fw
);
141 /* make sure the window is not hilighted */
142 border_draw_decorations(
143 fw
, PART_ALL
, False
, False
, CLEAR_ALL
, NULL
, NULL
);
149 static Bool
__check_allow_focus(
150 Window w
, FvwmWindow
*fw
, fpol_set_focus_by_t set_by
)
154 if (fw
== NULL
|| set_by
== FOCUS_SET_FORCE
)
156 /* always allow to delete focus */
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 */
167 if (fpol_query_allow_set_focus(&FW_FOCUS_POLICY(fw
), set_by
))
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
))
185 /* Watch out: fw may not be on the windowlist and the windowlist may be
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 */
195 /* find the window on the windowlist */
196 for (fw2
= &Scr
.FvwmRoot
; fw2
&& fw2
!= fw
; fw2
= fw2
->next
)
202 /* the window is on the (non-zero length) windowlist */
203 /* make fw2 point to the last window on the list */
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
;
222 /* pluck window from list and deposit at top */
223 /* remove fw from list */
226 fw
->prev
->next
= 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
;
245 static Bool
__try_other_screen_focus(const FvwmWindow
*fw
)
247 if (fw
== NULL
&& !Scr
.flags
.is_pointer_on_this_screen
)
251 sf
= get_focus_window();
252 set_focus_window(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. */
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
)
274 if (__try_forbid_user_focus(w
, fw
) == True
)
278 __try_program_focus(w
, fw
);
279 if (__check_allow_focus(w
, fw
, args
->set_by
) == False
)
283 __update_windowlist(fw
, args
->set_by
, args
->is_focus_by_flip_focus_cmd
);
284 if (__try_other_screen_focus(fw
) == True
)
289 if (fw
&& !args
->do_forbid_warp
)
291 if (IS_ICONIFIED(fw
))
296 rc
= get_visible_icon_geometry(fw
, &r
);
297 if (!rc
|| !IsRectangleOnThisPage(&r
, fw
->Desk
))
303 else if (!IsRectangleOnThisPage(&(fw
->g
.frame
), fw
->Desk
))
310 sf
= get_focus_window();
313 FOCUS_SET(Scr
.NoFocusWin
);
314 set_focus_window(NULL
);
315 Scr
.UnknownWinFocused
= None
;
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
)))
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
);
359 set_focus_window(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 */
375 FOCUS_SET(Scr
.NoFocusWin
);
376 set_focus_window(NULL
);
383 static void set_focus_to_fwin(
384 Window w
, FvwmWindow
*fw
, sftfwin_args_t
*args
)
388 sf
= get_focus_window();
389 if (!args
->do_force
&& fw
== sf
)
391 focus_grab_buttons(sf
);
394 __set_focus_to_fwin(w
, fw
, args
);
395 /* Make sure the button grabs on the new and the old focused windows
397 if (args
->client_entered
)
399 focus_grab_buttons_client_entered(fw
);
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());
414 focus_grab_buttons(get_focus_window());
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
,
433 FvwmWindow
*t
= exc
->w
.fw
;
435 if (t
== (FvwmWindow
*)0 ||
436 (IS_ICONIFIED(t
) && FW_W_ICON_TITLE(t
) == None
))
440 if (t
->Desk
!= Scr
.CurrentDesk
)
449 rc
= get_visible_icon_title_geometry(t
, &g
);
452 get_visible_icon_picture_geometry(t
, &g
);
454 cx
= g
.x
+ g
.width
/ 2;
455 cy
= g
.y
+ g
.height
/ 2;
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
);
473 rc
= get_visible_icon_title_geometry(t
, &g
);
476 get_visible_icon_picture_geometry(t
, &g
);
478 x
= g
.x
+ g
.width
/ 2;
479 y
= g
.y
+ g
.height
/ 2;
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)
494 (t
->g
.frame
.width
- 1) * warp_x
/ 100;
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)
513 (t
->g
.frame
.height
- 1) * warp_y
/ 100;
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
)
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);
539 static Bool
focus_query_grab_buttons(FvwmWindow
*fw
, Bool client_entered
)
544 if (fw
->Desk
!= Scr
.CurrentDesk
|| IS_ICONIFIED(fw
))
548 is_focused
= focus_is_focused(fw
);
549 if (!is_focused
&& FP_DO_FOCUS_CLICK_CLIENT(FW_FOCUS_POLICY(fw
)))
553 if (is_on_top_of_layer_and_above_unmanaged(fw
))
559 flag
= FP_DO_RAISE_FOCUSED_CLIENT_CLICK(FW_FOCUS_POLICY(fw
));
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
);
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
)))
584 else if (t
== NULL
&& FP_DO_RELEASE_FOCUS(FW_FOCUS_POLICY(fw
)))
586 for (t
= fw
->next
; t
!= NULL
&& set_focus_to
== NULL
;
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 */
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
))
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
)
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
);
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
);
649 do_not_warp
= StrEquals(PeekToken(action
, NULL
), "NoWarp");
652 if (fw
->Desk
!= Scr
.CurrentDesk
)
656 if (IS_ICONIFIED(fw
))
661 rc
= get_visible_icon_title_geometry(fw
, &g
);
664 get_visible_icon_picture_geometry(fw
, &g
);
666 cx
= g
.x
+ g
.width
/ 2;
667 cy
= g
.y
+ g
.height
/ 2;
671 cx
= fw
->g
.frame
.x
+ fw
->g
.frame
.width
/2;
672 cy
= fw
->g
.frame
.y
+ fw
->g
.frame
.height
/2;
675 cx
< 0 || cx
>= Scr
.MyDisplayWidth
||
676 cy
< 0 || cy
>= Scr
.MyDisplayHeight
)
681 dx
= ((cx
+ Scr
.Vx
) / Scr
.MyDisplayWidth
) *
683 dy
= ((cy
+ Scr
.Vy
) / 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
)
695 fw
, 0, 0, fw
->g
.frame
.width
,
696 fw
->g
.frame
.height
, False
);
698 FP_DO_WARP_POINTER_ON_FOCUS_FUNC(
699 FW_FOCUS_POLICY(fw
)))
701 FWarpPointerUpdateEvpos(
702 exc
->x
.elast
, dpy
, None
, Scr
.Root
, 0,
708 UngrabEm(GRAB_NORMAL
);
710 if (fw
->Desk
== Scr
.CurrentDesk
)
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
;
730 static void __focus_grab_one_button(
731 FvwmWindow
*fw
, int button
, int grab_buttons
)
735 do_grab
= (grab_buttons
& (1 << button
));
736 if ((do_grab
& (1 << button
)) == (fw
->grabbed_buttons
& (1 << button
)))
743 dpy
, button
+ 1, AnyModifier
, FW_W_PARENT(fw
), True
,
744 ButtonPressMask
, GrabModeSync
, GrabModeAsync
, None
,
746 /* Set window flags accordingly as we grab or ungrab. */
747 fw
->grabbed_buttons
|= (1 << button
);
751 XUngrabButton(dpy
, button
+ 1, AnyModifier
, FW_W_PARENT(fw
));
752 fw
->grabbed_buttons
&= ~(1 << button
);
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
)
778 c
= &FP_DO_RAISE_FOCUSED_CLICK(FW_FOCUS_POLICY(fw
));
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
)
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
)
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 */
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
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
))))
838 /* Returns true if the focus has to be restored to a different window after
840 Bool
focus_query_close_release_focus(const FvwmWindow
*fw
)
842 if (fw
== NULL
|| fw
!= get_focus_window())
846 if (!IS_TRANSIENT(fw
) &&
847 (FW_W_TRANSIENTFOR(fw
) == Scr
.Root
||
848 FP_DO_GRAB_FOCUS(FW_FOCUS_POLICY(fw
))))
852 else if (IS_TRANSIENT(fw
) &&
853 FP_DO_GRAB_FOCUS_TRANSIENT(FW_FOCUS_POLICY(fw
)))
861 static void __focus_grab_buttons(FvwmWindow
*fw
, Bool client_entered
)
864 Bool do_grab_window
= False
;
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. */
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
)
882 for (i
= 0; i
< NUMBER_OF_EXTENDED_MOUSE_BUTTONS
; i
++)
884 __focus_grab_one_button(fw
, i
, grab_buttons
);
886 MyXUngrabServer (dpy
);
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
)
907 fw
= Scr
.FvwmRoot
.stack_next
;
908 fw
!= &Scr
.FvwmRoot
&& fw
->layer
>= layer
;
911 if (fw
->layer
== layer
)
913 focus_grab_buttons(fw
);
920 void focus_grab_buttons_all(void)
924 for (fw
= Scr
.FvwmRoot
.next
; fw
!= NULL
; fw
= fw
->next
)
926 focus_grab_buttons(fw
);
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
;
946 sf_args
.client_entered
= 1;
950 sf_args
.client_entered
= 0;
952 set_focus_to_fwin(FW_W(fw
), fw
, &sf_args
);
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
);
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
);
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
);
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
);
1030 Bool
IsLastFocusSetByMouse(void)
1032 return lastFocusType
;
1036 /* same as above, but forces to regrab buttons on the window under the pointer
1038 void focus_grab_buttons_on_pointer_window(void)
1044 dpy
, Scr
.Root
, &JunkRoot
, &w
, &JunkX
, &JunkY
, &JunkX
,
1047 /* pointer is not on this screen */
1050 if (XFindContext(dpy
, w
, FvwmContext
, (caddr_t
*) &fw
) == XCNOENT
)
1052 /* pointer is not over a window */
1055 focus_grab_buttons(fw
);
1060 /* functions to access ScreenFocus, LastScreenFocus and PreviousFocus */
1061 FvwmWindow
*get_focus_window(void)
1066 void set_focus_window(FvwmWindow
*fw
)
1073 FvwmWindow
*get_last_screen_focus_window(void)
1075 return LastScreenFocus
;
1078 void set_last_screen_focus_window(FvwmWindow
*fw
)
1080 LastScreenFocus
= fw
;
1085 void update_last_screen_focus_window(FvwmWindow
*fw
)
1087 if (fw
== LastScreenFocus
)
1089 LastScreenFocus
= NULL
;
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
;
1105 fw
->focus_model
= FM_NO_INPUT
;
1110 if (WM_TAKES_FOCUS(fw
))
1112 fw
->focus_model
= FM_LOCALLY_ACTIVE
;
1116 fw
->focus_model
= FM_PASSIVE
;
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
;
1132 if (XGetWindowAttributes(dpy
, FW_W(fw
), &winattrs
))
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
);
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 */
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
)
1163 case FM_GLOBALLY_ACTIVE
:
1164 case FM_LOCALLY_ACTIVE
:
1171 focus_force_refresh_focus(fw
);
1177 /* ---------------------------- builtin commands --------------------------- */
1179 void CMD_FlipFocus(F_CMD_ARGS
)
1181 /* Reorder the window list */
1182 __activate_window_by_command(F_PASS_ARGS
, 1);
1187 void CMD_Focus(F_CMD_ARGS
)
1189 __activate_window_by_command(F_PASS_ARGS
, 0);
1194 void CMD_WarpToWindow(F_CMD_ARGS
)
1196 int val1_unit
, val2_unit
, n
;
1199 n
= GetTwoArguments(action
, &val1
, &val2
, &val1_unit
, &val2_unit
);
1200 if (exc
->w
.wcontext
!= C_UNMANAGED
)
1204 warp_to_fvwm_window(
1205 exc
, val1
, val1_unit
, val2
, val2_unit
);
1209 warp_to_fvwm_window(exc
, 0, 0, 0, 0);
1225 dpy
, exc
->w
.w
, &JunkRoot
, &wx
, &wy
,
1226 (unsigned int*)&ww
, (unsigned int*)&wh
,
1227 (unsigned int*)&JunkBW
,
1228 (unsigned int*)&JunkDepth
))
1232 if (val1_unit
!= Scr
.MyDisplayWidth
)
1238 x
= (ww
- 1) * val1
/ 100;
1240 if (val2_unit
!= Scr
.MyDisplayHeight
)
1246 y
= (wh
- 1) * val2
/ 100;
1257 FWarpPointerUpdateEvpos(
1258 exc
->x
.elast
, dpy
, None
, exc
->w
.w
, 0, 0, 0, 0, x
, y
);