From f7b2e1360967df7c6e242968ce5c4076bbff3593 Mon Sep 17 00:00:00 2001 From: James Tabor Date: Mon, 22 Aug 2016 13:28:02 +0000 Subject: [PATCH] [NtUser] - Defer the changing of the window region while setting the window position. - Patch based on Stefano Toncich work. See CORE-6897 and possibly CORE-7229. svn path=/trunk/; revision=72429 --- reactos/win32ss/user/ntuser/winpos.c | 122 ++++++++++++++++++++++----- 1 file changed, 102 insertions(+), 20 deletions(-) diff --git a/reactos/win32ss/user/ntuser/winpos.c b/reactos/win32ss/user/ntuser/winpos.c index 868280fa774..43ba8767803 100644 --- a/reactos/win32ss/user/ntuser/winpos.c +++ b/reactos/win32ss/user/ntuser/winpos.c @@ -32,6 +32,40 @@ VOID FASTCALL IntLinkWindow(PWND Wnd,PWND WndInsertAfter); /* FUNCTIONS *****************************************************************/ +#if DBG +/*********************************************************************** + * dump_winpos_flags + */ +static void dump_winpos_flags(UINT flags) +{ + static const DWORD dumped_flags = (SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | + SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_SHOWWINDOW | + SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOOWNERZORDER | + SWP_NOSENDCHANGING | SWP_DEFERERASE | SWP_ASYNCWINDOWPOS | + SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_STATECHANGED); + TRACE("flags:"); + if(flags & SWP_NOSIZE) TRACE(" SWP_NOSIZE"); + if(flags & SWP_NOMOVE) TRACE(" SWP_NOMOVE"); + if(flags & SWP_NOZORDER) TRACE(" SWP_NOZORDER"); + if(flags & SWP_NOREDRAW) TRACE(" SWP_NOREDRAW"); + if(flags & SWP_NOACTIVATE) TRACE(" SWP_NOACTIVATE"); + if(flags & SWP_FRAMECHANGED) TRACE(" SWP_FRAMECHANGED"); + if(flags & SWP_SHOWWINDOW) TRACE(" SWP_SHOWWINDOW"); + if(flags & SWP_HIDEWINDOW) TRACE(" SWP_HIDEWINDOW"); + if(flags & SWP_NOCOPYBITS) TRACE(" SWP_NOCOPYBITS"); + if(flags & SWP_NOOWNERZORDER) TRACE(" SWP_NOOWNERZORDER"); + if(flags & SWP_NOSENDCHANGING) TRACE(" SWP_NOSENDCHANGING"); + if(flags & SWP_DEFERERASE) TRACE(" SWP_DEFERERASE"); + if(flags & SWP_ASYNCWINDOWPOS) TRACE(" SWP_ASYNCWINDOWPOS"); + if(flags & SWP_NOCLIENTSIZE) TRACE(" SWP_NOCLIENTSIZE"); + if(flags & SWP_NOCLIENTMOVE) TRACE(" SWP_NOCLIENTMOVE"); + if(flags & SWP_STATECHANGED) TRACE(" SWP_STATECHANGED"); + + if(flags & ~dumped_flags) TRACE(" %08x", flags & ~dumped_flags); + TRACE("\n"); +} +#endif + BOOL FASTCALL IntGetClientOrigin(PWND Window OPTIONAL, LPPOINT Point) { @@ -220,6 +254,30 @@ PWND FASTCALL IntGetLastTopMostWindow(VOID) return NULL; } +VOID +SelectWindowRgn( PWND Window, HRGN hRgnClip) +{ + if (Window->hrgnClip) + { + /* Delete no longer needed region handle */ + IntGdiSetRegionOwner(Window->hrgnClip, GDI_OBJ_HMGR_POWNED); + GreDeleteObject(Window->hrgnClip); + Window->hrgnClip = NULL; + } + + if (hRgnClip > HRGN_WINDOW) + { + /*if (Window != UserGetDesktopWindow()) // Window->fnid != FNID_DESKTOP) + { + NtGdiOffsetRgn(hRgnClip, Window->rcWindow.left, Window->rcWindow.top); + }*/ + /* Set public ownership */ + IntGdiSetRegionOwner(hRgnClip, GDI_OBJ_HMGR_PUBLIC); + + Window->hrgnClip = hRgnClip; + } +} + // // This helps with CORE-6129 forcing modal dialog active when another app is minimized or closed. // @@ -1758,11 +1816,17 @@ co_WinPosSetWindowPos( HDC Dc; RECTL CopyRect; PWND Ancestor; - BOOL bPointerInWindow; + BOOL bPointerInWindow, PosChanged = FALSE; //PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); ASSERT_REFS_CO(Window); + TRACE("pwnd %p, after %p, %d,%d (%dx%d), flags %s", + Window, WndInsertAfter, x, y, cx, cy, flags); +#if DBG + dump_winpos_flags(flags); +#endif + /* FIXME: Get current active window from active queue. Why? since r2915. */ bPointerInWindow = IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y); @@ -1862,6 +1926,13 @@ co_WinPosSetWindowPos( } } + //// HACK 3 + if (Window->hrgnNewFrame) + { + SelectWindowRgn( Window, Window->hrgnNewFrame ); // Should be PSMWP->acvr->hrgnClip + Window->hrgnNewFrame = NULL; + } + WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect, valid_rects); // ERR("co_WinPosDoNCCALCSize returned 0x%x\n valid dest: %d %d %d %d\n valid src : %d %d %d %d\n", WvrFlags, @@ -1884,6 +1955,7 @@ co_WinPosSetWindowPos( WinPosInternalMoveWindow(Window, NewClientRect.left - OldClientRect.left, NewClientRect.top - OldClientRect.top); + PosChanged = TRUE; } Window->rcWindow = NewWindowRect; @@ -1951,11 +2023,12 @@ co_WinPosSetWindowPos( * class need to be completely repainted on (horizontal/vertical) size * change. */ - if ( VisBefore != NULL && - VisAfter != NULL && - !(WinPos.flags & SWP_NOCOPYBITS) && - ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)) && - !(Window->ExStyle & WS_EX_TRANSPARENT) ) + if ( ( VisBefore != NULL && + VisAfter != NULL && + !(WinPos.flags & SWP_NOCOPYBITS) && + ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)) && + !(Window->ExStyle & WS_EX_TRANSPARENT) ) || + ( !PosChanged && (WinPos.flags & SWP_FRAMECHANGED) && VisBefore) ) { /* @@ -2000,8 +2073,9 @@ co_WinPosSetWindowPos( REGION_Delete(CopyRgn); CopyRgn = NULL; } - else if (OldWindowRect.left != NewWindowRect.left || - OldWindowRect.top != NewWindowRect.top) + else if ( OldWindowRect.left != NewWindowRect.left || + OldWindowRect.top != NewWindowRect.top || + (WinPos.flags & SWP_FRAMECHANGED) ) { HRGN DcRgn = NtGdiCreateRectRgn(0, 0, 0, 0); PREGION DcRgnObj = REGION_LockRgn(DcRgn); @@ -2041,7 +2115,19 @@ co_WinPosSetWindowPos( { CopyRgn = NULL; } - +#if 0 + /////// Fixes NoPopup tests but breaks msg_paint tests. + if ( !PosChanged && (WinPos.flags & SWP_FRAMECHANGED) && VisBefore) + { + PWND Parent = Window->spwndParent; + ERR("SWP_FRAMECHANGED no chg\n"); + if ( !(Window->style & WS_CHILD) && (Parent) && (Parent->style & WS_CLIPCHILDREN)) + { + ERR("SWP_FRAMECHANGED Parent WS_CLIPCHILDREN\n"); + //IntInvalidateWindows( Window, VisBefore, /*RDW_ERASE |*/ RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); + } + } +#endif /* We need to redraw what wasn't visible before */ if (VisAfter != NULL) { @@ -3303,20 +3389,16 @@ NtUserSetWindowRgn( RETURN( 0); } - if (Window->hrgnClip) - { - /* Delete no longer needed region handle */ - IntGdiSetRegionOwner(Window->hrgnClip, GDI_OBJ_HMGR_POWNED); - GreDeleteObject(Window->hrgnClip); - } - + //// HACK 1 : Work around the lack of supporting DeferWindowPos. if (hrgnCopy) { - /* Set public ownership */ - IntGdiSetRegionOwner(hrgnCopy, GDI_OBJ_HMGR_PUBLIC); + Window->hrgnNewFrame = hrgnCopy; // Should be PSMWP->acvr->hrgnClip } - Window->hrgnClip = hrgnCopy; - + else + { + Window->hrgnNewFrame = (HRGN) 1; + } + //// HACK 2 Ret = co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, bRedraw ? flags : (flags|SWP_NOREDRAW) ); RETURN( (INT)Ret);