Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
With this series, all user32 tests should pass with null graphics driver (and even more, as some todo_wine succeed), except for the monitor and sysparams tests, which require monitor and mode enumeration.
It's pretty much doable to implement some fake adapters and monitor modes, but it would be better to factor it with winex11.drv as much as possible (replacing driver callbacks with gpu / adapter enumeration callbacks for instance).
There was also some attempt to refactor that area to make it live either in wineserver or in some dedicated process, so it will require a bit of coordination here.
dlls/user32/winpos.c | 6 ++++-- dlls/wineandroid.drv/window.c | 1 - dlls/winemac.drv/window.c | 1 - dlls/winex11.drv/window.c | 1 - 4 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/dlls/user32/winpos.c b/dlls/user32/winpos.c index c6f806f7beb..cf7e7914869 100644 --- a/dlls/user32/winpos.c +++ b/dlls/user32/winpos.c @@ -1044,7 +1044,7 @@ static BOOL show_window( HWND hwnd, INT cmd ) BOOL wasVisible = (style & WS_VISIBLE) != 0; BOOL showFlag = TRUE; RECT newPos = {0, 0, 0, 0}; - UINT swp = 0; + UINT new_swp, swp = 0;
TRACE("hwnd=%p, cmd=%d, wasVisible %d\n", hwnd, cmd, wasVisible);
@@ -1117,7 +1117,9 @@ static BOOL show_window( HWND hwnd, INT cmd ) if (!IsWindow( hwnd )) goto done; }
- swp = USER_Driver->pShowWindow( hwnd, cmd, &newPos, swp ); + if (IsRectEmpty( &newPos )) new_swp = swp; + else new_swp = USER_Driver->pShowWindow( hwnd, cmd, &newPos, swp ); + swp = new_swp;
parent = GetAncestor( hwnd, GA_PARENT ); if (parent && !IsWindowVisible( parent ) && !(swp & SWP_STATECHANGED)) diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c index 1cb1bbbadc9..1c61d4eb76e 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -1385,7 +1385,6 @@ void CDECL ANDROID_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flag */ UINT CDECL ANDROID_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp ) { - if (IsRectEmpty( rect )) return swp; if (!IsIconic( hwnd )) return swp; /* always hide icons off-screen */ if (rect->left != -32000 || rect->top != -32000) diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index e7f5327fcdc..4e60189ead9 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -1798,7 +1798,6 @@ UINT CDECL macdrv_ShowWindow(HWND hwnd, INT cmd, RECT *rect, UINT swp) hwnd, data ? data->cocoa_window : NULL, cmd, wine_dbgstr_rect(rect), swp);
if (!data || !data->cocoa_window) goto done; - if (IsRectEmpty(rect)) goto done; if (GetWindowLongW(hwnd, GWL_STYLE) & WS_MINIMIZE) { if (rect->left != -32000 || rect->top != -32000) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index b3ae5c54408..c30fe6d39b0 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2560,7 +2560,6 @@ UINT CDECL X11DRV_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp ) struct x11drv_win_data *data = get_win_data( hwnd );
if (!data || !data->whole_window) goto done; - if (IsRectEmpty( rect )) goto done; if (style & WS_MINIMIZE) { if (((rect->left != -32000 || rect->top != -32000)) && hide_icon( data ))
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/driver.c | 2 +- dlls/user32/winpos.c | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/dlls/user32/driver.c b/dlls/user32/driver.c index 1c3b62eff2b..35e206f5e98 100644 --- a/dlls/user32/driver.c +++ b/dlls/user32/driver.c @@ -356,7 +356,7 @@ static void CDECL nulldrv_SetWindowText( HWND hwnd, LPCWSTR text )
static UINT CDECL nulldrv_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp ) { - return swp; + return ~0; /* use default implementation */ }
static LRESULT CDECL nulldrv_SysCommand( HWND hwnd, WPARAM wparam, LPARAM lparam ) diff --git a/dlls/user32/winpos.c b/dlls/user32/winpos.c index cf7e7914869..de5d50d4c3a 100644 --- a/dlls/user32/winpos.c +++ b/dlls/user32/winpos.c @@ -1118,7 +1118,16 @@ static BOOL show_window( HWND hwnd, INT cmd ) }
if (IsRectEmpty( &newPos )) new_swp = swp; - else new_swp = USER_Driver->pShowWindow( hwnd, cmd, &newPos, swp ); + else if ((new_swp = USER_Driver->pShowWindow( hwnd, cmd, &newPos, swp )) == ~0) + { + if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) new_swp = swp; + else if (IsIconic( hwnd ) && (newPos.left != -32000 || newPos.top != -32000)) + { + OffsetRect( &newPos, -32000 - newPos.left, -32000 - newPos.top ); + new_swp = swp & ~(SWP_NOMOVE | SWP_NOCLIENTMOVE); + } + else new_swp = swp; + } swp = new_swp;
parent = GetAncestor( hwnd, GA_PARENT );
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=90487
Your paranoid android.
=== debiant2 (32 bit Chinese:China report) ===
user32: input.c:2160: Test failed: GetRawInputBuffer returned 4 input.c:2155: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2160: Test failed: GetRawInputBuffer returned 0 input.c:2161: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2162: Test failed: Unexpected rawinput data: 0 input.c:2163: Test failed: Unexpected rawinput data: 0 input.c:2164: Test failed: Unexpected rawinput data: 0 input.c:2222: Test failed: GetRawInputData succeeded input.c:2223: Test failed: GetRawInputData returned deadbeef input.c:2336: Test failed: Spurious WM_INPUT messages
=== debiant2 (64 bit WoW report) ===
user32: input.c:2155: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2160: Test failed: GetRawInputBuffer returned 0 input.c:2161: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2162: Test failed: Unexpected rawinput data: 0 input.c:2163: Test failed: Unexpected rawinput data: 0 input.c:2164: Test failed: Unexpected rawinput data: 0 input.c:2222: Test failed: GetRawInputData succeeded input.c:2223: Test failed: GetRawInputData returned deadbeef input.c:2336: Test failed: Spurious WM_INPUT messages
When there's nothing to wait for.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/driver.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/user32/driver.c b/dlls/user32/driver.c index 35e206f5e98..cb9dda6a692 100644 --- a/dlls/user32/driver.c +++ b/dlls/user32/driver.c @@ -305,6 +305,7 @@ static void CDECL nulldrv_GetDC( HDC hdc, HWND hwnd, HWND top_win, const RECT *w static DWORD CDECL nulldrv_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, DWORD timeout, DWORD mask, DWORD flags ) { + if (!count && !timeout) return WAIT_TIMEOUT; return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL, timeout, flags & MWMO_ALERTABLE ); }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=90488
Your paranoid android.
=== debiant2 (32 bit Chinese:China report) ===
user32: input.c:2160: Test failed: GetRawInputBuffer returned 4 input.c:2155: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2160: Test failed: GetRawInputBuffer returned 0 input.c:2161: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2162: Test failed: Unexpected rawinput data: 0 input.c:2163: Test failed: Unexpected rawinput data: 0 input.c:2164: Test failed: Unexpected rawinput data: 0 input.c:2222: Test failed: GetRawInputData succeeded input.c:2223: Test failed: GetRawInputData returned deadbeef input.c:2336: Test failed: Spurious WM_INPUT messages
=== debiant2 (64 bit WoW report) ===
user32: input.c:2160: Test failed: GetRawInputBuffer returned 4 input.c:2155: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2160: Test failed: GetRawInputBuffer returned 0 input.c:2161: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2162: Test failed: Unexpected rawinput data: 0 input.c:2163: Test failed: Unexpected rawinput data: 0 input.c:2164: Test failed: Unexpected rawinput data: 0 input.c:2222: Test failed: GetRawInputData succeeded input.c:2223: Test failed: GetRawInputData returned deadbeef input.c:2336: Test failed: Spurious WM_INPUT messages
On 5/14/21 6:40 AM, Rémi Bernon wrote:
When there's nothing to wait for.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/user32/driver.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/user32/driver.c b/dlls/user32/driver.c index 35e206f5e98..cb9dda6a692 100644 --- a/dlls/user32/driver.c +++ b/dlls/user32/driver.c @@ -305,6 +305,7 @@ static void CDECL nulldrv_GetDC( HDC hdc, HWND hwnd, HWND top_win, const RECT *w static DWORD CDECL nulldrv_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, DWORD timeout, DWORD mask, DWORD flags ) {
- if (!count && !timeout) return WAIT_TIMEOUT; return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL, timeout, flags & MWMO_ALERTABLE ); }
Why is this necessary? In fact, won't this give wrong results if there is a queued message available?
On 5/14/21 5:54 PM, Zebediah Figura (she/her) wrote:
On 5/14/21 6:40 AM, Rémi Bernon wrote:
When there's nothing to wait for.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/user32/driver.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/user32/driver.c b/dlls/user32/driver.c index 35e206f5e98..cb9dda6a692 100644 --- a/dlls/user32/driver.c +++ b/dlls/user32/driver.c @@ -305,6 +305,7 @@ static void CDECL nulldrv_GetDC( HDC hdc, HWND hwnd, HWND top_win, const RECT *w static DWORD CDECL nulldrv_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, DWORD timeout, DWORD mask, DWORD flags ) { + if (!count && !timeout) return WAIT_TIMEOUT; return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL, timeout, flags & MWMO_ALERTABLE ); }
Why is this necessary? In fact, won't this give wrong results if there is a queued message available?
This is just the driver interface, winex11.drv returns the same thing when not in a X11 client thread, when there was no X11 event, or when events didn't get translated (which I think is not always very accurate).
Then only place where it would matter most is in wait_message, but it's usually called at least with the thread queue handle, so count >= 1 there.
Then it's otherwise called with count == 0 in PeekMessageW, only to try peeking again if the first peek failed and if the graphics driver indicated it received some events (if it didn't return WAIT_TIMEOUT).
This is making some test fail here with nulldrv, as it returns an error, and so we peek messages again although we should not.
It could maybe be made more robust and handle the error case in PeekMessageW, but I think it's better to make sure the graphics drivers behave similarly. It would be nice if this could be factored out but it seems difficult.
There's also another place where the return value is checked, which is in check_for_events, called when checking async key state, to decide whether to flush or not window surfaces but I don't think it matters.
For all other call sites, its return value isn't used.
On 5/14/21 11:14 AM, Rémi Bernon wrote:
On 5/14/21 5:54 PM, Zebediah Figura (she/her) wrote:
On 5/14/21 6:40 AM, Rémi Bernon wrote:
When there's nothing to wait for.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/user32/driver.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/user32/driver.c b/dlls/user32/driver.c index 35e206f5e98..cb9dda6a692 100644 --- a/dlls/user32/driver.c +++ b/dlls/user32/driver.c @@ -305,6 +305,7 @@ static void CDECL nulldrv_GetDC( HDC hdc, HWND hwnd, HWND top_win, const RECT *w static DWORD CDECL nulldrv_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, DWORD timeout, DWORD mask, DWORD flags ) { + if (!count && !timeout) return WAIT_TIMEOUT; return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL, timeout, flags & MWMO_ALERTABLE ); }
Why is this necessary? In fact, won't this give wrong results if there is a queued message available?
This is just the driver interface, winex11.drv returns the same thing when not in a X11 client thread, when there was no X11 event, or when events didn't get translated (which I think is not always very accurate).
Then only place where it would matter most is in wait_message, but it's usually called at least with the thread queue handle, so count >= 1 there.
Then it's otherwise called with count == 0 in PeekMessageW, only to
try
peeking again if the first peek failed and if the graphics driver indicated it received some events (if it didn't return WAIT_TIMEOUT).
This is making some test fail here with nulldrv, as it returns an error, and so we peek messages again although we should not.
It could maybe be made more robust and handle the error case in PeekMessageW, but I think it's better to make sure the graphics drivers behave similarly. It would be nice if this could be factored out but it seems difficult.
There's also another place where the return value is checked, which is in check_for_events, called when checking async key state, to decide whether to flush or not window surfaces but I don't think it matters.
For all other call sites, its return value isn't used.
Sorry, I see my mental error, yeah.
It does bother me that this condition includes "!timeout", but as you say that's true in winex11 too, and we never call it with a 0 count and nonzero timeout anyway.
(I'd still replace that with "if (!count) Sleep(timeout); return WAIT_TIMEOUT" if it were me, but...)
When high word is 0, and unless it has an explicit layout id.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/input.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/user32/input.c b/dlls/user32/input.c index 5d9bbe14cd6..ba0292c8f88 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -1548,7 +1548,8 @@ HKL WINAPI LoadKeyboardLayoutW( const WCHAR *name, UINT flags ) FIXME_(keyboard)( "name %s, flags %x, semi-stub!\n", debugstr_w( name ), flags );
tmp = wcstoul( name, NULL, 16 ); - layout = UlongToHandle( tmp ); + if (HIWORD( tmp )) layout = UlongToHandle( tmp ); + else layout = UlongToHandle( MAKELONG( LOWORD( tmp ), LOWORD( tmp ) ) );
wcscpy( layout_path, L"System\CurrentControlSet\Control\Keyboard Layouts\" ); wcscat( layout_path, name );
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=90489
Your paranoid android.
=== debiant2 (32 bit Chinese:China report) ===
user32: input.c:2160: Test failed: GetRawInputBuffer returned 4 input.c:2155: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2160: Test failed: GetRawInputBuffer returned 0 input.c:2161: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2162: Test failed: Unexpected rawinput data: 0 input.c:2163: Test failed: Unexpected rawinput data: 0 input.c:2164: Test failed: Unexpected rawinput data: 0 input.c:2222: Test failed: GetRawInputData succeeded input.c:2223: Test failed: GetRawInputData returned deadbeef input.c:2336: Test failed: Spurious WM_INPUT messages win.c:10178: Test failed: Expected foreground window 000E0120, got 00EB00D4 win.c:10180: Test failed: GetActiveWindow() = 00000000 win.c:10180: Test failed: GetFocus() = 00000000 win.c:10181: Test failed: Received WM_ACTIVATEAPP(1), did not expect it. win.c:10182: Test failed: Received WM_ACTIVATEAPP(0), did not expect it. win.c:10190: Test failed: Expected foreground window 000E0120, got 00000000 win.c:10192: Test failed: GetActiveWindow() = 00000000 win.c:10192: Test failed: GetFocus() = 00000000 win.c:10200: Test failed: Received WM_ACTIVATEAPP(1), did not expect it.
=== debiant2 (64 bit WoW report) ===
user32: input.c:2155: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2160: Test failed: GetRawInputBuffer returned 0 input.c:2161: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2162: Test failed: Unexpected rawinput data: 0 input.c:2163: Test failed: Unexpected rawinput data: 0 input.c:2164: Test failed: Unexpected rawinput data: 0 input.c:2222: Test failed: GetRawInputData succeeded input.c:2223: Test failed: GetRawInputData returned deadbeef input.c:2336: Test failed: Spurious WM_INPUT messages
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- programs/explorer/desktop.c | 20 ++++++++------------ programs/explorer/systray.c | 2 +- 2 files changed, 9 insertions(+), 13 deletions(-)
diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c index 51d1535aea6..2ba276f52cb 100644 --- a/programs/explorer/desktop.c +++ b/programs/explorer/desktop.c @@ -959,6 +959,7 @@ void manage_desktop( WCHAR *arg ) const WCHAR *name = NULL; BOOL enable_shell = FALSE; void (WINAPI *pShellDDEInit)( BOOL ) = NULL; + HMODULE shell32;
/* get the rest of the command line (if any) */ while (*p && !is_whitespace(*p)) p++; @@ -1028,20 +1029,15 @@ void manage_desktop( WCHAR *arg ) initialize_display_settings(); initialize_appbar();
- if (graphics_driver) - { - HMODULE shell32; - - if (using_root) enable_shell = FALSE; + if (using_root) enable_shell = FALSE;
- initialize_systray( graphics_driver, using_root, enable_shell ); - if (!using_root) initialize_launchers( hwnd ); + initialize_systray( graphics_driver, using_root, enable_shell ); + if (!using_root) initialize_launchers( hwnd );
- if ((shell32 = LoadLibraryW( L"shell32.dll" )) && - (pShellDDEInit = (void *)GetProcAddress( shell32, (LPCSTR)188))) - { - pShellDDEInit( TRUE ); - } + if ((shell32 = LoadLibraryW( L"shell32.dll" )) && + (pShellDDEInit = (void *)GetProcAddress( shell32, (LPCSTR)188))) + { + pShellDDEInit( TRUE ); } }
diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c index 161b4b57e58..0c978451151 100644 --- a/programs/explorer/systray.c +++ b/programs/explorer/systray.c @@ -900,7 +900,7 @@ void initialize_systray( HMODULE graphics_driver, BOOL using_root, BOOL arg_enab WNDCLASSEXW class; static const WCHAR classname[] = {'S','h','e','l','l','_','T','r','a','y','W','n','d',0};
- if (using_root) wine_notify_icon = (void *)GetProcAddress( graphics_driver, "wine_notify_icon" ); + if (using_root && graphics_driver) wine_notify_icon = (void *)GetProcAddress( graphics_driver, "wine_notify_icon" );
icon_cx = GetSystemMetrics( SM_CXSMICON ) + 2*ICON_BORDER; icon_cy = GetSystemMetrics( SM_CYSMICON ) + 2*ICON_BORDER;
Which creates an off-screen window surface for top-level non-layered or SLWA-layered windows.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- 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 cb9dda6a692..c4b4ecbcc46 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 db082462f1b..33baa6e861e 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 680defc2071..6dc88f8fd7b 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -22,6 +22,7 @@ #include <stdarg.h> #include <stdlib.h> #include <string.h> +#include <limits.h>
#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 de5d50d4c3a..21cebf99aa5 100644 --- a/dlls/user32/winpos.c +++ b/dlls/user32/winpos.c @@ -2114,8 +2114,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; @@ -2125,6 +2133,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; }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=90491
Your paranoid android.
=== debiant2 (32 bit Chinese:China report) ===
user32: input.c:2160: Test failed: GetRawInputBuffer returned 4 input.c:2155: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2160: Test failed: GetRawInputBuffer returned 0 input.c:2161: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2162: Test failed: Unexpected rawinput data: 0 input.c:2163: Test failed: Unexpected rawinput data: 0 input.c:2164: Test failed: Unexpected rawinput data: 0 input.c:2222: Test failed: GetRawInputData succeeded input.c:2223: Test failed: GetRawInputData returned deadbeef input.c:2336: Test failed: Spurious WM_INPUT messages
=== debiant2 (64 bit WoW report) ===
user32: input.c:2160: Test failed: GetRawInputBuffer returned 4 input.c:2155: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2160: Test failed: GetRawInputBuffer returned 0 input.c:2161: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2162: Test failed: Unexpected rawinput data: 0 input.c:2163: Test failed: Unexpected rawinput data: 0 input.c:2164: Test failed: Unexpected rawinput data: 0 input.c:2222: Test failed: GetRawInputData succeeded input.c:2223: Test failed: GetRawInputData returned deadbeef input.c:2336: Test failed: Spurious WM_INPUT messages
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=90486
Your paranoid android.
=== debiant2 (32 bit Chinese:China report) ===
user32: input.c:2160: Test failed: GetRawInputBuffer returned 4 input.c:2155: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2160: Test failed: GetRawInputBuffer returned 0 input.c:2161: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2162: Test failed: Unexpected rawinput data: 0 input.c:2163: Test failed: Unexpected rawinput data: 0 input.c:2164: Test failed: Unexpected rawinput data: 0 input.c:2222: Test failed: GetRawInputData succeeded input.c:2223: Test failed: GetRawInputData returned deadbeef input.c:2336: Test failed: Spurious WM_INPUT messages
=== debiant2 (64 bit WoW report) ===
user32: input.c:2160: Test failed: GetRawInputBuffer returned 4 input.c:2155: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2160: Test failed: GetRawInputBuffer returned 0 input.c:2161: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2162: Test failed: Unexpected rawinput data: 0 input.c:2163: Test failed: Unexpected rawinput data: 0 input.c:2164: Test failed: Unexpected rawinput data: 0 input.c:2222: Test failed: GetRawInputData succeeded input.c:2223: Test failed: GetRawInputData returned deadbeef input.c:2336: Test failed: Spurious WM_INPUT messages