Use a new DLLDEFS variable in configure/Makefiles to actually remove
[wine] / windows / nonclient.c
1 /*
2  * Non-client area window functions
3  *
4  * Copyright 1994 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "wine/winuser16.h"
29 #include "wownt32.h"
30 #include "win.h"
31 #include "user.h"
32 #include "dce.h"
33 #include "controls.h"
34 #include "cursoricon.h"
35 #include "winpos.h"
36 #include "nonclient.h"
37 #include "shellapi.h"
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
41 WINE_DECLARE_DEBUG_CHANNEL(shell);
42
43 BOOL NC_DrawGrayButton(HDC hdc, int x, int y);
44
45 static const BYTE lpGrayMask[] = { 0xAA, 0xA0,
46                       0x55, 0x50,
47                       0xAA, 0xA0,
48                       0x55, 0x50,
49                       0xAA, 0xA0,
50                       0x55, 0x50,
51                       0xAA, 0xA0,
52                       0x55, 0x50,
53                       0xAA, 0xA0,
54                       0x55, 0x50};
55
56 #define SC_ABOUTWINE            (SC_SCREENSAVE+1)
57 #define SC_PUTMARK              (SC_SCREENSAVE+2)
58
59   /* Some useful macros */
60 #define HAS_DLGFRAME(style,exStyle) \
61     (((exStyle) & WS_EX_DLGMODALFRAME) || \
62      (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
63
64 #define HAS_THICKFRAME(style,exStyle) \
65     (((style) & WS_THICKFRAME) && \
66      !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
67
68 #define HAS_THINFRAME(style) \
69     (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
70
71 #define HAS_BIGFRAME(style,exStyle) \
72     (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
73      ((exStyle) & WS_EX_DLGMODALFRAME))
74
75 #define HAS_STATICOUTERFRAME(style,exStyle) \
76     (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
77      WS_EX_STATICEDGE)
78
79 #define HAS_ANYFRAME(style,exStyle) \
80     (((style) & (WS_THICKFRAME | WS_DLGFRAME | WS_BORDER)) || \
81      ((exStyle) & WS_EX_DLGMODALFRAME) || \
82      !((style) & (WS_CHILD | WS_POPUP)))
83
84 #define HAS_MENU(w)  (!((w)->dwStyle & WS_CHILD) && ((w)->wIDmenu != 0))
85
86
87 /******************************************************************************
88  * NC_AdjustRectOuter
89  *
90  * Computes the size of the "outside" parts of the window based on the
91  * parameters of the client area.
92  *
93  + PARAMS
94  *     LPRECT16  rect
95  *     DWORD  style
96  *     BOOL  menu
97  *     DWORD  exStyle
98  *
99  * NOTES
100  *     "Outer" parts of a window means the whole window frame, caption and
101  *     menu bar. It does not include "inner" parts of the frame like client
102  *     edge, static edge or scroll bars.
103  *
104  *****************************************************************************/
105
106 static void
107 NC_AdjustRectOuter (LPRECT rect, DWORD style, BOOL menu, DWORD exStyle)
108 {
109     int adjust;
110     if(style & WS_ICONIC) return;
111
112     if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) ==
113         WS_EX_STATICEDGE)
114     {
115         adjust = 1; /* for the outer frame always present */
116     }
117     else
118     {
119         adjust = 0;
120         if ((exStyle & WS_EX_DLGMODALFRAME) ||
121             (style & (WS_THICKFRAME|WS_DLGFRAME))) adjust = 2; /* outer */
122     }
123     if (style & WS_THICKFRAME)
124         adjust +=  ( GetSystemMetrics (SM_CXFRAME)
125                    - GetSystemMetrics (SM_CXDLGFRAME)); /* The resize border */
126     if ((style & (WS_BORDER|WS_DLGFRAME)) ||
127         (exStyle & WS_EX_DLGMODALFRAME))
128         adjust++; /* The other border */
129
130     InflateRect (rect, adjust, adjust);
131
132     if ((style & WS_CAPTION) == WS_CAPTION)
133     {
134         if (exStyle & WS_EX_TOOLWINDOW)
135             rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
136         else
137             rect->top -= GetSystemMetrics(SM_CYCAPTION);
138     }
139     if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
140 }
141
142
143 /******************************************************************************
144  * NC_AdjustRectInner
145  *
146  * Computes the size of the "inside" part of the window based on the
147  * parameters of the client area.
148  *
149  + PARAMS
150  *     LPRECT16 rect
151  *     DWORD    style
152  *     DWORD    exStyle
153  *
154  * NOTES
155  *     "Inner" part of a window means the window frame inside of the flat
156  *     window frame. It includes the client edge, the static edge and the
157  *     scroll bars.
158  *
159  *****************************************************************************/
160
161 static void
162 NC_AdjustRectInner (LPRECT rect, DWORD style, DWORD exStyle)
163 {
164     if(style & WS_ICONIC) return;
165
166     if (exStyle & WS_EX_CLIENTEDGE)
167         InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
168
169     if (style & WS_VSCROLL)
170     {
171         if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
172             rect->left  -= GetSystemMetrics(SM_CXVSCROLL);
173         else
174             rect->right += GetSystemMetrics(SM_CXVSCROLL);
175     }
176     if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
177 }
178
179
180
181 static HICON NC_IconForWindow( HWND hwnd )
182 {
183     HICON hIcon = 0;
184     WND *wndPtr = WIN_GetPtr( hwnd );
185
186     if (wndPtr && wndPtr != WND_OTHER_PROCESS)
187     {
188         hIcon = wndPtr->hIconSmall;
189         if (!hIcon) hIcon = wndPtr->hIcon;
190         WIN_ReleasePtr( wndPtr );
191     }
192     if (!hIcon) hIcon = (HICON) GetClassLongA( hwnd, GCL_HICONSM );
193     if (!hIcon) hIcon = (HICON) GetClassLongA( hwnd, GCL_HICON );
194
195     /* If there is no hIcon specified and this is a modal dialog,
196      * get the default one.
197      */
198     if (!hIcon && (GetWindowLongA( hwnd, GWL_STYLE ) & DS_MODALFRAME))
199         hIcon = LoadImageA(0, (LPSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
200     return hIcon;
201 }
202
203 /***********************************************************************
204  *              DrawCaption (USER32.@) Draws a caption bar
205  *
206  * PARAMS
207  *     hwnd   [I]
208  *     hdc    [I]
209  *     lpRect [I]
210  *     uFlags [I]
211  *
212  * RETURNS
213  *     Success:
214  *     Failure:
215  */
216
217 BOOL WINAPI
218 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
219 {
220     return DrawCaptionTempA (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x1F);
221 }
222
223
224 /***********************************************************************
225  *              DrawCaptionTempA (USER32.@)
226  */
227 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
228                               HICON hIcon, LPCSTR str, UINT uFlags)
229 {
230     LPWSTR strW;
231     INT len;
232     BOOL ret = FALSE;
233
234     if (!(uFlags & DC_TEXT) || !str)
235         return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
236
237     len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
238     if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
239     {
240         MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
241         ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
242         HeapFree( GetProcessHeap (), 0, strW );
243     }
244     return ret;
245 }
246
247
248 /***********************************************************************
249  *              DrawCaptionTempW (USER32.@)
250  */
251 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
252                               HICON hIcon, LPCWSTR str, UINT uFlags)
253 {
254     RECT   rc = *rect;
255
256     TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
257           hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
258
259     /* drawing background */
260     if (uFlags & DC_INBUTTON) {
261         FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
262
263         if (uFlags & DC_ACTIVE) {
264             HBRUSH hbr = SelectObject (hdc, UITOOLS_GetPattern55AABrush ());
265             PatBlt (hdc, rc.left, rc.top,
266                       rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
267             SelectObject (hdc, hbr);
268         }
269     }
270     else {
271         FillRect (hdc, &rc, GetSysColorBrush ((uFlags & DC_ACTIVE) ?
272                     COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
273     }
274
275
276     /* drawing icon */
277     if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
278         POINT pt;
279
280         pt.x = rc.left + 2;
281         pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
282
283         if (!hIcon) hIcon = NC_IconForWindow(hwnd);
284         DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
285                     GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
286         rc.left += (rc.bottom - rc.top);
287     }
288
289     /* drawing text */
290     if (uFlags & DC_TEXT) {
291         HFONT hOldFont;
292
293         if (uFlags & DC_INBUTTON)
294             SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
295         else if (uFlags & DC_ACTIVE)
296             SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
297         else
298             SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
299
300         SetBkMode (hdc, TRANSPARENT);
301
302         if (hFont)
303             hOldFont = SelectObject (hdc, hFont);
304         else {
305             NONCLIENTMETRICSW nclm;
306             HFONT hNewFont;
307             nclm.cbSize = sizeof(NONCLIENTMETRICSW);
308             SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
309             hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
310                 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
311             hOldFont = SelectObject (hdc, hNewFont);
312         }
313
314         if (str)
315             DrawTextW (hdc, str, -1, &rc,
316                          DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
317         else {
318             WCHAR szText[128];
319             INT nLen;
320             nLen = GetWindowTextW (hwnd, szText, 128);
321             DrawTextW (hdc, szText, nLen, &rc,
322                          DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
323         }
324
325         if (hFont)
326             SelectObject (hdc, hOldFont);
327         else
328             DeleteObject (SelectObject (hdc, hOldFont));
329     }
330
331     /* drawing focus ??? */
332     if (uFlags & 0x2000)
333         FIXME("undocumented flag (0x2000)!\n");
334
335     return 0;
336 }
337
338
339 /***********************************************************************
340  *              AdjustWindowRect (USER32.@)
341  */
342 BOOL WINAPI AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
343 {
344     return AdjustWindowRectEx( rect, style, menu, 0 );
345 }
346
347
348 /***********************************************************************
349  *              AdjustWindowRectEx (USER32.@)
350  */
351 BOOL WINAPI AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
352 {
353     /* Correct the window style */
354     style &= (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME | WS_CHILD);
355     exStyle &= (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE |
356                 WS_EX_STATICEDGE | WS_EX_TOOLWINDOW);
357     if (exStyle & WS_EX_DLGMODALFRAME) style &= ~WS_THICKFRAME;
358
359     TRACE("(%ld,%ld)-(%ld,%ld) %08lx %d %08lx\n",
360           rect->left, rect->top, rect->right, rect->bottom,
361           style, menu, exStyle );
362
363     NC_AdjustRectOuter( rect, style, menu, exStyle );
364     NC_AdjustRectInner( rect, style, exStyle );
365
366     return TRUE;
367 }
368
369
370 /***********************************************************************
371  *           NC_HandleNCCalcSize
372  *
373  * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
374  */
375 LONG NC_HandleNCCalcSize( HWND hwnd, RECT *winRect )
376 {
377     RECT tmpRect = { 0, 0, 0, 0 };
378     LONG result = 0;
379     LONG cls_style = GetClassLongA(hwnd, GCL_STYLE);
380     LONG style = GetWindowLongA( hwnd, GWL_STYLE );
381     LONG exStyle = GetWindowLongA( hwnd, GWL_EXSTYLE );
382
383     if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
384     if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
385
386     if (!IsIconic(hwnd))
387     {
388         NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
389
390         winRect->left   -= tmpRect.left;
391         winRect->top    -= tmpRect.top;
392         winRect->right  -= tmpRect.right;
393         winRect->bottom -= tmpRect.bottom;
394
395         if (!(style & WS_CHILD) && GetMenu(hwnd))
396         {
397             TRACE("Calling GetMenuBarHeight with hwnd %p, width %ld, at (%ld, %ld).\n",
398                   hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
399
400             winRect->top +=
401                 MENU_GetMenuBarHeight( hwnd,
402                                        winRect->right - winRect->left,
403                                        -tmpRect.left, -tmpRect.top ) + 1;
404         }
405
406         SetRect(&tmpRect, 0, 0, 0, 0);
407         NC_AdjustRectInner (&tmpRect, style, exStyle);
408         winRect->left   -= tmpRect.left;
409         winRect->top    -= tmpRect.top;
410         winRect->right  -= tmpRect.right;
411         winRect->bottom -= tmpRect.bottom;
412
413         if (winRect->top > winRect->bottom)
414             winRect->bottom = winRect->top;
415
416         if (winRect->left > winRect->right)
417             winRect->right = winRect->left;
418     }
419     return result;
420 }
421
422
423 /***********************************************************************
424  *           NC_GetInsideRect
425  *
426  * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
427  * but without the borders (if any).
428  * The rectangle is in window coordinates (for drawing with GetWindowDC()).
429  */
430 void NC_GetInsideRect( HWND hwnd, RECT *rect )
431 {
432     WND * wndPtr = WIN_FindWndPtr( hwnd );
433
434     rect->top    = rect->left = 0;
435     rect->right  = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
436     rect->bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
437
438     if (wndPtr->dwStyle & WS_ICONIC) goto END;
439
440     /* Remove frame from rectangle */
441     if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
442     {
443         InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
444     }
445     else if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
446     {
447         InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
448     }
449     else if (HAS_THINFRAME( wndPtr->dwStyle ))
450     {
451         InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
452     }
453
454     /* We have additional border information if the window
455      * is a child (but not an MDI child) */
456     if ( (wndPtr->dwStyle & WS_CHILD)  &&
457          ( (wndPtr->dwExStyle & WS_EX_MDICHILD) == 0 ) )
458     {
459         if (wndPtr->dwExStyle & WS_EX_CLIENTEDGE)
460             InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
461         if (wndPtr->dwExStyle & WS_EX_STATICEDGE)
462             InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
463     }
464
465 END:
466     WIN_ReleaseWndPtr(wndPtr);
467     return;
468 }
469
470
471 /***********************************************************************
472  * NC_DoNCHitTest
473  *
474  * Handle a WM_NCHITTEST message. Called from NC_HandleNCHitTest().
475  *
476  * FIXME:  Just a modified copy of the Win 3.1 version.
477  */
478
479 static LONG NC_DoNCHitTest (WND *wndPtr, POINT pt )
480 {
481     RECT rect, rcClient;
482     POINT ptClient;
483
484     TRACE("hwnd=%p pt=%ld,%ld\n", wndPtr->hwndSelf, pt.x, pt.y );
485
486     GetWindowRect(wndPtr->hwndSelf, &rect );
487     if (!PtInRect( &rect, pt )) return HTNOWHERE;
488
489     if (wndPtr->dwStyle & WS_MINIMIZE) return HTCAPTION;
490
491     /* Check client area */
492     ptClient = pt;
493     ScreenToClient( wndPtr->hwndSelf, &ptClient );
494     GetClientRect( wndPtr->hwndSelf, &rcClient );
495     if (PtInRect( &rcClient, ptClient )) return HTCLIENT;
496
497     /* Check borders */
498     if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
499     {
500         InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
501         if (!PtInRect( &rect, pt ))
502         {
503             /* Check top sizing border */
504             if (pt.y < rect.top)
505             {
506                 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
507                 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
508                 return HTTOP;
509             }
510             /* Check bottom sizing border */
511             if (pt.y >= rect.bottom)
512             {
513                 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
514                 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
515                 return HTBOTTOM;
516             }
517             /* Check left sizing border */
518             if (pt.x < rect.left)
519             {
520                 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
521                 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
522                 return HTLEFT;
523             }
524             /* Check right sizing border */
525             if (pt.x >= rect.right)
526             {
527                 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
528                 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
529                 return HTRIGHT;
530             }
531         }
532     }
533     else  /* No thick frame */
534     {
535         if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
536             InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
537         else if (HAS_THINFRAME( wndPtr->dwStyle ))
538             InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
539         if (!PtInRect( &rect, pt )) return HTBORDER;
540     }
541
542     /* Check caption */
543
544     if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION)
545     {
546         if (wndPtr->dwExStyle & WS_EX_TOOLWINDOW)
547             rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
548         else
549             rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
550         if (!PtInRect( &rect, pt ))
551         {
552             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 + 1, rect.top + 1, hIcon,
659                     GetSystemMetrics(SM_CXSIZE) - 1,
660                     GetSystemMetrics(SM_CYSIZE) - 1, 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_CYCAPTION) - 1;
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     RECT rectClient, rectWindow;
947     int has_menu;
948
949     if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
950     has_menu = HAS_MENU(wndPtr);
951     dwStyle = wndPtr->dwStyle;
952     dwExStyle = wndPtr->dwExStyle;
953     flags = wndPtr->flags;
954     rectClient = wndPtr->rectClient;
955     rectWindow = wndPtr->rectWindow;
956     WIN_ReleasePtr( wndPtr );
957
958     if ( dwStyle & WS_MINIMIZE ||
959          !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
960
961     active  = flags & WIN_NCACTIVATED;
962
963     TRACE("%p %d\n", hwnd, active );
964
965     /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
966        the call to GetDCEx implying that it is allowed not to use it either.
967        However, the suggested GetDCEx(    , DCX_WINDOW | DCX_INTERSECTRGN)
968        will cause clipRgn to be deleted after ReleaseDC().
969        Now, how is the "system" supposed to tell what happened?
970      */
971
972     if (!(hdc = GetDCEx( hwnd, (clip > (HRGN)1) ? clip : 0, DCX_USESTYLE | DCX_WINDOW |
973                               ((clip > (HRGN)1) ?(DCX_INTERSECTRGN | DCX_KEEPCLIPRGN) : 0) ))) return;
974
975
976     if (ExcludeVisRect16( HDC_16(hdc), rectClient.left-rectWindow.left,
977                         rectClient.top-rectWindow.top,
978                         rectClient.right-rectWindow.left,
979                         rectClient.bottom-rectWindow.top )
980         == NULLREGION)
981     {
982         ReleaseDC( hwnd, hdc );
983         return;
984     }
985
986     rect.top = rect.left = 0;
987     rect.right  = rectWindow.right - rectWindow.left;
988     rect.bottom = rectWindow.bottom - rectWindow.top;
989
990     if( clip > (HRGN)1 )
991         GetRgnBox( clip, &rectClip );
992     else
993     {
994         clip = 0;
995         rectClip = rect;
996     }
997
998     SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
999
1000     if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1001         DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1002     }
1003     else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1004         DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1005     }
1006
1007     NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1008
1009     if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1010     {
1011         RECT  r = rect;
1012         if (dwExStyle & WS_EX_TOOLWINDOW) {
1013             r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1014             rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1015         }
1016         else {
1017             r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1018             rect.top += GetSystemMetrics(SM_CYCAPTION);
1019         }
1020         if( !clip || IntersectRect( &rfuzz, &r, &rectClip ) )
1021             NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1022     }
1023
1024     if (has_menu)
1025     {
1026         RECT r = rect;
1027         r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1028
1029         TRACE("Calling DrawMenuBar with rect (%ld, %ld)-(%ld, %ld)\n",
1030               r.left, r.top, r.right, r.bottom);
1031
1032         rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1033     }
1034
1035     TRACE("After MenuBar, rect is (%ld, %ld)-(%ld, %ld).\n",
1036           rect.left, rect.top, rect.right, rect.bottom );
1037
1038     if (dwExStyle & WS_EX_CLIENTEDGE)
1039         DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1040
1041     /* Draw the scroll-bars */
1042
1043     if (dwStyle & WS_VSCROLL)
1044         SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1045     if (dwStyle & WS_HSCROLL)
1046         SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1047
1048     /* Draw the "size-box" */
1049     if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1050     {
1051         RECT r = rect;
1052         if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1053             r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1054         else
1055             r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1056         r.top  = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1057         FillRect( hdc, &r,  GetSysColorBrush(COLOR_SCROLLBAR) );
1058     }
1059
1060     ReleaseDC( hwnd, hdc );
1061 }
1062
1063
1064
1065
1066 /***********************************************************************
1067  *           NC_HandleNCPaint
1068  *
1069  * Handle a WM_NCPAINT message. Called from DefWindowProc().
1070  */
1071 LONG NC_HandleNCPaint( HWND hwnd , HRGN clip)
1072 {
1073     DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1074
1075     if( dwStyle & WS_VISIBLE )
1076     {
1077         if( dwStyle & WS_MINIMIZE )
1078             WINPOS_RedrawIconTitle( hwnd );
1079         else
1080             NC_DoNCPaint( hwnd, clip, FALSE );
1081     }
1082     return 0;
1083 }
1084
1085
1086 /***********************************************************************
1087  *           NC_HandleNCActivate
1088  *
1089  * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1090  */
1091 LONG NC_HandleNCActivate( HWND hwnd, WPARAM wParam )
1092 {
1093     WND* wndPtr = WIN_FindWndPtr( hwnd );
1094
1095     /* Lotus Notes draws menu descriptions in the caption of its main
1096      * window. When it wants to restore original "system" view, it just
1097      * sends WM_NCACTIVATE message to itself. Any optimizations here in
1098      * attempt to minimize redrawings lead to a not restored caption.
1099      */
1100     if (wndPtr)
1101     {
1102         if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1103         else wndPtr->flags &= ~WIN_NCACTIVATED;
1104         WIN_ReleaseWndPtr(wndPtr);
1105
1106         if (IsIconic(hwnd)) 
1107             WINPOS_RedrawIconTitle( hwnd );
1108         else
1109             NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1110     }
1111     return TRUE;
1112 }
1113
1114
1115 /***********************************************************************
1116  *           NC_HandleSetCursor
1117  *
1118  * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1119  */
1120 LONG NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1121 {
1122     hwnd = WIN_GetFullHandle( (HWND)wParam );
1123
1124     switch((short)LOWORD(lParam))
1125     {
1126     case HTERROR:
1127         {
1128             WORD msg = HIWORD( lParam );
1129             if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1130                 (msg == WM_RBUTTONDOWN))
1131                 MessageBeep(0);
1132         }
1133         break;
1134
1135     case HTCLIENT:
1136         {
1137             HCURSOR hCursor = (HCURSOR)GetClassLongA(hwnd, GCL_HCURSOR);
1138             if(hCursor) {
1139                 SetCursor(hCursor);
1140                 return TRUE;
1141             }
1142             return FALSE;
1143         }
1144
1145     case HTLEFT:
1146     case HTRIGHT:
1147         return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1148
1149     case HTTOP:
1150     case HTBOTTOM:
1151         return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1152
1153     case HTTOPLEFT:
1154     case HTBOTTOMRIGHT:
1155         return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1156
1157     case HTTOPRIGHT:
1158     case HTBOTTOMLEFT:
1159         return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1160     }
1161
1162     /* Default cursor: arrow */
1163     return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1164 }
1165
1166 /***********************************************************************
1167  *           NC_GetSysPopupPos
1168  */
1169 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1170 {
1171     if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1172     else
1173     {
1174         WND *wndPtr = WIN_FindWndPtr( hwnd );
1175         if (!wndPtr) return;
1176
1177         NC_GetInsideRect( hwnd, rect );
1178         OffsetRect( rect, wndPtr->rectWindow.left, wndPtr->rectWindow.top);
1179         if (wndPtr->dwStyle & WS_CHILD)
1180             ClientToScreen( GetParent(hwnd), (POINT *)rect );
1181         rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1182         rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1183         WIN_ReleaseWndPtr( wndPtr );
1184     }
1185 }
1186
1187 /***********************************************************************
1188  *           NC_TrackMinMaxBox
1189  *
1190  * Track a mouse button press on the minimize or maximize box.
1191  *
1192  * The big difference between 3.1 and 95 is the disabled button state.
1193  * In win95 the system button can be disabled, so it can ignore the mouse
1194  * event.
1195  *
1196  */
1197 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1198 {
1199     MSG msg;
1200     HDC hdc = GetWindowDC( hwnd );
1201     BOOL pressed = TRUE;
1202     UINT state;
1203     DWORD wndStyle = GetWindowLongA( hwnd, GWL_STYLE);
1204     HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1205
1206     void  (*paintButton)(HWND, HDC, BOOL, BOOL);
1207
1208     if (wParam == HTMINBUTTON)
1209     {
1210         /* If the style is not present, do nothing */
1211         if (!(wndStyle & WS_MINIMIZEBOX))
1212             return;
1213
1214         /* Check if the sysmenu item for minimize is there  */
1215         state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1216
1217         paintButton = &NC_DrawMinButton;
1218     }
1219     else
1220     {
1221         /* If the style is not present, do nothing */
1222         if (!(wndStyle & WS_MAXIMIZEBOX))
1223             return;
1224
1225         /* Check if the sysmenu item for maximize is there  */
1226         state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1227
1228         paintButton = &NC_DrawMaxButton;
1229     }
1230
1231     SetCapture( hwnd );
1232
1233     (*paintButton)( hwnd, hdc, TRUE, FALSE);
1234
1235     while(1)
1236     {
1237         BOOL oldstate = pressed;
1238
1239         if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1240         if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1241
1242         if(msg.message == WM_LBUTTONUP)
1243             break;
1244
1245         if(msg.message != WM_MOUSEMOVE)
1246             continue;
1247
1248         pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1249         if (pressed != oldstate)
1250            (*paintButton)( hwnd, hdc, pressed, FALSE);
1251     }
1252
1253     if(pressed)
1254         (*paintButton)(hwnd, hdc, FALSE, FALSE);
1255
1256     ReleaseCapture();
1257     ReleaseDC( hwnd, hdc );
1258
1259     /* If the item minimize or maximize of the sysmenu are not there */
1260     /* or if the style is not present, do nothing */
1261     if ((!pressed) || (state == 0xFFFFFFFF))
1262         return;
1263
1264     if (wParam == HTMINBUTTON)
1265         SendMessageA( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1266     else
1267         SendMessageA( hwnd, WM_SYSCOMMAND,
1268                       IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1269 }
1270
1271 /***********************************************************************
1272  * NC_TrackCloseButton
1273  *
1274  * Track a mouse button press on the Win95 close button.
1275  */
1276 static void NC_TrackCloseButton (HWND hwnd, WORD wParam)
1277 {
1278     MSG msg;
1279     HDC hdc;
1280     BOOL pressed = TRUE;
1281     HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1282     UINT state;
1283
1284     if(hSysMenu == 0)
1285         return;
1286
1287     state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1288
1289     /* If the item close of the sysmenu is disabled or not there do nothing */
1290     if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1291         return;
1292
1293     hdc = GetWindowDC( hwnd );
1294
1295     SetCapture( hwnd );
1296
1297     NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1298
1299     while(1)
1300     {
1301         BOOL oldstate = pressed;
1302
1303         if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1304         if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1305
1306         if(msg.message == WM_LBUTTONUP)
1307             break;
1308
1309         if(msg.message != WM_MOUSEMOVE)
1310             continue;
1311
1312         pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1313         if (pressed != oldstate)
1314            NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1315     }
1316
1317     if(pressed)
1318         NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1319
1320     ReleaseCapture();
1321     ReleaseDC( hwnd, hdc );
1322     if (!pressed) return;
1323
1324     SendMessageA( hwnd, WM_SYSCOMMAND, SC_CLOSE, MAKELONG(msg.pt.x,msg.pt.y) );
1325 }
1326
1327
1328 /***********************************************************************
1329  *           NC_TrackScrollBar
1330  *
1331  * Track a mouse button press on the horizontal or vertical scroll-bar.
1332  */
1333 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1334 {
1335     INT scrollbar;
1336
1337     if ((wParam & 0xfff0) == SC_HSCROLL)
1338     {
1339         if ((wParam & 0x0f) != HTHSCROLL) return;
1340         scrollbar = SB_HORZ;
1341     }
1342     else  /* SC_VSCROLL */
1343     {
1344         if ((wParam & 0x0f) != HTVSCROLL) return;
1345         scrollbar = SB_VERT;
1346     }
1347     SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1348 }
1349
1350
1351 /***********************************************************************
1352  *           NC_HandleNCLButtonDown
1353  *
1354  * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1355  */
1356 LONG NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1357 {
1358     LONG style = GetWindowLongA( hwnd, GWL_STYLE );
1359
1360     switch(wParam)  /* Hit test */
1361     {
1362     case HTCAPTION:
1363         {
1364             HWND top = GetAncestor( hwnd, GA_ROOT );
1365
1366             if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1367                 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1368             break;
1369         }
1370
1371     case HTSYSMENU:
1372          if( style & WS_SYSMENU )
1373          {
1374              if( !(style & WS_MINIMIZE) )
1375              {
1376                 HDC hDC = GetWindowDC(hwnd);
1377                 NC_DrawSysButton( hwnd, hDC, TRUE );
1378                 ReleaseDC( hwnd, hDC );
1379              }
1380              SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1381          }
1382          break;
1383
1384     case HTMENU:
1385         SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1386         break;
1387
1388     case HTHSCROLL:
1389         SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1390         break;
1391
1392     case HTVSCROLL:
1393         SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1394         break;
1395
1396     case HTMINBUTTON:
1397     case HTMAXBUTTON:
1398         NC_TrackMinMaxBox( hwnd, wParam );
1399         break;
1400
1401     case HTCLOSE:
1402         NC_TrackCloseButton (hwnd, wParam);
1403         break;
1404
1405     case HTLEFT:
1406     case HTRIGHT:
1407     case HTTOP:
1408     case HTTOPLEFT:
1409     case HTTOPRIGHT:
1410     case HTBOTTOM:
1411     case HTBOTTOMLEFT:
1412     case HTBOTTOMRIGHT:
1413         /* Old comment:
1414          * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1415          * This was previously done by setting wParam=SC_SIZE + wParam - 2
1416          */
1417         /* But that is not what WinNT does. Instead it sends this. This
1418          * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1419          * SC_MOUSEMENU into wParam.
1420          */
1421         SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1422         break;
1423
1424     case HTBORDER:
1425         break;
1426     }
1427     return 0;
1428 }
1429
1430
1431 /***********************************************************************
1432  *           NC_HandleNCLButtonDblClk
1433  *
1434  * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1435  */
1436 LONG NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1437 {
1438     /*
1439      * if this is an icon, send a restore since we are handling
1440      * a double click
1441      */
1442     if (IsIconic(hwnd))
1443     {
1444         SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1445         return 0;
1446     }
1447
1448     switch(wParam)  /* Hit test */
1449     {
1450     case HTCAPTION:
1451         /* stop processing if WS_MAXIMIZEBOX is missing */
1452         if (GetWindowLongA( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1453             SendMessageW( hwnd, WM_SYSCOMMAND,
1454                           IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1455         break;
1456
1457     case HTSYSMENU:
1458         if (!(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE))
1459             SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1460         break;
1461
1462     case HTHSCROLL:
1463         SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1464         break;
1465
1466     case HTVSCROLL:
1467         SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1468         break;
1469     }
1470     return 0;
1471 }
1472
1473
1474 /***********************************************************************
1475  *           NC_HandleSysCommand
1476  *
1477  * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1478  */
1479 LONG NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1480 {
1481     TRACE("Handling WM_SYSCOMMAND %x %lx\n", wParam, lParam );
1482
1483     if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1484         return 0;
1485
1486     switch (wParam & 0xfff0)
1487     {
1488     case SC_SIZE:
1489     case SC_MOVE:
1490         if (USER_Driver.pSysCommandSizeMove)
1491             USER_Driver.pSysCommandSizeMove( hwnd, wParam );
1492         break;
1493
1494     case SC_MINIMIZE:
1495         if (hwnd == GetForegroundWindow())
1496             ShowOwnedPopups(hwnd,FALSE);
1497         ShowWindow( hwnd, SW_MINIMIZE );
1498         break;
1499
1500     case SC_MAXIMIZE:
1501         if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1502             ShowOwnedPopups(hwnd,TRUE);
1503         ShowWindow( hwnd, SW_MAXIMIZE );
1504         break;
1505
1506     case SC_RESTORE:
1507         if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1508             ShowOwnedPopups(hwnd,TRUE);
1509         ShowWindow( hwnd, SW_RESTORE );
1510         break;
1511
1512     case SC_CLOSE:
1513         return SendMessageA( hwnd, WM_CLOSE, 0, 0 );
1514
1515     case SC_VSCROLL:
1516     case SC_HSCROLL:
1517         {
1518             POINT pt;
1519             pt.x = (short)LOWORD(lParam);
1520             pt.y = (short)HIWORD(lParam);
1521             NC_TrackScrollBar( hwnd, wParam, pt );
1522         }
1523         break;
1524
1525     case SC_MOUSEMENU:
1526         {
1527             POINT pt;
1528             pt.x = (short)LOWORD(lParam);
1529             pt.y = (short)HIWORD(lParam);
1530             MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1531         }
1532         break;
1533
1534     case SC_KEYMENU:
1535         MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1536         break;
1537
1538     case SC_TASKLIST:
1539         WinExec( "taskman.exe", SW_SHOWNORMAL );
1540         break;
1541
1542     case SC_SCREENSAVE:
1543         if (wParam == SC_ABOUTWINE)
1544         {
1545             HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1546             if (hmodule)
1547             {
1548                 FARPROC aboutproc = GetProcAddress( hmodule, "ShellAboutA" );
1549                 if (aboutproc) aboutproc( hwnd, PACKAGE_NAME, PACKAGE_STRING, 0 );
1550                 FreeLibrary( hmodule );
1551             }
1552         }
1553         else
1554           if (wParam == SC_PUTMARK)
1555             DPRINTF("Debug mark requested by user\n");
1556         break;
1557
1558     case SC_HOTKEY:
1559     case SC_ARRANGE:
1560     case SC_NEXTWINDOW:
1561     case SC_PREVWINDOW:
1562         FIXME("unimplemented!\n");
1563         break;
1564     }
1565     return 0;
1566 }
1567
1568 /*************************************************************
1569 *  NC_DrawGrayButton
1570 *
1571 * Stub for the grayed button of the caption
1572 *
1573 *************************************************************/
1574
1575 BOOL NC_DrawGrayButton(HDC hdc, int x, int y)
1576 {
1577     HBITMAP hMaskBmp;
1578     HDC hdcMask;
1579     HBRUSH hOldBrush;
1580
1581     hMaskBmp = CreateBitmap (12, 10, 1, 1, lpGrayMask);
1582
1583     if(hMaskBmp == 0)
1584         return FALSE;
1585
1586     hdcMask = CreateCompatibleDC (0);
1587     SelectObject (hdcMask, hMaskBmp);
1588
1589     /* Draw the grayed bitmap using the mask */
1590     hOldBrush = SelectObject (hdc, (HGDIOBJ)RGB(128, 128, 128));
1591     BitBlt (hdc, x, y, 12, 10,
1592             hdcMask, 0, 0, 0xB8074A);
1593
1594     /* Clean up */
1595     SelectObject (hdc, hOldBrush);
1596     DeleteObject(hMaskBmp);
1597     DeleteDC (hdcMask);
1598
1599     return TRUE;
1600 }
1601
1602 /***********************************************************************
1603  *              GetTitleBarInfo (USER32.@)
1604  * TODO: Handle STATE_SYSTEM_PRESSED
1605  */
1606 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1607     DWORD dwStyle;
1608     DWORD dwExStyle;
1609     RECT wndRect;
1610
1611     TRACE("(%p %p)\n", hwnd, tbi);
1612
1613     if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1614         TRACE("Invalid TITLEBARINFO size: %ld\n", tbi->cbSize);
1615         SetLastError(ERROR_INVALID_PARAMETER);
1616         return FALSE;
1617     }
1618     dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1619     dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1620     NC_GetInsideRect(hwnd, &tbi->rcTitleBar);
1621
1622     GetWindowRect(hwnd, &wndRect);
1623
1624     tbi->rcTitleBar.top += wndRect.top;
1625     tbi->rcTitleBar.left += wndRect.left;
1626     tbi->rcTitleBar.right += wndRect.left;
1627
1628     tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1629     if(dwExStyle & WS_EX_TOOLWINDOW)
1630         tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1631     else {
1632         tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1633         tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1634     }
1635
1636     ZeroMemory(&tbi->rgstate, sizeof(tbi->rgstate));
1637     /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1638      * Under XP it seems to
1639      */
1640     tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1641     if(dwStyle & WS_CAPTION) {
1642         tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1643         if(dwStyle & WS_SYSMENU) {
1644             if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1645                 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1646                 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1647             }
1648             else {
1649                 if(!(dwStyle & WS_MINIMIZEBOX))
1650                     tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1651                 if(!(dwStyle & WS_MAXIMIZEBOX))
1652                     tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1653             }
1654             if(!(dwExStyle & WS_EX_CONTEXTHELP))
1655                 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1656             if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1657                 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1658         }
1659         else {
1660             tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1661             tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1662             tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1663             tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1664         }
1665     }
1666     else
1667         tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1668     return TRUE;
1669 }