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