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