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