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