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