From 115d07d6866a440f62995f6f9376abcaafae04cb Mon Sep 17 00:00:00 2001 From: James Tabor Date: Fri, 18 Mar 2011 22:41:22 +0000 Subject: [PATCH] [Win32k] - Implement the set of DeferWindowPos functions. Regedit (one of many application) uses it and allocated three when it should be four. This was a good test to verify the batch list growing routine. Instead of drawing per DeferWindowPos call, now a real list is created and run down as a batch. - ReactOS should handle this the correct way and a good test case is located here: http://bugs.winehq.org/show_bug.cgi?id=23187 - The code is from wine and modified for the use in ReactOS. svn path=/trunk/; revision=51089 --- reactos/dll/win32/user32/windows/window.c | 24 +-- reactos/include/reactos/win32k/ntuser.h | 4 +- .../subsystems/win32/win32k/include/winpos.h | 29 +++ .../subsystems/win32/win32k/ntuser/ntstubs.c | 33 +-- .../subsystems/win32/win32k/ntuser/object.c | 1 + .../win32/win32k/ntuser/simplecall.c | 32 +++ .../subsystems/win32/win32k/ntuser/winpos.c | 198 ++++++++++++++++++ 7 files changed, 265 insertions(+), 56 deletions(-) diff --git a/reactos/dll/win32/user32/windows/window.c b/reactos/dll/win32/user32/windows/window.c index 2025d815617..4cc757fcf5f 100644 --- a/reactos/dll/win32/user32/windows/window.c +++ b/reactos/dll/win32/user32/windows/window.c @@ -65,17 +65,7 @@ AllowSetForegroundWindow(DWORD dwProcessId) HDWP WINAPI BeginDeferWindowPos(int nNumWindows) { - if (nNumWindows < 0) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } -#if 0 - UNIMPLEMENTED; - return (HDWP)0; -#else - return (HDWP)1; -#endif + return (HDWP)NtUserCallOneParam((DWORD_PTR)nNumWindows, ONEPARAM_ROUTINE_BEGINDEFERWNDPOS); } @@ -567,12 +557,7 @@ DeferWindowPos(HDWP hWinPosInfo, int cy, UINT uFlags) { -#if 0 return NtUserDeferWindowPos(hWinPosInfo, hWnd, hWndInsertAfter, x, y, cx, cy, uFlags); -#else - SetWindowPos(hWnd, hWndInsertAfter, x, y, cx, cy, uFlags); - return hWinPosInfo; -#endif } @@ -582,12 +567,7 @@ DeferWindowPos(HDWP hWinPosInfo, BOOL WINAPI EndDeferWindowPos(HDWP hWinPosInfo) { -#if 0 - UNIMPLEMENTED; - return FALSE; -#else - return TRUE; -#endif + return NtUserEndDeferWindowPosEx(hWinPosInfo, 0); } diff --git a/reactos/include/reactos/win32k/ntuser.h b/reactos/include/reactos/win32k/ntuser.h index d9f28d6fa0e..484a3a4b84c 100644 --- a/reactos/include/reactos/win32k/ntuser.h +++ b/reactos/include/reactos/win32k/ntuser.h @@ -1631,10 +1631,10 @@ NtUserEnableScrollBar( UINT wSBflags, UINT wArrows); -DWORD +BOOL NTAPI NtUserEndDeferWindowPosEx( - DWORD Unknown0, + HDWP WinPosInfo, DWORD Unknown1); BOOL NTAPI diff --git a/reactos/subsystems/win32/win32k/include/winpos.h b/reactos/subsystems/win32/win32k/include/winpos.h index 7f1c52a4124..a230972ab5a 100644 --- a/reactos/subsystems/win32/win32k/include/winpos.h +++ b/reactos/subsystems/win32/win32k/include/winpos.h @@ -1,5 +1,32 @@ #pragma once +typedef struct _CVR // Tag Ussw +{ + WINDOWPOS pos; + LONG xClientNew; + LONG yClientNew; + LONG cxClientNew; + LONG cyClientNew; + RECT rcBlt; + LONG dxBlt; + LONG dyBlt; + UINT fsRE; + HRGN hrgnVisOld; + PTHREADINFO pti; + HRGN hrgnClip; + HRGN hrgnInterMonitor; +} CVR, *PCVR; + +typedef struct _SMWP +{ + HEAD head; + UINT bShellNotify:1; + UINT bHandle:1; + INT ccvr; + INT ccvrAlloc; + PCVR acvr; +} SMWP, *PSMWP; + #define IntPtInWindow(WndObject,x,y) \ ((x) >= (WndObject)->rcWindow.left && \ (x) < (WndObject)->rcWindow.right && \ @@ -36,3 +63,5 @@ VOID FASTCALL co_WinPosActivateOtherWindow(PWND Window); VOID FASTCALL WinPosInitInternalPos(PWND WindowObject, POINT *pt, RECTL *RestoreRect); +BOOL FASTCALL IntEndDeferWindowPosEx(HDWP); +HDWP FASTCALL IntDeferWindowPos(HDWP,HWND,HWND,INT,INT,INT,INT,UINT); diff --git a/reactos/subsystems/win32/win32k/ntuser/ntstubs.c b/reactos/subsystems/win32/win32k/ntuser/ntstubs.c index 7d405821102..774ee67e84b 100644 --- a/reactos/subsystems/win32/win32k/ntuser/ntstubs.c +++ b/reactos/subsystems/win32/win32k/ntuser/ntstubs.c @@ -1168,18 +1168,6 @@ NtUserDrawMenuBarTemp( return 0; } -/* - * @unimplemented - */ -DWORD APIENTRY -NtUserEndDeferWindowPosEx(DWORD Unknown0, - DWORD Unknown1) -{ - UNIMPLEMENTED - - return 0; -} - /* * FillWindow: Called from User; Dialog, Edit and ListBox procs during a WM_ERASEBKGND. */ @@ -1205,7 +1193,7 @@ NtUserFlashWindowEx(IN PFLASHWINFO pfwi) { UNIMPLEMENTED - return 0; + return 1; } /* @@ -1305,25 +1293,6 @@ NtUserWindowFromPhysicalPoint(POINT Point) return NULL; } -/* - * @unimplemented - */ -HDWP APIENTRY -NtUserDeferWindowPos(HDWP WinPosInfo, - HWND Wnd, - HWND WndInsertAfter, - int x, - int y, - int cx, - int cy, - UINT Flags) -{ - UNIMPLEMENTED - - return 0; -} - - /* * NtUserResolveDesktopForWOW * diff --git a/reactos/subsystems/win32/win32k/ntuser/object.c b/reactos/subsystems/win32/win32k/ntuser/object.c index 8376f0bfd84..4df5c8f8f6d 100644 --- a/reactos/subsystems/win32/win32k/ntuser/object.c +++ b/reactos/subsystems/win32/win32k/ntuser/object.c @@ -177,6 +177,7 @@ UserHandleOwnerByType(USER_OBJECT_TYPE type) case otHook: case otCallProc: case otAccel: + case otSMWP: pi = GetW32ProcessInfo(); break; diff --git a/reactos/subsystems/win32/win32k/ntuser/simplecall.c b/reactos/subsystems/win32/win32k/ntuser/simplecall.c index 2c4844f0e98..1e74111f4f5 100644 --- a/reactos/subsystems/win32/win32k/ntuser/simplecall.c +++ b/reactos/subsystems/win32/win32k/ntuser/simplecall.c @@ -157,6 +157,38 @@ NtUserCallOneParam( MsqPostQuitMessage(pti->MessageQueue, Param); RETURN(TRUE); } + + case ONEPARAM_ROUTINE_BEGINDEFERWNDPOS: + { + PSMWP psmwp; + HDWP hDwp = NULL; + if (Param < 0) + { + EngSetLastError(ERROR_INVALID_PARAMETER); + RETURN(0); + } + /* Windows allows zero count, in which case it allocates context for 8 moves */ + if (Param == 0) Param = 8; + + psmwp = (PSMWP) UserCreateObject( gHandleTable, + NULL, + (PHANDLE)&hDwp, + otSMWP, + sizeof(SMWP)); + if (!psmwp) RETURN(0); + psmwp->acvr = ExAllocatePoolWithTag(PagedPool, Param * sizeof(CVR), USERTAG_SWP); + if (!psmwp->acvr) + { + UserDeleteObject(hDwp, otSMWP); + RETURN(0); + } + RtlZeroMemory(psmwp->acvr, Param * sizeof(CVR)); + psmwp->bHandle = TRUE; + psmwp->ccvr = 0; // actualCount + psmwp->ccvrAlloc = Param; // suggestedCount + RETURN((DWORD_PTR)hDwp); + } + case ONEPARAM_ROUTINE_SHOWCURSOR: RETURN( (DWORD_PTR)UserShowCursor((BOOL)Param) ); diff --git a/reactos/subsystems/win32/win32k/ntuser/winpos.c b/reactos/subsystems/win32/win32k/ntuser/winpos.c index 6a9dfd2b169..0d6b268bdb0 100644 --- a/reactos/subsystems/win32/win32k/ntuser/winpos.c +++ b/reactos/subsystems/win32/win32k/ntuser/winpos.c @@ -1673,6 +1673,204 @@ co_WinPosWindowFromPoint(PWND ScopeWin, POINT *WinPoint, USHORT* HitTest) return Window; } +HDWP +FASTCALL +IntDeferWindowPos( HDWP hdwp, + HWND hwnd, + HWND hwndAfter, + INT x, + INT y, + INT cx, + INT cy, + UINT flags ) +{ + PSMWP pDWP; + int i; + HDWP retvalue = hdwp; + + DPRINT("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n", + hdwp, hwnd, hwndAfter, x, y, cx, cy, flags); + + if (flags & ~(SWP_NOSIZE | SWP_NOMOVE | + SWP_NOZORDER | SWP_NOREDRAW | + SWP_NOACTIVATE | SWP_NOCOPYBITS | + SWP_NOOWNERZORDER|SWP_SHOWWINDOW | + SWP_HIDEWINDOW | SWP_FRAMECHANGED)) + { + EngSetLastError(ERROR_INVALID_PARAMETER); + return NULL; + } + + if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, otSMWP))) + { + EngSetLastError(ERROR_INVALID_DWP_HANDLE); + return NULL; + } + + for (i = 0; i < pDWP->ccvr; i++) + { + if (pDWP->acvr[i].pos.hwnd == hwnd) + { + /* Merge with the other changes */ + if (!(flags & SWP_NOZORDER)) + { + pDWP->acvr[i].pos.hwndInsertAfter = hwndAfter; + } + if (!(flags & SWP_NOMOVE)) + { + pDWP->acvr[i].pos.x = x; + pDWP->acvr[i].pos.y = y; + } + if (!(flags & SWP_NOSIZE)) + { + pDWP->acvr[i].pos.cx = cx; + pDWP->acvr[i].pos.cy = cy; + } + pDWP->acvr[i].pos.flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE | + SWP_NOZORDER | SWP_NOREDRAW | + SWP_NOACTIVATE | SWP_NOCOPYBITS| + SWP_NOOWNERZORDER); + pDWP->acvr[i].pos.flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW | + SWP_FRAMECHANGED); + goto END; + } + } + if (pDWP->ccvr >= pDWP->ccvrAlloc) + { + PCVR newpos = ExAllocatePoolWithTag(PagedPool, pDWP->ccvrAlloc * 2 * sizeof(CVR), USERTAG_SWP); + if (!newpos) + { + retvalue = NULL; + goto END; + } + RtlZeroMemory(newpos, pDWP->ccvrAlloc * 2 * sizeof(CVR)); + RtlCopyMemory(newpos, pDWP->acvr, pDWP->ccvrAlloc * sizeof(CVR)); + ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP); + pDWP->ccvrAlloc *= 2; + pDWP->acvr = newpos; + } + pDWP->acvr[pDWP->ccvr].pos.hwnd = hwnd; + pDWP->acvr[pDWP->ccvr].pos.hwndInsertAfter = hwndAfter; + pDWP->acvr[pDWP->ccvr].pos.x = x; + pDWP->acvr[pDWP->ccvr].pos.y = y; + pDWP->acvr[pDWP->ccvr].pos.cx = cx; + pDWP->acvr[pDWP->ccvr].pos.cy = cy; + pDWP->acvr[pDWP->ccvr].pos.flags = flags; + pDWP->acvr[pDWP->ccvr].hrgnClip = NULL; + pDWP->acvr[pDWP->ccvr].hrgnInterMonitor = NULL; + pDWP->ccvr++; +END: + return retvalue; +} + +BOOL FASTCALL IntEndDeferWindowPosEx( HDWP hdwp ) +{ + PSMWP pDWP; + PCVR winpos; + BOOL res = TRUE; + int i; + + DPRINT("%p\n", hdwp); + + if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, otSMWP))) + { + EngSetLastError(ERROR_INVALID_DWP_HANDLE); + return FALSE; + } + + for (i = 0, winpos = pDWP->acvr; res && i < pDWP->ccvr; i++, winpos++) + { + DPRINT("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n", + winpos->pos.hwnd, winpos->pos.hwndInsertAfter, winpos->pos.x, winpos->pos.y, + winpos->pos.cx, winpos->pos.cy, winpos->pos.flags); + + res = co_WinPosSetWindowPos( UserGetWindowObject(winpos->pos.hwnd), + winpos->pos.hwndInsertAfter, + winpos->pos.x, + winpos->pos.y, + winpos->pos.cx, + winpos->pos.cy, + winpos->pos.flags); + } + ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP); + UserDeleteObject(hdwp, otSMWP); + return res; +} + +/* + * @implemented + */ +BOOL APIENTRY +NtUserEndDeferWindowPosEx(HDWP WinPosInfo, + DWORD Unknown1) +{ + BOOL Ret; + DPRINT("Enter NtUserEndDeferWindowPosEx\n"); + UserEnterExclusive(); + Ret = IntEndDeferWindowPosEx(WinPosInfo); + DPRINT("Leave NtUserEndDeferWindowPosEx, ret=%i\n", Ret); + UserLeave(); + return Ret; +} + +/* + * @implemented + */ +HDWP APIENTRY +NtUserDeferWindowPos(HDWP WinPosInfo, + HWND Wnd, + HWND WndInsertAfter, + int x, + int y, + int cx, + int cy, + UINT Flags) +{ + PWND pWnd, pWndIA; + HDWP Ret = NULL; + UINT Tmp = ~(SWP_ASYNCWINDOWPOS|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_NOREPOSITION| + SWP_NOCOPYBITS|SWP_HIDEWINDOW|SWP_SHOWWINDOW|SWP_FRAMECHANGED| + SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE); + + DPRINT("Enter NtUsereferWindowPos\n"); + UserEnterExclusive(); + + if ( Flags & Tmp ) + { + EngSetLastError(ERROR_INVALID_FLAGS); + goto Exit; + } + + pWnd = UserGetWindowObject(Wnd); + if ( !pWnd || + pWnd == IntGetDesktopWindow() || + pWnd == IntGetMessageWindow() ) + { + goto Exit; + } + + if ( WndInsertAfter && + WndInsertAfter != HWND_BOTTOM && + WndInsertAfter != HWND_TOPMOST && + WndInsertAfter != HWND_NOTOPMOST ) + { + pWndIA = UserGetWindowObject(WndInsertAfter); + if ( !pWndIA || + pWndIA == IntGetDesktopWindow() || + pWndIA == IntGetMessageWindow() ) + { + goto Exit; + } + } + + Ret = IntDeferWindowPos(WinPosInfo, Wnd, WndInsertAfter, x, y, cx, cy, Flags); + +Exit: + DPRINT("Leave NtUserDeferWindowPos, ret=%i\n", Ret); + UserLeave(); + return Ret; +} + BOOL APIENTRY NtUserGetMinMaxInfo( -- 2.17.1