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