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@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).