user32: Store icon objects directly in the cache instead of using a separate structure.
[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     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, WPARAM wparam, 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             {
456                 /* rectangle is in screen coords when wparam is false */
457                 if (!wparam && (exStyle & WS_EX_LAYOUTRTL)) exStyle ^= WS_EX_LEFTSCROLLBAR;
458
459                 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
460                     winRect->left  += GetSystemMetrics(SM_CXVSCROLL);
461                 else
462                     winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
463             }
464
465         if (style & WS_HSCROLL)
466             if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
467                     winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
468
469         if (winRect->top > winRect->bottom)
470             winRect->bottom = winRect->top;
471
472         if (winRect->left > winRect->right)
473             winRect->right = winRect->left;
474     }
475     return result;
476 }
477
478
479 /***********************************************************************
480  *           NC_GetInsideRect
481  *
482  * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
483  * but without the borders (if any).
484  */
485 static void NC_GetInsideRect( HWND hwnd, enum coords_relative relative, RECT *rect,
486                               DWORD style, DWORD ex_style )
487 {
488     WIN_GetRectangles( hwnd, relative, rect, NULL );
489
490     if (style & WS_ICONIC) return;
491
492     /* Remove frame from rectangle */
493     if (HAS_THICKFRAME( style, ex_style ))
494     {
495         InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
496     }
497     else if (HAS_DLGFRAME( style, ex_style ))
498     {
499         InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
500     }
501     else if (HAS_THINFRAME( style ))
502     {
503         InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
504     }
505
506     /* We have additional border information if the window
507      * is a child (but not an MDI child) */
508     if ((style & WS_CHILD) && !(ex_style & WS_EX_MDICHILD))
509     {
510         if (ex_style & WS_EX_CLIENTEDGE)
511             InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
512         if (ex_style & WS_EX_STATICEDGE)
513             InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
514     }
515 }
516
517
518 /***********************************************************************
519  * NC_HandleNCHitTest
520  *
521  * Handle a WM_NCHITTEST message. Called from DefWindowProc().
522  */
523 LRESULT NC_HandleNCHitTest( HWND hwnd, POINT pt )
524 {
525     RECT rect, rcClient;
526     DWORD style, ex_style;
527
528     TRACE("hwnd=%p pt=%d,%d\n", hwnd, pt.x, pt.y );
529
530     WIN_GetRectangles( hwnd, COORDS_SCREEN, &rect, &rcClient );
531     if (!PtInRect( &rect, pt )) return HTNOWHERE;
532
533     style = GetWindowLongW( hwnd, GWL_STYLE );
534     ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
535     if (style & WS_MINIMIZE) return HTCAPTION;
536
537     if (PtInRect( &rcClient, pt )) return HTCLIENT;
538
539     /* Check borders */
540     if (HAS_THICKFRAME( style, ex_style ))
541     {
542         InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
543         if (!PtInRect( &rect, pt ))
544         {
545             /* Check top sizing border */
546             if (pt.y < rect.top)
547             {
548                 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
549                 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
550                 return HTTOP;
551             }
552             /* Check bottom sizing border */
553             if (pt.y >= rect.bottom)
554             {
555                 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
556                 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
557                 return HTBOTTOM;
558             }
559             /* Check left sizing border */
560             if (pt.x < rect.left)
561             {
562                 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
563                 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
564                 return HTLEFT;
565             }
566             /* Check right sizing border */
567             if (pt.x >= rect.right)
568             {
569                 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
570                 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
571                 return HTRIGHT;
572             }
573         }
574     }
575     else  /* No thick frame */
576     {
577         if (HAS_DLGFRAME( style, ex_style ))
578             InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
579         else if (HAS_THINFRAME( style ))
580             InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
581         if (!PtInRect( &rect, pt )) return HTBORDER;
582     }
583
584     /* Check caption */
585
586     if ((style & WS_CAPTION) == WS_CAPTION)
587     {
588         if (ex_style & WS_EX_TOOLWINDOW)
589             rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
590         else
591             rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
592         if (!PtInRect( &rect, pt ))
593         {
594             BOOL min_or_max_box = (style & WS_MAXIMIZEBOX) ||
595                                   (style & WS_MINIMIZEBOX);
596             if (ex_style & WS_EX_LAYOUTRTL)
597             {
598                 /* Check system menu */
599                 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
600                 {
601                     rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
602                     if (pt.x > rect.right) return HTSYSMENU;
603                 }
604
605                 /* Check close button */
606                 if (style & WS_SYSMENU)
607                 {
608                     rect.left += GetSystemMetrics(SM_CYCAPTION);
609                     if (pt.x < rect.left) return HTCLOSE;
610                 }
611
612                 /* Check maximize box */
613                 /* In win95 there is automatically a Maximize button when there is a minimize one*/
614                 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
615                 {
616                     rect.left += GetSystemMetrics(SM_CXSIZE);
617                     if (pt.x < rect.left) return HTMAXBUTTON;
618                 }
619
620                 /* Check minimize box */
621                 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
622                 {
623                     rect.left += GetSystemMetrics(SM_CXSIZE);
624                     if (pt.x < rect.left) return HTMINBUTTON;
625                 }
626             }
627             else
628             {
629                 /* Check system menu */
630                 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
631                 {
632                     rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
633                     if (pt.x < rect.left) return HTSYSMENU;
634                 }
635
636                 /* Check close button */
637                 if (style & WS_SYSMENU)
638                 {
639                     rect.right -= GetSystemMetrics(SM_CYCAPTION);
640                     if (pt.x > rect.right) return HTCLOSE;
641                 }
642
643                 /* Check maximize box */
644                 /* In win95 there is automatically a Maximize button when there is a minimize one*/
645                 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
646                 {
647                     rect.right -= GetSystemMetrics(SM_CXSIZE);
648                     if (pt.x > rect.right) return HTMAXBUTTON;
649                 }
650
651                 /* Check minimize box */
652                 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
653                 {
654                     rect.right -= GetSystemMetrics(SM_CXSIZE);
655                     if (pt.x > rect.right) return HTMINBUTTON;
656                 }
657             }
658             return HTCAPTION;
659         }
660     }
661
662       /* Check menu bar */
663
664     if (HAS_MENU( hwnd, style ) && (pt.y < rcClient.top) &&
665         (pt.x >= rcClient.left) && (pt.x < rcClient.right))
666         return HTMENU;
667
668       /* Check vertical scroll bar */
669
670     if (ex_style & WS_EX_LAYOUTRTL) ex_style ^= WS_EX_LEFTSCROLLBAR;
671     if (style & WS_VSCROLL)
672     {
673         if((ex_style & WS_EX_LEFTSCROLLBAR) != 0)
674             rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
675         else
676             rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
677         if (PtInRect( &rcClient, pt )) return HTVSCROLL;
678     }
679
680       /* Check horizontal scroll bar */
681
682     if (style & WS_HSCROLL)
683     {
684         rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
685         if (PtInRect( &rcClient, pt ))
686         {
687             /* Check size box */
688             if ((style & WS_VSCROLL) &&
689                 ((((ex_style & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
690                 (((ex_style & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
691                 return HTSIZE;
692             return HTHSCROLL;
693         }
694     }
695
696     /* Has to return HTNOWHERE if nothing was found
697        Could happen when a window has a customized non client area */
698     return HTNOWHERE;
699 }
700
701
702 /******************************************************************************
703  *
704  *   NC_DrawSysButton
705  *
706  *   Draws the system icon.
707  *
708  *****************************************************************************/
709 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
710 {
711     HICON hIcon = NC_IconForWindow( hwnd );
712
713     if (hIcon)
714     {
715         RECT rect;
716         DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
717         DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
718
719         NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
720         DrawIconEx (hdc, rect.left + 2, rect.top + 1, hIcon,
721                     GetSystemMetrics(SM_CXSMICON),
722                     GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
723     }
724     return (hIcon != 0);
725 }
726
727
728 /******************************************************************************
729  *
730  *   NC_DrawCloseButton
731  *
732  *   Draws the close button.
733  *
734  *   If bGrayed is true, then draw a disabled Close button
735  *
736  *****************************************************************************/
737
738 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
739 {
740     RECT rect;
741     DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
742     DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
743
744     NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
745
746     /* A tool window has a smaller Close button */
747     if (ex_style & WS_EX_TOOLWINDOW)
748     {
749         INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE   */
750         INT iBmpWidth = 11;  /* it uses 11x11 for  the close button in tool window */
751         INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
752
753         rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
754         rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
755         rect.bottom = rect.top + iBmpHeight;
756         rect.right = rect.left + iBmpWidth;
757     }
758     else
759     {
760         rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
761         rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
762         rect.top += 2;
763         rect.right -= 2;
764     }
765     DrawFrameControl( hdc, &rect, DFC_CAPTION,
766                       (DFCS_CAPTIONCLOSE |
767                        (down ? DFCS_PUSHED : 0) |
768                        (bGrayed ? DFCS_INACTIVE : 0)) );
769 }
770
771 /******************************************************************************
772  *   NC_DrawMaxButton
773  *
774  *   Draws the maximize button for windows.
775  *   If bGrayed is true, then draw a disabled Maximize button
776  */
777 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
778 {
779     RECT rect;
780     UINT flags;
781     DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
782     DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
783
784     /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
785     if (ex_style & WS_EX_TOOLWINDOW) return;
786
787     flags = (style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
788
789     NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
790     if (style & WS_SYSMENU)
791         rect.right -= GetSystemMetrics(SM_CXSIZE);
792     rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
793     rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
794     rect.top += 2;
795     rect.right -= 2;
796     if (down) flags |= DFCS_PUSHED;
797     if (bGrayed) flags |= DFCS_INACTIVE;
798     DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
799 }
800
801 /******************************************************************************
802  *   NC_DrawMinButton
803  *
804  *   Draws the minimize button for windows.
805  *   If bGrayed is true, then draw a disabled Minimize button
806  */
807 static void  NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
808 {
809     RECT rect;
810     UINT flags = DFCS_CAPTIONMIN;
811     DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
812     DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
813
814     /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
815     if (ex_style & WS_EX_TOOLWINDOW) return;
816
817     NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
818     if (style & WS_SYSMENU)
819         rect.right -= GetSystemMetrics(SM_CXSIZE);
820     if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
821         rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
822     rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
823     rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
824     rect.top += 2;
825     rect.right -= 2;
826     if (down) flags |= DFCS_PUSHED;
827     if (bGrayed) flags |= DFCS_INACTIVE;
828     DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
829 }
830
831 /******************************************************************************
832  *
833  *   NC_DrawFrame
834  *
835  *   Draw a window frame inside the given rectangle, and update the rectangle.
836  *
837  *   Bugs
838  *        Many.  First, just what IS a frame in Win95?  Note that the 3D look
839  *        on the outer edge is handled by NC_DoNCPaint.  As is the inner
840  *        edge.  The inner rectangle just inside the frame is handled by the
841  *        Caption code.
842  *
843  *        In short, for most people, this function should be a nop (unless
844  *        you LIKE thick borders in Win95/NT4.0 -- I've been working with
845  *        them lately, but just to get this code right).  Even so, it doesn't
846  *        appear to be so.  It's being worked on...
847  *
848  *****************************************************************************/
849
850 static void  NC_DrawFrame( HDC  hdc, RECT  *rect, BOOL  active, DWORD style, DWORD exStyle)
851 {
852     INT width, height;
853
854     /* Firstly the "thick" frame */
855     if (style & WS_THICKFRAME)
856     {
857         width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
858         height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
859
860         SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
861                                             COLOR_INACTIVEBORDER) );
862         /* Draw frame */
863         PatBlt( hdc, rect->left, rect->top,
864                   rect->right - rect->left, height, PATCOPY );
865         PatBlt( hdc, rect->left, rect->top,
866                   width, rect->bottom - rect->top, PATCOPY );
867         PatBlt( hdc, rect->left, rect->bottom - 1,
868                   rect->right - rect->left, -height, PATCOPY );
869         PatBlt( hdc, rect->right - 1, rect->top,
870                   -width, rect->bottom - rect->top, PATCOPY );
871
872         InflateRect( rect, -width, -height );
873     }
874
875     /* Now the other bit of the frame */
876     if ((style & (WS_BORDER|WS_DLGFRAME)) ||
877         (exStyle & WS_EX_DLGMODALFRAME))
878     {
879         width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
880         height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
881         /* This should give a value of 1 that should also work for a border */
882
883         SelectObject( hdc, GetSysColorBrush(
884                       (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
885                           COLOR_3DFACE :
886                       (exStyle & WS_EX_STATICEDGE) ?
887                           COLOR_WINDOWFRAME :
888                       (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
889                           COLOR_3DFACE :
890                       /* else */
891                           COLOR_WINDOWFRAME));
892
893         /* Draw frame */
894         PatBlt( hdc, rect->left, rect->top,
895                   rect->right - rect->left, height, PATCOPY );
896         PatBlt( hdc, rect->left, rect->top,
897                   width, rect->bottom - rect->top, PATCOPY );
898         PatBlt( hdc, rect->left, rect->bottom - 1,
899                   rect->right - rect->left, -height, PATCOPY );
900         PatBlt( hdc, rect->right - 1, rect->top,
901                   -width, rect->bottom - rect->top, PATCOPY );
902
903         InflateRect( rect, -width, -height );
904     }
905 }
906
907
908 /******************************************************************************
909  *
910  *   NC_DrawCaption
911  *
912  *   Draw the window caption for windows.
913  *   The correct pen for the window frame must be selected in the DC.
914  *
915  *****************************************************************************/
916
917 static void  NC_DrawCaption( HDC  hdc, RECT *rect, HWND hwnd, DWORD  style, 
918                              DWORD  exStyle, BOOL active )
919 {
920     RECT  r = *rect;
921     WCHAR buffer[256];
922     HPEN  hPrevPen;
923     HMENU hSysMenu;
924     BOOL gradient = FALSE;
925
926     hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
927                      ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
928                                  WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
929                       COLOR_WINDOWFRAME : COLOR_3DFACE) );
930     MoveToEx( hdc, r.left, r.bottom - 1, NULL );
931     LineTo( hdc, r.right, r.bottom - 1 );
932     SelectObject( hdc, hPrevPen );
933     r.bottom--;
934
935     SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
936     NC_DrawCaptionBar (hdc, &r, style, active, gradient);
937
938     if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
939         if (NC_DrawSysButton (hwnd, hdc, FALSE))
940             r.left += GetSystemMetrics(SM_CXSMICON) + 2;
941     }
942
943     if (style & WS_SYSMENU)
944     {
945         UINT state;
946
947         /* Go get the sysmenu */
948         hSysMenu = GetSystemMenu(hwnd, FALSE);
949         state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
950
951         /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
952         NC_DrawCloseButton (hwnd, hdc, FALSE,
953                             (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
954         r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
955
956         if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
957         {
958             /* In win95 the two buttons are always there */
959             /* But if the menu item is not in the menu they're disabled*/
960
961             NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
962             r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
963
964             NC_DrawMinButton( hwnd, hdc, FALSE,  (!(style & WS_MINIMIZEBOX)));
965             r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
966         }
967     }
968
969     if (GetWindowTextW( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
970     {
971         NONCLIENTMETRICSW nclm;
972         HFONT hFont, hOldFont;
973         nclm.cbSize = sizeof(nclm);
974         SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
975         if (exStyle & WS_EX_TOOLWINDOW)
976             hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
977         else
978             hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
979         hOldFont = SelectObject (hdc, hFont);
980         if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
981         else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
982         SetBkMode( hdc, TRANSPARENT );
983         r.left += 2;
984         DrawTextW( hdc, buffer, -1, &r,
985                      DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
986         DeleteObject (SelectObject (hdc, hOldFont));
987     }
988 }
989
990
991 /******************************************************************************
992  *   NC_DoNCPaint
993  *
994  *   Paint the non-client area for windows.
995  */
996 static void  NC_DoNCPaint( HWND  hwnd, HRGN  clip, BOOL  suppress_menupaint )
997 {
998     HDC hdc;
999     RECT rfuzz, rect, rectClip;
1000     BOOL active;
1001     WND *wndPtr;
1002     DWORD dwStyle, dwExStyle;
1003     WORD flags;
1004     HRGN hrgn;
1005     RECT rectClient;
1006
1007     if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
1008     dwStyle = wndPtr->dwStyle;
1009     dwExStyle = wndPtr->dwExStyle;
1010     flags = wndPtr->flags;
1011     WIN_ReleasePtr( wndPtr );
1012
1013     if ( dwStyle & WS_MINIMIZE ||
1014          !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
1015
1016     active  = flags & WIN_NCACTIVATED;
1017
1018     TRACE("%p %d\n", hwnd, active );
1019
1020     /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
1021        the call to GetDCEx implying that it is allowed not to use it either.
1022        However, the suggested GetDCEx(    , DCX_WINDOW | DCX_INTERSECTRGN)
1023        will cause clipRgn to be deleted after ReleaseDC().
1024        Now, how is the "system" supposed to tell what happened?
1025      */
1026
1027     WIN_GetRectangles( hwnd, COORDS_SCREEN, NULL, &rectClient );
1028     hrgn = CreateRectRgnIndirect( &rectClient );
1029
1030     if (clip > (HRGN)1)
1031     {
1032         CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
1033         hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
1034     }
1035     else
1036     {
1037         hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
1038     }
1039
1040     if (!hdc) return;
1041
1042     WIN_GetRectangles( hwnd, COORDS_WINDOW, &rect, NULL );
1043     GetClipBox( hdc, &rectClip );
1044
1045     SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1046
1047     if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1048         DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1049     }
1050     else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1051         DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1052     }
1053
1054     NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1055
1056     if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1057     {
1058         RECT  r = rect;
1059         if (dwExStyle & WS_EX_TOOLWINDOW) {
1060             r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1061             rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1062         }
1063         else {
1064             r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1065             rect.top += GetSystemMetrics(SM_CYCAPTION);
1066         }
1067         if( IntersectRect( &rfuzz, &r, &rectClip ) )
1068             NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1069     }
1070
1071     if (HAS_MENU( hwnd, dwStyle ))
1072     {
1073         RECT r = rect;
1074         r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1075
1076         TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
1077
1078         rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1079     }
1080
1081     TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
1082
1083     if (dwExStyle & WS_EX_CLIENTEDGE)
1084         DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1085
1086     /* Draw the scroll-bars */
1087
1088     if (dwStyle & WS_VSCROLL)
1089         SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1090     if (dwStyle & WS_HSCROLL)
1091         SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1092
1093     /* Draw the "size-box" */
1094     if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1095     {
1096         RECT r = rect;
1097         if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1098             r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1099         else
1100             r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1101         r.top  = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1102         FillRect( hdc, &r,  GetSysColorBrush(COLOR_SCROLLBAR) );
1103     }
1104
1105     ReleaseDC( hwnd, hdc );
1106 }
1107
1108
1109
1110
1111 /***********************************************************************
1112  *           NC_HandleNCPaint
1113  *
1114  * Handle a WM_NCPAINT message. Called from DefWindowProc().
1115  */
1116 LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
1117 {
1118     DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1119
1120     if( dwStyle & WS_VISIBLE )
1121     {
1122         if( dwStyle & WS_MINIMIZE )
1123             WINPOS_RedrawIconTitle( hwnd );
1124         else
1125             NC_DoNCPaint( hwnd, clip, FALSE );
1126     }
1127     return 0;
1128 }
1129
1130
1131 /***********************************************************************
1132  *           NC_HandleNCActivate
1133  *
1134  * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1135  */
1136 LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
1137 {
1138     WND* wndPtr = WIN_GetPtr( hwnd );
1139
1140     if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return FALSE;
1141
1142     /* Lotus Notes draws menu descriptions in the caption of its main
1143      * window. When it wants to restore original "system" view, it just
1144      * sends WM_NCACTIVATE message to itself. Any optimizations here in
1145      * attempt to minimize redrawings lead to a not restored caption.
1146      */
1147     if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1148     else wndPtr->flags &= ~WIN_NCACTIVATED;
1149     WIN_ReleasePtr( wndPtr );
1150
1151     /* This isn't documented but is reproducible in at least XP SP2 and
1152      * Outlook 2007 depends on it
1153      */
1154     if (lParam != -1)
1155     {
1156         if (IsIconic(hwnd))
1157             WINPOS_RedrawIconTitle( hwnd );
1158         else
1159             NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1160     }
1161
1162     return TRUE;
1163 }
1164
1165
1166 /***********************************************************************
1167  *           NC_HandleSetCursor
1168  *
1169  * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1170  */
1171 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1172 {
1173     hwnd = WIN_GetFullHandle( (HWND)wParam );
1174
1175     switch((short)LOWORD(lParam))
1176     {
1177     case HTERROR:
1178         {
1179             WORD msg = HIWORD( lParam );
1180             if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1181                 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1182                 MessageBeep(0);
1183         }
1184         break;
1185
1186     case HTCLIENT:
1187         {
1188             HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1189             if(hCursor) {
1190                 SetCursor(hCursor);
1191                 return TRUE;
1192             }
1193             return FALSE;
1194         }
1195
1196     case HTLEFT:
1197     case HTRIGHT:
1198         return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1199
1200     case HTTOP:
1201     case HTBOTTOM:
1202         return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1203
1204     case HTTOPLEFT:
1205     case HTBOTTOMRIGHT:
1206         return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1207
1208     case HTTOPRIGHT:
1209     case HTBOTTOMLEFT:
1210         return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1211     }
1212
1213     /* Default cursor: arrow */
1214     return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1215 }
1216
1217 /***********************************************************************
1218  *           NC_GetSysPopupPos
1219  */
1220 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1221 {
1222     if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1223     else
1224     {
1225         DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
1226         DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
1227
1228         NC_GetInsideRect( hwnd, COORDS_CLIENT, rect, style, ex_style );
1229         rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1230         rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1231         MapWindowPoints( hwnd, 0, (POINT *)rect, 2 );
1232     }
1233 }
1234
1235 /***********************************************************************
1236  *           NC_TrackMinMaxBox
1237  *
1238  * Track a mouse button press on the minimize or maximize box.
1239  *
1240  * The big difference between 3.1 and 95 is the disabled button state.
1241  * In win95 the system button can be disabled, so it can ignore the mouse
1242  * event.
1243  *
1244  */
1245 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1246 {
1247     MSG msg;
1248     HDC hdc = GetWindowDC( hwnd );
1249     BOOL pressed = TRUE;
1250     UINT state;
1251     DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1252     HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1253
1254     void  (*paintButton)(HWND, HDC, BOOL, BOOL);
1255
1256     if (wParam == HTMINBUTTON)
1257     {
1258         /* If the style is not present, do nothing */
1259         if (!(wndStyle & WS_MINIMIZEBOX))
1260             return;
1261
1262         /* Check if the sysmenu item for minimize is there  */
1263         state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1264
1265         paintButton = NC_DrawMinButton;
1266     }
1267     else
1268     {
1269         /* If the style is not present, do nothing */
1270         if (!(wndStyle & WS_MAXIMIZEBOX))
1271             return;
1272
1273         /* Check if the sysmenu item for maximize is there  */
1274         state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1275
1276         paintButton = NC_DrawMaxButton;
1277     }
1278
1279     SetCapture( hwnd );
1280
1281     (*paintButton)( hwnd, hdc, TRUE, FALSE);
1282
1283     while(1)
1284     {
1285         BOOL oldstate = pressed;
1286
1287         if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1288         if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1289
1290         if(msg.message == WM_LBUTTONUP)
1291             break;
1292
1293         if(msg.message != WM_MOUSEMOVE)
1294             continue;
1295
1296         pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1297         if (pressed != oldstate)
1298            (*paintButton)( hwnd, hdc, pressed, FALSE);
1299     }
1300
1301     if(pressed)
1302         (*paintButton)(hwnd, hdc, FALSE, FALSE);
1303
1304     ReleaseCapture();
1305     ReleaseDC( hwnd, hdc );
1306
1307     /* If the item minimize or maximize of the sysmenu are not there */
1308     /* or if the style is not present, do nothing */
1309     if ((!pressed) || (state == 0xFFFFFFFF))
1310         return;
1311
1312     if (wParam == HTMINBUTTON)
1313         SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1314     else
1315         SendMessageW( hwnd, WM_SYSCOMMAND,
1316                       IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1317 }
1318
1319 /***********************************************************************
1320  * NC_TrackCloseButton
1321  *
1322  * Track a mouse button press on the Win95 close button.
1323  */
1324 static void NC_TrackCloseButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
1325 {
1326     MSG msg;
1327     HDC hdc;
1328     BOOL pressed = TRUE;
1329     HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1330     UINT state;
1331
1332     if(hSysMenu == 0)
1333         return;
1334
1335     state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1336
1337     /* If the item close of the sysmenu is disabled or not there do nothing */
1338     if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1339         return;
1340
1341     hdc = GetWindowDC( hwnd );
1342
1343     SetCapture( hwnd );
1344
1345     NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1346
1347     while(1)
1348     {
1349         BOOL oldstate = pressed;
1350
1351         if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1352         if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1353
1354         if(msg.message == WM_LBUTTONUP)
1355             break;
1356
1357         if(msg.message != WM_MOUSEMOVE)
1358             continue;
1359
1360         pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1361         if (pressed != oldstate)
1362            NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1363     }
1364
1365     if(pressed)
1366         NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1367
1368     ReleaseCapture();
1369     ReleaseDC( hwnd, hdc );
1370     if (!pressed) return;
1371
1372     SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1373 }
1374
1375
1376 /***********************************************************************
1377  *           NC_TrackScrollBar
1378  *
1379  * Track a mouse button press on the horizontal or vertical scroll-bar.
1380  */
1381 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1382 {
1383     INT scrollbar;
1384
1385     if ((wParam & 0xfff0) == SC_HSCROLL)
1386     {
1387         if ((wParam & 0x0f) != HTHSCROLL) return;
1388         scrollbar = SB_HORZ;
1389     }
1390     else  /* SC_VSCROLL */
1391     {
1392         if ((wParam & 0x0f) != HTVSCROLL) return;
1393         scrollbar = SB_VERT;
1394     }
1395     SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1396 }
1397
1398
1399 /***********************************************************************
1400  *           NC_HandleNCLButtonDown
1401  *
1402  * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1403  */
1404 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1405 {
1406     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1407
1408     switch(wParam)  /* Hit test */
1409     {
1410     case HTCAPTION:
1411         {
1412             HWND top = GetAncestor( hwnd, GA_ROOT );
1413
1414             if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1415                 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1416             break;
1417         }
1418
1419     case HTSYSMENU:
1420          if( style & WS_SYSMENU )
1421          {
1422              if( !(style & WS_MINIMIZE) )
1423              {
1424                 HDC hDC = GetWindowDC(hwnd);
1425                 NC_DrawSysButton( hwnd, hDC, TRUE );
1426                 ReleaseDC( hwnd, hDC );
1427              }
1428              SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1429          }
1430          break;
1431
1432     case HTMENU:
1433         SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1434         break;
1435
1436     case HTHSCROLL:
1437         SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1438         break;
1439
1440     case HTVSCROLL:
1441         SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1442         break;
1443
1444     case HTMINBUTTON:
1445     case HTMAXBUTTON:
1446         NC_TrackMinMaxBox( hwnd, wParam );
1447         break;
1448
1449     case HTCLOSE:
1450         NC_TrackCloseButton (hwnd, wParam, lParam);
1451         break;
1452
1453     case HTLEFT:
1454     case HTRIGHT:
1455     case HTTOP:
1456     case HTTOPLEFT:
1457     case HTTOPRIGHT:
1458     case HTBOTTOM:
1459     case HTBOTTOMLEFT:
1460     case HTBOTTOMRIGHT:
1461         /* Old comment:
1462          * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1463          * This was previously done by setting wParam=SC_SIZE + wParam - 2
1464          */
1465         /* But that is not what WinNT does. Instead it sends this. This
1466          * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1467          * SC_MOUSEMENU into wParam.
1468          */
1469         SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1470         break;
1471
1472     case HTBORDER:
1473         break;
1474     }
1475     return 0;
1476 }
1477
1478
1479 /***********************************************************************
1480  *           NC_HandleNCLButtonDblClk
1481  *
1482  * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1483  */
1484 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1485 {
1486     /*
1487      * if this is an icon, send a restore since we are handling
1488      * a double click
1489      */
1490     if (IsIconic(hwnd))
1491     {
1492         SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1493         return 0;
1494     }
1495
1496     switch(wParam)  /* Hit test */
1497     {
1498     case HTCAPTION:
1499         /* stop processing if WS_MAXIMIZEBOX is missing */
1500         if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1501             SendMessageW( hwnd, WM_SYSCOMMAND,
1502                           IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1503         break;
1504
1505     case HTSYSMENU:
1506         {
1507             HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1508             UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1509
1510             /* If the item close of the sysmenu is disabled or not there do nothing */
1511             if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1512                 break;
1513
1514             SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1515             break;
1516         }
1517
1518     case HTHSCROLL:
1519         SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1520         break;
1521
1522     case HTVSCROLL:
1523         SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1524         break;
1525     }
1526     return 0;
1527 }
1528
1529
1530 /***********************************************************************
1531  *           NC_HandleSysCommand
1532  *
1533  * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1534  */
1535 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1536 {
1537     TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1538
1539     if (!IsWindowEnabled( hwnd )) return 0;
1540
1541     if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1542         return 0;
1543
1544     if (!USER_Driver->pSysCommand( hwnd, wParam, lParam ))
1545         return 0;
1546
1547     switch (wParam & 0xfff0)
1548     {
1549     case SC_SIZE:
1550     case SC_MOVE:
1551         WINPOS_SysCommandSizeMove( hwnd, wParam );
1552         break;
1553
1554     case SC_MINIMIZE:
1555         if (hwnd == GetActiveWindow())
1556             ShowOwnedPopups(hwnd,FALSE);
1557         ShowWindow( hwnd, SW_MINIMIZE );
1558         break;
1559
1560     case SC_MAXIMIZE:
1561         if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1562             ShowOwnedPopups(hwnd,TRUE);
1563         ShowWindow( hwnd, SW_MAXIMIZE );
1564         break;
1565
1566     case SC_RESTORE:
1567         if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1568             ShowOwnedPopups(hwnd,TRUE);
1569         ShowWindow( hwnd, SW_RESTORE );
1570         break;
1571
1572     case SC_CLOSE:
1573         return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1574
1575     case SC_VSCROLL:
1576     case SC_HSCROLL:
1577         {
1578             POINT pt;
1579             pt.x = (short)LOWORD(lParam);
1580             pt.y = (short)HIWORD(lParam);
1581             NC_TrackScrollBar( hwnd, wParam, pt );
1582         }
1583         break;
1584
1585     case SC_MOUSEMENU:
1586         {
1587             POINT pt;
1588             pt.x = (short)LOWORD(lParam);
1589             pt.y = (short)HIWORD(lParam);
1590             MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1591         }
1592         break;
1593
1594     case SC_KEYMENU:
1595         MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1596         break;
1597
1598     case SC_TASKLIST:
1599         WinExec( "taskman.exe", SW_SHOWNORMAL );
1600         break;
1601
1602     case SC_SCREENSAVE:
1603         if (wParam == SC_ABOUTWINE)
1604         {
1605             HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1606             if (hmodule)
1607             {
1608                 BOOL (WINAPI *aboutproc)(HWND, LPCSTR, LPCSTR, HICON);
1609
1610                 aboutproc = (void *)GetProcAddress( hmodule, "ShellAboutA" );
1611                 if (aboutproc) aboutproc( hwnd, PACKAGE_STRING, NULL, 0 );
1612                 FreeLibrary( hmodule );
1613             }
1614         }
1615         break;
1616
1617     case SC_HOTKEY:
1618     case SC_ARRANGE:
1619     case SC_NEXTWINDOW:
1620     case SC_PREVWINDOW:
1621         FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1622         break;
1623     }
1624     return 0;
1625 }
1626
1627 /***********************************************************************
1628  *              GetTitleBarInfo (USER32.@)
1629  * TODO: Handle STATE_SYSTEM_PRESSED
1630  */
1631 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1632     DWORD dwStyle;
1633     DWORD dwExStyle;
1634
1635     TRACE("(%p %p)\n", hwnd, tbi);
1636
1637     if(!tbi) {
1638         SetLastError(ERROR_NOACCESS);
1639         return FALSE;
1640     }
1641
1642     if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1643         TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1644         SetLastError(ERROR_INVALID_PARAMETER);
1645         return FALSE;
1646     }
1647     dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1648     dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1649     NC_GetInsideRect(hwnd, COORDS_SCREEN, &tbi->rcTitleBar, dwStyle, dwExStyle);
1650
1651     tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1652     if(dwExStyle & WS_EX_TOOLWINDOW)
1653         tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1654     else {
1655         tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1656         tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1657     }
1658
1659     ZeroMemory(tbi->rgstate, sizeof(tbi->rgstate));
1660     /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1661      * Under XP it seems to
1662      */
1663     tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1664     if(dwStyle & WS_CAPTION) {
1665         tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1666         if(dwStyle & WS_SYSMENU) {
1667             if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1668                 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1669                 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1670             }
1671             else {
1672                 if(!(dwStyle & WS_MINIMIZEBOX))
1673                     tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1674                 if(!(dwStyle & WS_MAXIMIZEBOX))
1675                     tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1676             }
1677             if(!(dwExStyle & WS_EX_CONTEXTHELP))
1678                 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1679             if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1680                 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1681         }
1682         else {
1683             tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1684             tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1685             tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1686             tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1687         }
1688     }
1689     else
1690         tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1691     return TRUE;
1692 }