2 * Non-client area window functions
4 * Copyright 1994 Alexandre Julliard
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.
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.
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
28 #include "user_private.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(nonclient
);
34 #define SC_ABOUTWINE (SC_SCREENSAVE+1)
36 /* Some useful macros */
37 #define HAS_DLGFRAME(style,exStyle) \
38 (((exStyle) & WS_EX_DLGMODALFRAME) || \
39 (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
41 #define HAS_THICKFRAME(style,exStyle) \
42 (((style) & WS_THICKFRAME) && \
43 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
45 #define HAS_THINFRAME(style) \
46 (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
48 #define HAS_BIGFRAME(style,exStyle) \
49 (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
50 ((exStyle) & WS_EX_DLGMODALFRAME))
52 #define HAS_STATICOUTERFRAME(style,exStyle) \
53 (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
56 #define HAS_MENU(hwnd,style) ((((style) & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
59 static void adjust_window_rect( RECT
*rect
, DWORD style
, BOOL menu
, DWORD exStyle
, NONCLIENTMETRICSW
*ncm
)
63 if ((exStyle
& (WS_EX_STATICEDGE
|WS_EX_DLGMODALFRAME
)) == WS_EX_STATICEDGE
)
64 adjust
= 1; /* for the outer frame always present */
65 else if ((exStyle
& WS_EX_DLGMODALFRAME
) || (style
& (WS_THICKFRAME
|WS_DLGFRAME
)))
66 adjust
= 2; /* outer */
68 if (style
& WS_THICKFRAME
)
69 adjust
+= ncm
->iBorderWidth
+ ncm
->iPaddedBorderWidth
; /* The resize border */
71 if ((style
& (WS_BORDER
|WS_DLGFRAME
)) || (exStyle
& WS_EX_DLGMODALFRAME
))
72 adjust
++; /* The other border */
74 InflateRect (rect
, adjust
, adjust
);
76 if ((style
& WS_CAPTION
) == WS_CAPTION
)
78 if (exStyle
& WS_EX_TOOLWINDOW
)
79 rect
->top
-= ncm
->iSmCaptionHeight
+ 1;
81 rect
->top
-= ncm
->iCaptionHeight
+ 1;
83 if (menu
) rect
->top
-= ncm
->iMenuHeight
+ 1;
85 if (exStyle
& WS_EX_CLIENTEDGE
)
86 InflateRect(rect
, GetSystemMetrics(SM_CXEDGE
), GetSystemMetrics(SM_CYEDGE
));
90 static HICON
NC_IconForWindow( HWND hwnd
)
93 WND
*wndPtr
= WIN_GetPtr( hwnd
);
95 if (wndPtr
&& wndPtr
!= WND_OTHER_PROCESS
&& wndPtr
!= WND_DESKTOP
)
97 hIcon
= wndPtr
->hIconSmall
;
98 if (!hIcon
) hIcon
= wndPtr
->hIcon
;
99 WIN_ReleasePtr( wndPtr
);
101 if (!hIcon
) hIcon
= (HICON
) GetClassLongPtrW( hwnd
, GCLP_HICONSM
);
102 if (!hIcon
) hIcon
= (HICON
) GetClassLongPtrW( hwnd
, GCLP_HICON
);
104 /* If there is no icon specified and this is not a modal dialog,
105 * get the default one.
107 if (!hIcon
&& !(GetWindowLongW( hwnd
, GWL_EXSTYLE
) & WS_EX_DLGMODALFRAME
))
108 hIcon
= LoadImageW(0, (LPCWSTR
)IDI_WINLOGO
, IMAGE_ICON
, GetSystemMetrics(SM_CXSMICON
),
109 GetSystemMetrics(SM_CYSMICON
), LR_DEFAULTCOLOR
| LR_SHARED
);
113 /* Draws the bar part(ie the big rectangle) of the caption */
114 static void NC_DrawCaptionBar (HDC hdc
, const RECT
*rect
, DWORD dwStyle
,
115 BOOL active
, BOOL gradient
)
119 TRIVERTEX vertices
[4];
121 GetSysColor (active
? COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
);
123 GetSysColor (active
? COLOR_GRADIENTACTIVECAPTION
124 : COLOR_GRADIENTINACTIVECAPTION
);
125 int buttonsAreaSize
= GetSystemMetrics(SM_CYCAPTION
) - 1;
126 static GRADIENT_RECT mesh
[] = {{0, 1}, {1, 2}, {2, 3}};
128 vertices
[0].Red
= vertices
[1].Red
= GetRValue (colLeft
) << 8;
129 vertices
[0].Green
= vertices
[1].Green
= GetGValue (colLeft
) << 8;
130 vertices
[0].Blue
= vertices
[1].Blue
= GetBValue (colLeft
) << 8;
131 vertices
[0].Alpha
= vertices
[1].Alpha
= 0xff00;
132 vertices
[2].Red
= vertices
[3].Red
= GetRValue (colRight
) << 8;
133 vertices
[2].Green
= vertices
[3].Green
= GetGValue (colRight
) << 8;
134 vertices
[2].Blue
= vertices
[3].Blue
= GetBValue (colRight
) << 8;
135 vertices
[2].Alpha
= vertices
[3].Alpha
= 0xff00;
137 if ((dwStyle
& WS_SYSMENU
)
138 && ((dwStyle
& WS_MAXIMIZEBOX
) || (dwStyle
& WS_MINIMIZEBOX
)))
139 buttonsAreaSize
+= 2 * (GetSystemMetrics(SM_CXSIZE
) + 1);
141 /* area behind icon; solid filled with left color */
142 vertices
[0].x
= rect
->left
;
143 vertices
[0].y
= rect
->top
;
144 if (dwStyle
& WS_SYSMENU
)
145 vertices
[1].x
= min (rect
->left
+ GetSystemMetrics(SM_CXSMICON
), rect
->right
);
147 vertices
[1].x
= vertices
[0].x
;
148 vertices
[1].y
= rect
->bottom
;
150 /* area behind text; gradient */
151 vertices
[2].x
= max (vertices
[1].x
, rect
->right
- buttonsAreaSize
);
152 vertices
[2].y
= rect
->top
;
154 /* area behind buttons; solid filled with right color */
155 vertices
[3].x
= rect
->right
;
156 vertices
[3].y
= rect
->bottom
;
158 GdiGradientFill (hdc
, vertices
, 4, mesh
, 3, GRADIENT_FILL_RECT_H
);
161 FillRect (hdc
, rect
, GetSysColorBrush (active
?
162 COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
));
165 /***********************************************************************
166 * DrawCaption (USER32.@) Draws a caption bar
180 DrawCaption (HWND hwnd
, HDC hdc
, const RECT
*lpRect
, UINT uFlags
)
182 return DrawCaptionTempW (hwnd
, hdc
, lpRect
, 0, 0, NULL
, uFlags
& 0x103F);
186 /***********************************************************************
187 * DrawCaptionTempA (USER32.@)
189 BOOL WINAPI
DrawCaptionTempA (HWND hwnd
, HDC hdc
, const RECT
*rect
, HFONT hFont
,
190 HICON hIcon
, LPCSTR str
, UINT uFlags
)
196 if (!(uFlags
& DC_TEXT
) || !str
)
197 return DrawCaptionTempW( hwnd
, hdc
, rect
, hFont
, hIcon
, NULL
, uFlags
);
199 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
200 if ((strW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
202 MultiByteToWideChar( CP_ACP
, 0, str
, -1, strW
, len
);
203 ret
= DrawCaptionTempW (hwnd
, hdc
, rect
, hFont
, hIcon
, strW
, uFlags
);
204 HeapFree( GetProcessHeap (), 0, strW
);
210 /***********************************************************************
211 * DrawCaptionTempW (USER32.@)
213 BOOL WINAPI
DrawCaptionTempW (HWND hwnd
, HDC hdc
, const RECT
*rect
, HFONT hFont
,
214 HICON hIcon
, LPCWSTR str
, UINT uFlags
)
218 TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
219 hwnd
, hdc
, rect
, hFont
, hIcon
, debugstr_w(str
), uFlags
);
221 /* drawing background */
222 if (uFlags
& DC_INBUTTON
) {
223 FillRect (hdc
, &rc
, GetSysColorBrush (COLOR_3DFACE
));
225 if (uFlags
& DC_ACTIVE
) {
226 HBRUSH hbr
= SelectObject (hdc
, SYSCOLOR_Get55AABrush());
227 PatBlt (hdc
, rc
.left
, rc
.top
,
228 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
, 0xFA0089);
229 SelectObject (hdc
, hbr
);
233 DWORD style
= GetWindowLongW (hwnd
, GWL_STYLE
);
234 NC_DrawCaptionBar (hdc
, &rc
, style
, uFlags
& DC_ACTIVE
, uFlags
& DC_GRADIENT
);
239 if ((uFlags
& DC_ICON
) && !(uFlags
& DC_SMALLCAP
)) {
243 pt
.y
= (rc
.bottom
+ rc
.top
- GetSystemMetrics(SM_CYSMICON
)) / 2;
245 if (!hIcon
) hIcon
= NC_IconForWindow(hwnd
);
246 NtUserDrawIconEx( hdc
, pt
.x
, pt
.y
, hIcon
, GetSystemMetrics(SM_CXSMICON
),
247 GetSystemMetrics(SM_CYSMICON
), 0, 0, DI_NORMAL
);
248 rc
.left
= pt
.x
+ GetSystemMetrics( SM_CXSMICON
);
252 if (uFlags
& DC_TEXT
) {
256 if (uFlags
& DC_INBUTTON
)
257 SetTextColor (hdc
, GetSysColor (COLOR_BTNTEXT
));
258 else if (uFlags
& DC_ACTIVE
)
259 SetTextColor (hdc
, GetSysColor (COLOR_CAPTIONTEXT
));
261 SetTextColor (hdc
, GetSysColor (COLOR_INACTIVECAPTIONTEXT
));
263 SetBkMode (hdc
, TRANSPARENT
);
266 hOldFont
= SelectObject (hdc
, hFont
);
268 NONCLIENTMETRICSW nclm
;
270 nclm
.cbSize
= sizeof(NONCLIENTMETRICSW
);
271 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS
, 0, &nclm
, 0);
272 hNewFont
= CreateFontIndirectW ((uFlags
& DC_SMALLCAP
) ?
273 &nclm
.lfSmCaptionFont
: &nclm
.lfCaptionFont
);
274 hOldFont
= SelectObject (hdc
, hNewFont
);
279 if (!GetWindowTextW( hwnd
, text
, ARRAY_SIZE( text
))) text
[0] = 0;
283 DrawTextW( hdc
, str
, -1, &rc
, ((uFlags
& 0x4000) ? DT_CENTER
: DT_LEFT
) |
284 DT_SINGLELINE
| DT_VCENTER
| DT_NOPREFIX
| DT_END_ELLIPSIS
);
287 SelectObject (hdc
, hOldFont
);
289 DeleteObject (SelectObject (hdc
, hOldFont
));
292 /* drawing focus ??? */
294 FIXME("undocumented flag (0x2000)!\n");
300 /***********************************************************************
301 * AdjustWindowRect (USER32.@)
303 BOOL WINAPI DECLSPEC_HOTPATCH
AdjustWindowRect( LPRECT rect
, DWORD style
, BOOL menu
)
305 return AdjustWindowRectEx( rect
, style
, menu
, 0 );
309 /***********************************************************************
310 * AdjustWindowRectEx (USER32.@)
312 BOOL WINAPI DECLSPEC_HOTPATCH
AdjustWindowRectEx( LPRECT rect
, DWORD style
, BOOL menu
, DWORD exStyle
)
314 NONCLIENTMETRICSW ncm
;
316 TRACE("(%s) %08x %d %08x\n", wine_dbgstr_rect(rect
), style
, menu
, exStyle
);
318 ncm
.cbSize
= sizeof(ncm
);
319 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
321 adjust_window_rect( rect
, style
, menu
, exStyle
, &ncm
);
326 /***********************************************************************
327 * AdjustWindowRectExForDpi (USER32.@)
329 BOOL WINAPI DECLSPEC_HOTPATCH
AdjustWindowRectExForDpi( LPRECT rect
, DWORD style
, BOOL menu
,
330 DWORD exStyle
, UINT dpi
)
332 NONCLIENTMETRICSW ncm
;
334 TRACE("(%s) %08x %d %08x %u\n", wine_dbgstr_rect(rect
), style
, menu
, exStyle
, dpi
);
336 ncm
.cbSize
= sizeof(ncm
);
337 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
339 adjust_window_rect( rect
, style
, menu
, exStyle
, &ncm
);
344 /***********************************************************************
345 * NC_HandleNCCalcSize
347 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
349 void NC_HandleNCCalcSize( HWND hwnd
, WPARAM wparam
, RECT
*winRect
)
351 RECT tmpRect
= { 0, 0, 0, 0 };
352 LONG style
= GetWindowLongW( hwnd
, GWL_STYLE
);
353 LONG exStyle
= GetWindowLongW( hwnd
, GWL_EXSTYLE
);
358 if (!(style
& WS_MINIMIZE
))
360 AdjustWindowRectEx( &tmpRect
, style
, FALSE
, exStyle
& ~WS_EX_CLIENTEDGE
);
362 winRect
->left
-= tmpRect
.left
;
363 winRect
->top
-= tmpRect
.top
;
364 winRect
->right
-= tmpRect
.right
;
365 winRect
->bottom
-= tmpRect
.bottom
;
367 if (((style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) && GetMenu(hwnd
))
369 TRACE("Calling GetMenuBarHeight with hwnd %p, width %d, at (%d, %d).\n",
370 hwnd
, winRect
->right
- winRect
->left
, -tmpRect
.left
, -tmpRect
.top
);
373 MENU_GetMenuBarHeight( hwnd
,
374 winRect
->right
- winRect
->left
,
375 -tmpRect
.left
, -tmpRect
.top
);
378 if( exStyle
& WS_EX_CLIENTEDGE
)
379 if( winRect
->right
- winRect
->left
> 2 * GetSystemMetrics(SM_CXEDGE
) &&
380 winRect
->bottom
- winRect
->top
> 2 * GetSystemMetrics(SM_CYEDGE
))
381 InflateRect( winRect
, - GetSystemMetrics(SM_CXEDGE
),
382 - GetSystemMetrics(SM_CYEDGE
));
384 if (style
& WS_VSCROLL
)
385 if (winRect
->right
- winRect
->left
>= GetSystemMetrics(SM_CXVSCROLL
))
387 /* rectangle is in screen coords when wparam is false */
388 if (!wparam
&& (exStyle
& WS_EX_LAYOUTRTL
)) exStyle
^= WS_EX_LEFTSCROLLBAR
;
390 if((exStyle
& WS_EX_LEFTSCROLLBAR
) != 0)
391 winRect
->left
+= GetSystemMetrics(SM_CXVSCROLL
);
393 winRect
->right
-= GetSystemMetrics(SM_CXVSCROLL
);
396 if (style
& WS_HSCROLL
)
397 if( winRect
->bottom
- winRect
->top
> GetSystemMetrics(SM_CYHSCROLL
))
398 winRect
->bottom
-= GetSystemMetrics(SM_CYHSCROLL
);
400 if (winRect
->top
> winRect
->bottom
)
401 winRect
->bottom
= winRect
->top
;
403 if (winRect
->left
> winRect
->right
)
404 winRect
->right
= winRect
->left
;
408 winRect
->right
= winRect
->left
;
409 winRect
->bottom
= winRect
->top
;
414 /***********************************************************************
417 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
418 * but without the borders (if any).
420 static void NC_GetInsideRect( HWND hwnd
, enum coords_relative relative
, RECT
*rect
,
421 DWORD style
, DWORD ex_style
)
423 WIN_GetRectangles( hwnd
, relative
, rect
, NULL
);
425 /* Remove frame from rectangle */
426 if (HAS_THICKFRAME( style
, ex_style
))
428 InflateRect( rect
, -GetSystemMetrics(SM_CXFRAME
), -GetSystemMetrics(SM_CYFRAME
) );
430 else if (HAS_DLGFRAME( style
, ex_style
))
432 InflateRect( rect
, -GetSystemMetrics(SM_CXDLGFRAME
), -GetSystemMetrics(SM_CYDLGFRAME
));
434 else if (HAS_THINFRAME( style
))
436 InflateRect( rect
, -GetSystemMetrics(SM_CXBORDER
), -GetSystemMetrics(SM_CYBORDER
) );
439 /* We have additional border information if the window
440 * is a child (but not an MDI child) */
441 if ((style
& WS_CHILD
) && !(ex_style
& WS_EX_MDICHILD
))
443 if (ex_style
& WS_EX_CLIENTEDGE
)
444 InflateRect (rect
, -GetSystemMetrics(SM_CXEDGE
), -GetSystemMetrics(SM_CYEDGE
));
445 if (ex_style
& WS_EX_STATICEDGE
)
446 InflateRect (rect
, -GetSystemMetrics(SM_CXBORDER
), -GetSystemMetrics(SM_CYBORDER
));
451 /***********************************************************************
454 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
456 LRESULT
NC_HandleNCHitTest( HWND hwnd
, POINT pt
)
459 DWORD style
, ex_style
;
461 TRACE("hwnd=%p pt=%d,%d\n", hwnd
, pt
.x
, pt
.y
);
463 WIN_GetRectangles( hwnd
, COORDS_SCREEN
, &rect
, &rcClient
);
464 if (!PtInRect( &rect
, pt
)) return HTNOWHERE
;
466 style
= GetWindowLongW( hwnd
, GWL_STYLE
);
467 ex_style
= GetWindowLongW( hwnd
, GWL_EXSTYLE
);
469 if (PtInRect( &rcClient
, pt
)) return HTCLIENT
;
472 if (HAS_THICKFRAME( style
, ex_style
))
474 InflateRect( &rect
, -GetSystemMetrics(SM_CXFRAME
), -GetSystemMetrics(SM_CYFRAME
) );
475 if (!PtInRect( &rect
, pt
))
477 /* Check top sizing border */
480 if (pt
.x
< rect
.left
+GetSystemMetrics(SM_CXSIZE
)) return HTTOPLEFT
;
481 if (pt
.x
>= rect
.right
-GetSystemMetrics(SM_CXSIZE
)) return HTTOPRIGHT
;
484 /* Check bottom sizing border */
485 if (pt
.y
>= rect
.bottom
)
487 if (pt
.x
< rect
.left
+GetSystemMetrics(SM_CXSIZE
)) return HTBOTTOMLEFT
;
488 if (pt
.x
>= rect
.right
-GetSystemMetrics(SM_CXSIZE
)) return HTBOTTOMRIGHT
;
491 /* Check left sizing border */
492 if (pt
.x
< rect
.left
)
494 if (pt
.y
< rect
.top
+GetSystemMetrics(SM_CYSIZE
)) return HTTOPLEFT
;
495 if (pt
.y
>= rect
.bottom
-GetSystemMetrics(SM_CYSIZE
)) return HTBOTTOMLEFT
;
498 /* Check right sizing border */
499 if (pt
.x
>= rect
.right
)
501 if (pt
.y
< rect
.top
+GetSystemMetrics(SM_CYSIZE
)) return HTTOPRIGHT
;
502 if (pt
.y
>= rect
.bottom
-GetSystemMetrics(SM_CYSIZE
)) return HTBOTTOMRIGHT
;
507 else /* No thick frame */
509 if (HAS_DLGFRAME( style
, ex_style
))
510 InflateRect(&rect
, -GetSystemMetrics(SM_CXDLGFRAME
), -GetSystemMetrics(SM_CYDLGFRAME
));
511 else if (HAS_THINFRAME( style
))
512 InflateRect(&rect
, -GetSystemMetrics(SM_CXBORDER
), -GetSystemMetrics(SM_CYBORDER
));
513 if (!PtInRect( &rect
, pt
)) return HTBORDER
;
518 if ((style
& WS_CAPTION
) == WS_CAPTION
)
520 if (ex_style
& WS_EX_TOOLWINDOW
)
521 rect
.top
+= GetSystemMetrics(SM_CYSMCAPTION
) - 1;
523 rect
.top
+= GetSystemMetrics(SM_CYCAPTION
) - 1;
524 if (!PtInRect( &rect
, pt
))
526 BOOL min_or_max_box
= (style
& WS_SYSMENU
) && (style
& (WS_MINIMIZEBOX
|WS_MAXIMIZEBOX
));
527 if (ex_style
& WS_EX_LAYOUTRTL
)
529 /* Check system menu */
530 if ((style
& WS_SYSMENU
) && !(ex_style
& WS_EX_TOOLWINDOW
) && NC_IconForWindow(hwnd
))
532 rect
.right
-= GetSystemMetrics(SM_CYCAPTION
) - 1;
533 if (pt
.x
> rect
.right
) return HTSYSMENU
;
536 /* Check close button */
537 if (style
& WS_SYSMENU
)
539 rect
.left
+= GetSystemMetrics(SM_CYCAPTION
);
540 if (pt
.x
< rect
.left
) return HTCLOSE
;
543 /* Check maximize box */
544 /* In win95 there is automatically a Maximize button when there is a minimize one*/
545 if (min_or_max_box
&& !(ex_style
& WS_EX_TOOLWINDOW
))
547 rect
.left
+= GetSystemMetrics(SM_CXSIZE
);
548 if (pt
.x
< rect
.left
) return HTMAXBUTTON
;
551 /* Check minimize box */
552 if (min_or_max_box
&& !(ex_style
& WS_EX_TOOLWINDOW
))
554 rect
.left
+= GetSystemMetrics(SM_CXSIZE
);
555 if (pt
.x
< rect
.left
) return HTMINBUTTON
;
560 /* Check system menu */
561 if ((style
& WS_SYSMENU
) && !(ex_style
& WS_EX_TOOLWINDOW
) && NC_IconForWindow(hwnd
))
563 rect
.left
+= GetSystemMetrics(SM_CYCAPTION
) - 1;
564 if (pt
.x
< rect
.left
) return HTSYSMENU
;
567 /* Check close button */
568 if (style
& WS_SYSMENU
)
570 rect
.right
-= GetSystemMetrics(SM_CYCAPTION
);
571 if (pt
.x
> rect
.right
) return HTCLOSE
;
574 /* Check maximize box */
575 /* In win95 there is automatically a Maximize button when there is a minimize one*/
576 if (min_or_max_box
&& !(ex_style
& WS_EX_TOOLWINDOW
))
578 rect
.right
-= GetSystemMetrics(SM_CXSIZE
);
579 if (pt
.x
> rect
.right
) return HTMAXBUTTON
;
582 /* Check minimize box */
583 if (min_or_max_box
&& !(ex_style
& WS_EX_TOOLWINDOW
))
585 rect
.right
-= GetSystemMetrics(SM_CXSIZE
);
586 if (pt
.x
> rect
.right
) return HTMINBUTTON
;
595 if (HAS_MENU( hwnd
, style
) && (pt
.y
< rcClient
.top
) &&
596 (pt
.x
>= rcClient
.left
) && (pt
.x
< rcClient
.right
))
599 /* Check vertical scroll bar */
601 if (ex_style
& WS_EX_LAYOUTRTL
) ex_style
^= WS_EX_LEFTSCROLLBAR
;
602 if (style
& WS_VSCROLL
)
604 if((ex_style
& WS_EX_LEFTSCROLLBAR
) != 0)
605 rcClient
.left
-= GetSystemMetrics(SM_CXVSCROLL
);
607 rcClient
.right
+= GetSystemMetrics(SM_CXVSCROLL
);
608 if (PtInRect( &rcClient
, pt
)) return HTVSCROLL
;
611 /* Check horizontal scroll bar */
613 if (style
& WS_HSCROLL
)
615 rcClient
.bottom
+= GetSystemMetrics(SM_CYHSCROLL
);
616 if (PtInRect( &rcClient
, pt
))
619 if ((style
& WS_VSCROLL
) &&
620 ((((ex_style
& WS_EX_LEFTSCROLLBAR
) != 0) && (pt
.x
<= rcClient
.left
+ GetSystemMetrics(SM_CXVSCROLL
))) ||
621 (((ex_style
& WS_EX_LEFTSCROLLBAR
) == 0) && (pt
.x
>= rcClient
.right
- GetSystemMetrics(SM_CXVSCROLL
)))))
627 /* Has to return HTNOWHERE if nothing was found
628 Could happen when a window has a customized non client area */
632 LRESULT
NC_HandleNCMouseMove(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
637 TRACE("hwnd=%p wparam=%#lx lparam=%#lx\n", hwnd
, wParam
, lParam
);
639 if (wParam
!= HTHSCROLL
&& wParam
!= HTVSCROLL
)
642 WIN_GetRectangles(hwnd
, COORDS_CLIENT
, &rect
, NULL
);
644 pt
.x
= (short)LOWORD(lParam
);
645 pt
.y
= (short)HIWORD(lParam
);
646 ScreenToClient(hwnd
, &pt
);
649 SCROLL_HandleScrollEvent(hwnd
, wParam
== HTHSCROLL
? SB_HORZ
: SB_VERT
, WM_NCMOUSEMOVE
, pt
);
653 LRESULT
NC_HandleNCMouseLeave(HWND hwnd
)
655 LONG style
= GetWindowLongW(hwnd
, GWL_STYLE
);
658 TRACE("hwnd=%p\n", hwnd
);
660 if (style
& WS_HSCROLL
)
661 SCROLL_HandleScrollEvent(hwnd
, SB_HORZ
, WM_NCMOUSELEAVE
, pt
);
662 if (style
& WS_VSCROLL
)
663 SCROLL_HandleScrollEvent(hwnd
, SB_VERT
, WM_NCMOUSELEAVE
, pt
);
668 /******************************************************************************
672 * Draws the system icon.
674 *****************************************************************************/
675 BOOL
NC_DrawSysButton (HWND hwnd
, HDC hdc
, BOOL down
)
677 HICON hIcon
= NC_IconForWindow( hwnd
);
683 DWORD style
= GetWindowLongW( hwnd
, GWL_STYLE
);
684 DWORD ex_style
= GetWindowLongW( hwnd
, GWL_EXSTYLE
);
686 NC_GetInsideRect( hwnd
, COORDS_WINDOW
, &rect
, style
, ex_style
);
687 pt
.x
= rect
.left
+ 2;
688 pt
.y
= rect
.top
+ (GetSystemMetrics(SM_CYCAPTION
) - GetSystemMetrics(SM_CYSMICON
)) / 2;
689 NtUserDrawIconEx( hdc
, pt
.x
, pt
.y
, hIcon
,
690 GetSystemMetrics(SM_CXSMICON
),
691 GetSystemMetrics(SM_CYSMICON
), 0, 0, DI_NORMAL
);
697 /******************************************************************************
701 * Draws the close button.
703 * If bGrayed is true, then draw a disabled Close button
705 *****************************************************************************/
707 static void NC_DrawCloseButton (HWND hwnd
, HDC hdc
, BOOL down
, BOOL bGrayed
)
710 DWORD style
= GetWindowLongW( hwnd
, GWL_STYLE
);
711 DWORD ex_style
= GetWindowLongW( hwnd
, GWL_EXSTYLE
);
713 NC_GetInsideRect( hwnd
, COORDS_WINDOW
, &rect
, style
, ex_style
);
715 /* A tool window has a smaller Close button */
716 if (ex_style
& WS_EX_TOOLWINDOW
)
718 INT iBmpHeight
= 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
719 INT iBmpWidth
= 11; /* it uses 11x11 for the close button in tool window */
720 INT iCaptionHeight
= GetSystemMetrics(SM_CYSMCAPTION
);
722 rect
.top
= rect
.top
+ (iCaptionHeight
- 1 - iBmpHeight
) / 2;
723 rect
.left
= rect
.right
- (iCaptionHeight
+ 1 + iBmpWidth
) / 2;
724 rect
.bottom
= rect
.top
+ iBmpHeight
;
725 rect
.right
= rect
.left
+ iBmpWidth
;
729 rect
.left
= rect
.right
- GetSystemMetrics(SM_CXSIZE
);
730 rect
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYSIZE
) - 2;
734 DrawFrameControl( hdc
, &rect
, DFC_CAPTION
,
736 (down
? DFCS_PUSHED
: 0) |
737 (bGrayed
? DFCS_INACTIVE
: 0)) );
740 /******************************************************************************
743 * Draws the maximize button for windows.
744 * If bGrayed is true, then draw a disabled Maximize button
746 static void NC_DrawMaxButton(HWND hwnd
,HDC hdc
,BOOL down
, BOOL bGrayed
)
750 DWORD style
= GetWindowLongW( hwnd
, GWL_STYLE
);
751 DWORD ex_style
= GetWindowLongW( hwnd
, GWL_EXSTYLE
);
753 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
754 if (ex_style
& WS_EX_TOOLWINDOW
) return;
756 flags
= (style
& WS_MAXIMIZE
) ? DFCS_CAPTIONRESTORE
: DFCS_CAPTIONMAX
;
758 NC_GetInsideRect( hwnd
, COORDS_WINDOW
, &rect
, style
, ex_style
);
759 if (style
& WS_SYSMENU
)
760 rect
.right
-= GetSystemMetrics(SM_CXSIZE
);
761 rect
.left
= rect
.right
- GetSystemMetrics(SM_CXSIZE
);
762 rect
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYSIZE
) - 2;
765 if (down
) flags
|= DFCS_PUSHED
;
766 if (bGrayed
) flags
|= DFCS_INACTIVE
;
767 DrawFrameControl( hdc
, &rect
, DFC_CAPTION
, flags
);
770 /******************************************************************************
773 * Draws the minimize button for windows.
774 * If bGrayed is true, then draw a disabled Minimize button
776 static void NC_DrawMinButton(HWND hwnd
,HDC hdc
,BOOL down
, BOOL bGrayed
)
780 DWORD style
= GetWindowLongW( hwnd
, GWL_STYLE
);
781 DWORD ex_style
= GetWindowLongW( hwnd
, GWL_EXSTYLE
);
783 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
784 if (ex_style
& WS_EX_TOOLWINDOW
) return;
786 flags
= (style
& WS_MINIMIZE
) ? DFCS_CAPTIONRESTORE
: DFCS_CAPTIONMIN
;
788 NC_GetInsideRect( hwnd
, COORDS_WINDOW
, &rect
, style
, ex_style
);
789 if (style
& WS_SYSMENU
)
790 rect
.right
-= GetSystemMetrics(SM_CXSIZE
);
791 if (style
& (WS_MAXIMIZEBOX
|WS_MINIMIZEBOX
))
792 rect
.right
-= GetSystemMetrics(SM_CXSIZE
) - 2;
793 rect
.left
= rect
.right
- GetSystemMetrics(SM_CXSIZE
);
794 rect
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYSIZE
) - 2;
797 if (down
) flags
|= DFCS_PUSHED
;
798 if (bGrayed
) flags
|= DFCS_INACTIVE
;
799 DrawFrameControl( hdc
, &rect
, DFC_CAPTION
, flags
);
802 /******************************************************************************
806 * Draw a window frame inside the given rectangle, and update the rectangle.
809 * Many. First, just what IS a frame in Win95? Note that the 3D look
810 * on the outer edge is handled by NC_DoNCPaint. As is the inner
811 * edge. The inner rectangle just inside the frame is handled by the
814 * In short, for most people, this function should be a nop (unless
815 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
816 * them lately, but just to get this code right). Even so, it doesn't
817 * appear to be so. It's being worked on...
819 *****************************************************************************/
821 static void NC_DrawFrame( HDC hdc
, RECT
*rect
, BOOL active
, DWORD style
, DWORD exStyle
)
825 /* Firstly the "thick" frame */
826 if (style
& WS_THICKFRAME
)
828 width
= GetSystemMetrics(SM_CXFRAME
) - GetSystemMetrics(SM_CXDLGFRAME
);
829 height
= GetSystemMetrics(SM_CYFRAME
) - GetSystemMetrics(SM_CYDLGFRAME
);
831 SelectObject( hdc
, GetSysColorBrush(active
? COLOR_ACTIVEBORDER
:
832 COLOR_INACTIVEBORDER
) );
834 PatBlt( hdc
, rect
->left
, rect
->top
,
835 rect
->right
- rect
->left
, height
, PATCOPY
);
836 PatBlt( hdc
, rect
->left
, rect
->top
,
837 width
, rect
->bottom
- rect
->top
, PATCOPY
);
838 PatBlt( hdc
, rect
->left
, rect
->bottom
- 1,
839 rect
->right
- rect
->left
, -height
, PATCOPY
);
840 PatBlt( hdc
, rect
->right
- 1, rect
->top
,
841 -width
, rect
->bottom
- rect
->top
, PATCOPY
);
843 InflateRect( rect
, -width
, -height
);
846 /* Now the other bit of the frame */
847 if ((style
& (WS_BORDER
|WS_DLGFRAME
)) ||
848 (exStyle
& WS_EX_DLGMODALFRAME
))
850 width
= GetSystemMetrics(SM_CXDLGFRAME
) - GetSystemMetrics(SM_CXEDGE
);
851 height
= GetSystemMetrics(SM_CYDLGFRAME
) - GetSystemMetrics(SM_CYEDGE
);
852 /* This should give a value of 1 that should also work for a border */
854 SelectObject( hdc
, GetSysColorBrush(
855 (exStyle
& (WS_EX_DLGMODALFRAME
|WS_EX_CLIENTEDGE
)) ?
857 (exStyle
& WS_EX_STATICEDGE
) ?
859 (style
& (WS_DLGFRAME
|WS_THICKFRAME
)) ?
865 PatBlt( hdc
, rect
->left
, rect
->top
,
866 rect
->right
- rect
->left
, height
, PATCOPY
);
867 PatBlt( hdc
, rect
->left
, rect
->top
,
868 width
, rect
->bottom
- rect
->top
, PATCOPY
);
869 PatBlt( hdc
, rect
->left
, rect
->bottom
- 1,
870 rect
->right
- rect
->left
, -height
, PATCOPY
);
871 PatBlt( hdc
, rect
->right
- 1, rect
->top
,
872 -width
, rect
->bottom
- rect
->top
, PATCOPY
);
874 InflateRect( rect
, -width
, -height
);
879 /******************************************************************************
883 * Draw the window caption for windows.
884 * The correct pen for the window frame must be selected in the DC.
886 *****************************************************************************/
888 static void NC_DrawCaption( HDC hdc
, RECT
*rect
, HWND hwnd
, DWORD style
,
889 DWORD exStyle
, BOOL active
)
895 BOOL gradient
= FALSE
;
897 hPrevPen
= SelectObject( hdc
, SYSCOLOR_GetPen(
898 ((exStyle
& (WS_EX_STATICEDGE
|WS_EX_CLIENTEDGE
|
899 WS_EX_DLGMODALFRAME
)) == WS_EX_STATICEDGE
) ?
900 COLOR_WINDOWFRAME
: COLOR_3DFACE
) );
901 MoveToEx( hdc
, r
.left
, r
.bottom
- 1, NULL
);
902 LineTo( hdc
, r
.right
, r
.bottom
- 1 );
903 SelectObject( hdc
, hPrevPen
);
906 SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS
, 0, &gradient
, 0);
907 NC_DrawCaptionBar (hdc
, &r
, style
, active
, gradient
);
909 if ((style
& WS_SYSMENU
) && !(exStyle
& WS_EX_TOOLWINDOW
)) {
910 if (NC_DrawSysButton (hwnd
, hdc
, FALSE
))
911 r
.left
+= GetSystemMetrics(SM_CXSMICON
) + 2;
914 if (style
& WS_SYSMENU
)
918 /* Go get the sysmenu */
919 hSysMenu
= GetSystemMenu(hwnd
, FALSE
);
920 state
= GetMenuState(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
);
922 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
923 NC_DrawCloseButton (hwnd
, hdc
, FALSE
,
924 (state
& (MF_DISABLED
| MF_GRAYED
)) || (state
== 0xFFFFFFFF));
925 r
.right
-= GetSystemMetrics(SM_CYCAPTION
) - 1;
927 if ((style
& WS_MAXIMIZEBOX
) || (style
& WS_MINIMIZEBOX
))
929 /* In win95 the two buttons are always there */
930 /* But if the menu item is not in the menu they're disabled*/
932 NC_DrawMaxButton( hwnd
, hdc
, FALSE
, (!(style
& WS_MAXIMIZEBOX
)));
933 r
.right
-= GetSystemMetrics(SM_CXSIZE
) + 1;
935 NC_DrawMinButton( hwnd
, hdc
, FALSE
, (!(style
& WS_MINIMIZEBOX
)));
936 r
.right
-= GetSystemMetrics(SM_CXSIZE
) + 1;
940 if (GetWindowTextW( hwnd
, buffer
, ARRAY_SIZE( buffer
)))
942 NONCLIENTMETRICSW nclm
;
943 HFONT hFont
, hOldFont
;
944 nclm
.cbSize
= sizeof(nclm
);
945 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS
, 0, &nclm
, 0);
946 if (exStyle
& WS_EX_TOOLWINDOW
)
947 hFont
= CreateFontIndirectW (&nclm
.lfSmCaptionFont
);
949 hFont
= CreateFontIndirectW (&nclm
.lfCaptionFont
);
950 hOldFont
= SelectObject (hdc
, hFont
);
951 if (active
) SetTextColor( hdc
, GetSysColor( COLOR_CAPTIONTEXT
) );
952 else SetTextColor( hdc
, GetSysColor( COLOR_INACTIVECAPTIONTEXT
) );
953 SetBkMode( hdc
, TRANSPARENT
);
955 DrawTextW( hdc
, buffer
, -1, &r
,
956 DT_SINGLELINE
| DT_VCENTER
| DT_NOPREFIX
| DT_LEFT
);
957 DeleteObject (SelectObject (hdc
, hOldFont
));
962 /******************************************************************************
965 * Paint the non-client area for windows.
967 static void NC_DoNCPaint( HWND hwnd
, HRGN clip
)
970 RECT rfuzz
, rect
, rectClip
;
973 DWORD dwStyle
, dwExStyle
;
978 if (!(wndPtr
= WIN_GetPtr( hwnd
)) || wndPtr
== WND_OTHER_PROCESS
) return;
979 dwStyle
= wndPtr
->dwStyle
;
980 dwExStyle
= wndPtr
->dwExStyle
;
981 flags
= wndPtr
->flags
;
982 WIN_ReleasePtr( wndPtr
);
984 active
= flags
& WIN_NCACTIVATED
;
986 TRACE("%p %d\n", hwnd
, active
);
988 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
989 the call to GetDCEx implying that it is allowed not to use it either.
990 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
991 will cause clipRgn to be deleted after ReleaseDC().
992 Now, how is the "system" supposed to tell what happened?
995 WIN_GetRectangles( hwnd
, COORDS_SCREEN
, NULL
, &rectClient
);
996 hrgn
= CreateRectRgnIndirect( &rectClient
);
1000 CombineRgn( hrgn
, clip
, hrgn
, RGN_DIFF
);
1001 hdc
= GetDCEx( hwnd
, hrgn
, DCX_USESTYLE
| DCX_WINDOW
| DCX_INTERSECTRGN
);
1005 hdc
= GetDCEx( hwnd
, hrgn
, DCX_USESTYLE
| DCX_WINDOW
| DCX_EXCLUDERGN
);
1010 DeleteObject( hrgn
);
1014 WIN_GetRectangles( hwnd
, COORDS_WINDOW
, &rect
, NULL
);
1015 GetClipBox( hdc
, &rectClip
);
1017 SelectObject( hdc
, SYSCOLOR_GetPen(COLOR_WINDOWFRAME
) );
1019 if (HAS_STATICOUTERFRAME(dwStyle
, dwExStyle
)) {
1020 DrawEdge (hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
| BF_ADJUST
);
1022 else if (HAS_BIGFRAME( dwStyle
, dwExStyle
)) {
1023 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
| BF_ADJUST
);
1026 NC_DrawFrame(hdc
, &rect
, active
, dwStyle
, dwExStyle
);
1028 if ((dwStyle
& WS_CAPTION
) == WS_CAPTION
)
1031 if (dwExStyle
& WS_EX_TOOLWINDOW
) {
1032 r
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYSMCAPTION
);
1033 rect
.top
+= GetSystemMetrics(SM_CYSMCAPTION
);
1036 r
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYCAPTION
);
1037 rect
.top
+= GetSystemMetrics(SM_CYCAPTION
);
1039 if( IntersectRect( &rfuzz
, &r
, &rectClip
) )
1040 NC_DrawCaption(hdc
, &r
, hwnd
, dwStyle
, dwExStyle
, active
);
1043 if (HAS_MENU( hwnd
, dwStyle
))
1046 r
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYMENU
);
1048 TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r
));
1050 rect
.top
+= MENU_DrawMenuBar( hdc
, &r
, hwnd
) + 1;
1053 TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect
));
1055 if (dwExStyle
& WS_EX_CLIENTEDGE
)
1056 DrawEdge (hdc
, &rect
, EDGE_SUNKEN
, BF_RECT
| BF_ADJUST
);
1058 /* Draw the scroll-bars */
1059 SCROLL_DrawNCScrollBar( hwnd
, hdc
, dwStyle
& WS_HSCROLL
, dwStyle
& WS_VSCROLL
);
1061 /* Draw the "size-box" */
1062 if ((dwStyle
& WS_VSCROLL
) && (dwStyle
& WS_HSCROLL
))
1065 if((dwExStyle
& WS_EX_LEFTSCROLLBAR
) != 0)
1066 r
.right
= r
.left
+ GetSystemMetrics(SM_CXVSCROLL
) + 1;
1068 r
.left
= r
.right
- GetSystemMetrics(SM_CXVSCROLL
) + 1;
1069 r
.top
= r
.bottom
- GetSystemMetrics(SM_CYHSCROLL
) + 1;
1070 FillRect( hdc
, &r
, GetSysColorBrush( COLOR_BTNFACE
) );
1073 ReleaseDC( hwnd
, hdc
);
1079 /***********************************************************************
1082 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1084 LRESULT
NC_HandleNCPaint( HWND hwnd
, HRGN clip
)
1086 HWND parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
1087 DWORD dwStyle
= GetWindowLongW( hwnd
, GWL_STYLE
);
1089 if( dwStyle
& WS_VISIBLE
)
1091 NC_DoNCPaint( hwnd
, clip
);
1093 if (parent
== GetDesktopWindow())
1094 PostMessageW( parent
, WM_PARENTNOTIFY
, WM_NCPAINT
, (LPARAM
)hwnd
);
1100 /***********************************************************************
1101 * NC_HandleNCActivate
1103 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1105 LRESULT
NC_HandleNCActivate( HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1107 /* Lotus Notes draws menu descriptions in the caption of its main
1108 * window. When it wants to restore original "system" view, it just
1109 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1110 * attempt to minimize redrawings lead to a not restored caption.
1112 if (wParam
) win_set_flags( hwnd
, WIN_NCACTIVATED
, 0 );
1113 else win_set_flags( hwnd
, 0, WIN_NCACTIVATED
);
1115 /* This isn't documented but is reproducible in at least XP SP2 and
1116 * Outlook 2007 depends on it
1120 NC_DoNCPaint( hwnd
, (HRGN
)1 );
1122 if (NtUserGetAncestor( hwnd
, GA_PARENT
) == GetDesktopWindow())
1123 PostMessageW( GetDesktopWindow(), WM_PARENTNOTIFY
, WM_NCACTIVATE
, (LPARAM
)hwnd
);
1130 /***********************************************************************
1131 * NC_HandleSetCursor
1133 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1135 LRESULT
NC_HandleSetCursor( HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1137 hwnd
= WIN_GetFullHandle( (HWND
)wParam
);
1139 switch((short)LOWORD(lParam
))
1143 WORD msg
= HIWORD( lParam
);
1144 if ((msg
== WM_LBUTTONDOWN
) || (msg
== WM_MBUTTONDOWN
) ||
1145 (msg
== WM_RBUTTONDOWN
) || (msg
== WM_XBUTTONDOWN
))
1152 HCURSOR hCursor
= (HCURSOR
)GetClassLongPtrW(hwnd
, GCLP_HCURSOR
);
1154 NtUserSetCursor(hCursor
);
1162 return (LRESULT
)NtUserSetCursor( LoadCursorA( 0, (LPSTR
)IDC_SIZEWE
) );
1166 return (LRESULT
)NtUserSetCursor( LoadCursorA( 0, (LPSTR
)IDC_SIZENS
) );
1170 return (LRESULT
)NtUserSetCursor( LoadCursorA( 0, (LPSTR
)IDC_SIZENWSE
) );
1174 return (LRESULT
)NtUserSetCursor( LoadCursorA( 0, (LPSTR
)IDC_SIZENESW
) );
1177 /* Default cursor: arrow */
1178 return (LRESULT
)NtUserSetCursor( LoadCursorA( 0, (LPSTR
)IDC_ARROW
) );
1181 /***********************************************************************
1184 void NC_GetSysPopupPos( HWND hwnd
, RECT
* rect
)
1186 if (IsIconic(hwnd
)) GetWindowRect( hwnd
, rect
);
1189 DWORD style
= GetWindowLongW( hwnd
, GWL_STYLE
);
1190 DWORD ex_style
= GetWindowLongW( hwnd
, GWL_EXSTYLE
);
1192 NC_GetInsideRect( hwnd
, COORDS_CLIENT
, rect
, style
, ex_style
);
1193 rect
->right
= rect
->left
+ GetSystemMetrics(SM_CYCAPTION
) - 1;
1194 rect
->bottom
= rect
->top
+ GetSystemMetrics(SM_CYCAPTION
) - 1;
1195 MapWindowPoints( hwnd
, 0, (POINT
*)rect
, 2 );
1199 /***********************************************************************
1202 * Track a mouse button press on the minimize or maximize box.
1204 * The big difference between 3.1 and 95 is the disabled button state.
1205 * In win95 the system button can be disabled, so it can ignore the mouse
1209 static void NC_TrackMinMaxBox( HWND hwnd
, WORD wParam
)
1212 HDC hdc
= GetWindowDC( hwnd
);
1213 BOOL pressed
= TRUE
;
1215 DWORD wndStyle
= GetWindowLongW( hwnd
, GWL_STYLE
);
1216 HMENU hSysMenu
= GetSystemMenu(hwnd
, FALSE
);
1218 void (*paintButton
)(HWND
, HDC
, BOOL
, BOOL
);
1220 if (wParam
== HTMINBUTTON
)
1222 /* If the style is not present, do nothing */
1223 if (!(wndStyle
& WS_MINIMIZEBOX
))
1226 /* Check if the sysmenu item for minimize is there */
1227 state
= GetMenuState(hSysMenu
, SC_MINIMIZE
, MF_BYCOMMAND
);
1229 paintButton
= NC_DrawMinButton
;
1233 /* If the style is not present, do nothing */
1234 if (!(wndStyle
& WS_MAXIMIZEBOX
))
1237 /* Check if the sysmenu item for maximize is there */
1238 state
= GetMenuState(hSysMenu
, SC_MAXIMIZE
, MF_BYCOMMAND
);
1240 paintButton
= NC_DrawMaxButton
;
1245 (*paintButton
)( hwnd
, hdc
, TRUE
, FALSE
);
1249 BOOL oldstate
= pressed
;
1251 if (!GetMessageW( &msg
, 0, WM_MOUSEFIRST
, WM_MOUSELAST
)) break;
1252 if (CallMsgFilterW( &msg
, MSGF_MAX
)) continue;
1254 if(msg
.message
== WM_LBUTTONUP
)
1257 if(msg
.message
!= WM_MOUSEMOVE
)
1260 pressed
= (NC_HandleNCHitTest( hwnd
, msg
.pt
) == wParam
);
1261 if (pressed
!= oldstate
)
1262 (*paintButton
)( hwnd
, hdc
, pressed
, FALSE
);
1266 (*paintButton
)(hwnd
, hdc
, FALSE
, FALSE
);
1269 ReleaseDC( hwnd
, hdc
);
1271 /* If the minimize or maximize items of the sysmenu are not there */
1272 /* or if the style is not present, do nothing */
1273 if ((!pressed
) || (state
== 0xFFFFFFFF))
1276 if (wParam
== HTMINBUTTON
)
1277 SendMessageW( hwnd
, WM_SYSCOMMAND
,
1278 IsIconic(hwnd
) ? SC_RESTORE
: SC_MINIMIZE
, MAKELONG(msg
.pt
.x
,msg
.pt
.y
) );
1280 SendMessageW( hwnd
, WM_SYSCOMMAND
,
1281 IsZoomed(hwnd
) ? SC_RESTORE
:SC_MAXIMIZE
, MAKELONG(msg
.pt
.x
,msg
.pt
.y
) );
1284 /***********************************************************************
1285 * NC_TrackCloseButton
1287 * Track a mouse button press on the Win95 close button.
1289 static void NC_TrackCloseButton (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1293 BOOL pressed
= TRUE
;
1294 HMENU hSysMenu
= GetSystemMenu(hwnd
, FALSE
);
1300 state
= GetMenuState(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
);
1302 /* If the close item of the sysmenu is disabled or not present do nothing */
1303 if((state
& MF_DISABLED
) || (state
& MF_GRAYED
) || (state
== 0xFFFFFFFF))
1306 hdc
= GetWindowDC( hwnd
);
1310 NC_DrawCloseButton (hwnd
, hdc
, TRUE
, FALSE
);
1314 BOOL oldstate
= pressed
;
1316 if (!GetMessageW( &msg
, 0, WM_MOUSEFIRST
, WM_MOUSELAST
)) break;
1317 if (CallMsgFilterW( &msg
, MSGF_MAX
)) continue;
1319 if(msg
.message
== WM_LBUTTONUP
)
1322 if(msg
.message
!= WM_MOUSEMOVE
)
1325 pressed
= (NC_HandleNCHitTest( hwnd
, msg
.pt
) == wParam
);
1326 if (pressed
!= oldstate
)
1327 NC_DrawCloseButton (hwnd
, hdc
, pressed
, FALSE
);
1331 NC_DrawCloseButton (hwnd
, hdc
, FALSE
, FALSE
);
1334 ReleaseDC( hwnd
, hdc
);
1335 if (!pressed
) return;
1337 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, lParam
);
1341 /***********************************************************************
1344 * Track a mouse button press on the horizontal or vertical scroll-bar.
1346 static void NC_TrackScrollBar( HWND hwnd
, WPARAM wParam
, POINT pt
)
1350 if ((wParam
& 0xfff0) == SC_HSCROLL
)
1352 if ((wParam
& 0x0f) != HTHSCROLL
) return;
1353 scrollbar
= SB_HORZ
;
1355 else /* SC_VSCROLL */
1357 if ((wParam
& 0x0f) != HTVSCROLL
) return;
1358 scrollbar
= SB_VERT
;
1360 SCROLL_TrackScrollBar( hwnd
, scrollbar
, pt
);
1364 /***********************************************************************
1365 * NC_HandleNCLButtonDown
1367 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1369 LRESULT
NC_HandleNCLButtonDown( HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1371 LONG style
= GetWindowLongW( hwnd
, GWL_STYLE
);
1373 switch(wParam
) /* Hit test */
1377 HWND top
= hwnd
, parent
;
1380 if ((GetWindowLongW( top
, GWL_STYLE
) & (WS_POPUP
|WS_CHILD
)) != WS_CHILD
)
1382 parent
= NtUserGetAncestor( top
, GA_PARENT
);
1383 if (!parent
|| parent
== GetDesktopWindow()) break;
1387 if (FOCUS_MouseActivate( top
) || (GetActiveWindow() == top
))
1388 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_MOVE
+ HTCAPTION
, lParam
);
1393 if (style
& WS_SYSMENU
)
1395 HDC hDC
= GetWindowDC( hwnd
);
1396 NC_DrawSysButton( hwnd
, hDC
, TRUE
);
1397 ReleaseDC( hwnd
, hDC
);
1398 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_MOUSEMENU
+ HTSYSMENU
, lParam
);
1403 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_MOUSEMENU
, lParam
);
1407 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_HSCROLL
+ HTHSCROLL
, lParam
);
1411 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_VSCROLL
+ HTVSCROLL
, lParam
);
1416 NC_TrackMinMaxBox( hwnd
, wParam
);
1420 NC_TrackCloseButton (hwnd
, wParam
, lParam
);
1432 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1433 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1435 /* But that is not what WinNT does. Instead it sends this. This
1436 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1437 * SC_MOUSEMENU into wParam.
1439 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_SIZE
+ wParam
- (HTLEFT
-WMSZ_LEFT
), lParam
);
1449 /***********************************************************************
1450 * NC_HandleNCRButtonDown
1452 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1454 LRESULT
NC_HandleNCRButtonDown( HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1457 INT hittest
= wParam
;
1466 if (!GetMessageW( &msg
, 0, WM_MOUSEFIRST
, WM_MOUSELAST
)) break;
1467 if (CallMsgFilterW( &msg
, MSGF_MAX
)) continue;
1468 if (msg
.message
== WM_RBUTTONUP
)
1470 hittest
= NC_HandleNCHitTest( hwnd
, msg
.pt
);
1475 if (hittest
== HTCAPTION
|| hittest
== HTSYSMENU
)
1476 SendMessageW( hwnd
, WM_CONTEXTMENU
, (WPARAM
)hwnd
, MAKELPARAM(msg
.pt
.x
, msg
.pt
.y
));
1483 /***********************************************************************
1484 * NC_HandleNCLButtonDblClk
1486 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1488 LRESULT
NC_HandleNCLButtonDblClk( HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1491 * if this is an icon, send a restore since we are handling
1496 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, lParam
);
1500 switch(wParam
) /* Hit test */
1503 /* stop processing if WS_MAXIMIZEBOX is missing */
1504 if (GetWindowLongW( hwnd
, GWL_STYLE
) & WS_MAXIMIZEBOX
)
1505 SendMessageW( hwnd
, WM_SYSCOMMAND
,
1506 IsZoomed(hwnd
) ? SC_RESTORE
: SC_MAXIMIZE
, lParam
);
1511 HMENU hSysMenu
= GetSystemMenu(hwnd
, FALSE
);
1512 UINT state
= GetMenuState(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
);
1514 /* If the close item of the sysmenu is disabled or not present do nothing */
1515 if ((state
& (MF_DISABLED
| MF_GRAYED
)) || (state
== 0xFFFFFFFF))
1518 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, lParam
);
1523 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_HSCROLL
+ HTHSCROLL
, lParam
);
1527 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_VSCROLL
+ HTVSCROLL
, lParam
);
1534 /***********************************************************************
1535 * NC_HandleSysCommand
1537 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1539 LRESULT
NC_HandleSysCommand( HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1541 TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd
, wParam
, lParam
);
1543 if (!IsWindowEnabled( hwnd
)) return 0;
1545 if (HOOK_CallHooks( WH_CBT
, HCBT_SYSCOMMAND
, wParam
, lParam
, TRUE
))
1548 if (!USER_Driver
->pSysCommand( hwnd
, wParam
, lParam
))
1551 switch (wParam
& 0xfff0)
1555 WINPOS_SysCommandSizeMove( hwnd
, wParam
);
1559 ShowOwnedPopups(hwnd
,FALSE
);
1560 ShowWindow( hwnd
, SW_MINIMIZE
);
1565 ShowOwnedPopups(hwnd
,TRUE
);
1566 ShowWindow( hwnd
, SW_MAXIMIZE
);
1571 ShowOwnedPopups(hwnd
,TRUE
);
1572 ShowWindow( hwnd
, SW_RESTORE
);
1576 return SendMessageW( hwnd
, WM_CLOSE
, 0, 0 );
1582 pt
.x
= (short)LOWORD(lParam
);
1583 pt
.y
= (short)HIWORD(lParam
);
1584 NC_TrackScrollBar( hwnd
, wParam
, pt
);
1591 pt
.x
= (short)LOWORD(lParam
);
1592 pt
.y
= (short)HIWORD(lParam
);
1593 MENU_TrackMouseMenuBar( hwnd
, wParam
& 0x000F, pt
);
1598 MENU_TrackKbdMenuBar( hwnd
, wParam
, (WCHAR
)lParam
);
1602 WinExec( "taskman.exe", SW_SHOWNORMAL
);
1606 if (wParam
== SC_ABOUTWINE
)
1608 HMODULE hmodule
= LoadLibraryA( "shell32.dll" );
1611 BOOL (WINAPI
*aboutproc
)(HWND
, LPCSTR
, LPCSTR
, HICON
);
1612 extern const char * CDECL
wine_get_version(void);
1615 sprintf( app
, "Wine %s", wine_get_version() );
1616 aboutproc
= (void *)GetProcAddress( hmodule
, "ShellAboutA" );
1617 if (aboutproc
) aboutproc( hwnd
, app
, NULL
, 0 );
1618 FreeLibrary( hmodule
);
1627 FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam
);
1633 /***********************************************************************
1634 * GetTitleBarInfo (USER32.@)
1635 * TODO: Handle STATE_SYSTEM_PRESSED
1637 BOOL WINAPI
GetTitleBarInfo(HWND hwnd
, PTITLEBARINFO tbi
) {
1641 TRACE("(%p %p)\n", hwnd
, tbi
);
1644 SetLastError(ERROR_NOACCESS
);
1648 if(tbi
->cbSize
!= sizeof(TITLEBARINFO
)) {
1649 TRACE("Invalid TITLEBARINFO size: %d\n", tbi
->cbSize
);
1650 SetLastError(ERROR_INVALID_PARAMETER
);
1653 dwStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
1654 dwExStyle
= GetWindowLongW(hwnd
, GWL_EXSTYLE
);
1655 NC_GetInsideRect(hwnd
, COORDS_SCREEN
, &tbi
->rcTitleBar
, dwStyle
, dwExStyle
);
1657 tbi
->rcTitleBar
.bottom
= tbi
->rcTitleBar
.top
;
1658 if(dwExStyle
& WS_EX_TOOLWINDOW
)
1659 tbi
->rcTitleBar
.bottom
+= GetSystemMetrics(SM_CYSMCAPTION
);
1661 tbi
->rcTitleBar
.bottom
+= GetSystemMetrics(SM_CYCAPTION
);
1662 tbi
->rcTitleBar
.left
+= GetSystemMetrics(SM_CXSIZE
);
1665 ZeroMemory(tbi
->rgstate
, sizeof(tbi
->rgstate
));
1666 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1667 * Under XP it seems to
1669 tbi
->rgstate
[0] = STATE_SYSTEM_FOCUSABLE
;
1670 if(dwStyle
& WS_CAPTION
) {
1671 tbi
->rgstate
[1] = STATE_SYSTEM_INVISIBLE
;
1672 if(dwStyle
& WS_SYSMENU
) {
1673 if(!(dwStyle
& (WS_MINIMIZEBOX
|WS_MAXIMIZEBOX
))) {
1674 tbi
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
1675 tbi
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
1678 if(!(dwStyle
& WS_MINIMIZEBOX
))
1679 tbi
->rgstate
[2] = STATE_SYSTEM_UNAVAILABLE
;
1680 if(!(dwStyle
& WS_MAXIMIZEBOX
))
1681 tbi
->rgstate
[3] = STATE_SYSTEM_UNAVAILABLE
;
1683 if(!(dwExStyle
& WS_EX_CONTEXTHELP
))
1684 tbi
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
1685 if(GetClassLongW(hwnd
, GCL_STYLE
) & CS_NOCLOSE
)
1686 tbi
->rgstate
[5] = STATE_SYSTEM_UNAVAILABLE
;
1689 tbi
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
1690 tbi
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
1691 tbi
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
1692 tbi
->rgstate
[5] = STATE_SYSTEM_INVISIBLE
;
1696 tbi
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;