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