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