xref: /reactos/win32ss/user/ntuser/nonclient.c (revision cdf90707)
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS Win32k subsystem
4  * PURPOSE:          Miscellaneous User functions
5  * FILE:             win32ss/user/ntuser/nonclient.c
6  * PROGRAMER:
7  */
8 
9 #include <win32k.h>
10 #include <windowsx.h>
11 
12 DBG_DEFAULT_CHANNEL(UserDefwnd);
13 
14 #define UserHasDlgFrameStyle(Style, ExStyle)                                   \
15  (((ExStyle) & WS_EX_DLGMODALFRAME) ||                                         \
16   (((Style) & WS_DLGFRAME) && (!((Style) & WS_THICKFRAME))))
17 
18 #define UserHasThickFrameStyle(Style, ExStyle)                                 \
19   (((Style) & WS_THICKFRAME) &&                                                \
20    (!(((Style) & (WS_DLGFRAME | WS_BORDER)) == WS_DLGFRAME)))
21 
22 #define UserHasThinFrameStyle(Style, ExStyle)                                  \
23   (((Style) & WS_BORDER) || (!((Style) & (WS_CHILD | WS_POPUP))))
24 
25 #define ON_LEFT_BORDER(hit) \
26  (((hit) == HTLEFT) || ((hit) == HTTOPLEFT) || ((hit) == HTBOTTOMLEFT))
27 #define ON_RIGHT_BORDER(hit) \
28  (((hit) == HTRIGHT) || ((hit) == HTTOPRIGHT) || ((hit) == HTBOTTOMRIGHT))
29 #define ON_TOP_BORDER(hit) \
30  (((hit) == HTTOP) || ((hit) == HTTOPLEFT) || ((hit) == HTTOPRIGHT))
31 #define ON_BOTTOM_BORDER(hit) \
32  (((hit) == HTBOTTOM) || ((hit) == HTBOTTOMLEFT) || ((hit) == HTBOTTOMRIGHT))
33 
34 #define HASSIZEGRIP(Style, ExStyle, ParentStyle, WindowRect, ParentClientRect) \
35             ((!(Style & WS_CHILD) && (Style & WS_THICKFRAME) && !(Style & WS_MAXIMIZE))  || \
36              ((Style & WS_CHILD) && (ParentStyle & WS_THICKFRAME) && !(ParentStyle & WS_MAXIMIZE) && \
37              (WindowRect.right - WindowRect.left == ParentClientRect.right) && \
38              (WindowRect.bottom - WindowRect.top == ParentClientRect.bottom)))
39 
40 
41 VOID FASTCALL
42 UserDrawWindowFrame(HDC hdc,
43                     RECTL *rect,
44 		    ULONG width,
45 		    ULONG height)
46 {
47    HBRUSH hbrush = NtGdiSelectBrush( hdc, gpsi->hbrGray );
48    NtGdiPatBlt( hdc, rect->left, rect->top, rect->right - rect->left - width, height, PATINVERT );
49    NtGdiPatBlt( hdc, rect->left, rect->top + height, width, rect->bottom - rect->top - height, PATINVERT );
50    NtGdiPatBlt( hdc, rect->left + width, rect->bottom - 1, rect->right - rect->left - width, -(LONG)height, PATINVERT );
51    NtGdiPatBlt( hdc, rect->right - 1, rect->top, -(LONG)width, rect->bottom - rect->top - height, PATINVERT );
52    NtGdiSelectBrush( hdc, hbrush );
53 }
54 
55 VOID FASTCALL
56 UserDrawMovingFrame(HDC hdc,
57                     RECTL *rect,
58                     BOOL thickframe)
59 {
60    if (thickframe) UserDrawWindowFrame(hdc, rect, UserGetSystemMetrics(SM_CXFRAME), UserGetSystemMetrics(SM_CYFRAME));
61    else UserDrawWindowFrame(hdc, rect, 1, 1);
62 }
63 
64 /***********************************************************************
65  *           NC_GetInsideRect
66  *
67  * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
68  * but without the borders (if any).
69  */
70 void FASTCALL // Previously known as "UserGetInsideRectNC"
71 NC_GetInsideRect(PWND Wnd, RECT *rect)
72 {
73     ULONG Style;
74     ULONG ExStyle;
75 
76     Style = Wnd->style;
77     ExStyle = Wnd->ExStyle;
78 
79     rect->top    = rect->left = 0;
80     rect->right  = Wnd->rcWindow.right - Wnd->rcWindow.left;
81     rect->bottom = Wnd->rcWindow.bottom - Wnd->rcWindow.top;
82 
83     if (Style & WS_ICONIC) return;
84 
85     /* Remove frame from rectangle */
86     if (UserHasThickFrameStyle(Style, ExStyle))
87     {
88         RECTL_vInflateRect(rect, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME));
89     }
90     else if (UserHasDlgFrameStyle(Style, ExStyle))
91     {
92         RECTL_vInflateRect(rect, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME));
93         /* FIXME: this isn't in NC_AdjustRect? why not? */
94         if (ExStyle & WS_EX_DLGMODALFRAME)
95             RECTL_vInflateRect( rect, -1, 0 );
96     }
97     else if (UserHasThinFrameStyle(Style, ExStyle))
98     {
99         RECTL_vInflateRect(rect, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
100     }
101 
102     /* We have additional border information if the window
103      * is a child (but not an MDI child) */
104     if ((Style & WS_CHILD) && !(ExStyle & WS_EX_MDICHILD))
105     {
106        if (ExStyle & WS_EX_CLIENTEDGE)
107           RECTL_vInflateRect (rect, -UserGetSystemMetrics(SM_CXEDGE), -UserGetSystemMetrics(SM_CYEDGE));
108        if (ExStyle & WS_EX_STATICEDGE)
109           RECTL_vInflateRect (rect, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
110     }
111 }
112 
113 /***********************************************************************
114  *           NC_GetSysPopupPos
115  */
116 void FASTCALL
117 NC_GetSysPopupPos(PWND Wnd, RECT *Rect)
118 {
119   RECT WindowRect;
120 
121   if ((Wnd->style & WS_MINIMIZE) != 0)
122   {
123       IntGetWindowRect(Wnd, Rect);
124   }
125   else
126     {
127       NC_GetInsideRect(Wnd, Rect);
128       IntGetWindowRect(Wnd, &WindowRect);
129       RECTL_vOffsetRect(Rect, WindowRect.left, WindowRect.top);
130       if (Wnd->style & WS_CHILD)
131       {
132           IntClientToScreen(IntGetParent(Wnd), (POINT *) Rect);
133       }
134       Rect->right = Rect->left + UserGetSystemMetrics(SM_CYCAPTION) - 1;
135       Rect->bottom = Rect->top + UserGetSystemMetrics(SM_CYCAPTION) - 1;
136     }
137 }
138 
139 LONG FASTCALL
140 DefWndStartSizeMove(PWND Wnd, WPARAM wParam, POINT *capturePoint)
141 {
142    LONG hittest = 0;
143    POINT pt;
144    MSG msg;
145    RECT rectWindow;
146    ULONG Style = Wnd->style;
147    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
148 
149    rectWindow = Wnd->rcWindow;
150 
151    if ((wParam & 0xfff0) == SC_MOVE)
152    {
153        /* Move pointer at the center of the caption */
154        RECT rect = rectWindow;
155        /* Note: to be exactly centered we should take the different types
156         * of border into account, but it shouldn't make more than a few pixels
157         * of difference so let's not bother with that */
158        if (Style & WS_SYSMENU)
159           rect.left += UserGetSystemMetrics(SM_CXSIZE) + 1;
160        if (Style & WS_MINIMIZEBOX)
161 	  rect.right -= UserGetSystemMetrics(SM_CXSIZE) + 1;
162        if (Style & WS_MAXIMIZEBOX)
163           rect.right -= UserGetSystemMetrics(SM_CXSIZE) + 1;
164        pt.x = (rect.right + rect.left) / 2;
165        pt.y = rect.top + UserGetSystemMetrics(SM_CYSIZE)/2;
166        hittest = HTCAPTION;
167        *capturePoint = pt;
168    }
169    else  /* SC_SIZE */
170    {
171        pt.x = pt.y = 0;
172        while (!hittest)
173        {
174           if (!co_IntGetPeekMessage(&msg, 0, 0, 0, PM_REMOVE, TRUE)) return 0;
175           if (IntCallMsgFilter( &msg, MSGF_SIZE )) continue;
176 
177 	  switch(msg.message)
178 	    {
179 	    case WM_MOUSEMOVE:
180 	      //// Clamp the mouse position to the window rectangle when starting a window resize.
181               pt.x = min( max( msg.pt.x, rectWindow.left ), rectWindow.right - 1 );
182               pt.y = min( max( msg.pt.y, rectWindow.top ), rectWindow.bottom - 1 );
183 	      hittest = GetNCHitEx(Wnd, pt);
184 	      if ((hittest < HTLEFT) || (hittest > HTBOTTOMRIGHT)) hittest = 0;
185 	      break;
186 
187 	    case WM_LBUTTONUP:
188 	      return 0;
189 
190 	    case WM_KEYDOWN:
191 	      switch (msg.wParam)
192 		{
193 		case VK_UP:
194 		  hittest = HTTOP;
195 		  pt.x = (rectWindow.left+rectWindow.right)/2;
196 		  pt.y =  rectWindow.top + UserGetSystemMetrics(SM_CYFRAME) / 2;
197 		  break;
198 		case VK_DOWN:
199 		  hittest = HTBOTTOM;
200 		  pt.x = (rectWindow.left+rectWindow.right)/2;
201 		  pt.y =  rectWindow.bottom - UserGetSystemMetrics(SM_CYFRAME) / 2;
202 		  break;
203 		case VK_LEFT:
204 		  hittest = HTLEFT;
205 		  pt.x =  rectWindow.left + UserGetSystemMetrics(SM_CXFRAME) / 2;
206 		  pt.y = (rectWindow.top+rectWindow.bottom)/2;
207 		  break;
208 		case VK_RIGHT:
209 		  hittest = HTRIGHT;
210 		  pt.x =  rectWindow.right - UserGetSystemMetrics(SM_CXFRAME) / 2;
211 		  pt.y = (rectWindow.top+rectWindow.bottom)/2;
212 		  break;
213 		case VK_RETURN:
214 		case VK_ESCAPE:
215 		  return 0;
216 		}
217               break;
218             default:
219               IntTranslateKbdMessage( &msg, 0 );
220               pti->TIF_flags |= TIF_MOVESIZETRACKING;
221               IntDispatchMessage( &msg );
222               pti->TIF_flags |= TIF_MOVESIZETRACKING;
223               break;
224 	    }
225        }
226        *capturePoint = pt;
227     }
228     UserSetCursorPos(pt.x, pt.y, 0, 0, FALSE);
229     co_IntSendMessage(UserHMGetHandle(Wnd), WM_SETCURSOR, (WPARAM)UserHMGetHandle(Wnd), MAKELONG(hittest, WM_MOUSEMOVE));
230     return hittest;
231 }
232 
233 //
234 //  System Command Size and Move
235 //
236 //  Perform SC_MOVE and SC_SIZE commands.
237 //
238 VOID FASTCALL
239 DefWndDoSizeMove(PWND pwnd, WORD wParam)
240 {
241    MSG msg;
242    RECT sizingRect, mouseRect, origRect, unmodRect;
243    HDC hdc;
244    LONG hittest = (LONG)(wParam & 0x0f);
245    PCURICON_OBJECT DragCursor = NULL, OldCursor = NULL;
246    POINT minTrack, maxTrack;
247    POINT capturePoint, pt;
248    ULONG Style, ExStyle;
249    BOOL thickframe;
250    BOOL iconic;
251    BOOL moved = FALSE;
252    BOOL DragFullWindows = FALSE;
253    PWND pWndParent = NULL;
254    WPARAM syscommand = (wParam & 0xfff0);
255    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
256    //PMONITOR mon = 0; Don't port sync from wine!!! This breaks explorer task bar sizing!!
257    //                  The task bar can grow in size and can not reduce due to the change
258    //                  in the work area.
259    DWORD ExStyleTB, StyleTB;
260    BOOL IsTaskBar;
261 
262    Style = pwnd->style;
263    ExStyle = pwnd->ExStyle;
264    iconic = (Style & WS_MINIMIZE) != 0;
265 
266    if ((Style & WS_MAXIMIZE) || !IntIsWindowVisible(pwnd)) return;
267 
268    thickframe = UserHasThickFrameStyle(Style, ExStyle) && !iconic;
269 
270    //
271    // Show window contents while dragging the window, get flag from registry data.
272    //
273    UserSystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &DragFullWindows, 0);
274 
275    pt.x = pti->ptLast.x;
276    pt.y = pti->ptLast.y;
277    capturePoint = pt;
278    UserClipCursor( NULL );
279 
280    TRACE("pwnd %p command %04lx, hittest %d, pos %d,%d\n",
281           pwnd, syscommand, hittest, pt.x, pt.y);
282 
283    if (syscommand == SC_MOVE)
284    {
285       if (!hittest) hittest = DefWndStartSizeMove(pwnd, wParam, &capturePoint);
286       if (!hittest) return;
287    }
288    else  /* SC_SIZE */
289    {
290       if (!thickframe) return;
291       if (hittest && (syscommand != SC_MOUSEMENU))
292       {
293           hittest += (HTLEFT - WMSZ_LEFT);
294       }
295       else
296       {
297           co_UserSetCapture(UserHMGetHandle(pwnd));
298           hittest = DefWndStartSizeMove(pwnd, wParam, &capturePoint);
299 	  if (!hittest)
300           {
301               IntReleaseCapture();
302               return;
303           }
304       }
305    }
306 
307    /* Get min/max info */
308 
309    co_WinPosGetMinMaxInfo(pwnd, NULL, NULL, &minTrack, &maxTrack);
310    sizingRect = pwnd->rcWindow;
311    origRect = sizingRect;
312    if (Style & WS_CHILD)
313    {
314       pWndParent = IntGetParent(pwnd);
315       IntGetClientRect( pWndParent, &mouseRect );
316       IntMapWindowPoints( pWndParent, 0, (LPPOINT)&mouseRect, 2 );
317       IntMapWindowPoints( 0, pWndParent, (LPPOINT)&sizingRect, 2 );
318       unmodRect = sizingRect;
319    }
320    else
321    {
322       if (!(ExStyle & WS_EX_TOPMOST))
323       {
324         UserSystemParametersInfo(SPI_GETWORKAREA, 0, &mouseRect, 0);
325       }
326       else
327       {
328         RECTL_vSetRect(&mouseRect, 0, 0, UserGetSystemMetrics(SM_CXSCREEN), UserGetSystemMetrics(SM_CYSCREEN));
329       }
330       unmodRect = sizingRect;
331    }
332 
333    if (ON_LEFT_BORDER(hittest))
334    {
335       mouseRect.left  = max( mouseRect.left, sizingRect.right-maxTrack.x+capturePoint.x-sizingRect.left );
336       mouseRect.right = min( mouseRect.right, sizingRect.right-minTrack.x+capturePoint.x-sizingRect.left );
337    }
338    else if (ON_RIGHT_BORDER(hittest))
339    {
340       mouseRect.left  = max( mouseRect.left, sizingRect.left+minTrack.x+capturePoint.x-sizingRect.right );
341       mouseRect.right = min( mouseRect.right, sizingRect.left+maxTrack.x+capturePoint.x-sizingRect.right );
342    }
343    if (ON_TOP_BORDER(hittest))
344    {
345       mouseRect.top    = max( mouseRect.top, sizingRect.bottom-maxTrack.y+capturePoint.y-sizingRect.top );
346       mouseRect.bottom = min( mouseRect.bottom,sizingRect.bottom-minTrack.y+capturePoint.y-sizingRect.top);
347    }
348    else if (ON_BOTTOM_BORDER(hittest))
349    {
350       mouseRect.top    = max( mouseRect.top, sizingRect.top+minTrack.y+capturePoint.y-sizingRect.bottom );
351       mouseRect.bottom = min( mouseRect.bottom, sizingRect.top+maxTrack.y+capturePoint.y-sizingRect.bottom );
352    }
353 
354    hdc = UserGetDCEx( pWndParent, 0, DCX_CACHE );
355    if (iconic)
356    {
357        DragCursor = pwnd->pcls->spicn;
358        if (DragCursor)
359        {
360            UserReferenceObject(DragCursor);
361        }
362        else
363        {
364            HCURSOR CursorHandle = (HCURSOR)co_IntSendMessage( UserHMGetHandle(pwnd), WM_QUERYDRAGICON, 0, 0 );
365            if (CursorHandle)
366            {
367                DragCursor = UserGetCurIconObject(CursorHandle);
368            }
369            else
370            {
371                iconic = FALSE;
372            }
373        }
374    }
375 
376    /* repaint the window before moving it around */
377    co_UserRedrawWindow( pwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
378 
379    IntNotifyWinEvent( EVENT_SYSTEM_MOVESIZESTART, pwnd, OBJID_WINDOW, CHILDID_SELF, 0);
380 
381    co_IntSendMessage( UserHMGetHandle(pwnd), WM_ENTERSIZEMOVE, 0, 0 );
382 
383    MsqSetStateWindow(pti, MSQ_STATE_MOVESIZE, UserHMGetHandle(pwnd));
384 
385    if (IntGetCapture() != UserHMGetHandle(pwnd)) co_UserSetCapture( UserHMGetHandle(pwnd) );
386 
387    pwnd->head.pti->TIF_flags |= TIF_MOVESIZETRACKING;
388 
389    for(;;)
390    {
391       int dx = 0, dy = 0;
392 
393       if (!co_IntGetPeekMessage(&msg, 0, 0, 0, PM_REMOVE, TRUE)) break;
394       if (IntCallMsgFilter( &msg, MSGF_SIZE )) continue;
395 
396       /* Exit on button-up */
397       if (msg.message == WM_LBUTTONUP)
398       {
399          /* Test for typical TaskBar ExStyle Values */
400          ExStyleTB = (ExStyle & WS_EX_TOOLWINDOW);
401          TRACE("ExStyle is '%x'.\n", ExStyleTB);
402 
403          /* Test for typical TaskBar Style Values */
404          StyleTB = (Style & (WS_POPUP | WS_VISIBLE |
405                         WS_CLIPSIBLINGS | WS_CLIPCHILDREN));
406          TRACE("Style is '%x'.\n", StyleTB);
407 
408          /* Test for masked typical TaskBar Style and ExStyles to detect TaskBar */
409          IsTaskBar = (StyleTB == (WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN))
410                      && (ExStyleTB == WS_EX_TOOLWINDOW);
411          TRACE("This %s the TaskBar.\n", IsTaskBar ? "is" : "is not");
412 
413          // check for snapping if was moved by caption
414          if (hittest == HTCAPTION && thickframe && (ExStyle & WS_EX_MDICHILD) == 0)
415          {
416             RECT snapRect;
417             BOOL doSideSnap = FALSE;
418             UserSystemParametersInfo(SPI_GETWORKAREA, 0, &snapRect, 0);
419 
420             /* if this is the taskbar, then we want to just exit */
421             if (IsTaskBar)
422             {
423                break;
424             }
425             // snap to left
426             if (pt.x <= snapRect.left)
427             {
428                snapRect.right = (snapRect.right - snapRect.left) / 2 + snapRect.left;
429                doSideSnap = TRUE;
430             }
431             // snap to right
432             if (pt.x >= snapRect.right-1)
433             {
434                snapRect.left = (snapRect.right - snapRect.left) / 2 + snapRect.left;
435                doSideSnap = TRUE;
436             }
437 
438             if (doSideSnap)
439             {
440                co_WinPosSetWindowPos(pwnd,
441                                      NULL,
442                                      snapRect.left,
443                                      snapRect.top,
444                                      snapRect.right - snapRect.left,
445                                      snapRect.bottom - snapRect.top,
446                                      SWP_NOACTIVATE);
447                pwnd->InternalPos.NormalRect = origRect;
448             }
449             else
450             {
451                // maximize if on dragged to top
452                if (pt.y <= snapRect.top)
453                {
454                   co_IntSendMessage(UserHMGetHandle(pwnd), WM_SYSCOMMAND, SC_MAXIMIZE, 0);
455                   pwnd->InternalPos.NormalRect = origRect;
456                }
457             }
458          }
459          break;
460       }
461 
462       /* Exit on Return or Esc */
463       if (msg.message == WM_KEYDOWN &&
464           (msg.wParam == VK_RETURN || msg.wParam == VK_ESCAPE))
465       {
466          break;
467       }
468 
469       if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE))
470       {
471          IntTranslateKbdMessage( &msg , 0 );
472          IntDispatchMessage( &msg );
473          continue;  /* We are not interested in other messages */
474       }
475 
476       pt = msg.pt;
477 
478       if (msg.message == WM_KEYDOWN) switch(msg.wParam)
479       {
480 	case VK_UP:    pt.y -= 8; break;
481 	case VK_DOWN:  pt.y += 8; break;
482 	case VK_LEFT:  pt.x -= 8; break;
483 	case VK_RIGHT: pt.x += 8; break;
484       }
485 
486       pt.x = max( pt.x, mouseRect.left );
487       pt.x = min( pt.x, mouseRect.right - 1 );
488       pt.y = max( pt.y, mouseRect.top );
489       pt.y = min( pt.y, mouseRect.bottom - 1 );
490 
491       dx = pt.x - capturePoint.x;
492       dy = pt.y - capturePoint.y;
493 
494       if (dx || dy)
495       {
496 	  if ( !moved )
497 	  {
498 	      moved = TRUE;
499           if ( iconic ) /* ok, no system popup tracking */
500           {
501               OldCursor = UserSetCursor(DragCursor, FALSE);
502               UserShowCursor( TRUE );
503           }
504           else if(!DragFullWindows)
505              UserDrawMovingFrame( hdc, &sizingRect, thickframe );
506 	  }
507 
508 	  if (msg.message == WM_KEYDOWN) UserSetCursorPos(pt.x, pt.y, 0, 0, FALSE);
509 	  else
510 	  {
511 	      RECT newRect = unmodRect;
512 
513 	      if (!iconic && !DragFullWindows) UserDrawMovingFrame( hdc, &sizingRect, thickframe );
514 	      if (hittest == HTCAPTION) RECTL_vOffsetRect( &newRect, dx, dy );
515 	      if (ON_LEFT_BORDER(hittest)) newRect.left += dx;
516 	      else if (ON_RIGHT_BORDER(hittest)) newRect.right += dx;
517 	      if (ON_TOP_BORDER(hittest)) newRect.top += dy;
518 	      else if (ON_BOTTOM_BORDER(hittest)) newRect.bottom += dy;
519 	      capturePoint = pt;
520 
521               //
522               //  Save the new position to the unmodified rectangle. This allows explorer task bar
523               //  sizing. Explorer will forces back the position unless a certain amount of sizing
524               //  has occurred.
525               //
526               unmodRect = newRect;
527 
528 	      /* determine the hit location */
529               if (syscommand == SC_SIZE)
530               {
531                   WPARAM wpSizingHit = 0;
532 
533                   if (hittest >= HTLEFT && hittest <= HTBOTTOMRIGHT)
534                       wpSizingHit = WMSZ_LEFT + (hittest - HTLEFT);
535                   co_IntSendMessage( UserHMGetHandle(pwnd), WM_SIZING, wpSizingHit, (LPARAM)&newRect );
536               }
537               else
538                   co_IntSendMessage( UserHMGetHandle(pwnd), WM_MOVING, 0, (LPARAM)&newRect );
539 
540 	      if (!iconic)
541               {
542                  if (!DragFullWindows)
543                      UserDrawMovingFrame( hdc, &newRect, thickframe );
544                  else
545                  {  // Moving the whole window now!
546                     HRGN hrgnNew;
547                     HRGN hrgnOrig = GreCreateRectRgnIndirect(&pwnd->rcWindow);
548 
549                     if (pwnd->hrgnClip != NULL)
550                        NtGdiCombineRgn(hrgnOrig, hrgnOrig, pwnd->hrgnClip, RGN_AND);
551 
552                     //// This causes the mdi child window to jump up when it is moved.
553                     //IntMapWindowPoints( 0, pWndParent, (POINT *)&rect, 2 );
554                     co_WinPosSetWindowPos(pwnd,
555                                           NULL,
556                                           newRect.left,
557                                           newRect.top,
558                                           newRect.right - newRect.left,
559                                           newRect.bottom - newRect.top,
560                                           SWP_NOACTIVATE | ((hittest == HTCAPTION) ? SWP_NOSIZE : 0));
561 
562                     hrgnNew = GreCreateRectRgnIndirect(&pwnd->rcWindow);
563                     if (pwnd->hrgnClip != NULL)
564                        NtGdiCombineRgn(hrgnNew, hrgnNew, pwnd->hrgnClip, RGN_AND);
565 
566                     if (hrgnNew)
567                     {
568                        if (hrgnOrig)
569                           NtGdiCombineRgn(hrgnOrig, hrgnOrig, hrgnNew, RGN_DIFF);
570                     }
571                     else
572                     {
573                        if (hrgnOrig)
574                        {
575                           GreDeleteObject(hrgnOrig);
576                           hrgnOrig = 0;
577                        }
578                     }
579 
580                     // Update all the windows after the move or size, including this window.
581                     UpdateThreadWindows(UserGetDesktopWindow()->spwndChild, pti, hrgnOrig);
582 
583                     if (hrgnOrig) GreDeleteObject(hrgnOrig);
584                     if (hrgnNew) GreDeleteObject(hrgnNew);
585                  }
586               }
587               sizingRect = newRect;
588 	  }
589       }
590    }
591 
592    pwnd->head.pti->TIF_flags &= ~TIF_MOVESIZETRACKING;
593 
594    IntReleaseCapture();
595 
596    if ( iconic )
597    {
598       if ( moved ) /* restore cursors, show icon title later on */
599       {
600           UserShowCursor( FALSE );
601           OldCursor = UserSetCursor(OldCursor, FALSE);
602       }
603 
604       /* It could be that the cursor was already changed while we were proceeding,
605        * so we must unreference whatever cursor was current at the time we restored the old one.
606        * Maybe it is DragCursor, but maybe it is another one and DragCursor got already freed.
607        */
608       if (OldCursor) UserDereferenceObject(OldCursor);
609    }
610    else if ( moved && !DragFullWindows )
611       UserDrawMovingFrame( hdc, &sizingRect, thickframe );
612 
613    UserReleaseDC(NULL, hdc, FALSE);
614 
615    //// This causes the mdi child window to jump up when it is moved.
616    //if (pWndParent) IntMapWindowPoints( 0, pWndParent, (POINT *)&sizingRect, 2 );
617 
618    if (co_HOOK_CallHooks(WH_CBT, HCBT_MOVESIZE, (WPARAM)UserHMGetHandle(pwnd), (LPARAM)&sizingRect))
619    {
620       ERR("DoSizeMove : WH_CBT Call Hook return!\n");
621       moved = FALSE;
622    }
623 
624    IntNotifyWinEvent( EVENT_SYSTEM_MOVESIZEEND, pwnd, OBJID_WINDOW, CHILDID_SELF, 0);
625 
626    MsqSetStateWindow(pti, MSQ_STATE_MOVESIZE, NULL);
627 
628    co_IntSendMessage( UserHMGetHandle(pwnd), WM_EXITSIZEMOVE, 0, 0 );
629    //// wine mdi hack
630    co_IntSendMessage( UserHMGetHandle(pwnd), WM_SETVISIBLE, !!(pwnd->style & WS_MINIMIZE), 0L);
631    ////
632    /* window moved or resized */
633    if (moved)
634    {
635       /* if the moving/resizing isn't canceled call SetWindowPos
636        * with the new position or the new size of the window
637        */
638       if (!((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) )
639       {
640 	  /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
641 	  if (!DragFullWindows || iconic )
642 	  {
643 	    co_WinPosSetWindowPos( pwnd,
644 	                           0,
645 	                           sizingRect.left,
646 	                           sizingRect.top,
647 			           sizingRect.right - sizingRect.left,
648 			           sizingRect.bottom - sizingRect.top,
649 			          ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
650           }
651       }
652       else
653       { /* restore previous size/position */
654 	if ( DragFullWindows )
655 	{
656 	  co_WinPosSetWindowPos( pwnd,
657 	                         0,
658 	                         origRect.left,
659 	                         origRect.top,
660 			         origRect.right - origRect.left,
661 			         origRect.bottom - origRect.top,
662 			        ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
663         }
664       }
665    }
666 
667    if ( IntIsWindow(UserHMGetHandle(pwnd)) )
668    {
669      if ( iconic )
670      {
671 	/* Single click brings up the system menu when iconized */
672 	if ( !moved )
673         {
674 	    if( Style & WS_SYSMENU )
675 	      co_IntSendMessage( UserHMGetHandle(pwnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y));
676         }
677      }
678    }
679 }
680 
681 PCURICON_OBJECT FASTCALL NC_IconForWindow( PWND pWnd )
682 {
683     PCURICON_OBJECT pIcon = NULL;
684     HICON hIcon;
685 
686    hIcon = UserGetProp(pWnd, gpsi->atomIconSmProp, TRUE);
687    if (!hIcon) hIcon = UserGetProp(pWnd, gpsi->atomIconProp, TRUE);
688 
689    if (!hIcon && pWnd->pcls->spicnSm)
690        return pWnd->pcls->spicnSm;
691    if (!hIcon && pWnd->pcls->spicn)
692        return pWnd->pcls->spicn;
693 
694    // WARNING: Wine code has this test completely wrong. The following is how
695    // Windows behaves for windows having the WS_EX_DLGMODALFRAME style set:
696    // it does not use the default icon! And it does not check for DS_MODALFRAME.
697    if (!hIcon && !(pWnd->ExStyle & WS_EX_DLGMODALFRAME))
698    {
699       hIcon = gpsi->hIconSmWindows; // Both are IDI_WINLOGO Small
700       if (!hIcon) hIcon = gpsi->hIconWindows;   // Reg size.
701    }
702    if (hIcon)
703    {
704        pIcon = (PCURICON_OBJECT)UserGetObjectNoErr(gHandleTable,
705                                                    hIcon,
706                                                    TYPE_CURSOR);
707    }
708    return pIcon;
709 }
710 
711 BOOL
712 UserDrawSysMenuButton(PWND pWnd, HDC hDC, LPRECT Rect, BOOL Down)
713 {
714    PCURICON_OBJECT WindowIcon;
715    BOOL Ret = FALSE;
716 
717    if ((WindowIcon = NC_IconForWindow(pWnd)))
718    {
719       UserReferenceObject(WindowIcon);
720 
721       Ret = UserDrawIconEx(hDC,
722                            Rect->left + 2,
723                            Rect->top + 2,
724                            WindowIcon,
725                            UserGetSystemMetrics(SM_CXSMICON),
726                            UserGetSystemMetrics(SM_CYSMICON),
727                            0, NULL, DI_NORMAL);
728 
729       UserDereferenceObject(WindowIcon);
730    }
731    return Ret;
732 }
733 
734 BOOL
735 IntIsScrollBarVisible(PWND pWnd, INT hBar)
736 {
737   SCROLLBARINFO sbi;
738   sbi.cbSize = sizeof(SCROLLBARINFO);
739 
740   if(!co_IntGetScrollBarInfo(pWnd, hBar, &sbi))
741     return FALSE;
742 
743   return !(sbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN);
744 }
745 
746 /*
747  * FIXME:
748  * - Cache bitmaps, then just bitblt instead of calling DFC() (and
749  *   wasting precious CPU cycles) every time
750  * - Center the buttons vertically in the rect
751  */
752 VOID
753 UserDrawCaptionButton(PWND pWnd, LPRECT Rect, DWORD Style, DWORD ExStyle, HDC hDC, BOOL bDown, ULONG Type)
754 {
755    RECT TempRect;
756 
757    if (!(Style & WS_SYSMENU))
758    {
759       return;
760    }
761 
762    TempRect = *Rect;
763 
764    switch (Type)
765    {
766       case DFCS_CAPTIONMIN:
767       {
768          if (ExStyle & WS_EX_TOOLWINDOW)
769             return; /* ToolWindows don't have min/max buttons */
770 
771          if (Style & WS_SYSMENU)
772              TempRect.right -= UserGetSystemMetrics(SM_CXSIZE) + 1;
773 
774          if (Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX))
775              TempRect.right -= UserGetSystemMetrics(SM_CXSIZE) - 2;
776 
777          TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSIZE) + 1;
778          TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSIZE) - 2;
779          TempRect.top += 2;
780          TempRect.right -= 1;
781 
782          DrawFrameControl(hDC, &TempRect, DFC_CAPTION,
783                           ((Style & WS_MINIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMIN) |
784                           (bDown ? DFCS_PUSHED : 0) |
785                           ((Style & WS_MINIMIZEBOX) ? 0 : DFCS_INACTIVE));
786          break;
787       }
788       case DFCS_CAPTIONMAX:
789       {
790          if (ExStyle & WS_EX_TOOLWINDOW)
791              return; /* ToolWindows don't have min/max buttons */
792 
793          if (Style & WS_SYSMENU)
794              TempRect.right -= UserGetSystemMetrics(SM_CXSIZE) + 1;
795 
796          TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSIZE) + 1;
797          TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSIZE) - 2;
798          TempRect.top += 2;
799          TempRect.right -= 1;
800 
801          DrawFrameControl(hDC, &TempRect, DFC_CAPTION,
802                           ((Style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX) |
803                           (bDown ? DFCS_PUSHED : 0) |
804                           ((Style & WS_MAXIMIZEBOX) ? 0 : DFCS_INACTIVE));
805          break;
806       }
807       case DFCS_CAPTIONCLOSE:
808       {
809           PMENU pSysMenu = IntGetSystemMenu(pWnd, FALSE);
810           UINT MenuState = IntGetMenuState(pSysMenu ? UserHMGetHandle(pSysMenu) : NULL, SC_CLOSE, MF_BYCOMMAND); /* in case of error MenuState==0xFFFFFFFF */
811 
812          /* A tool window has a smaller Close button */
813          if (ExStyle & WS_EX_TOOLWINDOW)
814          {
815             TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSMSIZE);
816             TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSMSIZE) - 2;
817          }
818          else
819          {
820             TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSIZE);
821             TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSIZE) - 2;
822          }
823          TempRect.top += 2;
824          TempRect.right -= 2;
825 
826          DrawFrameControl(hDC, &TempRect, DFC_CAPTION,
827                           (DFCS_CAPTIONCLOSE | (bDown ? DFCS_PUSHED : 0) |
828                           ((!(MenuState & (MF_GRAYED|MF_DISABLED)) && !(pWnd->pcls->style & CS_NOCLOSE)) ? 0 : DFCS_INACTIVE)));
829          break;
830       }
831    }
832 }
833 
834 VOID
835 UserDrawCaptionButtonWnd(PWND pWnd, HDC hDC, BOOL bDown, ULONG Type)
836 {
837    RECT WindowRect;
838    SIZE WindowBorder;
839 
840    IntGetWindowRect(pWnd, &WindowRect);
841 
842    WindowRect.right -= WindowRect.left;
843    WindowRect.bottom -= WindowRect.top;
844    WindowRect.left = WindowRect.top = 0;
845 
846    UserGetWindowBorders(pWnd->style, pWnd->ExStyle, &WindowBorder, FALSE);
847 
848    RECTL_vInflateRect(&WindowRect, -WindowBorder.cx, -WindowBorder.cy);
849 
850    UserDrawCaptionButton(pWnd, &WindowRect, pWnd->style, pWnd->ExStyle, hDC, bDown, Type);
851 }
852 
853 VOID
854 NC_DrawFrame( HDC hDC, RECT *CurrentRect, BOOL Active, DWORD Style, DWORD ExStyle)
855 {
856    /* Firstly the "thick" frame */
857    if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
858    {
859       LONG Width =
860          (UserGetSystemMetrics(SM_CXFRAME) - UserGetSystemMetrics(SM_CXDLGFRAME)) *
861          UserGetSystemMetrics(SM_CXBORDER);
862 
863       LONG Height =
864          (UserGetSystemMetrics(SM_CYFRAME) - UserGetSystemMetrics(SM_CYDLGFRAME)) *
865          UserGetSystemMetrics(SM_CYBORDER);
866 
867       NtGdiSelectBrush(hDC, IntGetSysColorBrush(Active ? COLOR_ACTIVEBORDER : COLOR_INACTIVEBORDER));
868 
869       /* Draw frame */
870       NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, CurrentRect->right - CurrentRect->left, Height, PATCOPY);
871       NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, Width, CurrentRect->bottom - CurrentRect->top, PATCOPY);
872       NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->bottom - 1, CurrentRect->right - CurrentRect->left, -Height, PATCOPY);
873       NtGdiPatBlt(hDC, CurrentRect->right - 1, CurrentRect->top, -Width, CurrentRect->bottom - CurrentRect->top, PATCOPY);
874 
875       RECTL_vInflateRect(CurrentRect, -Width, -Height);
876    }
877 
878    /* Now the other bit of the frame */
879    if (Style & (WS_DLGFRAME | WS_BORDER) || ExStyle & WS_EX_DLGMODALFRAME)
880    {
881       LONG Width = UserGetSystemMetrics(SM_CXBORDER);
882       LONG Height = UserGetSystemMetrics(SM_CYBORDER);
883 
884       NtGdiSelectBrush(hDC, IntGetSysColorBrush(
885          (ExStyle & (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE)) ? COLOR_3DFACE :
886          (ExStyle & WS_EX_STATICEDGE) ? COLOR_WINDOWFRAME :
887          (Style & (WS_DLGFRAME | WS_THICKFRAME)) ? COLOR_3DFACE :
888          COLOR_WINDOWFRAME));
889 
890       /* Draw frame */
891       NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, CurrentRect->right - CurrentRect->left, Height, PATCOPY);
892       NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, Width, CurrentRect->bottom - CurrentRect->top, PATCOPY);
893       NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->bottom - 1, CurrentRect->right - CurrentRect->left, -Height, PATCOPY);
894       NtGdiPatBlt(hDC, CurrentRect->right - 1, CurrentRect->top, -Width, CurrentRect->bottom - CurrentRect->top, PATCOPY);
895 
896       RECTL_vInflateRect(CurrentRect, -Width, -Height);
897    }
898 }
899 
900 VOID UserDrawCaptionBar(
901    PWND pWnd,
902    HDC hDC,
903    INT Flags)
904 {
905    DWORD Style, ExStyle;
906    RECT WindowRect, CurrentRect, TempRect;
907    HPEN PreviousPen;
908    BOOL Gradient = FALSE;
909    PCURICON_OBJECT pIcon = NULL;
910 
911    if (!(Flags & DC_NOVISIBLE) && !IntIsWindowVisible(pWnd)) return;
912 
913    TRACE("UserDrawCaptionBar: pWnd %p, hDc %p, Flags 0x%x.\n", pWnd, hDC, Flags);
914 
915    Style = pWnd->style;
916    ExStyle = pWnd->ExStyle;
917 
918    IntGetWindowRect(pWnd, &WindowRect);
919 
920    CurrentRect.top = CurrentRect.left = 0;
921    CurrentRect.right = WindowRect.right - WindowRect.left;
922    CurrentRect.bottom = WindowRect.bottom - WindowRect.top;
923 
924    /* Draw outer edge */
925    if (UserHasWindowEdge(Style, ExStyle))
926    {
927       DrawEdge(hDC, &CurrentRect, EDGE_RAISED, BF_RECT | BF_ADJUST);
928    }
929    else if (ExStyle & WS_EX_STATICEDGE)
930    {
931 #if 0
932       DrawEdge(hDC, &CurrentRect, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT);
933 #else
934       NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNSHADOW));
935       NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
936       NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
937 
938       NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNHIGHLIGHT));
939       NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
940       NtGdiPatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
941 
942       RECTL_vInflateRect(&CurrentRect, -1, -1);
943 #endif
944    }
945 
946    if (Flags & DC_FRAME) NC_DrawFrame(hDC, &CurrentRect, (Flags & DC_ACTIVE), Style, ExStyle);
947 
948    /* Draw caption */
949    if ((Style & WS_CAPTION) == WS_CAPTION)
950    {
951       TempRect = CurrentRect;
952 
953       Flags |= DC_TEXT|DC_BUTTONS; // Icon will be checked if not already set.
954 
955       if (UserSystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &Gradient, 0) && Gradient)
956       {
957          Flags |= DC_GRADIENT;
958       }
959 
960       if (ExStyle & WS_EX_TOOLWINDOW)
961       {
962          Flags |= DC_SMALLCAP;
963          TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSMCAPTION) - 1;
964          CurrentRect.top += UserGetSystemMetrics(SM_CYSMCAPTION);
965       }
966       else
967       {
968          TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYCAPTION) - 1;
969          CurrentRect.top += UserGetSystemMetrics(SM_CYCAPTION);
970       }
971 
972       if (!(Flags & DC_ICON)               &&
973           !(Flags & DC_SMALLCAP)           &&
974            (Style & WS_SYSMENU)            &&
975           !(ExStyle & WS_EX_TOOLWINDOW) )
976       {
977          pIcon = NC_IconForWindow(pWnd); // Force redraw of caption with icon if DC_ICON not flaged....
978       }
979       UserDrawCaption(pWnd, hDC, &TempRect, NULL, pIcon ? UserHMGetHandle(pIcon) : NULL, NULL, Flags);
980 
981       /* Draw buttons */
982       if (Style & WS_SYSMENU)
983       {
984          UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONCLOSE);
985          if ((Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(ExStyle & WS_EX_TOOLWINDOW))
986          {
987             UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMIN);
988             UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMAX);
989          }
990       }
991 
992       if (!(Style & WS_MINIMIZE))
993       {
994          /* Line under caption */
995          PreviousPen = NtGdiSelectPen(hDC, NtGdiGetStockObject(DC_PEN));
996 
997          IntSetDCPenColor( hDC, IntGetSysColor(((ExStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
998                                              COLOR_WINDOWFRAME : COLOR_3DFACE));
999 
1000          GreMoveTo(hDC, TempRect.left, TempRect.bottom, NULL);
1001 
1002          NtGdiLineTo(hDC, TempRect.right, TempRect.bottom);
1003 
1004          NtGdiSelectPen(hDC, PreviousPen);
1005       }
1006    }
1007 
1008    if (!(Style & WS_MINIMIZE))
1009    {
1010       /* Draw menu bar */
1011       if (pWnd->state & WNDS_HASMENU && pWnd->IDMenu) // Should be pWnd->spmenu
1012       {
1013           PMENU menu;
1014           if ((menu = UserGetMenuObject(UlongToHandle(pWnd->IDMenu)))) // FIXME! Use pWnd->spmenu,
1015           {
1016              TempRect = CurrentRect;
1017              TempRect.bottom = TempRect.top + menu->cyMenu; // Should be pWnd->spmenu->cyMenu;
1018              CurrentRect.top += MENU_DrawMenuBar(hDC, &TempRect, pWnd, FALSE);
1019           }
1020       }
1021 
1022       if (ExStyle & WS_EX_CLIENTEDGE)
1023       {
1024           DrawEdge(hDC, &CurrentRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1025       }
1026    }
1027 }
1028 
1029 // Note from Wine:
1030 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
1031    the call to GetDCEx implying that it is allowed not to use it either.
1032    However, the suggested GetDCEx(    , DCX_WINDOW | DCX_INTERSECTRGN)
1033    will cause clipRgn to be deleted after ReleaseDC().
1034    Now, how is the "system" supposed to tell what happened?
1035  */
1036 /*
1037  * FIXME:
1038  * - Drawing of WS_BORDER after scrollbars
1039  * - Correct drawing of size-box
1040  */
1041 LRESULT
1042 NC_DoNCPaint(PWND pWnd, HDC hDC, INT Flags)
1043 {
1044    DWORD Style, ExStyle;
1045    PWND Parent;
1046    RECT WindowRect, CurrentRect, TempRect;
1047    BOOL Active = FALSE;
1048 
1049    if (!IntIsWindowVisible(pWnd) ||
1050        (pWnd->state & WNDS_NONCPAINT && !(pWnd->state & WNDS_FORCEMENUDRAW)) ||
1051         IntEqualRect(&pWnd->rcWindow, &pWnd->rcClient) )
1052       return 0;
1053 
1054    Style = pWnd->style;
1055 
1056    TRACE("DefWndNCPaint: pWnd %p, hDc %p, Active %s.\n", pWnd, hDC, Flags & DC_ACTIVE ? "TRUE" : "FALSE");
1057 
1058    Parent = IntGetParent(pWnd);
1059    ExStyle = pWnd->ExStyle;
1060 
1061    if (Flags == -1) // NC paint mode.
1062    {
1063       if (ExStyle & WS_EX_MDICHILD)
1064       {
1065          Active = IntIsChildWindow(gpqForeground->spwndActive, pWnd);
1066 
1067          if (Active)
1068             Active = (UserHMGetHandle(pWnd) == (HWND)co_IntSendMessage(UserHMGetHandle(Parent), WM_MDIGETACTIVE, 0, 0));
1069       }
1070       else
1071       {
1072          Active = (gpqForeground == pWnd->head.pti->MessageQueue);
1073       }
1074       Flags = DC_NC; // Redraw everything!
1075    }
1076    else
1077       Flags |= DC_NC;
1078 
1079 
1080    IntGetWindowRect(pWnd, &WindowRect);
1081 
1082    CurrentRect.top = CurrentRect.left = 0;
1083    CurrentRect.right = WindowRect.right - WindowRect.left;
1084    CurrentRect.bottom = WindowRect.bottom - WindowRect.top;
1085 
1086    /* Draw outer edge */
1087    if (UserHasWindowEdge(pWnd->style, pWnd->ExStyle))
1088    {
1089       DrawEdge(hDC, &CurrentRect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1090    }
1091    else if (pWnd->ExStyle & WS_EX_STATICEDGE)
1092    {
1093 #if 0
1094       DrawEdge(hDC, &CurrentRect, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT);
1095 #else
1096       NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNSHADOW));
1097       NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
1098       NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
1099 
1100       NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNHIGHLIGHT));
1101       NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
1102       NtGdiPatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
1103 
1104       RECTL_vInflateRect(&CurrentRect, -1, -1);
1105 #endif
1106    }
1107 
1108    if (Flags & DC_FRAME) NC_DrawFrame(hDC, &CurrentRect, Active ? Active : (Flags & DC_ACTIVE), Style, ExStyle);
1109 
1110    /* Draw caption */
1111    if ((Style & WS_CAPTION) == WS_CAPTION)
1112    {
1113       HPEN PreviousPen;
1114       BOOL Gradient = FALSE;
1115 
1116       if (Flags & DC_REDRAWHUNGWND)
1117       {
1118          Flags &= ~DC_REDRAWHUNGWND;
1119          Flags |= DC_NOSENDMSG;
1120       }
1121 
1122       if (UserSystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &Gradient, 0) && Gradient)
1123       {
1124          Flags |= DC_GRADIENT;
1125       }
1126 
1127       if (Active)
1128       {
1129          if (pWnd->state & WNDS_ACTIVEFRAME)
1130             Flags |= DC_ACTIVE;
1131          else
1132          {
1133             ERR("Wnd is active and not set active!\n");
1134          }
1135       }
1136 
1137       TempRect = CurrentRect;
1138 
1139       if (ExStyle & WS_EX_TOOLWINDOW)
1140       {
1141          Flags |= DC_SMALLCAP;
1142          TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSMCAPTION) - 1;
1143          CurrentRect.top += UserGetSystemMetrics(SM_CYSMCAPTION);
1144       }
1145       else
1146       {
1147          TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYCAPTION) - 1;
1148          CurrentRect.top += UserGetSystemMetrics(SM_CYCAPTION);
1149       }
1150 
1151       UserDrawCaption(pWnd, hDC, &TempRect, NULL, NULL, NULL, Flags);
1152 
1153       /* Draw buttons */
1154       if (Style & WS_SYSMENU)
1155       {
1156          UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONCLOSE);
1157          if ((Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(ExStyle & WS_EX_TOOLWINDOW))
1158          {
1159             UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMIN);
1160             UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMAX);
1161          }
1162       }
1163       if (!(Style & WS_MINIMIZE))
1164       {
1165         /* Line under caption */
1166          PreviousPen = NtGdiSelectPen(hDC, NtGdiGetStockObject(DC_PEN));
1167 
1168          IntSetDCPenColor( hDC, IntGetSysColor(
1169                          ((ExStyle & (WS_EX_STATICEDGE | WS_EX_CLIENTEDGE | WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
1170                           COLOR_WINDOWFRAME : COLOR_3DFACE));
1171 
1172          GreMoveTo(hDC, TempRect.left, TempRect.bottom, NULL);
1173 
1174          NtGdiLineTo(hDC, TempRect.right, TempRect.bottom);
1175 
1176          NtGdiSelectPen(hDC, PreviousPen);
1177       }
1178    }
1179 
1180    if (!(Style & WS_MINIMIZE))
1181    {
1182      /* Draw menu bar */
1183      if (pWnd->state & WNDS_HASMENU && pWnd->IDMenu) // Should be pWnd->spmenu
1184      {
1185          if (!(Flags & DC_NOSENDMSG))
1186          {
1187              PMENU menu;
1188              // Fix crash in test_menu_locked_by_window, should use pWnd->spmenu....
1189              if ((menu = UserGetMenuObject(UlongToHandle(pWnd->IDMenu)))) // FIXME! Use pWnd->spmenu,
1190              {
1191                 TempRect = CurrentRect;
1192                 TempRect.bottom = TempRect.top + menu->cyMenu; // Should be pWnd->spmenu->cyMenu;
1193                 CurrentRect.top += MENU_DrawMenuBar(hDC, &TempRect, pWnd, FALSE);
1194              }
1195          }
1196      }
1197 
1198      if (ExStyle & WS_EX_CLIENTEDGE)
1199      {
1200          DrawEdge(hDC, &CurrentRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1201      }
1202 
1203      /* Draw the scrollbars */
1204      if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) &&
1205          IntIsScrollBarVisible(pWnd, OBJID_VSCROLL) && IntIsScrollBarVisible(pWnd, OBJID_HSCROLL))
1206      {
1207         RECT ParentClientRect;
1208 
1209         TempRect = CurrentRect;
1210 
1211         if (ExStyle & WS_EX_LEFTSCROLLBAR)
1212            TempRect.right = TempRect.left + UserGetSystemMetrics(SM_CXVSCROLL);
1213         else
1214            TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXVSCROLL);
1215 
1216         TempRect.top = TempRect.bottom - UserGetSystemMetrics(SM_CYHSCROLL);
1217 
1218         FillRect(hDC, &TempRect, IntGetSysColorBrush(COLOR_BTNFACE));
1219 
1220         if (Parent)
1221         {
1222            IntGetClientRect(Parent, &ParentClientRect);
1223 
1224            if (HASSIZEGRIP(Style, ExStyle, Parent->style, WindowRect, ParentClientRect))
1225            {
1226               DrawFrameControl(hDC, &TempRect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
1227            }
1228         }
1229 
1230         IntDrawScrollBar(pWnd, hDC, SB_VERT);
1231         IntDrawScrollBar(pWnd, hDC, SB_HORZ);
1232      }
1233      else
1234      {
1235         if (Style & WS_VSCROLL && IntIsScrollBarVisible(pWnd, OBJID_VSCROLL))
1236         {
1237            IntDrawScrollBar(pWnd, hDC, SB_VERT);
1238         }
1239         else if (Style & WS_HSCROLL && IntIsScrollBarVisible(pWnd, OBJID_HSCROLL))
1240         {
1241            IntDrawScrollBar(pWnd, hDC, SB_HORZ);
1242         }
1243      }
1244    }
1245    return 0; // For WM_NCPAINT message, return 0.
1246 }
1247 
1248 LRESULT NC_HandleNCCalcSize( PWND Wnd, WPARAM wparam, RECTL *Rect, BOOL Suspended )
1249 {
1250    LRESULT Result = 0;
1251    SIZE WindowBorders;
1252    RECT OrigRect;
1253    LONG Style = Wnd->style;
1254    LONG  exStyle = Wnd->ExStyle;
1255 
1256    if (Rect == NULL)
1257    {
1258       return Result;
1259    }
1260    OrigRect = *Rect;
1261 
1262    Wnd->state &= ~WNDS_HASCAPTION;
1263 
1264    if (wparam)
1265    {
1266       if (Wnd->pcls->style & CS_VREDRAW)
1267       {
1268          Result |= WVR_VREDRAW;
1269       }
1270       if (Wnd->pcls->style & CS_HREDRAW)
1271       {
1272          Result |= WVR_HREDRAW;
1273       }
1274       Result |= WVR_VALIDRECTS;
1275    }
1276 
1277    if (!(Wnd->style & WS_MINIMIZE))
1278    {
1279       if (UserHasWindowEdge(Wnd->style, Wnd->ExStyle))
1280       {
1281          UserGetWindowBorders(Wnd->style, Wnd->ExStyle, &WindowBorders, FALSE);
1282          RECTL_vInflateRect(Rect, -WindowBorders.cx, -WindowBorders.cy);
1283       }
1284       else if ((Wnd->ExStyle & WS_EX_STATICEDGE) || (Wnd->style & WS_BORDER))
1285       {
1286          RECTL_vInflateRect(Rect, -1, -1);
1287       }
1288 
1289       if ((Wnd->style & WS_CAPTION) == WS_CAPTION)
1290       {
1291          Wnd->state |= WNDS_HASCAPTION;
1292 
1293          if (Wnd->ExStyle & WS_EX_TOOLWINDOW)
1294             Rect->top += UserGetSystemMetrics(SM_CYSMCAPTION);
1295          else
1296             Rect->top += UserGetSystemMetrics(SM_CYCAPTION);
1297       }
1298 
1299       if (HAS_MENU(Wnd, Style))
1300       {
1301          HDC hDC = UserGetDCEx(Wnd, 0, DCX_USESTYLE | DCX_WINDOW);
1302 
1303          Wnd->state |= WNDS_HASMENU;
1304 
1305          if (hDC)
1306          {
1307            RECT CliRect = *Rect;
1308            CliRect.bottom -= OrigRect.top;
1309            CliRect.right -= OrigRect.left;
1310            CliRect.left -= OrigRect.left;
1311            CliRect.top -= OrigRect.top;
1312            if (!Suspended) Rect->top += MENU_DrawMenuBar(hDC, &CliRect, Wnd, TRUE);
1313            UserReleaseDC(Wnd, hDC, FALSE);
1314          }
1315       }
1316 
1317       if (Wnd->ExStyle & WS_EX_CLIENTEDGE)
1318       {
1319          RECTL_vInflateRect(Rect, -2 * UserGetSystemMetrics(SM_CXBORDER), -2 * UserGetSystemMetrics(SM_CYBORDER));
1320       }
1321 
1322       if (Style & WS_VSCROLL)
1323       {
1324          if (Rect->right - Rect->left >= UserGetSystemMetrics(SM_CXVSCROLL))
1325          {
1326              Wnd->state |= WNDS_HASVERTICALSCROOLLBAR;
1327 
1328              /* rectangle is in screen coords when wparam is false */
1329              if (!wparam && (exStyle & WS_EX_LAYOUTRTL)) exStyle ^= WS_EX_LEFTSCROLLBAR;
1330 
1331              if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
1332                  Rect->left  += UserGetSystemMetrics(SM_CXVSCROLL);
1333              else
1334                  Rect->right -= UserGetSystemMetrics(SM_CXVSCROLL);
1335           }
1336       }
1337 
1338       if (Style & WS_HSCROLL)
1339       {
1340          if( Rect->bottom - Rect->top > UserGetSystemMetrics(SM_CYHSCROLL))
1341          {
1342               Wnd->state |= WNDS_HASHORIZONTALSCROLLBAR;
1343 
1344               Rect->bottom -= UserGetSystemMetrics(SM_CYHSCROLL);
1345          }
1346       }
1347 
1348       if (Rect->top > Rect->bottom)
1349          Rect->bottom = Rect->top;
1350 
1351       if (Rect->left > Rect->right)
1352          Rect->right = Rect->left;
1353    }
1354    else
1355    {
1356       Rect->right = Rect->left;
1357       Rect->bottom = Rect->top;
1358    }
1359 
1360    return Result;
1361 }
1362 
1363 static
1364 INT NC_DoNCActive(PWND Wnd)
1365 {
1366    INT Ret = 0;
1367 
1368    if ( IntGetSysColor(COLOR_CAPTIONTEXT) != IntGetSysColor(COLOR_INACTIVECAPTIONTEXT) ||
1369         IntGetSysColor(COLOR_ACTIVECAPTION) != IntGetSysColor(COLOR_INACTIVECAPTION) )
1370        Ret = DC_CAPTION;
1371 
1372    if (!(Wnd->style & WS_MINIMIZED) && UserHasThickFrameStyle(Wnd->style, Wnd->ExStyle))
1373    {
1374       //if (IntGetSysColor(COLOR_ACTIVEBORDER) != IntGetSysColor(COLOR_INACTIVEBORDER)) // Why are these the same?
1375       {
1376           Ret = DC_FRAME;
1377       }
1378    }
1379    return Ret;
1380 }
1381 
1382 LRESULT NC_HandleNCActivate( PWND Wnd, WPARAM wParam, LPARAM lParam )
1383 {
1384    INT Flags;
1385   /* Lotus Notes draws menu descriptions in the caption of its main
1386    * window. When it wants to restore original "system" view, it just
1387    * sends WM_NCACTIVATE message to itself. Any optimizations here in
1388    * attempt to minimize redrawings lead to a not restored caption.
1389    */
1390    if (wParam & DC_ACTIVE)
1391    {
1392       Wnd->state |= WNDS_ACTIVEFRAME|WNDS_HASCAPTION;
1393       wParam = DC_CAPTION|DC_ACTIVE;
1394    }
1395    else
1396    {
1397       Wnd->state &= ~WNDS_ACTIVEFRAME;
1398       wParam = DC_CAPTION;
1399    }
1400 
1401    if ((Wnd->state & WNDS_NONCPAINT) || !(Wnd->style & WS_VISIBLE))
1402       return TRUE;
1403 
1404    /* This isn't documented but is reproducible in at least XP SP2 and
1405     * Outlook 2007 depends on it
1406     */
1407    // MSDN:
1408    // If this parameter is set to -1, DefWindowProc does not repaint the
1409    // nonclient area to reflect the state change.
1410    if ( lParam != -1 &&
1411         ( Flags = NC_DoNCActive(Wnd)) != 0 )
1412    {
1413       HDC hDC;
1414       HRGN hRgnTemp = NULL, hRgn = (HRGN)lParam;
1415 
1416       if (GreIsHandleValid(hRgn))
1417       {
1418          hRgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0);
1419          if (NtGdiCombineRgn(hRgnTemp, hRgn, 0, RGN_COPY) == ERROR)
1420          {
1421             GreDeleteObject(hRgnTemp);
1422             hRgnTemp = NULL;
1423          }
1424       }
1425 
1426       if ((hDC = UserGetDCEx(Wnd, hRgnTemp, DCX_WINDOW|DCX_USESTYLE)))
1427       {
1428          NC_DoNCPaint(Wnd, hDC, wParam | Flags); // Redraw MENUs.
1429          UserReleaseDC(Wnd, hDC, FALSE);
1430       }
1431       else
1432          GreDeleteObject(hRgnTemp);
1433    }
1434 
1435    return TRUE;
1436 }
1437 
1438 VOID
1439 NC_DoButton(PWND pWnd, WPARAM wParam, LPARAM lParam)
1440 {
1441    MSG Msg;
1442    HDC WindowDC;
1443    BOOL Pressed = TRUE, OldState;
1444    WPARAM SCMsg;
1445    PMENU SysMenu;
1446    ULONG ButtonType;
1447    DWORD Style;
1448    UINT MenuState;
1449 
1450    Style = pWnd->style;
1451    switch (wParam)
1452    {
1453       case HTCLOSE:
1454          SysMenu = IntGetSystemMenu(pWnd, FALSE);
1455          MenuState = IntGetMenuState(SysMenu ? UserHMGetHandle(SysMenu) : NULL, SC_CLOSE, MF_BYCOMMAND); /* in case of error MenuState==0xFFFFFFFF */
1456          if (!(Style & WS_SYSMENU) || (MenuState & (MF_GRAYED|MF_DISABLED)) || (pWnd->style & CS_NOCLOSE))
1457             return;
1458          ButtonType = DFCS_CAPTIONCLOSE;
1459          SCMsg = SC_CLOSE;
1460          break;
1461       case HTMINBUTTON:
1462          if (!(Style & WS_MINIMIZEBOX))
1463             return;
1464          ButtonType = DFCS_CAPTIONMIN;
1465          SCMsg = ((Style & WS_MINIMIZE) ? SC_RESTORE : SC_MINIMIZE);
1466          break;
1467       case HTMAXBUTTON:
1468          if (!(Style & WS_MAXIMIZEBOX))
1469             return;
1470          ButtonType = DFCS_CAPTIONMAX;
1471          SCMsg = ((Style & WS_MAXIMIZE) ? SC_RESTORE : SC_MAXIMIZE);
1472          break;
1473 
1474       default:
1475          ASSERT(FALSE);
1476          return;
1477    }
1478 
1479    /*
1480     * FIXME: Not sure where to do this, but we must flush the pending
1481     * window updates when someone clicks on the close button and at
1482     * the same time the window is overlapped with another one. This
1483     * looks like a good place for now...
1484     */
1485    co_IntUpdateWindows(pWnd, RDW_ALLCHILDREN, FALSE);
1486 
1487    WindowDC = UserGetWindowDC(pWnd);
1488    UserDrawCaptionButtonWnd(pWnd, WindowDC, TRUE, ButtonType);
1489 
1490    co_UserSetCapture(UserHMGetHandle(pWnd));
1491 
1492    for (;;)
1493    {
1494       if (!co_IntGetPeekMessage(&Msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, TRUE)) break;
1495       if (IntCallMsgFilter( &Msg, MSGF_MAX )) continue;
1496 
1497       if (Msg.message == WM_LBUTTONUP)
1498          break;
1499 
1500       if (Msg.message != WM_MOUSEMOVE)
1501          continue;
1502 
1503       OldState = Pressed;
1504       Pressed = (GetNCHitEx(pWnd, Msg.pt) == wParam);
1505       if (Pressed != OldState)
1506          UserDrawCaptionButtonWnd(pWnd, WindowDC, Pressed, ButtonType);
1507    }
1508 
1509    if (Pressed)
1510       UserDrawCaptionButtonWnd(pWnd, WindowDC, FALSE, ButtonType);
1511    IntReleaseCapture();
1512    UserReleaseDC(pWnd, WindowDC, FALSE);
1513    if (Pressed)
1514       co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SCMsg, SCMsg == SC_CLOSE ? lParam : MAKELONG(Msg.pt.x,Msg.pt.y));
1515 }
1516 
1517 
1518 LRESULT
1519 NC_HandleNCLButtonDown(PWND pWnd, WPARAM wParam, LPARAM lParam)
1520 {
1521     switch (wParam)
1522     {
1523         case HTCAPTION:
1524         {
1525             PWND TopWnd = pWnd, parent;
1526             while(1)
1527             {
1528                 if ((TopWnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
1529                     break;
1530                 parent = UserGetAncestor( TopWnd, GA_PARENT );
1531                 if (!parent || UserIsDesktopWindow(parent)) break;
1532                 TopWnd = parent;
1533             }
1534 
1535             if ( (pWnd && (pWnd->ExStyle & WS_EX_NOACTIVATE)) ||
1536                  co_IntSetForegroundWindowMouse(TopWnd) ||
1537                  //NtUserCallHwndLock(hTopWnd, HWNDLOCK_ROUTINE_SETFOREGROUNDWINDOWMOUSE) ||
1538                  UserGetActiveWindow() == UserHMGetHandle(TopWnd))
1539             {
1540                co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam);
1541             }
1542             break;
1543         }
1544         case HTSYSMENU:
1545         {
1546           LONG style = pWnd->style;
1547           if (style & WS_SYSMENU)
1548           {
1549               if(!(style & WS_MINIMIZE) )
1550               {
1551                 RECT rect;
1552                 HDC hDC = UserGetWindowDC(pWnd);
1553                 NC_GetInsideRect(pWnd, &rect);
1554                 UserDrawSysMenuButton(pWnd, hDC, &rect, TRUE);
1555                 UserReleaseDC( pWnd, hDC, FALSE );
1556               }
1557 	      co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam);
1558 	  }
1559 	  break;
1560         }
1561         case HTMENU:
1562         {
1563             co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTMENU, lParam);
1564             break;
1565         }
1566         case HTHSCROLL:
1567         {
1568             co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam);
1569             break;
1570         }
1571         case HTVSCROLL:
1572         {
1573             co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam);
1574             break;
1575         }
1576         case HTMINBUTTON:
1577         case HTMAXBUTTON:
1578         case HTCLOSE:
1579         {
1580           NC_DoButton(pWnd, wParam, lParam);
1581           break;
1582         }
1583         case HTLEFT:
1584         case HTRIGHT:
1585         case HTTOP:
1586         case HTBOTTOM:
1587         case HTTOPLEFT:
1588         case HTTOPRIGHT:
1589         case HTBOTTOMLEFT:
1590         case HTBOTTOMRIGHT:
1591         {
1592            /* Old comment:
1593             * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1594             * This was previously done by setting wParam=SC_SIZE + wParam - 2
1595             */
1596            /* But that is not what WinNT does. Instead it sends this. This
1597             * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1598             * SC_MOUSEMENU into wParam.
1599             */
1600             co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT - WMSZ_LEFT), lParam);
1601             break;
1602         }
1603         case HTBORDER:
1604             break;
1605     }
1606     return(0);
1607 }
1608 
1609 
1610 LRESULT
1611 NC_HandleNCLButtonDblClk(PWND pWnd, WPARAM wParam, LPARAM lParam)
1612 {
1613   ULONG Style;
1614 
1615   Style = pWnd->style;
1616   switch(wParam)
1617   {
1618     case HTCAPTION:
1619     {
1620       /* Maximize/Restore the window */
1621       if((Style & WS_CAPTION) == WS_CAPTION && (Style & WS_MAXIMIZEBOX))
1622       {
1623         co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, ((Style & (WS_MINIMIZE | WS_MAXIMIZE)) ? SC_RESTORE : SC_MAXIMIZE), 0);
1624       }
1625       break;
1626     }
1627     case HTSYSMENU:
1628     {
1629       PMENU SysMenu = IntGetSystemMenu(pWnd, FALSE);
1630       UINT state = IntGetMenuState(SysMenu ? UserHMGetHandle(SysMenu) : NULL, SC_CLOSE, MF_BYCOMMAND);
1631 
1632       /* If the close item of the sysmenu is disabled or not present do nothing */
1633       if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1634           break;
1635 
1636       co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_CLOSE, lParam);
1637       break;
1638     }
1639     case HTTOP:
1640     case HTBOTTOM:
1641     {
1642       RECT sizingRect = pWnd->rcWindow, mouseRect;
1643 
1644       if (pWnd->ExStyle & WS_EX_MDICHILD)
1645           break;
1646 
1647       UserSystemParametersInfo(SPI_GETWORKAREA, 0, &mouseRect, 0);
1648 
1649       co_WinPosSetWindowPos(pWnd,
1650                             0,
1651                             sizingRect.left,
1652                             mouseRect.top,
1653                             sizingRect.right - sizingRect.left,
1654                             mouseRect.bottom - mouseRect.top,
1655                             0);
1656       break;
1657     }
1658     default:
1659       return NC_HandleNCLButtonDown(pWnd, wParam, lParam);
1660   }
1661   return(0);
1662 }
1663 
1664 /***********************************************************************
1665  *           NC_HandleNCRButtonDown
1666  *
1667  * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1668  */
1669 LRESULT NC_HandleNCRButtonDown( PWND pwnd, WPARAM wParam, LPARAM lParam )
1670 {
1671   MSG msg;
1672   INT hittest = wParam;
1673 
1674   switch (hittest)
1675   {
1676   case HTCAPTION:
1677   case HTSYSMENU:
1678       if (!IntGetSystemMenu( pwnd, FALSE )) break;
1679 
1680       co_UserSetCapture( UserHMGetHandle(pwnd) );
1681       for (;;)
1682       {
1683           if (!co_IntGetPeekMessage(&msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, TRUE)) break;
1684           if (IntCallMsgFilter( &msg, MSGF_MAX )) continue;
1685           if (msg.message == WM_RBUTTONUP)
1686           {
1687              hittest = GetNCHitEx( pwnd, msg.pt );
1688              break;
1689           }
1690           if (UserHMGetHandle(pwnd) != IntGetCapture()) return 0;
1691       }
1692       IntReleaseCapture();
1693 
1694       if (hittest == HTCAPTION || hittest == HTSYSMENU || hittest == HTHSCROLL || hittest == HTVSCROLL)
1695       {
1696          TRACE("Msg pt %x and Msg.lParam %x and lParam %x\n",MAKELONG(msg.pt.x,msg.pt.y),msg.lParam,lParam);
1697          co_IntSendMessage( UserHMGetHandle(pwnd), WM_CONTEXTMENU, (WPARAM)UserHMGetHandle(pwnd), MAKELONG(msg.pt.x,msg.pt.y));
1698       }
1699       break;
1700   }
1701   return 0;
1702 }
1703 
1704 
1705 #if 0 // Old version, kept there for reference, which is also used
1706       // almost unmodified in uxtheme.dll (in nonclient.c)
1707 /*
1708  * FIXME:
1709  * - Check the scrollbar handling
1710  */
1711 LRESULT
1712 DefWndNCHitTest(HWND hWnd, POINT Point)
1713 {
1714    RECT WindowRect, ClientRect, OrigWndRect;
1715    POINT ClientPoint;
1716    SIZE WindowBorders;
1717    DWORD Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
1718    DWORD ExStyle = GetWindowLongPtrW(hWnd, GWL_EXSTYLE);
1719 
1720    GetWindowRect(hWnd, &WindowRect);
1721    if (!PtInRect(&WindowRect, Point))
1722    {
1723       return HTNOWHERE;
1724    }
1725    OrigWndRect = WindowRect;
1726 
1727    if (UserHasWindowEdge(Style, ExStyle))
1728    {
1729       LONG XSize, YSize;
1730 
1731       UserGetWindowBorders(Style, ExStyle, &WindowBorders, FALSE);
1732       InflateRect(&WindowRect, -WindowBorders.cx, -WindowBorders.cy);
1733       XSize = GetSystemMetrics(SM_CXSIZE) * GetSystemMetrics(SM_CXBORDER);
1734       YSize = GetSystemMetrics(SM_CYSIZE) * GetSystemMetrics(SM_CYBORDER);
1735       if (!PtInRect(&WindowRect, Point))
1736       {
1737          BOOL ThickFrame;
1738 
1739          ThickFrame = (Style & WS_THICKFRAME);
1740          if (Point.y < WindowRect.top)
1741          {
1742             if(Style & WS_MINIMIZE)
1743               return HTCAPTION;
1744             if(!ThickFrame)
1745               return HTBORDER;
1746             if (Point.x < (WindowRect.left + XSize))
1747                return HTTOPLEFT;
1748             if (Point.x >= (WindowRect.right - XSize))
1749                return HTTOPRIGHT;
1750             return HTTOP;
1751          }
1752          if (Point.y >= WindowRect.bottom)
1753          {
1754             if(Style & WS_MINIMIZE)
1755               return HTCAPTION;
1756             if(!ThickFrame)
1757               return HTBORDER;
1758             if (Point.x < (WindowRect.left + XSize))
1759                return HTBOTTOMLEFT;
1760             if (Point.x >= (WindowRect.right - XSize))
1761                return HTBOTTOMRIGHT;
1762             return HTBOTTOM;
1763          }
1764          if (Point.x < WindowRect.left)
1765          {
1766             if(Style & WS_MINIMIZE)
1767               return HTCAPTION;
1768             if(!ThickFrame)
1769               return HTBORDER;
1770             if (Point.y < (WindowRect.top + YSize))
1771                return HTTOPLEFT;
1772             if (Point.y >= (WindowRect.bottom - YSize))
1773                return HTBOTTOMLEFT;
1774             return HTLEFT;
1775          }
1776          if (Point.x >= WindowRect.right)
1777          {
1778             if(Style & WS_MINIMIZE)
1779               return HTCAPTION;
1780             if(!ThickFrame)
1781               return HTBORDER;
1782             if (Point.y < (WindowRect.top + YSize))
1783                return HTTOPRIGHT;
1784             if (Point.y >= (WindowRect.bottom - YSize))
1785                return HTBOTTOMRIGHT;
1786             return HTRIGHT;
1787          }
1788       }
1789    }
1790    else
1791    {
1792       if (ExStyle & WS_EX_STATICEDGE)
1793          InflateRect(&WindowRect,
1794             -GetSystemMetrics(SM_CXBORDER),
1795             -GetSystemMetrics(SM_CYBORDER));
1796       if (!PtInRect(&WindowRect, Point))
1797          return HTBORDER;
1798    }
1799 
1800    if ((Style & WS_CAPTION) == WS_CAPTION)
1801    {
1802       if (ExStyle & WS_EX_TOOLWINDOW)
1803          WindowRect.top += GetSystemMetrics(SM_CYSMCAPTION);
1804       else
1805          WindowRect.top += GetSystemMetrics(SM_CYCAPTION);
1806       if (!PtInRect(&WindowRect, Point))
1807       {
1808          if (Style & WS_SYSMENU)
1809          {
1810             if (ExStyle & WS_EX_TOOLWINDOW)
1811             {
1812                WindowRect.right -= GetSystemMetrics(SM_CXSMSIZE);
1813             }
1814             else
1815             {
1816                // if(!(ExStyle & WS_EX_DLGMODALFRAME))
1817                // FIXME: The real test should check whether there is
1818                // an icon for the system window, and if so, do the
1819                // rect.left increase.
1820                // See dll/win32/uxtheme/nonclient.c!DefWndNCHitTest
1821                // and win32ss/user/ntuser/nonclient.c!GetNCHitEx which does
1822                // the test better.
1823                   WindowRect.left += GetSystemMetrics(SM_CXSIZE);
1824                WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
1825             }
1826          }
1827          if (Point.x < WindowRect.left)
1828             return HTSYSMENU;
1829          if (WindowRect.right <= Point.x)
1830             return HTCLOSE;
1831          if (Style & WS_MAXIMIZEBOX || Style & WS_MINIMIZEBOX)
1832             WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
1833          if (Point.x >= WindowRect.right)
1834             return HTMAXBUTTON;
1835          if (Style & WS_MINIMIZEBOX)
1836             WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
1837          if (Point.x >= WindowRect.right)
1838             return HTMINBUTTON;
1839          return HTCAPTION;
1840       }
1841    }
1842 
1843    if(!(Style & WS_MINIMIZE))
1844    {
1845      ClientPoint = Point;
1846      ScreenToClient(hWnd, &ClientPoint);
1847      GetClientRect(hWnd, &ClientRect);
1848 
1849      if (PtInRect(&ClientRect, ClientPoint))
1850      {
1851         return HTCLIENT;
1852      }
1853 
1854      if (GetMenu(hWnd) && !(Style & WS_CHILD))
1855      {
1856         if (Point.x > 0 && Point.x < WindowRect.right && ClientPoint.y < 0)
1857            return HTMENU;
1858      }
1859 
1860      if (ExStyle & WS_EX_CLIENTEDGE)
1861      {
1862         InflateRect(&WindowRect, -2 * GetSystemMetrics(SM_CXBORDER),
1863            -2 * GetSystemMetrics(SM_CYBORDER));
1864      }
1865 
1866      if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) &&
1867          (WindowRect.bottom - WindowRect.top) > GetSystemMetrics(SM_CYHSCROLL))
1868      {
1869         RECT ParentRect, TempRect = WindowRect, TempRect2 = WindowRect;
1870         HWND Parent = GetParent(hWnd);
1871 
1872         TempRect.bottom -= GetSystemMetrics(SM_CYHSCROLL);
1873         if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1874            TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
1875         else
1876            TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
1877         if (PtInRect(&TempRect, Point))
1878            return HTVSCROLL;
1879 
1880         TempRect2.top = TempRect2.bottom - GetSystemMetrics(SM_CYHSCROLL);
1881         if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1882            TempRect2.left += GetSystemMetrics(SM_CXVSCROLL);
1883         else
1884            TempRect2.right -= GetSystemMetrics(SM_CXVSCROLL);
1885         if (PtInRect(&TempRect2, Point))
1886            return HTHSCROLL;
1887 
1888         TempRect.top = TempRect2.top;
1889         TempRect.bottom = TempRect2.bottom;
1890         if(Parent)
1891           GetClientRect(Parent, &ParentRect);
1892         if (PtInRect(&TempRect, Point) && HASSIZEGRIP(Style, ExStyle,
1893             GetWindowLongPtrW(Parent, GWL_STYLE), OrigWndRect, ParentRect))
1894         {
1895            if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1896               return HTBOTTOMLEFT;
1897            else
1898               return HTBOTTOMRIGHT;
1899         }
1900      }
1901      else
1902      {
1903         if (Style & WS_VSCROLL)
1904         {
1905            RECT TempRect = WindowRect;
1906 
1907            if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1908               TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
1909            else
1910               TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
1911            if (PtInRect(&TempRect, Point))
1912               return HTVSCROLL;
1913         } else
1914         if (Style & WS_HSCROLL)
1915         {
1916            RECT TempRect = WindowRect;
1917            TempRect.top = TempRect.bottom - GetSystemMetrics(SM_CYHSCROLL);
1918            if (PtInRect(&TempRect, Point))
1919               return HTHSCROLL;
1920         }
1921      }
1922    }
1923 
1924    return HTNOWHERE;
1925 }
1926 #endif
1927 
1928 DWORD FASTCALL
1929 GetNCHitEx(PWND pWnd, POINT pt)
1930 {
1931    RECT rcWindow, rcClient;
1932    DWORD Style, ExStyle;
1933 
1934    if (!pWnd) return HTNOWHERE;
1935 
1936    if (UserIsDesktopWindow(pWnd))
1937    {
1938       rcClient.left = rcClient.top = rcWindow.left = rcWindow.top = 0;
1939       rcWindow.right  = UserGetSystemMetrics(SM_CXSCREEN);
1940       rcWindow.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1941       rcClient.right  = UserGetSystemMetrics(SM_CXSCREEN);
1942       rcClient.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1943    }
1944    else
1945    {
1946       rcClient = pWnd->rcClient;
1947       rcWindow = pWnd->rcWindow;
1948    }
1949 
1950    if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y)) return HTNOWHERE;
1951 
1952    Style = pWnd->style;
1953    ExStyle = pWnd->ExStyle;
1954 
1955    if (Style & WS_MINIMIZE) return HTCAPTION;
1956 
1957    if (RECTL_bPointInRect( &rcClient,  pt.x, pt.y )) return HTCLIENT;
1958 
1959    /* Check borders */
1960    if (HAS_THICKFRAME( Style, ExStyle ))
1961    {
1962       RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME) );
1963       if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y ))
1964       {
1965             /* Check top sizing border */
1966             if (pt.y < rcWindow.top)
1967             {
1968                 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
1969                 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
1970                 return HTTOP;
1971             }
1972             /* Check bottom sizing border */
1973             if (pt.y >= rcWindow.bottom)
1974             {
1975                 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
1976                 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
1977                 return HTBOTTOM;
1978             }
1979             /* Check left sizing border */
1980             if (pt.x < rcWindow.left)
1981             {
1982                 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
1983                 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
1984                 return HTLEFT;
1985             }
1986             /* Check right sizing border */
1987             if (pt.x >= rcWindow.right)
1988             {
1989                 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
1990                 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
1991                 return HTRIGHT;
1992             }
1993         }
1994     }
1995     else  /* No thick frame */
1996     {
1997         if (HAS_DLGFRAME( Style, ExStyle ))
1998             RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME));
1999         else if (HAS_THINFRAME( Style, ExStyle ))
2000             RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
2001         else if (HAS_CLIENTFRAME( Style, ExStyle ))
2002             RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXEDGE), -UserGetSystemMetrics(SM_CYEDGE));
2003         if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y  )) return HTBORDER;
2004     }
2005 
2006     /* Check caption */
2007 
2008     if ((Style & WS_CAPTION) == WS_CAPTION)
2009     {
2010         if (ExStyle & WS_EX_TOOLWINDOW)
2011             rcWindow.top += UserGetSystemMetrics(SM_CYSMCAPTION) - 1;
2012         else
2013             rcWindow.top += UserGetSystemMetrics(SM_CYCAPTION) - 1;
2014         if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y ))
2015         {
2016             BOOL min_or_max_box = (Style & WS_SYSMENU) && (Style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX));
2017             if (ExStyle & WS_EX_LAYOUTRTL)
2018             {
2019                 /* Check system menu */
2020                 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd))
2021                 {
2022                     rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION) - 1;
2023                     if (pt.x > rcWindow.right) return HTSYSMENU;
2024                 }
2025 
2026                 /* Check close button */
2027                 if (Style & WS_SYSMENU)
2028                 {
2029                     rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION);
2030                     if (pt.x < rcWindow.left) return HTCLOSE;
2031                 }
2032 
2033                 /* Check maximize box */
2034                 /* In Win95 there is automatically a Maximize button when there is a minimize one */
2035                 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
2036                 {
2037                     rcWindow.left += UserGetSystemMetrics(SM_CXSIZE);
2038                     if (pt.x < rcWindow.left) return HTMAXBUTTON;
2039                 }
2040 
2041                 /* Check minimize box */
2042                 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
2043                 {
2044                     rcWindow.left += UserGetSystemMetrics(SM_CXSIZE);
2045                     if (pt.x < rcWindow.left) return HTMINBUTTON;
2046                 }
2047             }
2048             else
2049             {
2050                 /* Check system menu */
2051                 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd))
2052                 {
2053                     rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION) - 1;
2054                     if (pt.x < rcWindow.left) return HTSYSMENU;
2055                 }
2056 
2057                 /* Check close button */
2058                 if (Style & WS_SYSMENU)
2059                 {
2060                     rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION);
2061                     if (pt.x > rcWindow.right) return HTCLOSE;
2062                 }
2063 
2064                 /* Check maximize box */
2065                 /* In Win95 there is automatically a Maximize button when there is a minimize one */
2066                 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
2067                 {
2068                     rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE);
2069                     if (pt.x > rcWindow.right) return HTMAXBUTTON;
2070                 }
2071 
2072                 /* Check minimize box */
2073                 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
2074                 {
2075                     rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE);
2076                     if (pt.x > rcWindow.right) return HTMINBUTTON;
2077                 }
2078             }
2079             return HTCAPTION;
2080         }
2081     }
2082 
2083       /* Check menu bar */
2084 
2085     if (HAS_MENU( pWnd, Style ) && (pt.y < rcClient.top) &&
2086         (pt.x >= rcClient.left) && (pt.x < rcClient.right))
2087         return HTMENU;
2088 
2089       /* Check vertical scroll bar */
2090 
2091     if (ExStyle & WS_EX_LAYOUTRTL) ExStyle ^= WS_EX_LEFTSCROLLBAR;
2092     if (Style & WS_VSCROLL)
2093     {
2094         if((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
2095             rcClient.left -= UserGetSystemMetrics(SM_CXVSCROLL);
2096         else
2097             rcClient.right += UserGetSystemMetrics(SM_CXVSCROLL);
2098         if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTVSCROLL;
2099     }
2100 
2101       /* Check horizontal scroll bar */
2102 
2103     if (Style & WS_HSCROLL)
2104     {
2105         rcClient.bottom += UserGetSystemMetrics(SM_CYHSCROLL);
2106         if (RECTL_bPointInRect( &rcClient, pt.x, pt.y ))
2107         {
2108             /* Check size box */
2109             if ((Style & WS_VSCROLL) &&
2110                 ((((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + UserGetSystemMetrics(SM_CXVSCROLL))) ||
2111                 (((ExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - UserGetSystemMetrics(SM_CXVSCROLL)))))
2112                 return HTSIZE;
2113             return HTHSCROLL;
2114         }
2115     }
2116 
2117     /* Has to return HTNOWHERE if nothing was found
2118        Could happen when a window has a customized non client area */
2119     return HTNOWHERE;
2120 }
2121 
2122 /* EOF */
2123