setupapi: Improve parameter validation for SetupCreateDiskSpaceListA/W.
[wine] / dlls / user32 / nonclient.c
1 /*
2  * Non-client area window functions
3  *
4  * Copyright 1994 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winnls.h"
29 #include "win.h"
30 #include "user_private.h"
31 #include "controls.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
35
36 #define SC_ABOUTWINE            (SC_SCREENSAVE+1)
37
38   /* Some useful macros */
39 #define HAS_DLGFRAME(style,exStyle) \
40     (((exStyle) & WS_EX_DLGMODALFRAME) || \
41      (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
42
43 #define HAS_THICKFRAME(style,exStyle) \
44     (((style) & WS_THICKFRAME) && \
45      !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
46
47 #define HAS_THINFRAME(style) \
48     (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
49
50 #define HAS_BIGFRAME(style,exStyle) \
51     (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
52      ((exStyle) & WS_EX_DLGMODALFRAME))
53
54 #define HAS_STATICOUTERFRAME(style,exStyle) \
55     (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
56      WS_EX_STATICEDGE)
57
58 #define HAS_ANYFRAME(style,exStyle) \
59     (((style) & (WS_THICKFRAME | WS_DLGFRAME | WS_BORDER)) || \
60      ((exStyle) & WS_EX_DLGMODALFRAME) || \
61      !((style) & (WS_CHILD | WS_POPUP)))
62
63 #define HAS_MENU(w)  ((((w)->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) && ((w)->wIDmenu != 0))
64
65
66 /******************************************************************************
67  * NC_AdjustRectOuter
68  *
69  * Computes the size of the "outside" parts of the window based on the
70  * parameters of the client area.
71  *
72  * PARAMS
73  *     LPRECT  rect
74  *     DWORD  style
75  *     BOOL  menu
76  *     DWORD  exStyle
77  *
78  * NOTES
79  *     "Outer" parts of a window means the whole window frame, caption and
80  *     menu bar. It does not include "inner" parts of the frame like client
81  *     edge, static edge or scroll bars.
82  *
83  *****************************************************************************/
84
85 static void
86 NC_AdjustRectOuter (LPRECT rect, DWORD style, BOOL menu, DWORD exStyle)
87 {
88     int adjust;
89     if(style & WS_ICONIC) return;
90
91     if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) ==
92         WS_EX_STATICEDGE)
93     {
94         adjust = 1; /* for the outer frame always present */
95     }
96     else
97     {
98         adjust = 0;
99         if ((exStyle & WS_EX_DLGMODALFRAME) ||
100             (style & (WS_THICKFRAME|WS_DLGFRAME))) adjust = 2; /* outer */
101     }
102     if (style & WS_THICKFRAME)
103         adjust +=  ( GetSystemMetrics (SM_CXFRAME)
104                    - GetSystemMetrics (SM_CXDLGFRAME)); /* The resize border */
105     if ((style & (WS_BORDER|WS_DLGFRAME)) ||
106         (exStyle & WS_EX_DLGMODALFRAME))
107         adjust++; /* The other border */
108
109     InflateRect (rect, adjust, adjust);
110
111     if ((style & WS_CAPTION) == WS_CAPTION)
112     {
113         if (exStyle & WS_EX_TOOLWINDOW)
114             rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
115         else
116             rect->top -= GetSystemMetrics(SM_CYCAPTION);
117     }
118     if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
119 }
120
121
122 /******************************************************************************
123  * NC_AdjustRectInner
124  *
125  * Computes the size of the "inside" part of the window based on the
126  * parameters of the client area.
127  *
128  * PARAMS
129  *     LPRECT   rect
130  *     DWORD    style
131  *     DWORD    exStyle
132  *
133  * NOTES
134  *     "Inner" part of a window means the window frame inside of the flat
135  *     window frame. It includes the client edge, the static edge and the
136  *     scroll bars.
137  *
138  *****************************************************************************/
139
140 static void
141 NC_AdjustRectInner (LPRECT rect, DWORD style, DWORD exStyle)
142 {
143     if(style & WS_ICONIC) return;
144
145     if (exStyle & WS_EX_CLIENTEDGE)
146         InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
147
148     if (style & WS_VSCROLL)
149     {
150         if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
151             rect->left  -= GetSystemMetrics(SM_CXVSCROLL);
152         else
153             rect->right += GetSystemMetrics(SM_CXVSCROLL);
154     }
155     if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
156 }
157
158
159
160 static HICON NC_IconForWindow( HWND hwnd )
161 {
162     HICON hIcon = 0;
163     WND *wndPtr = WIN_GetPtr( hwnd );
164
165     if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
166     {
167         hIcon = wndPtr->hIconSmall;
168         if (!hIcon) hIcon = wndPtr->hIcon;
169         WIN_ReleasePtr( wndPtr );
170     }
171     if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICONSM );
172     if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICON );
173
174     /* If there is no hIcon specified and this is a modal dialog,
175      * get the default one.
176      */
177     if (!hIcon && (GetWindowLongW( hwnd, GWL_STYLE ) & DS_MODALFRAME))
178         hIcon = LoadImageW(0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
179     return hIcon;
180 }
181
182 /* Draws the bar part(ie the big rectangle) of the caption */
183 static void NC_DrawCaptionBar (HDC hdc, const RECT *rect, DWORD dwStyle, 
184                                BOOL active, BOOL gradient)
185 {
186     if (gradient)
187     {
188         TRIVERTEX vertices[6];
189         DWORD colLeft = 
190             GetSysColor (active ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION);
191         DWORD colRight = 
192             GetSysColor (active ? COLOR_GRADIENTACTIVECAPTION 
193                                 : COLOR_GRADIENTINACTIVECAPTION);
194         int v;
195         int buttonsAreaSize = GetSystemMetrics(SM_CYCAPTION) - 1;
196         static GRADIENT_RECT mesh[] = {{0, 1}, {2, 3}, {4, 5}};
197     
198         for (v = 0; v < 3; v++)
199         {
200             vertices[v].Red = GetRValue (colLeft) << 8;
201             vertices[v].Green = GetGValue (colLeft) << 8;
202             vertices[v].Blue = GetBValue (colLeft) << 8;
203             vertices[v].Alpha = 0x8000;
204             vertices[v+3].Red = GetRValue (colRight) << 8;
205             vertices[v+3].Green = GetGValue (colRight) << 8;
206             vertices[v+3].Blue = GetBValue (colRight) << 8;
207             vertices[v+3].Alpha = 0x8000;
208         }
209     
210         if ((dwStyle & WS_SYSMENU) 
211             && ((dwStyle & WS_MAXIMIZEBOX) || (dwStyle & WS_MINIMIZEBOX)))
212             buttonsAreaSize += 2 * (GetSystemMetrics(SM_CXSIZE) + 1);
213         
214         /* area behind icon; solid filled with left color */
215         vertices[0].x = rect->left;
216         vertices[0].y = rect->top;
217         if (dwStyle & WS_SYSMENU) 
218             vertices[1].x = 
219                 min (rect->left + GetSystemMetrics(SM_CXSMICON), rect->right);
220         else
221             vertices[1].x = vertices[0].x;
222         vertices[1].y = rect->bottom;
223         
224         /* area behind text; gradient */
225         vertices[2].x = vertices[1].x;
226         vertices[2].y = rect->top;
227         vertices[3].x = max (vertices[2].x, rect->right - buttonsAreaSize);
228         vertices[3].y = rect->bottom;
229         
230         /* area behind buttons; solid filled with right color */
231         vertices[4].x = vertices[3].x;
232         vertices[4].y = rect->top;
233         vertices[5].x = rect->right;
234         vertices[5].y = rect->bottom;
235         
236         GdiGradientFill (hdc, vertices, 6, mesh, 3, GRADIENT_FILL_RECT_H);
237     }
238     else
239         FillRect (hdc, rect, GetSysColorBrush (active ?
240                   COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
241 }
242
243 /***********************************************************************
244  *              DrawCaption (USER32.@) Draws a caption bar
245  *
246  * PARAMS
247  *     hwnd   [I]
248  *     hdc    [I]
249  *     lpRect [I]
250  *     uFlags [I]
251  *
252  * RETURNS
253  *     Success:
254  *     Failure:
255  */
256
257 BOOL WINAPI
258 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
259 {
260     return DrawCaptionTempW (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x103F);
261 }
262
263
264 /***********************************************************************
265  *              DrawCaptionTempA (USER32.@)
266  */
267 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
268                               HICON hIcon, LPCSTR str, UINT uFlags)
269 {
270     LPWSTR strW;
271     INT len;
272     BOOL ret = FALSE;
273
274     if (!(uFlags & DC_TEXT) || !str)
275         return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
276
277     len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
278     if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
279     {
280         MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
281         ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
282         HeapFree( GetProcessHeap (), 0, strW );
283     }
284     return ret;
285 }
286
287
288 /***********************************************************************
289  *              DrawCaptionTempW (USER32.@)
290  */
291 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
292                               HICON hIcon, LPCWSTR str, UINT uFlags)
293 {
294     RECT   rc = *rect;
295
296     TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
297           hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
298
299     /* drawing background */
300     if (uFlags & DC_INBUTTON) {
301         FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
302
303         if (uFlags & DC_ACTIVE) {
304             HBRUSH hbr = SelectObject (hdc, SYSCOLOR_55AABrush);
305             PatBlt (hdc, rc.left, rc.top,
306                       rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
307             SelectObject (hdc, hbr);
308         }
309     }
310     else {
311         DWORD style = GetWindowLongW (hwnd, GWL_STYLE);
312         NC_DrawCaptionBar (hdc, &rc, style, uFlags & DC_ACTIVE, uFlags & DC_GRADIENT);
313     }
314
315
316     /* drawing icon */
317     if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
318         POINT pt;
319
320         pt.x = rc.left + 2;
321         pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
322
323         if (!hIcon) hIcon = NC_IconForWindow(hwnd);
324         DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
325                     GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
326         rc.left += (rc.bottom - rc.top);
327     }
328
329     /* drawing text */
330     if (uFlags & DC_TEXT) {
331         HFONT hOldFont;
332
333         if (uFlags & DC_INBUTTON)
334             SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
335         else if (uFlags & DC_ACTIVE)
336             SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
337         else
338             SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
339
340         SetBkMode (hdc, TRANSPARENT);
341
342         if (hFont)
343             hOldFont = SelectObject (hdc, hFont);
344         else {
345             NONCLIENTMETRICSW nclm;
346             HFONT hNewFont;
347             nclm.cbSize = sizeof(NONCLIENTMETRICSW);
348             SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
349             hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
350                 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
351             hOldFont = SelectObject (hdc, hNewFont);
352         }
353
354         if (str)
355             DrawTextW (hdc, str, -1, &rc,
356                          DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
357         else {
358             WCHAR szText[128];
359             INT nLen;
360             nLen = GetWindowTextW (hwnd, szText, 128);
361             DrawTextW (hdc, szText, nLen, &rc,
362                          DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
363         }
364
365         if (hFont)
366             SelectObject (hdc, hOldFont);
367         else
368             DeleteObject (SelectObject (hdc, hOldFont));
369     }
370
371     /* drawing focus ??? */
372     if (uFlags & 0x2000)
373         FIXME("undocumented flag (0x2000)!\n");
374
375     return 0;
376 }
377
378
379 /***********************************************************************
380  *              AdjustWindowRect (USER32.@)
381  */
382 BOOL WINAPI AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
383 {
384     return AdjustWindowRectEx( rect, style, menu, 0 );
385 }
386
387
388 /***********************************************************************
389  *              AdjustWindowRectEx (USER32.@)
390  */
391 BOOL WINAPI AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
392 {
393     /* Correct the window style */
394     style &= (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME | WS_CHILD);
395     exStyle &= (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE |
396                 WS_EX_STATICEDGE | WS_EX_TOOLWINDOW);
397     if (exStyle & WS_EX_DLGMODALFRAME) style &= ~WS_THICKFRAME;
398
399     TRACE("(%s) %08x %d %08x\n", wine_dbgstr_rect(rect), style, menu, exStyle );
400
401     NC_AdjustRectOuter( rect, style, menu, exStyle );
402     NC_AdjustRectInner( rect, style, exStyle );
403
404     return TRUE;
405 }
406
407
408 /***********************************************************************
409  *           NC_HandleNCCalcSize
410  *
411  * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
412  */
413 LRESULT NC_HandleNCCalcSize( HWND hwnd, RECT *winRect )
414 {
415     RECT tmpRect = { 0, 0, 0, 0 };
416     LRESULT result = 0;
417     LONG cls_style = GetClassLongW(hwnd, GCL_STYLE);
418     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
419     LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
420
421     if (winRect == NULL)
422         return 0;
423
424     if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
425     if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
426
427     if (!IsIconic(hwnd))
428     {
429         NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
430
431         winRect->left   -= tmpRect.left;
432         winRect->top    -= tmpRect.top;
433         winRect->right  -= tmpRect.right;
434         winRect->bottom -= tmpRect.bottom;
435
436         if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
437         {
438             TRACE("Calling GetMenuBarHeight with hwnd %p, width %d, at (%d, %d).\n",
439                   hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
440
441             winRect->top +=
442                 MENU_GetMenuBarHeight( hwnd,
443                                        winRect->right - winRect->left,
444                                        -tmpRect.left, -tmpRect.top );
445         }
446
447         if( exStyle & WS_EX_CLIENTEDGE)
448             if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) &&
449                    winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE))
450                 InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE),
451                         - GetSystemMetrics(SM_CYEDGE));
452
453         if (style & WS_VSCROLL)
454             if( winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL)){
455                 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
456                     winRect->left  += GetSystemMetrics(SM_CXVSCROLL);
457                 else
458                     winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
459             }
460
461         if (style & WS_HSCROLL)
462             if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
463                     winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
464
465         if (winRect->top > winRect->bottom)
466             winRect->bottom = winRect->top;
467
468         if (winRect->left > winRect->right)
469             winRect->right = winRect->left;
470     }
471     return result;
472 }
473
474
475 /***********************************************************************
476  *           NC_GetInsideRect
477  *
478  * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
479  * but without the borders (if any).
480  */
481 static void NC_GetInsideRect( HWND hwnd, enum coords_relative relative, RECT *rect,
482                               DWORD style, DWORD ex_style )
483 {
484     WIN_GetRectangles( hwnd, relative, rect, NULL );
485
486     if (style & WS_ICONIC) return;
487
488     /* Remove frame from rectangle */
489     if (HAS_THICKFRAME( style, ex_style ))
490     {
491         InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
492     }
493     else if (HAS_DLGFRAME( style, ex_style ))
494     {
495         InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
496     }
497     else if (HAS_THINFRAME( style ))
498     {
499         InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
500     }
501
502     /* We have additional border information if the window
503      * is a child (but not an MDI child) */
504     if ((style & WS_CHILD) && !(ex_style & WS_EX_MDICHILD))
505     {
506         if (ex_style & WS_EX_CLIENTEDGE)
507             InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
508         if (ex_style & WS_EX_STATICEDGE)
509             InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
510     }
511 }
512
513
514 /***********************************************************************
515  * NC_DoNCHitTest
516  *
517  * Handle a WM_NCHITTEST message. Called from NC_HandleNCHitTest().
518  *
519  * FIXME:  Just a modified copy of the Win 3.1 version.
520  */
521
522 static LRESULT NC_DoNCHitTest (WND *wndPtr, POINT pt )
523 {
524     RECT rect, rcClient;
525     POINT ptClient;
526
527     TRACE("hwnd=%p pt=%d,%d\n", wndPtr->obj.handle, pt.x, pt.y );
528
529     GetWindowRect(wndPtr->obj.handle, &rect );
530     if (!PtInRect( &rect, pt )) return HTNOWHERE;
531
532     if (wndPtr->dwStyle & WS_MINIMIZE) return HTCAPTION;
533
534     /* Check client area */
535     ptClient = pt;
536     ScreenToClient( wndPtr->obj.handle, &ptClient );
537     GetClientRect( wndPtr->obj.handle, &rcClient );
538     if (PtInRect( &rcClient, ptClient )) return HTCLIENT;
539
540     /* Check borders */
541     if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
542     {
543         InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
544         if (!PtInRect( &rect, pt ))
545         {
546             /* Check top sizing border */
547             if (pt.y < rect.top)
548             {
549                 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
550                 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
551                 return HTTOP;
552             }
553             /* Check bottom sizing border */
554             if (pt.y >= rect.bottom)
555             {
556                 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
557                 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
558                 return HTBOTTOM;
559             }
560             /* Check left sizing border */
561             if (pt.x < rect.left)
562             {
563                 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
564                 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
565                 return HTLEFT;
566             }
567             /* Check right sizing border */
568             if (pt.x >= rect.right)
569             {
570                 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
571                 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
572                 return HTRIGHT;
573             }
574         }
575     }
576     else  /* No thick frame */
577     {
578         if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
579             InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
580         else if (HAS_THINFRAME( wndPtr->dwStyle ))
581             InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
582         if (!PtInRect( &rect, pt )) return HTBORDER;
583     }
584
585     /* Check caption */
586
587     if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION)
588     {
589         if (wndPtr->dwExStyle & WS_EX_TOOLWINDOW)
590             rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
591         else
592             rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
593         if (!PtInRect( &rect, pt ))
594         {
595             BOOL min_or_max_box = (wndPtr->dwStyle & WS_MAXIMIZEBOX) ||
596                                   (wndPtr->dwStyle & WS_MINIMIZEBOX);
597             /* Check system menu */
598             if ((wndPtr->dwStyle & WS_SYSMENU) && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
599             {
600                 if (NC_IconForWindow(wndPtr->obj.handle))
601                     rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
602             }
603             if (pt.x < rect.left) return HTSYSMENU;
604
605             /* Check close button */
606             if (wndPtr->dwStyle & WS_SYSMENU)
607                 rect.right -= GetSystemMetrics(SM_CYCAPTION);
608             if (pt.x > rect.right) return HTCLOSE;
609
610             /* Check maximize box */
611             /* In win95 there is automatically a Maximize button when there is a minimize one*/
612             if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
613                 rect.right -= GetSystemMetrics(SM_CXSIZE);
614             if (pt.x > rect.right) return HTMAXBUTTON;
615
616             /* Check minimize box */
617             /* In win95 there is automatically a Maximize button when there is a Maximize one*/
618             if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
619                 rect.right -= GetSystemMetrics(SM_CXSIZE);
620
621             if (pt.x > rect.right) return HTMINBUTTON;
622             return HTCAPTION;
623         }
624     }
625
626       /* Check vertical scroll bar */
627
628     if (wndPtr->dwStyle & WS_VSCROLL)
629     {
630         if((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
631             rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
632         else
633             rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
634         if (PtInRect( &rcClient, ptClient )) return HTVSCROLL;
635     }
636
637       /* Check horizontal scroll bar */
638
639     if (wndPtr->dwStyle & WS_HSCROLL)
640     {
641         rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
642         if (PtInRect( &rcClient, ptClient ))
643         {
644             /* Check size box */
645             if ((wndPtr->dwStyle & WS_VSCROLL) &&
646                 ((((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (ptClient.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
647                 (((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (ptClient.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
648                 return HTSIZE;
649             return HTHSCROLL;
650         }
651     }
652
653       /* Check menu bar */
654
655     if (HAS_MENU(wndPtr))
656     {
657         if ((ptClient.y < 0) && (ptClient.x >= 0) && (ptClient.x < rcClient.right))
658             return HTMENU;
659     }
660
661     /* Has to return HTNOWHERE if nothing was found
662        Could happen when a window has a customized non client area */
663     return HTNOWHERE;
664 }
665
666
667 /***********************************************************************
668  * NC_HandleNCHitTest
669  *
670  * Handle a WM_NCHITTEST message. Called from DefWindowProc().
671  */
672 LRESULT NC_HandleNCHitTest (HWND hwnd , POINT pt)
673 {
674     LRESULT retvalue;
675     WND *wndPtr = WIN_GetPtr( hwnd );
676
677     if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return HTERROR;
678
679     retvalue = NC_DoNCHitTest (wndPtr, pt);
680     WIN_ReleasePtr( wndPtr );
681     return retvalue;
682 }
683
684
685 /******************************************************************************
686  *
687  *   NC_DrawSysButton
688  *
689  *   Draws the system icon.
690  *
691  *****************************************************************************/
692 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
693 {
694     HICON hIcon = NC_IconForWindow( hwnd );
695
696     if (hIcon)
697     {
698         RECT rect;
699         DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
700         DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
701
702         NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
703         DrawIconEx (hdc, rect.left + 2, rect.top + 1, hIcon,
704                     GetSystemMetrics(SM_CXSMICON),
705                     GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
706     }
707     return (hIcon != 0);
708 }
709
710
711 /******************************************************************************
712  *
713  *   NC_DrawCloseButton
714  *
715  *   Draws the close button.
716  *
717  *   If bGrayed is true, then draw a disabled Close button
718  *
719  *****************************************************************************/
720
721 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
722 {
723     RECT rect;
724     DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
725     DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
726
727     NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
728
729     /* A tool window has a smaller Close button */
730     if (ex_style & WS_EX_TOOLWINDOW)
731     {
732         INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE   */
733         INT iBmpWidth = 11;  /* it uses 11x11 for  the close button in tool window */
734         INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
735
736         rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
737         rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
738         rect.bottom = rect.top + iBmpHeight;
739         rect.right = rect.left + iBmpWidth;
740     }
741     else
742     {
743         rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
744         rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
745         rect.top += 2;
746         rect.right -= 2;
747     }
748     DrawFrameControl( hdc, &rect, DFC_CAPTION,
749                       (DFCS_CAPTIONCLOSE |
750                        (down ? DFCS_PUSHED : 0) |
751                        (bGrayed ? DFCS_INACTIVE : 0)) );
752 }
753
754 /******************************************************************************
755  *   NC_DrawMaxButton
756  *
757  *   Draws the maximize button for windows.
758  *   If bGrayed is true, then draw a disabled Maximize button
759  */
760 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
761 {
762     RECT rect;
763     UINT flags;
764     DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
765     DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
766
767     /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
768     if (ex_style & WS_EX_TOOLWINDOW) return;
769
770     flags = (style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
771
772     NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
773     if (style & WS_SYSMENU)
774         rect.right -= GetSystemMetrics(SM_CXSIZE);
775     rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
776     rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
777     rect.top += 2;
778     rect.right -= 2;
779     if (down) flags |= DFCS_PUSHED;
780     if (bGrayed) flags |= DFCS_INACTIVE;
781     DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
782 }
783
784 /******************************************************************************
785  *   NC_DrawMinButton
786  *
787  *   Draws the minimize button for windows.
788  *   If bGrayed is true, then draw a disabled Minimize button
789  */
790 static void  NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
791 {
792     RECT rect;
793     UINT flags = DFCS_CAPTIONMIN;
794     DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
795     DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
796
797     /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
798     if (ex_style & WS_EX_TOOLWINDOW) return;
799
800     NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
801     if (style & WS_SYSMENU)
802         rect.right -= GetSystemMetrics(SM_CXSIZE);
803     if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
804         rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
805     rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
806     rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
807     rect.top += 2;
808     rect.right -= 2;
809     if (down) flags |= DFCS_PUSHED;
810     if (bGrayed) flags |= DFCS_INACTIVE;
811     DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
812 }
813
814 /******************************************************************************
815  *
816  *   NC_DrawFrame
817  *
818  *   Draw a window frame inside the given rectangle, and update the rectangle.
819  *
820  *   Bugs
821  *        Many.  First, just what IS a frame in Win95?  Note that the 3D look
822  *        on the outer edge is handled by NC_DoNCPaint.  As is the inner
823  *        edge.  The inner rectangle just inside the frame is handled by the
824  *        Caption code.
825  *
826  *        In short, for most people, this function should be a nop (unless
827  *        you LIKE thick borders in Win95/NT4.0 -- I've been working with
828  *        them lately, but just to get this code right).  Even so, it doesn't
829  *        appear to be so.  It's being worked on...
830  *
831  *****************************************************************************/
832
833 static void  NC_DrawFrame( HDC  hdc, RECT  *rect, BOOL  active, DWORD style, DWORD exStyle)
834 {
835     INT width, height;
836
837     /* Firstly the "thick" frame */
838     if (style & WS_THICKFRAME)
839     {
840         width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
841         height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
842
843         SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
844                                             COLOR_INACTIVEBORDER) );
845         /* Draw frame */
846         PatBlt( hdc, rect->left, rect->top,
847                   rect->right - rect->left, height, PATCOPY );
848         PatBlt( hdc, rect->left, rect->top,
849                   width, rect->bottom - rect->top, PATCOPY );
850         PatBlt( hdc, rect->left, rect->bottom - 1,
851                   rect->right - rect->left, -height, PATCOPY );
852         PatBlt( hdc, rect->right - 1, rect->top,
853                   -width, rect->bottom - rect->top, PATCOPY );
854
855         InflateRect( rect, -width, -height );
856     }
857
858     /* Now the other bit of the frame */
859     if ((style & (WS_BORDER|WS_DLGFRAME)) ||
860         (exStyle & WS_EX_DLGMODALFRAME))
861     {
862         width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
863         height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
864         /* This should give a value of 1 that should also work for a border */
865
866         SelectObject( hdc, GetSysColorBrush(
867                       (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
868                           COLOR_3DFACE :
869                       (exStyle & WS_EX_STATICEDGE) ?
870                           COLOR_WINDOWFRAME :
871                       (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
872                           COLOR_3DFACE :
873                       /* else */
874                           COLOR_WINDOWFRAME));
875
876         /* Draw frame */
877         PatBlt( hdc, rect->left, rect->top,
878                   rect->right - rect->left, height, PATCOPY );
879         PatBlt( hdc, rect->left, rect->top,
880                   width, rect->bottom - rect->top, PATCOPY );
881         PatBlt( hdc, rect->left, rect->bottom - 1,
882                   rect->right - rect->left, -height, PATCOPY );
883         PatBlt( hdc, rect->right - 1, rect->top,
884                   -width, rect->bottom - rect->top, PATCOPY );
885
886         InflateRect( rect, -width, -height );
887     }
888 }
889
890
891 /******************************************************************************
892  *
893  *   NC_DrawCaption
894  *
895  *   Draw the window caption for windows.
896  *   The correct pen for the window frame must be selected in the DC.
897  *
898  *****************************************************************************/
899
900 static void  NC_DrawCaption( HDC  hdc, RECT *rect, HWND hwnd, DWORD  style, 
901                              DWORD  exStyle, BOOL active )
902 {
903     RECT  r = *rect;
904     WCHAR buffer[256];
905     HPEN  hPrevPen;
906     HMENU hSysMenu;
907     BOOL gradient = FALSE;
908
909     hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
910                      ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
911                                  WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
912                       COLOR_WINDOWFRAME : COLOR_3DFACE) );
913     MoveToEx( hdc, r.left, r.bottom - 1, NULL );
914     LineTo( hdc, r.right, r.bottom - 1 );
915     SelectObject( hdc, hPrevPen );
916     r.bottom--;
917
918     SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
919     NC_DrawCaptionBar (hdc, &r, style, active, gradient);
920
921     if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
922         if (NC_DrawSysButton (hwnd, hdc, FALSE))
923             r.left += GetSystemMetrics(SM_CXSMICON) + 2;
924     }
925
926     if (style & WS_SYSMENU)
927     {
928         UINT state;
929
930         /* Go get the sysmenu */
931         hSysMenu = GetSystemMenu(hwnd, FALSE);
932         state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
933
934         /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
935         NC_DrawCloseButton (hwnd, hdc, FALSE,
936                             (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
937         r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
938
939         if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
940         {
941             /* In win95 the two buttons are always there */
942             /* But if the menu item is not in the menu they're disabled*/
943
944             NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
945             r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
946
947             NC_DrawMinButton( hwnd, hdc, FALSE,  (!(style & WS_MINIMIZEBOX)));
948             r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
949         }
950     }
951
952     if (GetWindowTextW( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
953     {
954         NONCLIENTMETRICSW nclm;
955         HFONT hFont, hOldFont;
956         nclm.cbSize = sizeof(nclm);
957         SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
958         if (exStyle & WS_EX_TOOLWINDOW)
959             hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
960         else
961             hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
962         hOldFont = SelectObject (hdc, hFont);
963         if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
964         else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
965         SetBkMode( hdc, TRANSPARENT );
966         r.left += 2;
967         DrawTextW( hdc, buffer, -1, &r,
968                      DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
969         DeleteObject (SelectObject (hdc, hOldFont));
970     }
971 }
972
973
974 /******************************************************************************
975  *   NC_DoNCPaint
976  *
977  *   Paint the non-client area for windows.
978  */
979 static void  NC_DoNCPaint( HWND  hwnd, HRGN  clip, BOOL  suppress_menupaint )
980 {
981     HDC hdc;
982     RECT rfuzz, rect, rectClip;
983     BOOL active;
984     WND *wndPtr;
985     DWORD dwStyle, dwExStyle;
986     WORD flags;
987     HRGN hrgn;
988     RECT rectClient;
989     int has_menu;
990
991     if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
992     has_menu = HAS_MENU(wndPtr);
993     dwStyle = wndPtr->dwStyle;
994     dwExStyle = wndPtr->dwExStyle;
995     flags = wndPtr->flags;
996     WIN_ReleasePtr( wndPtr );
997
998     if ( dwStyle & WS_MINIMIZE ||
999          !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
1000
1001     active  = flags & WIN_NCACTIVATED;
1002
1003     TRACE("%p %d\n", hwnd, active );
1004
1005     /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
1006        the call to GetDCEx implying that it is allowed not to use it either.
1007        However, the suggested GetDCEx(    , DCX_WINDOW | DCX_INTERSECTRGN)
1008        will cause clipRgn to be deleted after ReleaseDC().
1009        Now, how is the "system" supposed to tell what happened?
1010      */
1011
1012     WIN_GetRectangles( hwnd, COORDS_SCREEN, NULL, &rectClient );
1013     hrgn = CreateRectRgnIndirect( &rectClient );
1014
1015     if (clip > (HRGN)1)
1016     {
1017         CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
1018         hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
1019     }
1020     else
1021     {
1022         hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
1023     }
1024
1025     if (!hdc) return;
1026
1027     WIN_GetRectangles( hwnd, COORDS_WINDOW, &rect, NULL );
1028     GetClipBox( hdc, &rectClip );
1029
1030     SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1031
1032     if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1033         DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1034     }
1035     else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1036         DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1037     }
1038
1039     NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1040
1041     if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1042     {
1043         RECT  r = rect;
1044         if (dwExStyle & WS_EX_TOOLWINDOW) {
1045             r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1046             rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1047         }
1048         else {
1049             r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1050             rect.top += GetSystemMetrics(SM_CYCAPTION);
1051         }
1052         if( IntersectRect( &rfuzz, &r, &rectClip ) )
1053             NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1054     }
1055
1056     if (has_menu)
1057     {
1058         RECT r = rect;
1059         r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1060
1061         TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
1062
1063         rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1064     }
1065
1066     TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
1067
1068     if (dwExStyle & WS_EX_CLIENTEDGE)
1069         DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1070
1071     /* Draw the scroll-bars */
1072
1073     if (dwStyle & WS_VSCROLL)
1074         SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1075     if (dwStyle & WS_HSCROLL)
1076         SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1077
1078     /* Draw the "size-box" */
1079     if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1080     {
1081         RECT r = rect;
1082         if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1083             r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1084         else
1085             r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1086         r.top  = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1087         FillRect( hdc, &r,  GetSysColorBrush(COLOR_SCROLLBAR) );
1088     }
1089
1090     ReleaseDC( hwnd, hdc );
1091 }
1092
1093
1094
1095
1096 /***********************************************************************
1097  *           NC_HandleNCPaint
1098  *
1099  * Handle a WM_NCPAINT message. Called from DefWindowProc().
1100  */
1101 LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
1102 {
1103     DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1104
1105     if( dwStyle & WS_VISIBLE )
1106     {
1107         if( dwStyle & WS_MINIMIZE )
1108             WINPOS_RedrawIconTitle( hwnd );
1109         else
1110             NC_DoNCPaint( hwnd, clip, FALSE );
1111     }
1112     return 0;
1113 }
1114
1115
1116 /***********************************************************************
1117  *           NC_HandleNCActivate
1118  *
1119  * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1120  */
1121 LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
1122 {
1123     WND* wndPtr = WIN_GetPtr( hwnd );
1124
1125     if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return FALSE;
1126
1127     /* Lotus Notes draws menu descriptions in the caption of its main
1128      * window. When it wants to restore original "system" view, it just
1129      * sends WM_NCACTIVATE message to itself. Any optimizations here in
1130      * attempt to minimize redrawings lead to a not restored caption.
1131      */
1132     if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1133     else wndPtr->flags &= ~WIN_NCACTIVATED;
1134     WIN_ReleasePtr( wndPtr );
1135
1136     /* This isn't documented but is reproducible in at least XP SP2 and
1137      * Outlook 2007 depends on it
1138      */
1139     if (lParam != -1)
1140     {
1141         if (IsIconic(hwnd))
1142             WINPOS_RedrawIconTitle( hwnd );
1143         else
1144             NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1145     }
1146
1147     return TRUE;
1148 }
1149
1150
1151 /***********************************************************************
1152  *           NC_HandleSetCursor
1153  *
1154  * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1155  */
1156 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1157 {
1158     hwnd = WIN_GetFullHandle( (HWND)wParam );
1159
1160     switch((short)LOWORD(lParam))
1161     {
1162     case HTERROR:
1163         {
1164             WORD msg = HIWORD( lParam );
1165             if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1166                 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1167                 MessageBeep(0);
1168         }
1169         break;
1170
1171     case HTCLIENT:
1172         {
1173             HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1174             if(hCursor) {
1175                 SetCursor(hCursor);
1176                 return TRUE;
1177             }
1178             return FALSE;
1179         }
1180
1181     case HTLEFT:
1182     case HTRIGHT:
1183         return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1184
1185     case HTTOP:
1186     case HTBOTTOM:
1187         return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1188
1189     case HTTOPLEFT:
1190     case HTBOTTOMRIGHT:
1191         return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1192
1193     case HTTOPRIGHT:
1194     case HTBOTTOMLEFT:
1195         return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1196     }
1197
1198     /* Default cursor: arrow */
1199     return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1200 }
1201
1202 /***********************************************************************
1203  *           NC_GetSysPopupPos
1204  */
1205 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1206 {
1207     if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1208     else
1209     {
1210         DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
1211         DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
1212
1213         NC_GetInsideRect( hwnd, COORDS_SCREEN, rect, style, ex_style );
1214         rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1215         rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1216     }
1217 }
1218
1219 /***********************************************************************
1220  *           NC_TrackMinMaxBox
1221  *
1222  * Track a mouse button press on the minimize or maximize box.
1223  *
1224  * The big difference between 3.1 and 95 is the disabled button state.
1225  * In win95 the system button can be disabled, so it can ignore the mouse
1226  * event.
1227  *
1228  */
1229 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1230 {
1231     MSG msg;
1232     HDC hdc = GetWindowDC( hwnd );
1233     BOOL pressed = TRUE;
1234     UINT state;
1235     DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1236     HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1237
1238     void  (*paintButton)(HWND, HDC, BOOL, BOOL);
1239
1240     if (wParam == HTMINBUTTON)
1241     {
1242         /* If the style is not present, do nothing */
1243         if (!(wndStyle & WS_MINIMIZEBOX))
1244             return;
1245
1246         /* Check if the sysmenu item for minimize is there  */
1247         state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1248
1249         paintButton = NC_DrawMinButton;
1250     }
1251     else
1252     {
1253         /* If the style is not present, do nothing */
1254         if (!(wndStyle & WS_MAXIMIZEBOX))
1255             return;
1256
1257         /* Check if the sysmenu item for maximize is there  */
1258         state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1259
1260         paintButton = NC_DrawMaxButton;
1261     }
1262
1263     SetCapture( hwnd );
1264
1265     (*paintButton)( hwnd, hdc, TRUE, FALSE);
1266
1267     while(1)
1268     {
1269         BOOL oldstate = pressed;
1270
1271         if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1272         if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1273
1274         if(msg.message == WM_LBUTTONUP)
1275             break;
1276
1277         if(msg.message != WM_MOUSEMOVE)
1278             continue;
1279
1280         pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1281         if (pressed != oldstate)
1282            (*paintButton)( hwnd, hdc, pressed, FALSE);
1283     }
1284
1285     if(pressed)
1286         (*paintButton)(hwnd, hdc, FALSE, FALSE);
1287
1288     ReleaseCapture();
1289     ReleaseDC( hwnd, hdc );
1290
1291     /* If the item minimize or maximize of the sysmenu are not there */
1292     /* or if the style is not present, do nothing */
1293     if ((!pressed) || (state == 0xFFFFFFFF))
1294         return;
1295
1296     if (wParam == HTMINBUTTON)
1297         SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1298     else
1299         SendMessageW( hwnd, WM_SYSCOMMAND,
1300                       IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1301 }
1302
1303 /***********************************************************************
1304  * NC_TrackCloseButton
1305  *
1306  * Track a mouse button press on the Win95 close button.
1307  */
1308 static void NC_TrackCloseButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
1309 {
1310     MSG msg;
1311     HDC hdc;
1312     BOOL pressed = TRUE;
1313     HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1314     UINT state;
1315
1316     if(hSysMenu == 0)
1317         return;
1318
1319     state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1320
1321     /* If the item close of the sysmenu is disabled or not there do nothing */
1322     if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1323         return;
1324
1325     hdc = GetWindowDC( hwnd );
1326
1327     SetCapture( hwnd );
1328
1329     NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1330
1331     while(1)
1332     {
1333         BOOL oldstate = pressed;
1334
1335         if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1336         if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1337
1338         if(msg.message == WM_LBUTTONUP)
1339             break;
1340
1341         if(msg.message != WM_MOUSEMOVE)
1342             continue;
1343
1344         pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1345         if (pressed != oldstate)
1346            NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1347     }
1348
1349     if(pressed)
1350         NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1351
1352     ReleaseCapture();
1353     ReleaseDC( hwnd, hdc );
1354     if (!pressed) return;
1355
1356     SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1357 }
1358
1359
1360 /***********************************************************************
1361  *           NC_TrackScrollBar
1362  *
1363  * Track a mouse button press on the horizontal or vertical scroll-bar.
1364  */
1365 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1366 {
1367     INT scrollbar;
1368
1369     if ((wParam & 0xfff0) == SC_HSCROLL)
1370     {
1371         if ((wParam & 0x0f) != HTHSCROLL) return;
1372         scrollbar = SB_HORZ;
1373     }
1374     else  /* SC_VSCROLL */
1375     {
1376         if ((wParam & 0x0f) != HTVSCROLL) return;
1377         scrollbar = SB_VERT;
1378     }
1379     SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1380 }
1381
1382
1383 /***********************************************************************
1384  *           NC_HandleNCLButtonDown
1385  *
1386  * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1387  */
1388 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1389 {
1390     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1391
1392     switch(wParam)  /* Hit test */
1393     {
1394     case HTCAPTION:
1395         {
1396             HWND top = GetAncestor( hwnd, GA_ROOT );
1397
1398             if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1399                 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1400             break;
1401         }
1402
1403     case HTSYSMENU:
1404          if( style & WS_SYSMENU )
1405          {
1406              if( !(style & WS_MINIMIZE) )
1407              {
1408                 HDC hDC = GetWindowDC(hwnd);
1409                 NC_DrawSysButton( hwnd, hDC, TRUE );
1410                 ReleaseDC( hwnd, hDC );
1411              }
1412              SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1413          }
1414          break;
1415
1416     case HTMENU:
1417         SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1418         break;
1419
1420     case HTHSCROLL:
1421         SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1422         break;
1423
1424     case HTVSCROLL:
1425         SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1426         break;
1427
1428     case HTMINBUTTON:
1429     case HTMAXBUTTON:
1430         NC_TrackMinMaxBox( hwnd, wParam );
1431         break;
1432
1433     case HTCLOSE:
1434         NC_TrackCloseButton (hwnd, wParam, lParam);
1435         break;
1436
1437     case HTLEFT:
1438     case HTRIGHT:
1439     case HTTOP:
1440     case HTTOPLEFT:
1441     case HTTOPRIGHT:
1442     case HTBOTTOM:
1443     case HTBOTTOMLEFT:
1444     case HTBOTTOMRIGHT:
1445         /* Old comment:
1446          * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1447          * This was previously done by setting wParam=SC_SIZE + wParam - 2
1448          */
1449         /* But that is not what WinNT does. Instead it sends this. This
1450          * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1451          * SC_MOUSEMENU into wParam.
1452          */
1453         SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1454         break;
1455
1456     case HTBORDER:
1457         break;
1458     }
1459     return 0;
1460 }
1461
1462
1463 /***********************************************************************
1464  *           NC_HandleNCLButtonDblClk
1465  *
1466  * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1467  */
1468 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1469 {
1470     /*
1471      * if this is an icon, send a restore since we are handling
1472      * a double click
1473      */
1474     if (IsIconic(hwnd))
1475     {
1476         SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1477         return 0;
1478     }
1479
1480     switch(wParam)  /* Hit test */
1481     {
1482     case HTCAPTION:
1483         /* stop processing if WS_MAXIMIZEBOX is missing */
1484         if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1485             SendMessageW( hwnd, WM_SYSCOMMAND,
1486                           IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1487         break;
1488
1489     case HTSYSMENU:
1490         {
1491             HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1492             UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1493
1494             /* If the item close of the sysmenu is disabled or not there do nothing */
1495             if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1496                 break;
1497
1498             SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1499             break;
1500         }
1501
1502     case HTHSCROLL:
1503         SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1504         break;
1505
1506     case HTVSCROLL:
1507         SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1508         break;
1509     }
1510     return 0;
1511 }
1512
1513
1514 /***********************************************************************
1515  *           NC_HandleSysCommand
1516  *
1517  * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1518  */
1519 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1520 {
1521     TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1522
1523     if (!IsWindowEnabled( hwnd )) return 0;
1524
1525     if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1526         return 0;
1527
1528     if (!USER_Driver->pSysCommand( hwnd, wParam, lParam ))
1529         return 0;
1530
1531     switch (wParam & 0xfff0)
1532     {
1533     case SC_SIZE:
1534     case SC_MOVE:
1535         WINPOS_SysCommandSizeMove( hwnd, wParam );
1536         break;
1537
1538     case SC_MINIMIZE:
1539         if (hwnd == GetActiveWindow())
1540             ShowOwnedPopups(hwnd,FALSE);
1541         ShowWindow( hwnd, SW_MINIMIZE );
1542         break;
1543
1544     case SC_MAXIMIZE:
1545         if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1546             ShowOwnedPopups(hwnd,TRUE);
1547         ShowWindow( hwnd, SW_MAXIMIZE );
1548         break;
1549
1550     case SC_RESTORE:
1551         if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1552             ShowOwnedPopups(hwnd,TRUE);
1553         ShowWindow( hwnd, SW_RESTORE );
1554         break;
1555
1556     case SC_CLOSE:
1557         return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1558
1559     case SC_VSCROLL:
1560     case SC_HSCROLL:
1561         {
1562             POINT pt;
1563             pt.x = (short)LOWORD(lParam);
1564             pt.y = (short)HIWORD(lParam);
1565             NC_TrackScrollBar( hwnd, wParam, pt );
1566         }
1567         break;
1568
1569     case SC_MOUSEMENU:
1570         {
1571             POINT pt;
1572             pt.x = (short)LOWORD(lParam);
1573             pt.y = (short)HIWORD(lParam);
1574             MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1575         }
1576         break;
1577
1578     case SC_KEYMENU:
1579         MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1580         break;
1581
1582     case SC_TASKLIST:
1583         WinExec( "taskman.exe", SW_SHOWNORMAL );
1584         break;
1585
1586     case SC_SCREENSAVE:
1587         if (wParam == SC_ABOUTWINE)
1588         {
1589             HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1590             if (hmodule)
1591             {
1592                 BOOL (WINAPI *aboutproc)(HWND, LPCSTR, LPCSTR, HICON);
1593
1594                 aboutproc = (void *)GetProcAddress( hmodule, "ShellAboutA" );
1595                 if (aboutproc) aboutproc( hwnd, PACKAGE_STRING, NULL, 0 );
1596                 FreeLibrary( hmodule );
1597             }
1598         }
1599         break;
1600
1601     case SC_HOTKEY:
1602     case SC_ARRANGE:
1603     case SC_NEXTWINDOW:
1604     case SC_PREVWINDOW:
1605         FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1606         break;
1607     }
1608     return 0;
1609 }
1610
1611 /***********************************************************************
1612  *              GetTitleBarInfo (USER32.@)
1613  * TODO: Handle STATE_SYSTEM_PRESSED
1614  */
1615 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1616     DWORD dwStyle;
1617     DWORD dwExStyle;
1618
1619     TRACE("(%p %p)\n", hwnd, tbi);
1620
1621     if(!tbi) {
1622         SetLastError(ERROR_NOACCESS);
1623         return FALSE;
1624     }
1625
1626     if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1627         TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1628         SetLastError(ERROR_INVALID_PARAMETER);
1629         return FALSE;
1630     }
1631     dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1632     dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1633     NC_GetInsideRect(hwnd, COORDS_SCREEN, &tbi->rcTitleBar, dwStyle, dwExStyle);
1634
1635     tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1636     if(dwExStyle & WS_EX_TOOLWINDOW)
1637         tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1638     else {
1639         tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1640         tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1641     }
1642
1643     ZeroMemory(tbi->rgstate, sizeof(tbi->rgstate));
1644     /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1645      * Under XP it seems to
1646      */
1647     tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1648     if(dwStyle & WS_CAPTION) {
1649         tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1650         if(dwStyle & WS_SYSMENU) {
1651             if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1652                 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1653                 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1654             }
1655             else {
1656                 if(!(dwStyle & WS_MINIMIZEBOX))
1657                     tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1658                 if(!(dwStyle & WS_MAXIMIZEBOX))
1659                     tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1660             }
1661             if(!(dwExStyle & WS_EX_CONTEXTHELP))
1662                 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1663             if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1664                 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1665         }
1666         else {
1667             tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1668             tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1669             tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1670             tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1671         }
1672     }
1673     else
1674         tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1675     return TRUE;
1676 }