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