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