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