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