[PATCH resend] winex11.drv: Don't set the foreground for focus events that are older than the last SetFocus sent without an event

Rémi Bernon rbernon at codeweavers.com
Thu Aug 22 04:29:10 CDT 2019


On 8/15/19 3:57 PM, Gabriel Ivăncescu wrote:
> @@ -803,7 +820,7 @@ static void focus_out( Display *display , HWND hwnd )
>   
>       if (ximInComposeMode) return;
>   
> -    x11drv_thread_data()->last_focus = hwnd;
> +    thread_data->last_focus = hwnd;
>       if ((xic = X11DRV_get_ic( hwnd ))) XUnsetICFocus( xic );
>   
>       if (root_window != DefaultRootWindow(display))
> @@ -812,6 +829,12 @@ static void focus_out( Display *display , HWND hwnd )
>           return;
>       }
>       if (hwnd != GetForegroundWindow()) return;
> +
> +    if ((long)(thread_data->focus_serial - serial) > 0)
> +    {
> +        TRACE("ignoring old serial %lu/%lu\n", serial, thread_data->focus_serial);
> +        return;
> +    }

I'm not sure if this is the right thing to do here.

I understand the reason to skip calling SetForegroundWindow on FocusIn 
events - because SetFocus called by DefWinProc would already have done 
it before, as a consequence of ShowWindow / WM_ACTIVATE messages - but 
in the case of focus out events, I believe it is already skipped if the 
newly focused window is another Wine window.

Also we will not send the WM_CANCELMODE message anymore and I don't know 
if it is OK.

>       SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
>   
>       /* don't reset the foreground window, if the window which is
> @@ -855,7 +878,7 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev )
>           return TRUE;
>       }
>       if (!hwnd) return FALSE;
> -    focus_out( event->display, hwnd );
> +    focus_out( event->display, hwnd, event->serial );
>       return TRUE;
>   }
>   
> @@ -1385,6 +1408,7 @@ void wait_for_withdrawn_state( HWND hwnd, BOOL set )
>    */
>   void CDECL X11DRV_SetFocus( HWND hwnd )
>   {
> +    struct x11drv_thread_data *thread_data;
>       struct x11drv_win_data *data;
>   
>       HWND parent;
> @@ -1400,6 +1424,21 @@ void CDECL X11DRV_SetFocus( HWND hwnd )
>       }
>       if (!data->managed || data->embedder) set_input_focus( data );
>       release_win_data( data );
> +
> +    hwnd = GetAncestor(hwnd, GA_ROOT);
> +    if (hwnd != (thread_data = x11drv_thread_data())->setfocus_hwnd)

I think it would be more readable to initialize thread_data along with 
its declaration, like it's done elsewhere, unless there's a good reason 
not to.

> +    {
> +        thread_data->setfocus_hwnd = hwnd;
> +
> +        /* If we are not processing an event, store the current serial after syncing
> +           with the X server, so that we ignore all older focus-related events. This
> +           prevents focus being reverted later when the app processes its messages. */
> +        if (!thread_data->current_event)
> +        {
> +            XSync(thread_data->display, False);
> +            thread_data->focus_serial = LastKnownRequestProcessed(thread_data->display) + 1;
> +        }
> +    }
>   }
>   
>   
> diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
> index 0d3695b..63598d7 100644
> --- a/dlls/winex11.drv/x11drv.h
> +++ b/dlls/winex11.drv/x11drv.h
> @@ -326,10 +326,12 @@ struct x11drv_thread_data
>       XEvent  *current_event;        /* event currently being processed */
>       HWND     grab_hwnd;            /* window that currently grabs the mouse */
>       HWND     last_focus;           /* last window that had focus */
> +    HWND     setfocus_hwnd;        /* top-level window corresponding to the last SetFocus */
>       XIM      xim;                  /* input method */
>       HWND     last_xic_hwnd;        /* last xic window */
>       XFontSet font_set;             /* international text drawing font set */
>       Window   selection_wnd;        /* window used for selection interactions */
> +    unsigned long focus_serial;    /* serial number when last SetFocus without an event happened */
>       unsigned long warp_serial;     /* serial number of last pointer warp request */
>       Window   clip_window;          /* window used for cursor clipping */
>       HWND     clip_hwnd;            /* message window stored in desktop while clipping is active */
> 

I would rename focus_serial to setfocus_serial and keep it close to 
setfocus_hwnd as they are meant to work together - or the other way 
around. This way we also understand that set_focus

Otherwise I would say it looks OK to me with my limited knowledge of the 
whole thing works.
-- 
Rémi Bernon <rbernon at codeweavers.com>



More information about the wine-devel mailing list