wineps.drv: Slightly simplify a PPD parser code snippet.
[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(hwnd,style)  ((((style) & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
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
90     if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) ==
91         WS_EX_STATICEDGE)
92     {
93         adjust = 1; /* for the outer frame always present */
94     }
95     else
96     {
97         adjust = 0;
98         if ((exStyle & WS_EX_DLGMODALFRAME) ||
99             (style & (WS_THICKFRAME|WS_DLGFRAME))) adjust = 2; /* outer */
100     }
101     if ((style & WS_THICKFRAME) && !(exStyle & WS_EX_DLGMODALFRAME))
102         adjust +=  ( GetSystemMetrics (SM_CXFRAME)
103                    - GetSystemMetrics (SM_CXDLGFRAME)); /* The resize border */
104     if ((style & (WS_BORDER|WS_DLGFRAME)) ||
105         (exStyle & WS_EX_DLGMODALFRAME))
106         adjust++; /* The other border */
107
108     InflateRect (rect, adjust, adjust);
109
110     if ((style & WS_CAPTION) == WS_CAPTION)
111     {
112         if (exStyle & WS_EX_TOOLWINDOW)
113             rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
114         else
115             rect->top -= GetSystemMetrics(SM_CYCAPTION);
116     }
117     if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
118 }
119
120
121 /******************************************************************************
122  * NC_AdjustRectInner
123  *
124  * Computes the size of the "inside" part of the window based on the
125  * parameters of the client area.
126  *
127  * PARAMS
128  *     LPRECT   rect
129  *     DWORD    style
130  *     DWORD    exStyle
131  *
132  * NOTES
133  *     "Inner" part of a window means the window frame inside of the flat
134  *     window frame. It includes the client edge, the static edge and the
135  *     scroll bars.
136  *
137  *****************************************************************************/
138
139 static void
140 NC_AdjustRectInner (LPRECT rect, DWORD style, DWORD exStyle)
141 {
142     if (exStyle & WS_EX_CLIENTEDGE)
143         InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
144
145     if (style & WS_VSCROLL)
146     {
147         if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
148             rect->left  -= GetSystemMetrics(SM_CXVSCROLL);
149         else
150             rect->right += GetSystemMetrics(SM_CXVSCROLL);
151     }
152     if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
153 }
154
155
156
157 static HICON NC_IconForWindow( HWND hwnd )
158 {
159     HICON hIcon = 0;
160     WND *wndPtr = WIN_GetPtr( hwnd );
161
162     if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
163     {
164         hIcon = wndPtr->hIconSmall;
165         if (!hIcon) hIcon = wndPtr->hIcon;
166         WIN_ReleasePtr( wndPtr );
167     }
168     if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICONSM );
169     if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICON );
170
171     /* If there is no hIcon specified and this is a modal dialog,
172      * get the default one.
173      */
174     if (!hIcon && (GetWindowLongW( hwnd, GWL_STYLE ) & DS_MODALFRAME))
175         hIcon = LoadImageW(0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
176     return hIcon;
177 }
178
179 /* Draws the bar part(ie the big rectangle) of the caption */
180 static void NC_DrawCaptionBar (HDC hdc, const RECT *rect, DWORD dwStyle, 
181                                BOOL active, BOOL gradient)
182 {
183     if (gradient)
184     {
185         TRIVERTEX vertices[4];
186         DWORD colLeft = 
187             GetSysColor (active ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION);
188         DWORD colRight = 
189             GetSysColor (active ? COLOR_GRADIENTACTIVECAPTION 
190                                 : COLOR_GRADIENTINACTIVECAPTION);
191         int buttonsAreaSize = GetSystemMetrics(SM_CYCAPTION) - 1;
192         static GRADIENT_RECT mesh[] = {{0, 1}, {1, 2}, {2, 3}};
193
194         vertices[0].Red   = vertices[1].Red   = GetRValue (colLeft) << 8;
195         vertices[0].Green = vertices[1].Green = GetGValue (colLeft) << 8;
196         vertices[0].Blue  = vertices[1].Blue  = GetBValue (colLeft) << 8;
197         vertices[0].Alpha = vertices[1].Alpha = 0xff00;
198         vertices[2].Red   = vertices[3].Red   = GetRValue (colRight) << 8;
199         vertices[2].Green = vertices[3].Green = GetGValue (colRight) << 8;
200         vertices[2].Blue  = vertices[3].Blue  = GetBValue (colRight) << 8;
201         vertices[2].Alpha = vertices[3].Alpha = 0xff00;
202
203         if ((dwStyle & WS_SYSMENU)
204             && ((dwStyle & WS_MAXIMIZEBOX) || (dwStyle & WS_MINIMIZEBOX)))
205             buttonsAreaSize += 2 * (GetSystemMetrics(SM_CXSIZE) + 1);
206
207         /* area behind icon; solid filled with left color */
208         vertices[0].x = rect->left;
209         vertices[0].y = rect->top;
210         if (dwStyle & WS_SYSMENU)
211             vertices[1].x = min (rect->left + GetSystemMetrics(SM_CXSMICON), rect->right);
212         else
213             vertices[1].x = vertices[0].x;
214         vertices[1].y = rect->bottom;
215
216         /* area behind text; gradient */
217         vertices[2].x = max (vertices[1].x, rect->right - buttonsAreaSize);
218         vertices[2].y = rect->top;
219
220         /* area behind buttons; solid filled with right color */
221         vertices[3].x = rect->right;
222         vertices[3].y = rect->bottom;
223
224         GdiGradientFill (hdc, vertices, 4, mesh, 3, GRADIENT_FILL_RECT_H);
225     }
226     else
227         FillRect (hdc, rect, GetSysColorBrush (active ?
228                   COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
229 }
230
231 /***********************************************************************
232  *              DrawCaption (USER32.@) Draws a caption bar
233  *
234  * PARAMS
235  *     hwnd   [I]
236  *     hdc    [I]
237  *     lpRect [I]
238  *     uFlags [I]
239  *
240  * RETURNS
241  *     Success:
242  *     Failure:
243  */
244
245 BOOL WINAPI
246 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
247 {
248     return DrawCaptionTempW (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x103F);
249 }
250
251
252 /***********************************************************************
253  *              DrawCaptionTempA (USER32.@)
254  */
255 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
256                               HICON hIcon, LPCSTR str, UINT uFlags)
257 {
258     LPWSTR strW;
259     INT len;
260     BOOL ret = FALSE;
261
262     if (!(uFlags & DC_TEXT) || !str)
263         return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
264
265     len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
266     if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
267     {
268         MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
269         ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
270         HeapFree( GetProcessHeap (), 0, strW );
271     }
272     return ret;
273 }
274
275
276 /***********************************************************************
277  *              DrawCaptionTempW (USER32.@)
278  */
279 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
280                               HICON hIcon, LPCWSTR str, UINT uFlags)
281 {
282     RECT   rc = *rect;
283
284     TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
285           hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
286
287     /* drawing background */
288     if (uFlags & DC_INBUTTON) {
289         FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
290
291         if (uFlags & DC_ACTIVE) {
292             HBRUSH hbr = SelectObject (hdc, SYSCOLOR_55AABrush);
293             PatBlt (hdc, rc.left, rc.top,
294                       rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
295             SelectObject (hdc, hbr);
296         }
297     }
298     else {
299         DWORD style = GetWindowLongW (hwnd, GWL_STYLE);
300         NC_DrawCaptionBar (hdc, &rc, style, uFlags & DC_ACTIVE, uFlags & DC_GRADIENT);
301     }
302
303
304     /* drawing icon */
305     if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
306         POINT pt;
307
308         pt.x = rc.left + 2;
309         pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
310
311         if (!hIcon) hIcon = NC_IconForWindow(hwnd);
312         DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
313                     GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
314         rc.left += (rc.bottom - rc.top);
315     }
316
317     /* drawing text */
318     if (uFlags & DC_TEXT) {
319         HFONT hOldFont;
320
321         if (uFlags & DC_INBUTTON)
322             SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
323         else if (uFlags & DC_ACTIVE)
324             SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
325         else
326             SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
327
328         SetBkMode (hdc, TRANSPARENT);
329
330         if (hFont)
331             hOldFont = SelectObject (hdc, hFont);
332         else {
333             NONCLIENTMETRICSW nclm;
334             HFONT hNewFont;
335             nclm.cbSize = sizeof(NONCLIENTMETRICSW);
336             SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
337             hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
338                 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
339             hOldFont = SelectObject (hdc, hNewFont);
340         }
341
342         if (str)
343             DrawTextW (hdc, str, -1, &rc,
344                          DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
345         else {
346             WCHAR szText[128];
347             INT nLen;
348             nLen = GetWindowTextW (hwnd, szText, 128);
349             DrawTextW (hdc, szText, nLen, &rc,
350                          DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
351         }
352
353         if (hFont)
354             SelectObject (hdc, hOldFont);
355         else
356             DeleteObject (SelectObject (hdc, hOldFont));
357     }
358
359     /* drawing focus ??? */
360     if (uFlags & 0x2000)
361         FIXME("undocumented flag (0x2000)!\n");
362
363     return 0;
364 }
365
366
367 /***********************************************************************
368  *              AdjustWindowRect (USER32.@)
369  */
370 BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
371 {
372     return AdjustWindowRectEx( rect, style, menu, 0 );
373 }
374
375
376 /***********************************************************************
377  *              AdjustWindowRectEx (USER32.@)
378  */
379 BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
380 {
381     if (style & WS_ICONIC) return TRUE;
382     style &= ~(WS_HSCROLL | WS_VSCROLL);
383
384     TRACE("(%s) %08x %d %08x\n", wine_dbgstr_rect(rect), style, menu, exStyle );
385
386     NC_AdjustRectOuter( rect, style, menu, exStyle );
387     NC_AdjustRectInner( rect, style, exStyle );
388
389     return TRUE;
390 }
391
392
393 /***********************************************************************
394  *           NC_HandleNCCalcSize
395  *
396  * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
397  */
398 LRESULT NC_HandleNCCalcSize( HWND hwnd, WPARAM wparam, RECT *winRect )
399 {
400     RECT tmpRect = { 0, 0, 0, 0 };
401     LRESULT result = 0;
402     LONG cls_style = GetClassLongW(hwnd, GCL_STYLE);
403     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
404     LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
405
406     if (winRect == NULL)
407         return 0;
408
409     if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
410     if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
411
412     if (!(style & WS_ICONIC))
413     {
414         NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
415
416         winRect->left   -= tmpRect.left;
417         winRect->top    -= tmpRect.top;
418         winRect->right  -= tmpRect.right;
419         winRect->bottom -= tmpRect.bottom;
420
421         if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
422         {
423             TRACE("Calling GetMenuBarHeight with hwnd %p, width %d, at (%d, %d).\n",
424                   hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
425
426             winRect->top +=
427                 MENU_GetMenuBarHeight( hwnd,
428                                        winRect->right - winRect->left,
429                                        -tmpRect.left, -tmpRect.top );
430         }
431
432         if( exStyle & WS_EX_CLIENTEDGE)
433             if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) &&
434                    winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE))
435                 InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE),
436                         - GetSystemMetrics(SM_CYEDGE));
437
438         if (style & WS_VSCROLL)
439             if (winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL))
440             {
441                 /* rectangle is in screen coords when wparam is false */
442                 if (!wparam && (exStyle & WS_EX_LAYOUTRTL)) exStyle ^= WS_EX_LEFTSCROLLBAR;
443
444                 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
445                     winRect->left  += GetSystemMetrics(SM_CXVSCROLL);
446                 else
447                     winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
448             }
449
450         if (style & WS_HSCROLL)
451             if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
452                     winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
453
454         if (winRect->top > winRect->bottom)
455             winRect->bottom = winRect->top;
456
457         if (winRect->left > winRect->right)
458             winRect->right = winRect->left;
459     }
460     return result;
461 }
462
463
464 /***********************************************************************
465  *           NC_GetInsideRect
466  *
467  * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
468  * but without the borders (if any).
469  */
470 static void NC_GetInsideRect( HWND hwnd, enum coords_relative relative, RECT *rect,
471                               DWORD style, DWORD ex_style )
472 {
473     WIN_GetRectangles( hwnd, relative, rect, NULL );
474
475     if (style & WS_ICONIC) return;
476
477     /* Remove frame from rectangle */
478     if (HAS_THICKFRAME( style, ex_style ))
479     {
480         InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
481     }
482     else if (HAS_DLGFRAME( style, ex_style ))
483     {
484         InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
485     }
486     else if (HAS_THINFRAME( style ))
487     {
488         InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
489     }
490
491     /* We have additional border information if the window
492      * is a child (but not an MDI child) */
493     if ((style & WS_CHILD) && !(ex_style & WS_EX_MDICHILD))
494     {
495         if (ex_style & WS_EX_CLIENTEDGE)
496             InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
497         if (ex_style & WS_EX_STATICEDGE)
498             InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
499     }
500 }
501
502
503 /***********************************************************************
504  * NC_HandleNCHitTest
505  *
506  * Handle a WM_NCHITTEST message. Called from DefWindowProc().
507  */
508 LRESULT NC_HandleNCHitTest( HWND hwnd, POINT pt )
509 {
510     RECT rect, rcClient;
511     DWORD style, ex_style;
512
513     TRACE("hwnd=%p pt=%d,%d\n", hwnd, pt.x, pt.y );
514
515     WIN_GetRectangles( hwnd, COORDS_SCREEN, &rect, &rcClient );
516     if (!PtInRect( &rect, pt )) return HTNOWHERE;
517
518     style = GetWindowLongW( hwnd, GWL_STYLE );
519     ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
520     if (style & WS_MINIMIZE) return HTCAPTION;
521
522     if (PtInRect( &rcClient, pt )) return HTCLIENT;
523
524     /* Check borders */
525     if (HAS_THICKFRAME( style, ex_style ))
526     {
527         InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
528         if (!PtInRect( &rect, pt ))
529         {
530             /* Check top sizing border */
531             if (pt.y < rect.top)
532             {
533                 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
534                 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
535                 return HTTOP;
536             }
537             /* Check bottom sizing border */
538             if (pt.y >= rect.bottom)
539             {
540                 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
541                 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
542                 return HTBOTTOM;
543             }
544             /* Check left sizing border */
545             if (pt.x < rect.left)
546             {
547                 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
548                 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
549                 return HTLEFT;
550             }
551             /* Check right sizing border */
552             if (pt.x >= rect.right)
553             {
554                 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
555                 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
556                 return HTRIGHT;
557             }
558         }
559     }
560     else  /* No thick frame */
561     {
562         if (HAS_DLGFRAME( style, ex_style ))
563             InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
564         else if (HAS_THINFRAME( style ))
565             InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
566         if (!PtInRect( &rect, pt )) return HTBORDER;
567     }
568
569     /* Check caption */
570
571     if ((style & WS_CAPTION) == WS_CAPTION)
572     {
573         if (ex_style & WS_EX_TOOLWINDOW)
574             rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
575         else
576             rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
577         if (!PtInRect( &rect, pt ))
578         {
579             BOOL min_or_max_box = (style & WS_SYSMENU) && (style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX));
580             if (ex_style & WS_EX_LAYOUTRTL)
581             {
582                 /* Check system menu */
583                 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
584                 {
585                     rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
586                     if (pt.x > rect.right) return HTSYSMENU;
587                 }
588
589                 /* Check close button */
590                 if (style & WS_SYSMENU)
591                 {
592                     rect.left += GetSystemMetrics(SM_CYCAPTION);
593                     if (pt.x < rect.left) return HTCLOSE;
594                 }
595
596                 /* Check maximize box */
597                 /* In win95 there is automatically a Maximize button when there is a minimize one*/
598                 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
599                 {
600                     rect.left += GetSystemMetrics(SM_CXSIZE);
601                     if (pt.x < rect.left) return HTMAXBUTTON;
602                 }
603
604                 /* Check minimize box */
605                 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
606                 {
607                     rect.left += GetSystemMetrics(SM_CXSIZE);
608                     if (pt.x < rect.left) return HTMINBUTTON;
609                 }
610             }
611             else
612             {
613                 /* Check system menu */
614                 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
615                 {
616                     rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
617                     if (pt.x < rect.left) return HTSYSMENU;
618                 }
619
620                 /* Check close button */
621                 if (style & WS_SYSMENU)
622                 {
623                     rect.right -= GetSystemMetrics(SM_CYCAPTION);
624                     if (pt.x > rect.right) return HTCLOSE;
625                 }
626
627                 /* Check maximize box */
628                 /* In win95 there is automatically a Maximize button when there is a minimize one*/
629                 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
630                 {
631                     rect.right -= GetSystemMetrics(SM_CXSIZE);
632                     if (pt.x > rect.right) return HTMAXBUTTON;
633                 }
634
635                 /* Check minimize box */
636                 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
637                 {
638                     rect.right -= GetSystemMetrics(SM_CXSIZE);
639                     if (pt.x > rect.right) return HTMINBUTTON;
640                 }
641             }
642             return HTCAPTION;
643         }
644     }
645
646       /* Check menu bar */
647
648     if (HAS_MENU( hwnd, style ) && (pt.y < rcClient.top) &&
649         (pt.x >= rcClient.left) && (pt.x < rcClient.right))
650         return HTMENU;
651
652       /* Check vertical scroll bar */
653
654     if (ex_style & WS_EX_LAYOUTRTL) ex_style ^= WS_EX_LEFTSCROLLBAR;
655     if (style & WS_VSCROLL)
656     {
657         if((ex_style & WS_EX_LEFTSCROLLBAR) != 0)
658             rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
659         else
660             rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
661         if (PtInRect( &rcClient, pt )) return HTVSCROLL;
662     }
663
664       /* Check horizontal scroll bar */
665
666     if (style & WS_HSCROLL)
667     {
668         rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
669         if (PtInRect( &rcClient, pt ))
670         {
671             /* Check size box */
672             if ((style & WS_VSCROLL) &&
673                 ((((ex_style & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
674                 (((ex_style & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
675                 return HTSIZE;
676             return HTHSCROLL;
677         }
678     }
679
680     /* Has to return HTNOWHERE if nothing was found
681        Could happen when a window has a customized non client area */
682     return HTNOWHERE;
683 }
684
685
686 /******************************************************************************
687  *
688  *   NC_DrawSysButton
689  *
690  *   Draws the system icon.
691  *
692  *****************************************************************************/
693 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
694 {
695     HICON hIcon = NC_IconForWindow( hwnd );
696
697     if (hIcon)
698     {
699         RECT rect;
700         DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
701         DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
702
703         NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
704         DrawIconEx (hdc, rect.left + 2, rect.top + 1, hIcon,
705                     GetSystemMetrics(SM_CXSMICON),
706                     GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
707     }
708     return (hIcon != 0);
709 }
710
711
712 /******************************************************************************
713  *
714  *   NC_DrawCloseButton
715  *
716  *   Draws the close button.
717  *
718  *   If bGrayed is true, then draw a disabled Close button
719  *
720  *****************************************************************************/
721
722 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
723 {
724     RECT rect;
725     DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
726     DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
727
728     NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
729
730     /* A tool window has a smaller Close button */
731     if (ex_style & WS_EX_TOOLWINDOW)
732     {
733         INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE   */
734         INT iBmpWidth = 11;  /* it uses 11x11 for  the close button in tool window */
735         INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
736
737         rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
738         rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
739         rect.bottom = rect.top + iBmpHeight;
740         rect.right = rect.left + iBmpWidth;
741     }
742     else
743     {
744         rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
745         rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
746         rect.top += 2;
747         rect.right -= 2;
748     }
749     DrawFrameControl( hdc, &rect, DFC_CAPTION,
750                       (DFCS_CAPTIONCLOSE |
751                        (down ? DFCS_PUSHED : 0) |
752                        (bGrayed ? DFCS_INACTIVE : 0)) );
753 }
754
755 /******************************************************************************
756  *   NC_DrawMaxButton
757  *
758  *   Draws the maximize button for windows.
759  *   If bGrayed is true, then draw a disabled Maximize button
760  */
761 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
762 {
763     RECT rect;
764     UINT flags;
765     DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
766     DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
767
768     /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
769     if (ex_style & WS_EX_TOOLWINDOW) return;
770
771     flags = (style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
772
773     NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
774     if (style & WS_SYSMENU)
775         rect.right -= GetSystemMetrics(SM_CXSIZE);
776     rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
777     rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
778     rect.top += 2;
779     rect.right -= 2;
780     if (down) flags |= DFCS_PUSHED;
781     if (bGrayed) flags |= DFCS_INACTIVE;
782     DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
783 }
784
785 /******************************************************************************
786  *   NC_DrawMinButton
787  *
788  *   Draws the minimize button for windows.
789  *   If bGrayed is true, then draw a disabled Minimize button
790  */
791 static void  NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
792 {
793     RECT rect;
794     UINT flags = DFCS_CAPTIONMIN;
795     DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
796     DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
797
798     /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
799     if (ex_style & WS_EX_TOOLWINDOW) return;
800
801     NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
802     if (style & WS_SYSMENU)
803         rect.right -= GetSystemMetrics(SM_CXSIZE);
804     if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
805         rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
806     rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
807     rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
808     rect.top += 2;
809     rect.right -= 2;
810     if (down) flags |= DFCS_PUSHED;
811     if (bGrayed) flags |= DFCS_INACTIVE;
812     DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
813 }
814
815 /******************************************************************************
816  *
817  *   NC_DrawFrame
818  *
819  *   Draw a window frame inside the given rectangle, and update the rectangle.
820  *
821  *   Bugs
822  *        Many.  First, just what IS a frame in Win95?  Note that the 3D look
823  *        on the outer edge is handled by NC_DoNCPaint.  As is the inner
824  *        edge.  The inner rectangle just inside the frame is handled by the
825  *        Caption code.
826  *
827  *        In short, for most people, this function should be a nop (unless
828  *        you LIKE thick borders in Win95/NT4.0 -- I've been working with
829  *        them lately, but just to get this code right).  Even so, it doesn't
830  *        appear to be so.  It's being worked on...
831  *
832  *****************************************************************************/
833
834 static void  NC_DrawFrame( HDC  hdc, RECT  *rect, BOOL  active, DWORD style, DWORD exStyle)
835 {
836     INT width, height;
837
838     /* Firstly the "thick" frame */
839     if (style & WS_THICKFRAME)
840     {
841         width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
842         height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
843
844         SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
845                                             COLOR_INACTIVEBORDER) );
846         /* Draw frame */
847         PatBlt( hdc, rect->left, rect->top,
848                   rect->right - rect->left, height, PATCOPY );
849         PatBlt( hdc, rect->left, rect->top,
850                   width, rect->bottom - rect->top, PATCOPY );
851         PatBlt( hdc, rect->left, rect->bottom - 1,
852                   rect->right - rect->left, -height, PATCOPY );
853         PatBlt( hdc, rect->right - 1, rect->top,
854                   -width, rect->bottom - rect->top, PATCOPY );
855
856         InflateRect( rect, -width, -height );
857     }
858
859     /* Now the other bit of the frame */
860     if ((style & (WS_BORDER|WS_DLGFRAME)) ||
861         (exStyle & WS_EX_DLGMODALFRAME))
862     {
863         width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
864         height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
865         /* This should give a value of 1 that should also work for a border */
866
867         SelectObject( hdc, GetSysColorBrush(
868                       (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
869                           COLOR_3DFACE :
870                       (exStyle & WS_EX_STATICEDGE) ?
871                           COLOR_WINDOWFRAME :
872                       (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
873                           COLOR_3DFACE :
874                       /* else */
875                           COLOR_WINDOWFRAME));
876
877         /* Draw frame */
878         PatBlt( hdc, rect->left, rect->top,
879                   rect->right - rect->left, height, PATCOPY );
880         PatBlt( hdc, rect->left, rect->top,
881                   width, rect->bottom - rect->top, PATCOPY );
882         PatBlt( hdc, rect->left, rect->bottom - 1,
883                   rect->right - rect->left, -height, PATCOPY );
884         PatBlt( hdc, rect->right - 1, rect->top,
885                   -width, rect->bottom - rect->top, PATCOPY );
886
887         InflateRect( rect, -width, -height );
888     }
889 }
890
891
892 /******************************************************************************
893  *
894  *   NC_DrawCaption
895  *
896  *   Draw the window caption for windows.
897  *   The correct pen for the window frame must be selected in the DC.
898  *
899  *****************************************************************************/
900
901 static void  NC_DrawCaption( HDC  hdc, RECT *rect, HWND hwnd, DWORD  style, 
902                              DWORD  exStyle, BOOL active )
903 {
904     RECT  r = *rect;
905     WCHAR buffer[256];
906     HPEN  hPrevPen;
907     HMENU hSysMenu;
908     BOOL gradient = FALSE;
909
910     hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
911                      ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
912                                  WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
913                       COLOR_WINDOWFRAME : COLOR_3DFACE) );
914     MoveToEx( hdc, r.left, r.bottom - 1, NULL );
915     LineTo( hdc, r.right, r.bottom - 1 );
916     SelectObject( hdc, hPrevPen );
917     r.bottom--;
918
919     SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
920     NC_DrawCaptionBar (hdc, &r, style, active, gradient);
921
922     if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
923         if (NC_DrawSysButton (hwnd, hdc, FALSE))
924             r.left += GetSystemMetrics(SM_CXSMICON) + 2;
925     }
926
927     if (style & WS_SYSMENU)
928     {
929         UINT state;
930
931         /* Go get the sysmenu */
932         hSysMenu = GetSystemMenu(hwnd, FALSE);
933         state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
934
935         /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
936         NC_DrawCloseButton (hwnd, hdc, FALSE,
937                             (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
938         r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
939
940         if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
941         {
942             /* In win95 the two buttons are always there */
943             /* But if the menu item is not in the menu they're disabled*/
944
945             NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
946             r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
947
948             NC_DrawMinButton( hwnd, hdc, FALSE,  (!(style & WS_MINIMIZEBOX)));
949             r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
950         }
951     }
952
953     if (GetWindowTextW( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
954     {
955         NONCLIENTMETRICSW nclm;
956         HFONT hFont, hOldFont;
957         nclm.cbSize = sizeof(nclm);
958         SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
959         if (exStyle & WS_EX_TOOLWINDOW)
960             hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
961         else
962             hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
963         hOldFont = SelectObject (hdc, hFont);
964         if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
965         else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
966         SetBkMode( hdc, TRANSPARENT );
967         r.left += 2;
968         DrawTextW( hdc, buffer, -1, &r,
969                      DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
970         DeleteObject (SelectObject (hdc, hOldFont));
971     }
972 }
973
974
975 /******************************************************************************
976  *   NC_DoNCPaint
977  *
978  *   Paint the non-client area for windows.
979  */
980 static void  NC_DoNCPaint( HWND  hwnd, HRGN  clip, BOOL  suppress_menupaint )
981 {
982     HDC hdc;
983     RECT rfuzz, rect, rectClip;
984     BOOL active;
985     WND *wndPtr;
986     DWORD dwStyle, dwExStyle;
987     WORD flags;
988     HRGN hrgn;
989     RECT rectClient;
990
991     if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
992     dwStyle = wndPtr->dwStyle;
993     dwExStyle = wndPtr->dwExStyle;
994     flags = wndPtr->flags;
995     WIN_ReleasePtr( wndPtr );
996
997     if ( dwStyle & WS_MINIMIZE ||
998          !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
999
1000     active  = flags & WIN_NCACTIVATED;
1001
1002     TRACE("%p %d\n", hwnd, active );
1003
1004     /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
1005        the call to GetDCEx implying that it is allowed not to use it either.
1006        However, the suggested GetDCEx(    , DCX_WINDOW | DCX_INTERSECTRGN)
1007        will cause clipRgn to be deleted after ReleaseDC().
1008        Now, how is the "system" supposed to tell what happened?
1009      */
1010
1011     WIN_GetRectangles( hwnd, COORDS_SCREEN, NULL, &rectClient );
1012     hrgn = CreateRectRgnIndirect( &rectClient );
1013
1014     if (clip > (HRGN)1)
1015     {
1016         CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
1017         hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
1018     }
1019     else
1020     {
1021         hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
1022     }
1023
1024     if (!hdc) return;
1025
1026     WIN_GetRectangles( hwnd, COORDS_WINDOW, &rect, NULL );
1027     GetClipBox( hdc, &rectClip );
1028
1029     SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1030
1031     if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1032         DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1033     }
1034     else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1035         DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1036     }
1037
1038     NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1039
1040     if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1041     {
1042         RECT  r = rect;
1043         if (dwExStyle & WS_EX_TOOLWINDOW) {
1044             r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1045             rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1046         }
1047         else {
1048             r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1049             rect.top += GetSystemMetrics(SM_CYCAPTION);
1050         }
1051         if( IntersectRect( &rfuzz, &r, &rectClip ) )
1052             NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1053     }
1054
1055     if (HAS_MENU( hwnd, dwStyle ))
1056     {
1057         RECT r = rect;
1058         r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1059
1060         TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
1061
1062         rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1063     }
1064
1065     TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
1066
1067     if (dwExStyle & WS_EX_CLIENTEDGE)
1068         DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1069
1070     /* Draw the scroll-bars */
1071
1072     if (dwStyle & WS_VSCROLL)
1073         SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1074     if (dwStyle & WS_HSCROLL)
1075         SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1076
1077     /* Draw the "size-box" */
1078     if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1079     {
1080         RECT r = rect;
1081         if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1082             r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1083         else
1084             r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1085         r.top  = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1086         FillRect( hdc, &r,  GetSysColorBrush(COLOR_SCROLLBAR) );
1087     }
1088
1089     ReleaseDC( hwnd, hdc );
1090 }
1091
1092
1093
1094
1095 /***********************************************************************
1096  *           NC_HandleNCPaint
1097  *
1098  * Handle a WM_NCPAINT message. Called from DefWindowProc().
1099  */
1100 LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
1101 {
1102     DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1103
1104     if( dwStyle & WS_VISIBLE )
1105     {
1106         if( dwStyle & WS_MINIMIZE )
1107             WINPOS_RedrawIconTitle( hwnd );
1108         else
1109             NC_DoNCPaint( hwnd, clip, FALSE );
1110     }
1111     return 0;
1112 }
1113
1114
1115 /***********************************************************************
1116  *           NC_HandleNCActivate
1117  *
1118  * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1119  */
1120 LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
1121 {
1122     WND* wndPtr = WIN_GetPtr( hwnd );
1123
1124     if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return FALSE;
1125
1126     /* Lotus Notes draws menu descriptions in the caption of its main
1127      * window. When it wants to restore original "system" view, it just
1128      * sends WM_NCACTIVATE message to itself. Any optimizations here in
1129      * attempt to minimize redrawings lead to a not restored caption.
1130      */
1131     if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1132     else wndPtr->flags &= ~WIN_NCACTIVATED;
1133     WIN_ReleasePtr( wndPtr );
1134
1135     /* This isn't documented but is reproducible in at least XP SP2 and
1136      * Outlook 2007 depends on it
1137      */
1138     if (lParam != -1)
1139     {
1140         if (IsIconic(hwnd))
1141             WINPOS_RedrawIconTitle( hwnd );
1142         else
1143             NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1144     }
1145
1146     return TRUE;
1147 }
1148
1149
1150 /***********************************************************************
1151  *           NC_HandleSetCursor
1152  *
1153  * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1154  */
1155 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1156 {
1157     hwnd = WIN_GetFullHandle( (HWND)wParam );
1158
1159     switch((short)LOWORD(lParam))
1160     {
1161     case HTERROR:
1162         {
1163             WORD msg = HIWORD( lParam );
1164             if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1165                 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1166                 MessageBeep(0);
1167         }
1168         break;
1169
1170     case HTCLIENT:
1171         {
1172             HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1173             if(hCursor) {
1174                 SetCursor(hCursor);
1175                 return TRUE;
1176             }
1177             return FALSE;
1178         }
1179
1180     case HTLEFT:
1181     case HTRIGHT:
1182         return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1183
1184     case HTTOP:
1185     case HTBOTTOM:
1186         return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1187
1188     case HTTOPLEFT:
1189     case HTBOTTOMRIGHT:
1190         return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1191
1192     case HTTOPRIGHT:
1193     case HTBOTTOMLEFT:
1194         return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1195     }
1196
1197     /* Default cursor: arrow */
1198     return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1199 }
1200
1201 /***********************************************************************
1202  *           NC_GetSysPopupPos
1203  */
1204 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1205 {
1206     if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1207     else
1208     {
1209         DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
1210         DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
1211
1212         NC_GetInsideRect( hwnd, COORDS_CLIENT, rect, style, ex_style );
1213         rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1214         rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1215         MapWindowPoints( hwnd, 0, (POINT *)rect, 2 );
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_HandleNCRButtonDown
1465  *
1466  * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1467  */
1468 LRESULT NC_HandleNCRButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1469 {
1470     MSG msg;
1471     INT hittest = wParam;
1472
1473     switch (hittest)
1474     {
1475     case HTCAPTION:
1476     case HTSYSMENU:
1477         if (!GetSystemMenu( hwnd, FALSE )) break;
1478
1479         SetCapture( hwnd );
1480         for (;;)
1481         {
1482             if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1483             if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1484             if (msg.message == WM_RBUTTONUP)
1485             {
1486                 hittest = NC_HandleNCHitTest( hwnd, msg.pt );
1487                 break;
1488             }
1489         }
1490         ReleaseCapture();
1491         if (hittest == HTCAPTION || hittest == HTSYSMENU)
1492             SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, msg.lParam );
1493         break;
1494     }
1495     return 0;
1496 }
1497
1498
1499 /***********************************************************************
1500  *           NC_HandleNCLButtonDblClk
1501  *
1502  * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1503  */
1504 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1505 {
1506     /*
1507      * if this is an icon, send a restore since we are handling
1508      * a double click
1509      */
1510     if (IsIconic(hwnd))
1511     {
1512         SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1513         return 0;
1514     }
1515
1516     switch(wParam)  /* Hit test */
1517     {
1518     case HTCAPTION:
1519         /* stop processing if WS_MAXIMIZEBOX is missing */
1520         if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1521             SendMessageW( hwnd, WM_SYSCOMMAND,
1522                           IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1523         break;
1524
1525     case HTSYSMENU:
1526         {
1527             HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1528             UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1529
1530             /* If the item close of the sysmenu is disabled or not there do nothing */
1531             if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1532                 break;
1533
1534             SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1535             break;
1536         }
1537
1538     case HTHSCROLL:
1539         SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1540         break;
1541
1542     case HTVSCROLL:
1543         SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1544         break;
1545     }
1546     return 0;
1547 }
1548
1549
1550 /***********************************************************************
1551  *           NC_HandleSysCommand
1552  *
1553  * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1554  */
1555 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1556 {
1557     TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1558
1559     if (!IsWindowEnabled( hwnd )) return 0;
1560
1561     if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1562         return 0;
1563
1564     if (!USER_Driver->pSysCommand( hwnd, wParam, lParam ))
1565         return 0;
1566
1567     switch (wParam & 0xfff0)
1568     {
1569     case SC_SIZE:
1570     case SC_MOVE:
1571         WINPOS_SysCommandSizeMove( hwnd, wParam );
1572         break;
1573
1574     case SC_MINIMIZE:
1575         if (hwnd == GetActiveWindow())
1576             ShowOwnedPopups(hwnd,FALSE);
1577         ShowWindow( hwnd, SW_MINIMIZE );
1578         break;
1579
1580     case SC_MAXIMIZE:
1581         if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1582             ShowOwnedPopups(hwnd,TRUE);
1583         ShowWindow( hwnd, SW_MAXIMIZE );
1584         break;
1585
1586     case SC_RESTORE:
1587         if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1588             ShowOwnedPopups(hwnd,TRUE);
1589         ShowWindow( hwnd, SW_RESTORE );
1590         break;
1591
1592     case SC_CLOSE:
1593         return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1594
1595     case SC_VSCROLL:
1596     case SC_HSCROLL:
1597         {
1598             POINT pt;
1599             pt.x = (short)LOWORD(lParam);
1600             pt.y = (short)HIWORD(lParam);
1601             NC_TrackScrollBar( hwnd, wParam, pt );
1602         }
1603         break;
1604
1605     case SC_MOUSEMENU:
1606         {
1607             POINT pt;
1608             pt.x = (short)LOWORD(lParam);
1609             pt.y = (short)HIWORD(lParam);
1610             MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1611         }
1612         break;
1613
1614     case SC_KEYMENU:
1615         MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1616         break;
1617
1618     case SC_TASKLIST:
1619         WinExec( "taskman.exe", SW_SHOWNORMAL );
1620         break;
1621
1622     case SC_SCREENSAVE:
1623         if (wParam == SC_ABOUTWINE)
1624         {
1625             HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1626             if (hmodule)
1627             {
1628                 BOOL (WINAPI *aboutproc)(HWND, LPCSTR, LPCSTR, HICON);
1629
1630                 aboutproc = (void *)GetProcAddress( hmodule, "ShellAboutA" );
1631                 if (aboutproc) aboutproc( hwnd, PACKAGE_STRING, NULL, 0 );
1632                 FreeLibrary( hmodule );
1633             }
1634         }
1635         break;
1636
1637     case SC_HOTKEY:
1638     case SC_ARRANGE:
1639     case SC_NEXTWINDOW:
1640     case SC_PREVWINDOW:
1641         FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1642         break;
1643     }
1644     return 0;
1645 }
1646
1647 /***********************************************************************
1648  *              GetTitleBarInfo (USER32.@)
1649  * TODO: Handle STATE_SYSTEM_PRESSED
1650  */
1651 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1652     DWORD dwStyle;
1653     DWORD dwExStyle;
1654
1655     TRACE("(%p %p)\n", hwnd, tbi);
1656
1657     if(!tbi) {
1658         SetLastError(ERROR_NOACCESS);
1659         return FALSE;
1660     }
1661
1662     if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1663         TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1664         SetLastError(ERROR_INVALID_PARAMETER);
1665         return FALSE;
1666     }
1667     dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1668     dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1669     NC_GetInsideRect(hwnd, COORDS_SCREEN, &tbi->rcTitleBar, dwStyle, dwExStyle);
1670
1671     tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1672     if(dwExStyle & WS_EX_TOOLWINDOW)
1673         tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1674     else {
1675         tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1676         tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1677     }
1678
1679     ZeroMemory(tbi->rgstate, sizeof(tbi->rgstate));
1680     /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1681      * Under XP it seems to
1682      */
1683     tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1684     if(dwStyle & WS_CAPTION) {
1685         tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1686         if(dwStyle & WS_SYSMENU) {
1687             if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1688                 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1689                 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1690             }
1691             else {
1692                 if(!(dwStyle & WS_MINIMIZEBOX))
1693                     tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1694                 if(!(dwStyle & WS_MAXIMIZEBOX))
1695                     tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1696             }
1697             if(!(dwExStyle & WS_EX_CONTEXTHELP))
1698                 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1699             if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1700                 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1701         }
1702         else {
1703             tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1704             tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1705             tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1706             tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1707         }
1708     }
1709     else
1710         tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1711     return TRUE;
1712 }