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