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