From d86d39947ccbadb221c8416a00e842eb0961e332 Mon Sep 17 00:00:00 2001 From: James Tabor Date: Wed, 21 Oct 2015 00:13:23 +0000 Subject: [PATCH] [Win32SS] - Implement suspended window support, see CORE-10078. svn path=/trunk/; revision=69633 --- reactos/win32ss/user/ntuser/defwnd.c | 2 +- reactos/win32ss/user/ntuser/msgqueue.c | 30 +++++- reactos/win32ss/user/ntuser/msgqueue.h | 1 + reactos/win32ss/user/ntuser/nonclient.c | 40 +++++--- reactos/win32ss/user/ntuser/painting.c | 124 +++++++++++++++++++++++- reactos/win32ss/user/ntuser/painting.h | 1 + reactos/win32ss/user/ntuser/userfuncs.h | 2 +- 7 files changed, 180 insertions(+), 20 deletions(-) diff --git a/reactos/win32ss/user/ntuser/defwnd.c b/reactos/win32ss/user/ntuser/defwnd.c index 36cc914cb57..6336a4e102f 100644 --- a/reactos/win32ss/user/ntuser/defwnd.c +++ b/reactos/win32ss/user/ntuser/defwnd.c @@ -1094,7 +1094,7 @@ IntDefWindowProc( case WM_NCCALCSIZE: { - return NC_HandleNCCalcSize( Wnd, wParam, (RECTL *)lParam ); + return NC_HandleNCCalcSize( Wnd, wParam, (RECTL *)lParam, FALSE ); } case WM_NCACTIVATE: diff --git a/reactos/win32ss/user/ntuser/msgqueue.c b/reactos/win32ss/user/ntuser/msgqueue.c index dce1f9b131c..32c1253d3d2 100644 --- a/reactos/win32ss/user/ntuser/msgqueue.c +++ b/reactos/win32ss/user/ntuser/msgqueue.c @@ -1058,6 +1058,13 @@ co_MsqSendMessage(PTHREADINFO ptirec, return STATUS_UNSUCCESSFUL; } + if (IsThreadSuspended(ptirec)) + { + ERR("Sending to Suspended Thread Msg %lx\n",Msg); + if (uResult) *uResult = -1; + return STATUS_UNSUCCESSFUL; + } + // Should we do the same for No Wait? if ( HookMessage == MSQ_NORMAL ) { @@ -2037,7 +2044,28 @@ MsqIsHung(PTHREADINFO pti) LARGE_INTEGER LargeTickCount; KeQueryTickCount(&LargeTickCount); - return ((LargeTickCount.u.LowPart - pti->timeLast) > MSQ_HUNG); + + if ((LargeTickCount.u.LowPart - pti->timeLast) > MSQ_HUNG && + !(pti->pcti->fsWakeMask & QS_INPUT) && + !PsGetThreadFreezeCount(pti->pEThread) && + !(pti->ppi->W32PF_flags & W32PF_APPSTARTING)) + return TRUE; + + return FALSE; +} + +BOOL FASTCALL +IsThreadSuspended(PTHREADINFO pti) +{ + if (pti->pEThread) + { + BOOL Ret = TRUE; + ObReferenceObject(pti->pEThread); + if (!(pti->pEThread->Tcb.SuspendCount) && !PsGetThreadFreezeCount(pti->pEThread)) Ret = FALSE; + ObDereferenceObject(pti->pEThread); + return Ret; + } + return FALSE; } VOID diff --git a/reactos/win32ss/user/ntuser/msgqueue.h b/reactos/win32ss/user/ntuser/msgqueue.h index f7b92b48381..ca3c2a25738 100644 --- a/reactos/win32ss/user/ntuser/msgqueue.h +++ b/reactos/win32ss/user/ntuser/msgqueue.h @@ -251,6 +251,7 @@ VOID FASTCALL MsqWakeQueue(PTHREADINFO,DWORD,BOOL); VOID FASTCALL ClearMsgBitsMask(PTHREADINFO,UINT); BOOL FASTCALL IntCallMsgFilter(LPMSG,INT); WPARAM FASTCALL MsqGetDownKeyState(PUSER_MESSAGE_QUEUE); +BOOL FASTCALL IsThreadSuspended(PTHREADINFO); int UserShowCursor(BOOL bShow); PCURICON_OBJECT diff --git a/reactos/win32ss/user/ntuser/nonclient.c b/reactos/win32ss/user/ntuser/nonclient.c index 00c4398a9e3..14ffab20949 100644 --- a/reactos/win32ss/user/ntuser/nonclient.c +++ b/reactos/win32ss/user/ntuser/nonclient.c @@ -477,7 +477,12 @@ DefWndDoSizeMove(PWND pwnd, WORD wParam) UserDrawMovingFrame( hdc, &newRect, thickframe ); else { // Moving the whole window now! - PWND pwndTemp; + HRGN hrgnNew; + HRGN hrgnOrig = GreCreateRectRgnIndirect(&pwnd->rcWindow); + + if (pwnd->hrgnClip != NULL) + NtGdiCombineRgn(hrgnOrig, hrgnOrig, pwnd->hrgnClip, RGN_AND); + //// This causes the mdi child window to jump up when it is moved. //IntMapWindowPoints( 0, pWndParent, (POINT *)&rect, 2 ); co_WinPosSetWindowPos( pwnd, @@ -488,18 +493,29 @@ DefWndDoSizeMove(PWND pwnd, WORD wParam) newRect.bottom - newRect.top, ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 ); - // Update all the windows after the move or size, including this window. - for ( pwndTemp = pwnd->head.rpdesk->pDeskInfo->spwnd->spwndChild; - pwndTemp; - pwndTemp = pwndTemp->spwndNext ) + hrgnNew = GreCreateRectRgnIndirect(&pwnd->rcWindow); + if (pwnd->hrgnClip != NULL) + NtGdiCombineRgn(hrgnNew, hrgnNew, pwnd->hrgnClip, RGN_AND); + + if (hrgnNew) { - RECTL rect; - // Only the windows that overlap will be redrawn. - if (RECTL_bIntersectRect( &rect, &pwnd->rcWindow, &pwndTemp->rcWindow )) + if (hrgnOrig) + NtGdiCombineRgn(hrgnOrig, hrgnOrig, hrgnNew, RGN_DIFF); + } + else + { + if (hrgnOrig) { - co_UserRedrawWindow( pwndTemp, NULL, NULL, RDW_UPDATENOW | RDW_ALLCHILDREN); + GreDeleteObject(hrgnOrig); + hrgnOrig = 0; } } + + // Update all the windows after the move or size, including this window. + UpdateThreadWindows(UserGetDesktopWindow()->spwndChild, pti, hrgnOrig); + + if (hrgnOrig) GreDeleteObject(hrgnOrig); + if (hrgnNew) GreDeleteObject(hrgnNew); } } sizingRect = newRect; @@ -1163,7 +1179,7 @@ NC_DoNCPaint(PWND pWnd, HDC hDC, INT Flags) { TempRect = CurrentRect; TempRect.bottom = TempRect.top + menu->cyMenu; - CurrentRect.top += MENU_DrawMenuBar(hDC, &TempRect, pWnd, FALSE); + if (!(Flags & DC_NOSENDMSG)) CurrentRect.top += MENU_DrawMenuBar(hDC, &TempRect, pWnd, FALSE); } if (ExStyle & WS_EX_CLIENTEDGE) @@ -1214,7 +1230,7 @@ NC_DoNCPaint(PWND pWnd, HDC hDC, INT Flags) return 0; // For WM_NCPAINT message, return 0. } -LRESULT NC_HandleNCCalcSize( PWND Wnd, WPARAM wparam, RECTL *Rect ) +LRESULT NC_HandleNCCalcSize( PWND Wnd, WPARAM wparam, RECTL *Rect, BOOL Suspended ) { LRESULT Result = 0; SIZE WindowBorders; @@ -1277,7 +1293,7 @@ LRESULT NC_HandleNCCalcSize( PWND Wnd, WPARAM wparam, RECTL *Rect ) CliRect.right -= OrigRect.left; CliRect.left -= OrigRect.left; CliRect.top -= OrigRect.top; - Rect->top += MENU_DrawMenuBar(hDC, &CliRect, Wnd, TRUE); + if (!Suspended) Rect->top += MENU_DrawMenuBar(hDC, &CliRect, Wnd, TRUE); UserReleaseDC(Wnd, hDC, FALSE); } } diff --git a/reactos/win32ss/user/ntuser/painting.c b/reactos/win32ss/user/ntuser/painting.c index 94abd8a8dd4..0403d5f77c3 100644 --- a/reactos/win32ss/user/ntuser/painting.c +++ b/reactos/win32ss/user/ntuser/painting.c @@ -510,7 +510,7 @@ co_IntUpdateWindows(PWND Wnd, ULONG Flags, BOOL Recurse) { HWND hWnd = Wnd->head.h; - if ((Wnd->hrgnUpdate != NULL || Wnd->state & WNDS_INTERNALPAINT)) + if ( Wnd->hrgnUpdate != NULL || Wnd->state & WNDS_INTERNALPAINT ) { if (Wnd->hrgnUpdate) { @@ -1004,6 +1004,106 @@ co_UserRedrawWindow( return TRUE; } +VOID FASTCALL +PaintSuspendedWindow(PWND pwnd, HRGN hrgnOrig) +{ + if (pwnd->hrgnUpdate) + { + HDC hDC; + INT Flags = DC_NC|DC_NOSENDMSG; + HRGN hrgnTemp; + RECT Rect; + INT type; + PREGION prgn; + + if (pwnd->hrgnUpdate > HRGN_WINDOW) + { + hrgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0); + type = NtGdiCombineRgn( hrgnTemp, pwnd->hrgnUpdate, 0, RGN_COPY); + if (type == ERROR) + { + GreDeleteObject(hrgnTemp); + hrgnTemp = HRGN_WINDOW; + } + } + else + { + hrgnTemp = GreCreateRectRgnIndirect(&pwnd->rcWindow); + } + + if ( hrgnOrig && + hrgnTemp > HRGN_WINDOW && + NtGdiCombineRgn(hrgnTemp, hrgnTemp, hrgnOrig, RGN_AND) == NULLREGION) + { + GreDeleteObject(hrgnTemp); + return; + } + + hDC = UserGetDCEx(pwnd, hrgnTemp, DCX_WINDOW|DCX_INTERSECTRGN|DCX_USESTYLE|DCX_KEEPCLIPRGN); + + Rect = pwnd->rcWindow; + RECTL_vOffsetRect(&Rect, -pwnd->rcWindow.left, -pwnd->rcWindow.top); + + // Clear out client area! + FillRect(hDC, &Rect, IntGetSysColorBrush(COLOR_WINDOW)); + + NC_DoNCPaint(pwnd, hDC, Flags); // Redraw without MENUs. + + UserReleaseDC(pwnd, hDC, FALSE); + + prgn = REGION_LockRgn(hrgnTemp); + IntInvalidateWindows(pwnd, prgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN); + REGION_UnlockRgn(prgn); + + // Set updates for this window. + pwnd->state |= WNDS_SENDNCPAINT|WNDS_SENDERASEBACKGROUND|WNDS_UPDATEDIRTY; + + // DCX_KEEPCLIPRGN is set. Check it anyway. + if (hrgnTemp > HRGN_WINDOW && GreIsHandleValid(hrgnTemp)) GreDeleteObject(hrgnTemp); + } +} + +VOID FASTCALL +UpdateTheadChildren(PWND pWnd, HRGN hRgn) +{ + PaintSuspendedWindow( pWnd, hRgn ); + + if (!(pWnd->style & WS_CLIPCHILDREN)) + return; + + pWnd = pWnd->spwndChild; // invalidate children if any. + while (pWnd) + { + UpdateTheadChildren( pWnd, hRgn ); + pWnd = pWnd->spwndNext; + } +} + +VOID FASTCALL +UpdateThreadWindows(PWND pWnd, PTHREADINFO pti, HRGN hRgn) +{ + PWND pwndTemp; + + for ( pwndTemp = pWnd; + pwndTemp; + pwndTemp = pwndTemp->spwndNext ) + { + if (pwndTemp->head.pti == pti) + { + UserUpdateWindows(pwndTemp, RDW_ALLCHILDREN); + } + else + { + if (IsThreadSuspended(pwndTemp->head.pti)) + { + UpdateTheadChildren(pwndTemp, hRgn); + } + else + UserUpdateWindows(pwndTemp, RDW_ALLCHILDREN); + } + } +} + BOOL FASTCALL IntIsWindowDirty(PWND Wnd) { @@ -1631,7 +1731,7 @@ co_UserGetUpdateRgn(PWND Window, HRGN hRgn, BOOL bErase) { if (hrgnTemp) GreDeleteObject(hrgnTemp); NtGdiSetRectRgn(hRgn, 0, 0, 0, 0); - return NULLREGION; + return RegionType; } if (Window != UserGetDesktopWindow()) // Window->fnid == FNID_DESKTOP @@ -1684,9 +1784,23 @@ co_UserGetUpdateRect(PWND Window, PRECT pRect, BOOL bErase) if (IntIntersectWithParents(Window, pRect)) { - RECTL_vOffsetRect(pRect, - -Window->rcClient.left, - -Window->rcClient.top); + if (Window != UserGetDesktopWindow()) // Window->fnid == FNID_DESKTOP + { + RECTL_vOffsetRect(pRect, + -Window->rcClient.left, + -Window->rcClient.top); + } + if (Window->pcls->style & CS_OWNDC) + { + HDC hdc; + //DWORD layout; + hdc = UserGetDCEx(Window, NULL, DCX_USESTYLE); + //layout = NtGdiSetLayout(hdc, -1, 0); + //IntMapWindowPoints( 0, Window, (LPPOINT)pRect, 2 ); + GreDPtoLP( hdc, (LPPOINT)pRect, 2 ); + //NtGdiSetLayout(hdc, -1, layout); + UserReleaseDC(Window, hdc, FALSE); + } } else { diff --git a/reactos/win32ss/user/ntuser/painting.h b/reactos/win32ss/user/ntuser/painting.h index e70183b6e6e..e1ceb21f860 100644 --- a/reactos/win32ss/user/ntuser/painting.h +++ b/reactos/win32ss/user/ntuser/painting.h @@ -35,4 +35,5 @@ BOOL FASTCALL IntFlashWindowEx(PWND,PFLASHWINFO); BOOL FASTCALL IntIntersectWithParents(PWND, RECTL *); BOOL FASTCALL IntIsWindowDrawable(PWND); BOOL UserDrawCaption(PWND,HDC,RECTL*,HFONT,HICON,const PUNICODE_STRING,UINT); +VOID FASTCALL UpdateThreadWindows(PWND,PTHREADINFO,HRGN); diff --git a/reactos/win32ss/user/ntuser/userfuncs.h b/reactos/win32ss/user/ntuser/userfuncs.h index 34e1408b04a..e3067ceb3f4 100644 --- a/reactos/win32ss/user/ntuser/userfuncs.h +++ b/reactos/win32ss/user/ntuser/userfuncs.h @@ -131,7 +131,7 @@ VOID FASTCALL DefWndDoSizeMove(PWND pwnd, WORD wParam); LRESULT NC_DoNCPaint(PWND,HDC,INT); void FASTCALL NC_GetSysPopupPos(PWND, RECT *); LRESULT NC_HandleNCActivate( PWND Wnd, WPARAM wParam, LPARAM lParam ); -LRESULT NC_HandleNCCalcSize( PWND wnd, WPARAM wparam, RECTL *winRect ); +LRESULT NC_HandleNCCalcSize( PWND wnd, WPARAM wparam, RECTL *winRect, BOOL Suspended ); VOID NC_DrawFrame( HDC hDC, RECT *CurrentRect, BOOL Active, DWORD Style, DWORD ExStyle); VOID UserDrawCaptionBar( PWND pWnd, HDC hDC, INT Flags); void UserGetInsideRectNC(PWND Wnd, RECT *rect);