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