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