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