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