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