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