[Win32SS]
authorJames Tabor <james.tabor@reactos.org>
Wed, 21 Oct 2015 00:13:23 +0000 (00:13 +0000)
committerJames Tabor <james.tabor@reactos.org>
Wed, 21 Oct 2015 00:13:23 +0000 (00:13 +0000)
- Implement suspended window support, see CORE-10078.

svn path=/trunk/; revision=69633

reactos/win32ss/user/ntuser/defwnd.c
reactos/win32ss/user/ntuser/msgqueue.c
reactos/win32ss/user/ntuser/msgqueue.h
reactos/win32ss/user/ntuser/nonclient.c
reactos/win32ss/user/ntuser/painting.c
reactos/win32ss/user/ntuser/painting.h
reactos/win32ss/user/ntuser/userfuncs.h

index 36cc914..6336a4e 100644 (file)
@@ -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:
index dce1f9b..32c1253 100644 (file)
@@ -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
index f7b92b4..ca3c2a2 100644 (file)
@@ -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
index 00c4398..14ffab2 100644 (file)
@@ -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);
          }
       }
index 94abd8a..0403d5f 100644 (file)
@@ -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
       {
index e70183b..e1ceb21 100644 (file)
@@ -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);
 
index 34e1408..e3067ce 100644 (file)
@@ -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);