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