[PATCH] winex11.drv: Fix drawing of layered windows with a client window.

Rémi Bernon rbernon at codeweavers.com
Tue Apr 27 04:33:00 CDT 2021


On 4/27/21 10:51 AM, Giovanni Mascellani wrote:
> Testing on Windows 10, it seems that when a window has both a surface
> (because it is layered) and a client window (because a d3d9 or analogous
> device was created for it), the surface takes the priority, i.e., gdi
> and d3d9 are ignored, and just the layered bitmap is painted.
> 
> Before this change, expose events lead to redrawing the surface only
> on the whole window, but not on the client window. This implies that
> if a d3d9 device is created for a layered window, it takes the priority
> in the client window region, contradicting the behavior observed on
> Windows.
> 
> Signed-off-by: Giovanni Mascellani <gmascellani at codeweavers.com>
> ---
>   dlls/winex11.drv/event.c | 24 ++++++++++++------------
>   1 file changed, 12 insertions(+), 12 deletions(-)
> 
> diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
> index 99943478729..38c8bd825bb 100644
> --- a/dlls/winex11.drv/event.c
> +++ b/dlls/winex11.drv/event.c
> @@ -938,21 +938,21 @@ static BOOL X11DRV_Expose( HWND hwnd, XEvent *xev )
>       rect.right  = pos.x + event->width;
>       rect.bottom = pos.y + event->height;
>   
> -    if (event->window != data->client_window)
> +    if (event->window == data->client_window)
> +        OffsetRect( &rect, data->client_rect.left - data->whole_rect.left,
> +                    data->client_rect.top - data->whole_rect.top );
> +    if (data->surface)
>       {
> -        if (data->surface)
> -        {
> -            surface_region = expose_surface( data->surface, &rect );
> -            if (!surface_region) flags = 0;
> -            else OffsetRgn( surface_region, data->whole_rect.left - data->client_rect.left,
> -                            data->whole_rect.top - data->client_rect.top );
> +        surface_region = expose_surface( data->surface, &rect );
> +        if (!surface_region) flags = 0;
> +        else OffsetRgn( surface_region, data->whole_rect.left - data->client_rect.left,
> +                        data->whole_rect.top - data->client_rect.top );
>   
> -            if (data->vis.visualid != default_visual.visualid)
> -                data->surface->funcs->flush( data->surface );
> -        }
> -        OffsetRect( &rect, data->whole_rect.left - data->client_rect.left,
> -                    data->whole_rect.top - data->client_rect.top );
> +        if (data->vis.visualid != default_visual.visualid)
> +            data->surface->funcs->flush( data->surface );
>       }
> +    OffsetRect( &rect, data->whole_rect.left - data->client_rect.left,
> +                data->whole_rect.top - data->client_rect.top );
>   
>       if (event->window != root_window)
>       {
> 

As far as I can tell from a quick test with OpenGL rendering, there is 
two different behavior on Windows:

I'm only considering the layered attribute and calls on top-level 
windows, as I couldn't make it work on child windows, to the contrary to 
what MSDN says is supported on Windows > 8.


1) When UpdateLayeredWindow is called, the displayed image is the one 
that has been provided in the call, regardless of any later drawing call 
indeed, be it GDI or OpenGL. If the window has child windows, they 
aren't displayed either, regardless of the API they use too.


2) When SetLayeredWindowAttributes has been called, the window is 
displayed, with the transparency computed according to the attributes. 
If the window has child windows, they are displayed normally, but with 
the same transparency transformation. Drawing with GDI or OpenGL on the 
top-level or the child windows works as for a normal window, except for 
the transparency.


Here I would expect the surface flush to only work once until a later GL 
swap buffer / VK present override it (although I'm not completely sure 
when the Expose events are generated).

It may also work differently depending on if the client windows are 
off-screen or not (depending on whether it's a client window of a child 
or if the top-level has child windows).

Although this patch possibly fixes some bad cases I think the layered 
window implementation is actually incorrect in a more general way.


To make things simpler I think we should maybe make the off-screen GL/VK 
rendering the default and do the present ourselves on the top-level 
windows, and put the GL/VK on-screen /only/ when we're sure we can 
(which is hopefully still going to be quite often).
-- 
Rémi Bernon <rbernon at codeweavers.com>



More information about the wine-devel mailing list