From 454712a94d62849324d20014c786b0e7c452bf61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 14 May 2021 13:40:09 +0200 Subject: [PATCH] user32: Add a default WindowPosChanging implementation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Which creates an off-screen window surface for top-level non-layered or SLWA-layered windows. Signed-off-by: RĂ©mi Bernon Signed-off-by: Alexandre Julliard --- dlls/user32/driver.c | 3 +- dlls/user32/user_private.h | 3 +- dlls/user32/win.c | 131 ++++++++++++++++++++++++++++++++++ dlls/user32/winpos.c | 23 +++++- dlls/wineandroid.drv/window.c | 9 +-- dlls/winemac.drv/window.c | 5 +- dlls/winex11.drv/window.c | 7 +- 7 files changed, 168 insertions(+), 13 deletions(-) diff --git a/dlls/user32/driver.c b/dlls/user32/driver.c index 54a888b16d9..59a163c700d 100644 --- a/dlls/user32/driver.c +++ b/dlls/user32/driver.c @@ -376,10 +376,11 @@ static LRESULT CDECL nulldrv_WindowMessage( HWND hwnd, UINT msg, WPARAM wparam, return 0; } -static void CDECL nulldrv_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags, +static BOOL CDECL nulldrv_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags, const RECT *window_rect, const RECT *client_rect, RECT *visible_rect, struct window_surface **surface ) { + return FALSE; } static void CDECL nulldrv_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 82cf376ef54..cb780f0c963 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -105,7 +105,7 @@ typedef struct tagUSER_DRIVER { LRESULT (CDECL *pSysCommand)(HWND,WPARAM,LPARAM); BOOL (CDECL *pUpdateLayeredWindow)(HWND,const UPDATELAYEREDWINDOWINFO *,const RECT *); LRESULT (CDECL *pWindowMessage)(HWND,UINT,WPARAM,LPARAM); - void (CDECL *pWindowPosChanging)(HWND,HWND,UINT,const RECT *,const RECT *,RECT *,struct window_surface**); + BOOL (CDECL *pWindowPosChanging)(HWND,HWND,UINT,const RECT *,const RECT *,RECT *,struct window_surface**); void (CDECL *pWindowPosChanged)(HWND,HWND,UINT,const RECT *,const RECT *,const RECT *,const RECT *,struct window_surface*); /* system parameters */ BOOL (CDECL *pSystemParametersInfo)(UINT,UINT,void*,UINT); @@ -242,6 +242,7 @@ extern BOOL rawinput_from_hardware_message(RAWINPUT *rawinput, const struct hard extern struct rawinput_thread_data *rawinput_thread_data(void); extern void keyboard_init(void) DECLSPEC_HIDDEN; +extern void create_offscreen_window_surface( const RECT *visible_rect, struct window_surface **surface ) DECLSPEC_HIDDEN; extern void CLIPBOARD_ReleaseOwner( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL FOCUS_MouseActivate( HWND hwnd ) DECLSPEC_HIDDEN; diff --git a/dlls/user32/win.c b/dlls/user32/win.c index 86a1f50ca77..2f6b2fdf066 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "windef.h" #include "winbase.h" @@ -590,6 +591,136 @@ static const struct window_surface_funcs dummy_surface_funcs = struct window_surface dummy_surface = { &dummy_surface_funcs, { NULL, NULL }, 1, { 0, 0, 1, 1 } }; +/******************************************************************* + * Off-screen window surface. + */ + +struct offscreen_window_surface +{ + struct window_surface header; + CRITICAL_SECTION cs; + RECT bounds; + char *bits; + BITMAPINFO info; +}; + +static const struct window_surface_funcs offscreen_window_surface_funcs; + +static inline void reset_bounds( RECT *bounds ) +{ + bounds->left = bounds->top = INT_MAX; + bounds->right = bounds->bottom = INT_MIN; +} + +static struct offscreen_window_surface *impl_from_window_surface( struct window_surface *base ) +{ + if (!base || base->funcs != &offscreen_window_surface_funcs) return NULL; + return CONTAINING_RECORD( base, struct offscreen_window_surface, header ); +} + +static void CDECL offscreen_window_surface_lock( struct window_surface *base ) +{ + struct offscreen_window_surface *impl = impl_from_window_surface( base ); + EnterCriticalSection( &impl->cs ); +} + +static void CDECL offscreen_window_surface_unlock( struct window_surface *base ) +{ + struct offscreen_window_surface *impl = impl_from_window_surface( base ); + LeaveCriticalSection( &impl->cs ); +} + +static RECT *CDECL offscreen_window_surface_get_bounds( struct window_surface *base ) +{ + struct offscreen_window_surface *impl = impl_from_window_surface( base ); + return &impl->bounds; +} + +static void *CDECL offscreen_window_surface_get_bitmap_info( struct window_surface *base, BITMAPINFO *info ) +{ + struct offscreen_window_surface *impl = impl_from_window_surface( base ); + memcpy( info, &impl->info, offsetof( BITMAPINFO, bmiColors[0] ) ); + return impl->bits; +} + +static void CDECL offscreen_window_surface_set_region( struct window_surface *base, HRGN region ) +{ +} + +static void CDECL offscreen_window_surface_flush( struct window_surface *base ) +{ + struct offscreen_window_surface *impl = impl_from_window_surface( base ); + base->funcs->lock( base ); + reset_bounds( &impl->bounds ); + base->funcs->unlock( base ); +} + +static void CDECL offscreen_window_surface_destroy( struct window_surface *base ) +{ + struct offscreen_window_surface *impl = impl_from_window_surface( base ); + impl->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection( &impl->cs ); + free( impl ); +} + +static const struct window_surface_funcs offscreen_window_surface_funcs = +{ + offscreen_window_surface_lock, + offscreen_window_surface_unlock, + offscreen_window_surface_get_bitmap_info, + offscreen_window_surface_get_bounds, + offscreen_window_surface_set_region, + offscreen_window_surface_flush, + offscreen_window_surface_destroy +}; + +void create_offscreen_window_surface( const RECT *visible_rect, struct window_surface **surface ) +{ + struct offscreen_window_surface *impl; + SIZE_T size; + RECT surface_rect = *visible_rect; + + TRACE( "visible_rect %s, surface %p.\n", wine_dbgstr_rect( visible_rect ), surface ); + + OffsetRect( &surface_rect, -surface_rect.left, -surface_rect.top ); + surface_rect.right = (surface_rect.right + 0x1f) & ~0x1f; + surface_rect.bottom = (surface_rect.bottom + 0x1f) & ~0x1f; + + /* check that old surface is an offscreen_window_surface, or release it */ + if ((impl = impl_from_window_surface( *surface ))) + { + /* if the rect didn't change, keep the same surface */ + if (EqualRect( &surface_rect, &impl->header.rect )) return; + window_surface_release( &impl->header ); + } + else if (*surface) window_surface_release( *surface ); + + /* create a new window surface */ + *surface = NULL; + size = surface_rect.right * surface_rect.bottom * 4; + if (!(impl = calloc(1, offsetof( struct offscreen_window_surface, info.bmiColors[0] ) + size))) return; + + impl->header.funcs = &offscreen_window_surface_funcs; + impl->header.ref = 1; + impl->header.rect = surface_rect; + + InitializeCriticalSection( &impl->cs ); + impl->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": surface"); + reset_bounds( &impl->bounds ); + + impl->bits = (char *)&impl->info.bmiColors[0]; + impl->info.bmiHeader.biSize = sizeof( impl->info ); + impl->info.bmiHeader.biWidth = surface_rect.right; + impl->info.bmiHeader.biHeight = surface_rect.bottom; + impl->info.bmiHeader.biPlanes = 1; + impl->info.bmiHeader.biBitCount = 32; + impl->info.bmiHeader.biCompression = BI_RGB; + impl->info.bmiHeader.biSizeImage = size; + + TRACE( "created window surface %p\n", &impl->header ); + + *surface = &impl->header; +} /******************************************************************* * register_window_surface diff --git a/dlls/user32/winpos.c b/dlls/user32/winpos.c index 5a2b8ccdfe8..9ac8bedfd09 100644 --- a/dlls/user32/winpos.c +++ b/dlls/user32/winpos.c @@ -2115,8 +2115,16 @@ BOOL set_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, window_surface_add_ref( new_surface ); } visible_rect = *window_rect; - USER_Driver->pWindowPosChanging( hwnd, insert_after, swp_flags, - window_rect, client_rect, &visible_rect, &new_surface ); + if (!(ret = USER_Driver->pWindowPosChanging( hwnd, insert_after, swp_flags, + window_rect, client_rect, &visible_rect, &new_surface ))) + { + if (IsRectEmpty( window_rect )) visible_rect = *window_rect; + else + { + visible_rect = get_virtual_screen_rect(); + IntersectRect( &visible_rect, &visible_rect, window_rect ); + } + } WIN_GetRectangles( hwnd, COORDS_SCREEN, &old_window_rect, NULL ); if (IsRectEmpty( &valid_rects[0] )) valid_rects = NULL; @@ -2126,6 +2134,17 @@ BOOL set_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, if (new_surface) window_surface_release( new_surface ); return FALSE; } + + /* create or update window surface for top-level windows if the driver doesn't implement WindowPosChanging */ + if (!ret && new_surface && !IsRectEmpty( &visible_rect ) && + (!(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) || + GetLayeredWindowAttributes( hwnd, NULL, NULL, NULL ))) + { + window_surface_release( new_surface ); + if ((new_surface = win->surface)) window_surface_add_ref( new_surface ); + create_offscreen_window_surface( &visible_rect, &new_surface ); + } + old_visible_rect = win->visible_rect; old_client_rect = win->client_rect; old_surface = win->surface; diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c index 1c61d4eb76e..997bce15964 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -1291,9 +1291,9 @@ static inline BOOL get_surface_rect( const RECT *visible_rect, RECT *surface_rec /*********************************************************************** * ANDROID_WindowPosChanging */ -void CDECL ANDROID_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags, - const RECT *window_rect, const RECT *client_rect, RECT *visible_rect, - struct window_surface **surface ) +BOOL CDECL ANDROID_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags, + const RECT *window_rect, const RECT *client_rect, RECT *visible_rect, + struct window_surface **surface ) { struct android_win_data *data = get_win_data( hwnd ); RECT surface_rect; @@ -1306,7 +1306,7 @@ void CDECL ANDROID_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_fla hwnd, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect), GetWindowLongW( hwnd, GWL_STYLE ), swp_flags ); - if (!data && !(data = create_win_data( hwnd, window_rect, client_rect ))) return; + if (!data && !(data = create_win_data( hwnd, window_rect, client_rect ))) return TRUE; *visible_rect = *window_rect; @@ -1339,6 +1339,7 @@ void CDECL ANDROID_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_fla done: release_win_data( data ); + return TRUE; } diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index 4e60189ead9..14d6a6fd1b2 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -2052,7 +2052,7 @@ static inline RECT get_surface_rect(const RECT *visible_rect) /*********************************************************************** * WindowPosChanging (MACDRV.@) */ -void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags, +BOOL CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags, const RECT *window_rect, const RECT *client_rect, RECT *visible_rect, struct window_surface **surface) { @@ -2064,7 +2064,7 @@ void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect), wine_dbgstr_rect(visible_rect), surface); - if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return; + if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return TRUE; *visible_rect = *window_rect; macdrv_window_to_mac_rect(data, style, visible_rect, window_rect, client_rect); @@ -2097,6 +2097,7 @@ void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags done: release_win_data(data); + return TRUE; } diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index c30fe6d39b0..386f21c85d4 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2318,7 +2318,7 @@ static inline BOOL get_surface_rect( const RECT *visible_rect, RECT *surface_rec /*********************************************************************** * WindowPosChanging (X11DRV.@) */ -void CDECL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags, +BOOL CDECL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags, const RECT *window_rect, const RECT *client_rect, RECT *visible_rect, struct window_surface **surface ) { @@ -2328,7 +2328,7 @@ void CDECL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flag COLORREF key; BOOL layered = GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED; - if (!data && !(data = X11DRV_create_win_data( hwnd, window_rect, client_rect ))) return; + if (!data && !(data = X11DRV_create_win_data( hwnd, window_rect, client_rect ))) return TRUE; /* check if we need to switch the window to managed */ if (!data->managed && data->whole_window && is_window_managed( hwnd, swp_flags, window_rect )) @@ -2336,7 +2336,7 @@ void CDECL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flag TRACE( "making win %p/%lx managed\n", hwnd, data->whole_window ); release_win_data( data ); unmap_window( hwnd ); - if (!(data = get_win_data( hwnd ))) return; + if (!(data = get_win_data( hwnd ))) return TRUE; data->managed = TRUE; } @@ -2377,6 +2377,7 @@ void CDECL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flag done: release_win_data( data ); + return TRUE; }