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