winex11: Add support for merging redundant events, and use it for ConfigureNotify...
[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 )
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     if (IsIconic(hwnd))
1142         WINPOS_RedrawIconTitle( hwnd );
1143     else
1144         NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1145
1146     return TRUE;
1147 }
1148
1149
1150 /***********************************************************************
1151  *           NC_HandleSetCursor
1152  *
1153  * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1154  */
1155 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1156 {
1157     hwnd = WIN_GetFullHandle( (HWND)wParam );
1158
1159     switch((short)LOWORD(lParam))
1160     {
1161     case HTERROR:
1162         {
1163             WORD msg = HIWORD( lParam );
1164             if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1165                 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1166                 MessageBeep(0);
1167         }
1168         break;
1169
1170     case HTCLIENT:
1171         {
1172             HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1173             if(hCursor) {
1174                 SetCursor(hCursor);
1175                 return TRUE;
1176             }
1177             return FALSE;
1178         }
1179
1180     case HTLEFT:
1181     case HTRIGHT:
1182         return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1183
1184     case HTTOP:
1185     case HTBOTTOM:
1186         return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1187
1188     case HTTOPLEFT:
1189     case HTBOTTOMRIGHT:
1190         return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1191
1192     case HTTOPRIGHT:
1193     case HTBOTTOMLEFT:
1194         return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1195     }
1196
1197     /* Default cursor: arrow */
1198     return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1199 }
1200
1201 /***********************************************************************
1202  *           NC_GetSysPopupPos
1203  */
1204 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1205 {
1206     if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1207     else
1208     {
1209         WND *wndPtr = WIN_GetPtr( hwnd );
1210         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return;
1211
1212         NC_GetInsideRect( hwnd, rect );
1213         OffsetRect( rect, wndPtr->rectWindow.left, wndPtr->rectWindow.top);
1214         if (wndPtr->dwStyle & WS_CHILD)
1215             ClientToScreen( GetParent(hwnd), (POINT *)rect );
1216         rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1217         rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1218         WIN_ReleasePtr( wndPtr );
1219     }
1220 }
1221
1222 /***********************************************************************
1223  *           NC_TrackMinMaxBox
1224  *
1225  * Track a mouse button press on the minimize or maximize box.
1226  *
1227  * The big difference between 3.1 and 95 is the disabled button state.
1228  * In win95 the system button can be disabled, so it can ignore the mouse
1229  * event.
1230  *
1231  */
1232 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1233 {
1234     MSG msg;
1235     HDC hdc = GetWindowDC( hwnd );
1236     BOOL pressed = TRUE;
1237     UINT state;
1238     DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1239     HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1240
1241     void  (*paintButton)(HWND, HDC, BOOL, BOOL);
1242
1243     if (wParam == HTMINBUTTON)
1244     {
1245         /* If the style is not present, do nothing */
1246         if (!(wndStyle & WS_MINIMIZEBOX))
1247             return;
1248
1249         /* Check if the sysmenu item for minimize is there  */
1250         state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1251
1252         paintButton = &NC_DrawMinButton;
1253     }
1254     else
1255     {
1256         /* If the style is not present, do nothing */
1257         if (!(wndStyle & WS_MAXIMIZEBOX))
1258             return;
1259
1260         /* Check if the sysmenu item for maximize is there  */
1261         state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1262
1263         paintButton = &NC_DrawMaxButton;
1264     }
1265
1266     SetCapture( hwnd );
1267
1268     (*paintButton)( hwnd, hdc, TRUE, FALSE);
1269
1270     while(1)
1271     {
1272         BOOL oldstate = pressed;
1273
1274         if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1275         if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1276
1277         if(msg.message == WM_LBUTTONUP)
1278             break;
1279
1280         if(msg.message != WM_MOUSEMOVE)
1281             continue;
1282
1283         pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1284         if (pressed != oldstate)
1285            (*paintButton)( hwnd, hdc, pressed, FALSE);
1286     }
1287
1288     if(pressed)
1289         (*paintButton)(hwnd, hdc, FALSE, FALSE);
1290
1291     ReleaseCapture();
1292     ReleaseDC( hwnd, hdc );
1293
1294     /* If the item minimize or maximize of the sysmenu are not there */
1295     /* or if the style is not present, do nothing */
1296     if ((!pressed) || (state == 0xFFFFFFFF))
1297         return;
1298
1299     if (wParam == HTMINBUTTON)
1300         SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1301     else
1302         SendMessageW( hwnd, WM_SYSCOMMAND,
1303                       IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1304 }
1305
1306 /***********************************************************************
1307  * NC_TrackCloseButton
1308  *
1309  * Track a mouse button press on the Win95 close button.
1310  */
1311 static void NC_TrackCloseButton (HWND hwnd, WORD wParam)
1312 {
1313     MSG msg;
1314     HDC hdc;
1315     BOOL pressed = TRUE;
1316     HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1317     UINT state;
1318
1319     if(hSysMenu == 0)
1320         return;
1321
1322     state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1323
1324     /* If the item close of the sysmenu is disabled or not there do nothing */
1325     if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1326         return;
1327
1328     hdc = GetWindowDC( hwnd );
1329
1330     SetCapture( hwnd );
1331
1332     NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1333
1334     while(1)
1335     {
1336         BOOL oldstate = pressed;
1337
1338         if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1339         if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1340
1341         if(msg.message == WM_LBUTTONUP)
1342             break;
1343
1344         if(msg.message != WM_MOUSEMOVE)
1345             continue;
1346
1347         pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1348         if (pressed != oldstate)
1349            NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1350     }
1351
1352     if(pressed)
1353         NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1354
1355     ReleaseCapture();
1356     ReleaseDC( hwnd, hdc );
1357     if (!pressed) return;
1358
1359     SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, MAKELONG(msg.pt.x,msg.pt.y) );
1360 }
1361
1362
1363 /***********************************************************************
1364  *           NC_TrackScrollBar
1365  *
1366  * Track a mouse button press on the horizontal or vertical scroll-bar.
1367  */
1368 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1369 {
1370     INT scrollbar;
1371
1372     if ((wParam & 0xfff0) == SC_HSCROLL)
1373     {
1374         if ((wParam & 0x0f) != HTHSCROLL) return;
1375         scrollbar = SB_HORZ;
1376     }
1377     else  /* SC_VSCROLL */
1378     {
1379         if ((wParam & 0x0f) != HTVSCROLL) return;
1380         scrollbar = SB_VERT;
1381     }
1382     SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1383 }
1384
1385
1386 /***********************************************************************
1387  *           NC_HandleNCLButtonDown
1388  *
1389  * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1390  */
1391 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1392 {
1393     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1394
1395     switch(wParam)  /* Hit test */
1396     {
1397     case HTCAPTION:
1398         {
1399             HWND top = GetAncestor( hwnd, GA_ROOT );
1400
1401             if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1402                 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1403             break;
1404         }
1405
1406     case HTSYSMENU:
1407          if( style & WS_SYSMENU )
1408          {
1409              if( !(style & WS_MINIMIZE) )
1410              {
1411                 HDC hDC = GetWindowDC(hwnd);
1412                 NC_DrawSysButton( hwnd, hDC, TRUE );
1413                 ReleaseDC( hwnd, hDC );
1414              }
1415              SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1416          }
1417          break;
1418
1419     case HTMENU:
1420         SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1421         break;
1422
1423     case HTHSCROLL:
1424         SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1425         break;
1426
1427     case HTVSCROLL:
1428         SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1429         break;
1430
1431     case HTMINBUTTON:
1432     case HTMAXBUTTON:
1433         NC_TrackMinMaxBox( hwnd, wParam );
1434         break;
1435
1436     case HTCLOSE:
1437         NC_TrackCloseButton (hwnd, wParam);
1438         break;
1439
1440     case HTLEFT:
1441     case HTRIGHT:
1442     case HTTOP:
1443     case HTTOPLEFT:
1444     case HTTOPRIGHT:
1445     case HTBOTTOM:
1446     case HTBOTTOMLEFT:
1447     case HTBOTTOMRIGHT:
1448         /* Old comment:
1449          * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1450          * This was previously done by setting wParam=SC_SIZE + wParam - 2
1451          */
1452         /* But that is not what WinNT does. Instead it sends this. This
1453          * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1454          * SC_MOUSEMENU into wParam.
1455          */
1456         SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1457         break;
1458
1459     case HTBORDER:
1460         break;
1461     }
1462     return 0;
1463 }
1464
1465
1466 /***********************************************************************
1467  *           NC_HandleNCLButtonDblClk
1468  *
1469  * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1470  */
1471 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1472 {
1473     /*
1474      * if this is an icon, send a restore since we are handling
1475      * a double click
1476      */
1477     if (IsIconic(hwnd))
1478     {
1479         SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1480         return 0;
1481     }
1482
1483     switch(wParam)  /* Hit test */
1484     {
1485     case HTCAPTION:
1486         /* stop processing if WS_MAXIMIZEBOX is missing */
1487         if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1488             SendMessageW( hwnd, WM_SYSCOMMAND,
1489                           IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1490         break;
1491
1492     case HTSYSMENU:
1493         {
1494             HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1495             UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1496
1497             /* If the item close of the sysmenu is disabled or not there do nothing */
1498             if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1499                 break;
1500
1501             SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1502             break;
1503         }
1504
1505     case HTHSCROLL:
1506         SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1507         break;
1508
1509     case HTVSCROLL:
1510         SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1511         break;
1512     }
1513     return 0;
1514 }
1515
1516
1517 /***********************************************************************
1518  *           NC_HandleSysCommand
1519  *
1520  * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1521  */
1522 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1523 {
1524     TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1525
1526     if (!IsWindowEnabled( hwnd )) return 0;
1527
1528     if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1529         return 0;
1530
1531     switch (wParam & 0xfff0)
1532     {
1533     case SC_SIZE:
1534     case SC_MOVE:
1535         USER_Driver->pSysCommandSizeMove( hwnd, wParam );
1536         break;
1537
1538     case SC_MINIMIZE:
1539         if (hwnd == GetForegroundWindow())
1540             ShowOwnedPopups(hwnd,FALSE);
1541         ShowWindow( hwnd, SW_MINIMIZE );
1542         break;
1543
1544     case SC_MAXIMIZE:
1545         if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1546             ShowOwnedPopups(hwnd,TRUE);
1547         ShowWindow( hwnd, SW_MAXIMIZE );
1548         break;
1549
1550     case SC_RESTORE:
1551         if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1552             ShowOwnedPopups(hwnd,TRUE);
1553         ShowWindow( hwnd, SW_RESTORE );
1554         break;
1555
1556     case SC_CLOSE:
1557         return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1558
1559     case SC_VSCROLL:
1560     case SC_HSCROLL:
1561         {
1562             POINT pt;
1563             pt.x = (short)LOWORD(lParam);
1564             pt.y = (short)HIWORD(lParam);
1565             NC_TrackScrollBar( hwnd, wParam, pt );
1566         }
1567         break;
1568
1569     case SC_MOUSEMENU:
1570         {
1571             POINT pt;
1572             pt.x = (short)LOWORD(lParam);
1573             pt.y = (short)HIWORD(lParam);
1574             MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1575         }
1576         break;
1577
1578     case SC_KEYMENU:
1579         MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1580         break;
1581
1582     case SC_TASKLIST:
1583         WinExec( "taskman.exe", SW_SHOWNORMAL );
1584         break;
1585
1586     case SC_SCREENSAVE:
1587         if (wParam == SC_ABOUTWINE)
1588         {
1589             HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1590             if (hmodule)
1591             {
1592                 FARPROC aboutproc = GetProcAddress( hmodule, "ShellAboutA" );
1593                 if (aboutproc) aboutproc( hwnd, PACKAGE_NAME, PACKAGE_STRING, 0 );
1594                 FreeLibrary( hmodule );
1595             }
1596         }
1597         else
1598           if (wParam == SC_PUTMARK)
1599             DPRINTF("Debug mark requested by user\n");
1600         break;
1601
1602     case SC_HOTKEY:
1603     case SC_ARRANGE:
1604     case SC_NEXTWINDOW:
1605     case SC_PREVWINDOW:
1606         FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1607         break;
1608     }
1609     return 0;
1610 }
1611
1612 /***********************************************************************
1613  *              GetTitleBarInfo (USER32.@)
1614  * TODO: Handle STATE_SYSTEM_PRESSED
1615  */
1616 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1617     DWORD dwStyle;
1618     DWORD dwExStyle;
1619     RECT wndRect;
1620
1621     TRACE("(%p %p)\n", hwnd, tbi);
1622
1623     if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1624         TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1625         SetLastError(ERROR_INVALID_PARAMETER);
1626         return FALSE;
1627     }
1628     dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1629     dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1630     NC_GetInsideRect(hwnd, &tbi->rcTitleBar);
1631
1632     GetWindowRect(hwnd, &wndRect);
1633
1634     tbi->rcTitleBar.top += wndRect.top;
1635     tbi->rcTitleBar.left += wndRect.left;
1636     tbi->rcTitleBar.right += wndRect.left;
1637
1638     tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1639     if(dwExStyle & WS_EX_TOOLWINDOW)
1640         tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1641     else {
1642         tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1643         tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1644     }
1645
1646     ZeroMemory(&tbi->rgstate, sizeof(tbi->rgstate));
1647     /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1648      * Under XP it seems to
1649      */
1650     tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1651     if(dwStyle & WS_CAPTION) {
1652         tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1653         if(dwStyle & WS_SYSMENU) {
1654             if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1655                 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1656                 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1657             }
1658             else {
1659                 if(!(dwStyle & WS_MINIMIZEBOX))
1660                     tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1661                 if(!(dwStyle & WS_MAXIMIZEBOX))
1662                     tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1663             }
1664             if(!(dwExStyle & WS_EX_CONTEXTHELP))
1665                 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1666             if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1667                 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1668         }
1669         else {
1670             tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1671             tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1672             tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1673             tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1674         }
1675     }
1676     else
1677         tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1678     return TRUE;
1679 }