2 * ReactOS User32 Library
3 * - Window non-client area management
5 * Copyright (C) 2003 ReactOS Team
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 /* INCLUDES *******************************************************************/
26 #include <wine/debug.h>
27 WINE_DEFAULT_DEBUG_CHANNEL(user32
);
29 #define HAS_DLGFRAME(Style, ExStyle) \
30 (((ExStyle) & WS_EX_DLGMODALFRAME) || \
31 (((Style) & WS_DLGFRAME) && (!((Style) & (WS_THICKFRAME | WS_MINIMIZE)))))
33 #define HAS_THICKFRAME(Style, ExStyle) \
34 (((Style) & WS_THICKFRAME) && !((Style) & WS_MINIMIZE) && \
35 (!(((Style) & (WS_DLGFRAME | WS_BORDER)) == WS_DLGFRAME)))
37 #define HAS_THINFRAME(Style, ExStyle) \
38 (((Style) & (WS_BORDER | WS_MINIMIZE)) || (!((Style) & (WS_CHILD | WS_POPUP))))
40 #define HASSIZEGRIP(Style, ExStyle, ParentStyle, WindowRect, ParentClientRect) \
41 ((!(Style & WS_CHILD) && (Style & WS_THICKFRAME) && !(Style & WS_MAXIMIZE)) || \
42 ((Style & WS_CHILD) && (ParentStyle & WS_THICKFRAME) && !(ParentStyle & WS_MAXIMIZE) && \
43 (WindowRect.right - WindowRect.left == ParentClientRect.right) && \
44 (WindowRect.bottom - WindowRect.top == ParentClientRect.bottom)))
46 #ifndef STATE_SYSTEM_OFFSCREEN
47 #define STATE_SYSTEM_OFFSCREEN 0x00010000
51 * FIXME: This should be moved to a header
54 IntDrawScrollBar(HWND hWnd
, HDC hDC
, INT nBar
);
56 IntScrollHitTest(HWND hWnd
, INT nBar
, POINT pt
, BOOL bDragging
);
58 BOOL WINAPI
GdiGradientFill(HDC
,PTRIVERTEX
,ULONG
,PVOID
,ULONG
,ULONG
);
60 extern ATOM AtomInternalPos
;
62 /* PRIVATE FUNCTIONS **********************************************************/
65 IntIsScrollBarVisible(HWND hWnd
, INT hBar
)
68 sbi
.cbSize
= sizeof(SCROLLBARINFO
);
69 if(!NtUserGetScrollBarInfo(hWnd
, hBar
, &sbi
))
72 return !(sbi
.rgstate
[0] & STATE_SYSTEM_OFFSCREEN
);
76 UserHasWindowEdge(DWORD Style
, DWORD ExStyle
)
78 if (Style
& WS_MINIMIZE
)
80 if (ExStyle
& WS_EX_DLGMODALFRAME
)
82 if (ExStyle
& WS_EX_STATICEDGE
)
84 if (Style
& WS_THICKFRAME
)
87 if (Style
== WS_DLGFRAME
|| Style
== WS_CAPTION
)
93 UserGetWindowBorders(DWORD Style
, DWORD ExStyle
, SIZE
*Size
, BOOL WithClient
)
97 if (UserHasWindowEdge(Style
, ExStyle
))
99 else if (ExStyle
& WS_EX_STATICEDGE
)
101 if ((ExStyle
& WS_EX_CLIENTEDGE
) && WithClient
)
103 if (Style
& WS_CAPTION
|| ExStyle
& WS_EX_DLGMODALFRAME
)
105 Size
->cx
= Size
->cy
= Border
;
106 if ((Style
& WS_THICKFRAME
) && !(Style
& WS_MINIMIZE
))
108 Size
->cx
+= GetSystemMetrics(SM_CXFRAME
) - GetSystemMetrics(SM_CXDLGFRAME
);
109 Size
->cy
+= GetSystemMetrics(SM_CYFRAME
) - GetSystemMetrics(SM_CYDLGFRAME
);
111 Size
->cx
*= GetSystemMetrics(SM_CXBORDER
);
112 Size
->cy
*= GetSystemMetrics(SM_CYBORDER
);
116 UserHasMenu(HWND hWnd
, ULONG Style
)
118 return (!(Style
& WS_CHILD
) && GetMenu(hWnd
) != 0);
122 UserGetWindowIcon(HWND hwnd
)
126 SendMessageTimeout(hwnd
, WM_GETICON
, ICON_SMALL2
, 0, SMTO_ABORTIFHUNG
, 1000, (PDWORD_PTR
)&hIcon
);
128 if (!hIcon
) hIcon
= UserGetProp(hwnd
, gpsi
->atomIconSmProp
);
129 if (!hIcon
) hIcon
= UserGetProp(hwnd
, gpsi
->atomIconProp
);
130 if (!hIcon
) hIcon
= (HICON
)GetClassLongPtr(hwnd
, GCL_HICONSM
);
131 if (!hIcon
) hIcon
= (HICON
)GetClassLongPtr(hwnd
, GCL_HICON
);
132 if (!hIcon
&& (GetWindowLongW( hwnd
, GWL_STYLE
) & DS_MODALFRAME
))
134 if (!hIcon
) hIcon
= gpsi
->hIconSmWindows
; // Both are IDI_WINLOGO Small
135 if (!hIcon
) hIcon
= gpsi
->hIconWindows
; // Reg size.
141 UserDrawSysMenuButton(HWND hWnd
, HDC hDC
, LPRECT Rect
, BOOL Down
)
145 if ((WindowIcon
= UserGetWindowIcon(hWnd
)))
147 return DrawIconEx(hDC
, Rect
->left
+ 2, Rect
->top
+ 2, WindowIcon
,
148 GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
),
157 * - Cache bitmaps, then just bitblt instead of calling DFC() (and
158 * wasting precious CPU cycles) every time
159 * - Center the buttons verticaly in the rect
162 UserDrawCaptionButton(HWND hWnd
, LPRECT Rect
, DWORD Style
, DWORD ExStyle
, HDC hDC
, BOOL bDown
, ULONG Type
)
166 if (!(Style
& WS_SYSMENU
))
175 case DFCS_CAPTIONMIN
:
177 if (ExStyle
& WS_EX_TOOLWINDOW
)
178 return; /* ToolWindows don't have min/max buttons */
180 if (Style
& WS_SYSMENU
)
181 TempRect
.right
-= GetSystemMetrics(SM_CXSIZE
) + 1;
182 if (Style
& (WS_MAXIMIZEBOX
| WS_MINIMIZEBOX
))
183 TempRect
.right
-= GetSystemMetrics(SM_CXSIZE
) - 2;
184 TempRect
.left
= TempRect
.right
- GetSystemMetrics(SM_CXSIZE
) + 1;
185 TempRect
.bottom
= TempRect
.top
+ GetSystemMetrics(SM_CYSIZE
) - 2;
189 DrawFrameControl(hDC
, &TempRect
, DFC_CAPTION
,
190 ((Style
& WS_MINIMIZE
) ? DFCS_CAPTIONRESTORE
: DFCS_CAPTIONMIN
) |
191 (bDown
? DFCS_PUSHED
: 0) |
192 ((Style
& WS_MINIMIZEBOX
) ? 0 : DFCS_INACTIVE
));
195 case DFCS_CAPTIONMAX
:
197 if (ExStyle
& WS_EX_TOOLWINDOW
)
198 return; /* ToolWindows don't have min/max buttons */
200 if (Style
& WS_SYSMENU
)
201 TempRect
.right
-= GetSystemMetrics(SM_CXSIZE
) + 1;
202 TempRect
.left
= TempRect
.right
- GetSystemMetrics(SM_CXSIZE
) + 1;
203 TempRect
.bottom
= TempRect
.top
+ GetSystemMetrics(SM_CYSIZE
) - 2;
207 DrawFrameControl(hDC
, &TempRect
, DFC_CAPTION
,
208 ((Style
& WS_MAXIMIZE
) ? DFCS_CAPTIONRESTORE
: DFCS_CAPTIONMAX
) |
209 (bDown
? DFCS_PUSHED
: 0) |
210 ((Style
& WS_MAXIMIZEBOX
) ? 0 : DFCS_INACTIVE
));
213 case DFCS_CAPTIONCLOSE
:
215 HMENU hSysMenu
= GetSystemMenu(hWnd
, FALSE
);
216 UINT MenuState
= GetMenuState(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
); /* in case of error MenuState==0xFFFFFFFF */
218 /* FIXME: A tool window has a smaller Close button */
220 if (ExStyle
& WS_EX_TOOLWINDOW
)
222 TempRect
.left
= TempRect
.right
- GetSystemMetrics(SM_CXSMSIZE
);
223 TempRect
.bottom
= TempRect
.top
+ GetSystemMetrics(SM_CYSMSIZE
) - 2;
227 TempRect
.left
= TempRect
.right
- GetSystemMetrics(SM_CXSIZE
);
228 TempRect
.bottom
= TempRect
.top
+ GetSystemMetrics(SM_CYSIZE
) - 2;
233 DrawFrameControl(hDC
, &TempRect
, DFC_CAPTION
,
234 (DFCS_CAPTIONCLOSE
| (bDown
? DFCS_PUSHED
: 0) |
235 ((!(MenuState
& (MF_GRAYED
|MF_DISABLED
)) && !(GetClassLong(hWnd
, GCL_STYLE
) & CS_NOCLOSE
)) ? 0 : DFCS_INACTIVE
)));
242 UserDrawCaptionButtonWnd(HWND hWnd
, HDC hDC
, BOOL bDown
, ULONG Type
)
246 DWORD Style
, ExStyle
;
248 GetWindowRect(hWnd
, &WindowRect
);
249 WindowRect
.right
-= WindowRect
.left
;
250 WindowRect
.bottom
-= WindowRect
.top
;
251 WindowRect
.left
= WindowRect
.top
= 0;
252 Style
= GetWindowLongPtrW(hWnd
, GWL_STYLE
);
253 ExStyle
= GetWindowLongPtrW(hWnd
, GWL_EXSTYLE
);
254 UserGetWindowBorders(Style
, ExStyle
, &WindowBorder
, FALSE
);
255 InflateRect(&WindowRect
, -WindowBorder
.cx
, -WindowBorder
.cy
);
256 UserDrawCaptionButton(hWnd
, &WindowRect
, Style
, ExStyle
, hDC
, bDown
, Type
);
260 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
261 the call to GetDCEx implying that it is allowed not to use it either.
262 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
263 will cause clipRgn to be deleted after ReleaseDC().
264 Now, how is the "system" supposed to tell what happened?
268 * - Drawing of WS_BORDER after scrollbars
269 * - Correct drawing of size-box
272 DefWndNCPaint(HWND hWnd
, HRGN hRgn
, BOOL Active
)
275 DWORD Style
, ExStyle
;
277 RECT ClientRect
, WindowRect
, CurrentRect
, TempRect
;
279 if (!IsWindowVisible(hWnd
))
282 Style
= GetWindowLongPtrW(hWnd
, GWL_STYLE
);
284 hDC
= GetDCEx(hWnd
, hRgn
, DCX_WINDOW
| DCX_INTERSECTRGN
| DCX_USESTYLE
| DCX_KEEPCLIPRGN
);
290 Parent
= GetParent(hWnd
);
291 ExStyle
= GetWindowLongPtrW(hWnd
, GWL_EXSTYLE
);
294 if (ExStyle
& WS_EX_MDICHILD
)
296 Active
= IsChild(GetForegroundWindow(), hWnd
);
298 Active
= (hWnd
== (HWND
)SendMessageW(Parent
, WM_MDIGETACTIVE
, 0, 0));
302 Active
= (GetForegroundWindow() == hWnd
);
305 GetWindowRect(hWnd
, &WindowRect
);
306 GetClientRect(hWnd
, &ClientRect
);
308 CurrentRect
.top
= CurrentRect
.left
= 0;
309 CurrentRect
.right
= WindowRect
.right
- WindowRect
.left
;
310 CurrentRect
.bottom
= WindowRect
.bottom
- WindowRect
.top
;
312 /* Draw outer edge */
313 if (UserHasWindowEdge(Style
, ExStyle
))
315 DrawEdge(hDC
, &CurrentRect
, EDGE_RAISED
, BF_RECT
| BF_ADJUST
);
317 if (ExStyle
& WS_EX_STATICEDGE
)
320 DrawEdge(hDC
, &CurrentRect
, BDR_SUNKENINNER
, BF_RECT
| BF_ADJUST
| BF_FLAT
);
322 SelectObject(hDC
, GetSysColorBrush(COLOR_BTNSHADOW
));
323 PatBlt(hDC
, CurrentRect
.left
, CurrentRect
.top
, CurrentRect
.right
- CurrentRect
.left
, 1, PATCOPY
);
324 PatBlt(hDC
, CurrentRect
.left
, CurrentRect
.top
, 1, CurrentRect
.bottom
- CurrentRect
.top
, PATCOPY
);
326 SelectObject(hDC
, GetSysColorBrush(COLOR_BTNHIGHLIGHT
));
327 PatBlt(hDC
, CurrentRect
.left
, CurrentRect
.bottom
- 1, CurrentRect
.right
- CurrentRect
.left
, 1, PATCOPY
);
328 PatBlt(hDC
, CurrentRect
.right
- 1, CurrentRect
.top
, 1, CurrentRect
.bottom
- CurrentRect
.top
, PATCOPY
);
330 InflateRect(&CurrentRect
, -1, -1);
334 /* Firstly the "thick" frame */
335 if ((Style
& WS_THICKFRAME
) && !(Style
& WS_MINIMIZE
))
338 (GetSystemMetrics(SM_CXFRAME
) - GetSystemMetrics(SM_CXDLGFRAME
)) *
339 GetSystemMetrics(SM_CXBORDER
);
341 (GetSystemMetrics(SM_CYFRAME
) - GetSystemMetrics(SM_CYDLGFRAME
)) *
342 GetSystemMetrics(SM_CYBORDER
);
344 SelectObject(hDC
, GetSysColorBrush(Active
? COLOR_ACTIVEBORDER
:
345 COLOR_INACTIVEBORDER
));
348 PatBlt(hDC
, CurrentRect
.left
, CurrentRect
.top
, CurrentRect
.right
- CurrentRect
.left
, Height
, PATCOPY
);
349 PatBlt(hDC
, CurrentRect
.left
, CurrentRect
.top
, Width
, CurrentRect
.bottom
- CurrentRect
.top
, PATCOPY
);
351 PatBlt(hDC
, CurrentRect
.left
, CurrentRect
.bottom
- 1, CurrentRect
.right
- CurrentRect
.left
, -Height
, PATCOPY
);
352 PatBlt(hDC
, CurrentRect
.right
- 1, CurrentRect
.top
, -Width
, CurrentRect
.bottom
- CurrentRect
.top
, PATCOPY
);
354 PatBlt(hDC
, CurrentRect
.left
, CurrentRect
.bottom
, CurrentRect
.right
- CurrentRect
.left
, -Height
, PATCOPY
);
355 PatBlt(hDC
, CurrentRect
.right
, CurrentRect
.top
, -Width
, CurrentRect
.bottom
- CurrentRect
.top
, PATCOPY
);
358 InflateRect(&CurrentRect
, -Width
, -Height
);
361 /* Now the other bit of the frame */
362 if (Style
& (WS_DLGFRAME
| WS_BORDER
) || ExStyle
& WS_EX_DLGMODALFRAME
)
364 DWORD Width
= GetSystemMetrics(SM_CXBORDER
);
365 DWORD Height
= GetSystemMetrics(SM_CYBORDER
);
367 SelectObject(hDC
, GetSysColorBrush(
368 (ExStyle
& (WS_EX_DLGMODALFRAME
| WS_EX_CLIENTEDGE
)) ? COLOR_3DFACE
:
369 (ExStyle
& WS_EX_STATICEDGE
) ? COLOR_WINDOWFRAME
:
370 (Style
& (WS_DLGFRAME
| WS_THICKFRAME
)) ? COLOR_3DFACE
:
374 PatBlt(hDC
, CurrentRect
.left
, CurrentRect
.top
, CurrentRect
.right
- CurrentRect
.left
, Height
, PATCOPY
);
375 PatBlt(hDC
, CurrentRect
.left
, CurrentRect
.top
, Width
, CurrentRect
.bottom
- CurrentRect
.top
, PATCOPY
);
377 PatBlt(hDC
, CurrentRect
.left
, CurrentRect
.bottom
- 1, CurrentRect
.right
- CurrentRect
.left
, -Height
, PATCOPY
);
378 PatBlt(hDC
, CurrentRect
.right
- 1, CurrentRect
.top
, -Width
, CurrentRect
.bottom
- CurrentRect
.top
, PATCOPY
);
380 PatBlt(hDC
, CurrentRect
.left
, CurrentRect
.bottom
, CurrentRect
.right
- CurrentRect
.left
, -Height
, PATCOPY
);
381 PatBlt(hDC
, CurrentRect
.right
, CurrentRect
.top
, -Width
, CurrentRect
.bottom
- CurrentRect
.top
, PATCOPY
);
384 InflateRect(&CurrentRect
, -Width
, -Height
);
388 if ((Style
& WS_CAPTION
) == WS_CAPTION
)
390 DWORD CaptionFlags
= DC_ICON
| DC_TEXT
| DC_BUTTONS
;
392 BOOL Gradient
= FALSE
;
394 if(SystemParametersInfoW(SPI_GETGRADIENTCAPTIONS
, 0, &Gradient
, 0) && Gradient
)
396 CaptionFlags
|= DC_GRADIENT
;
399 TempRect
= CurrentRect
;
403 CaptionFlags
|= DC_ACTIVE
;
406 if (ExStyle
& WS_EX_TOOLWINDOW
)
408 CaptionFlags
|= DC_SMALLCAP
;
409 TempRect
.bottom
= TempRect
.top
+ GetSystemMetrics(SM_CYSMCAPTION
) - 1;
410 CurrentRect
.top
+= GetSystemMetrics(SM_CYSMCAPTION
);
414 TempRect
.bottom
= TempRect
.top
+ GetSystemMetrics(SM_CYCAPTION
) - 1;
415 CurrentRect
.top
+= GetSystemMetrics(SM_CYCAPTION
);
418 NtUserDrawCaption(hWnd
, hDC
, &TempRect
, CaptionFlags
);
421 if (Style
& WS_SYSMENU
)
423 UserDrawCaptionButton(hWnd
, &TempRect
, Style
, ExStyle
, hDC
, FALSE
, DFCS_CAPTIONCLOSE
);
424 if ((Style
& (WS_MAXIMIZEBOX
| WS_MINIMIZEBOX
)) && !(ExStyle
& WS_EX_TOOLWINDOW
))
426 UserDrawCaptionButton(hWnd
, &TempRect
, Style
, ExStyle
, hDC
, FALSE
, DFCS_CAPTIONMIN
);
427 UserDrawCaptionButton(hWnd
, &TempRect
, Style
, ExStyle
, hDC
, FALSE
, DFCS_CAPTIONMAX
);
430 if(!(Style
& WS_MINIMIZE
))
432 /* Line under caption */
433 PreviousPen
= SelectObject(hDC
, GetStockObject(DC_PEN
));
434 SetDCPenColor(hDC
, GetSysColor(
435 ((ExStyle
& (WS_EX_STATICEDGE
| WS_EX_CLIENTEDGE
|
436 WS_EX_DLGMODALFRAME
)) == WS_EX_STATICEDGE
) ?
437 COLOR_WINDOWFRAME
: COLOR_3DFACE
));
438 MoveToEx(hDC
, TempRect
.left
, TempRect
.bottom
, NULL
);
439 LineTo(hDC
, TempRect
.right
, TempRect
.bottom
);
440 SelectObject(hDC
, PreviousPen
);
444 if(!(Style
& WS_MINIMIZE
))
446 HMENU menu
= GetMenu(hWnd
);
448 if (menu
&& !(Style
& WS_CHILD
))
450 TempRect
= CurrentRect
;
451 TempRect
.bottom
= TempRect
.top
+ (UINT
)NtUserxSetMenuBarHeight(menu
, 0);
452 CurrentRect
.top
+= MenuDrawMenuBar(hDC
, &TempRect
, hWnd
, FALSE
);
455 if (ExStyle
& WS_EX_CLIENTEDGE
)
457 DrawEdge(hDC
, &CurrentRect
, EDGE_SUNKEN
, BF_RECT
| BF_ADJUST
);
460 /* Draw the scrollbars */
461 if ((Style
& WS_VSCROLL
) && (Style
& WS_HSCROLL
) &&
462 IntIsScrollBarVisible(hWnd
, OBJID_VSCROLL
) && IntIsScrollBarVisible(hWnd
, OBJID_HSCROLL
))
464 RECT ParentClientRect
;
466 TempRect
= CurrentRect
;
467 if (ExStyle
& WS_EX_LEFTSCROLLBAR
)
468 TempRect
.right
= TempRect
.left
+ GetSystemMetrics(SM_CXVSCROLL
);
470 TempRect
.left
= TempRect
.right
- GetSystemMetrics(SM_CXVSCROLL
);
471 TempRect
.top
= TempRect
.bottom
- GetSystemMetrics(SM_CYHSCROLL
);
472 FillRect(hDC
, &TempRect
, GetSysColorBrush(COLOR_BTNFACE
));
473 /* FIXME: Correct drawing of size-box with WS_EX_LEFTSCROLLBAR */
475 GetClientRect(Parent
, &ParentClientRect
);
476 if (HASSIZEGRIP(Style
, ExStyle
, GetWindowLongPtrW(Parent
, GWL_STYLE
), WindowRect
, ParentClientRect
))
478 DrawFrameControl(hDC
, &TempRect
, DFC_SCROLL
, DFCS_SCROLLSIZEGRIP
);
480 IntDrawScrollBar(hWnd
, hDC
, SB_VERT
);
481 IntDrawScrollBar(hWnd
, hDC
, SB_HORZ
);
485 if (Style
& WS_VSCROLL
&& IntIsScrollBarVisible(hWnd
, OBJID_VSCROLL
))
486 IntDrawScrollBar(hWnd
, hDC
, SB_VERT
);
487 else if (Style
& WS_HSCROLL
&& IntIsScrollBarVisible(hWnd
, OBJID_HSCROLL
))
488 IntDrawScrollBar(hWnd
, hDC
, SB_HORZ
);
492 ReleaseDC(hWnd
, hDC
);
493 if (hRgn
!= HRGN_WINDOW
)
494 DeleteObject(hRgn
); // We use DCX_KEEPCLIPRGN
496 return 0; // For WM_NCPAINT message, return 0.
500 DefWndNCCalcSize(HWND hWnd
, BOOL CalcSizeStruct
, RECT
*Rect
)
503 DWORD Style
= GetClassLongPtrW(hWnd
, GCL_STYLE
);
516 if (Style
& CS_VREDRAW
)
518 Result
|= WVR_VREDRAW
;
520 if (Style
& CS_HREDRAW
)
522 Result
|= WVR_HREDRAW
;
524 Result
|= WVR_VALIDRECTS
;
527 Style
= GetWindowLongPtrW(hWnd
, GWL_STYLE
);
528 ExStyle
= GetWindowLongPtrW(hWnd
, GWL_EXSTYLE
);
530 if (!(Style
& WS_MINIMIZE
))
532 HMENU menu
= GetMenu(hWnd
);
534 if (UserHasWindowEdge(Style
, ExStyle
))
536 UserGetWindowBorders(Style
, ExStyle
, &WindowBorders
, FALSE
);
537 InflateRect(Rect
, -WindowBorders
.cx
, -WindowBorders
.cy
);
539 if ((ExStyle
& WS_EX_STATICEDGE
) || (Style
& WS_BORDER
))
541 InflateRect(Rect
, -1, -1);
544 if ((Style
& WS_CAPTION
) == WS_CAPTION
)
546 if (ExStyle
& WS_EX_TOOLWINDOW
)
547 Rect
->top
+= GetSystemMetrics(SM_CYSMCAPTION
);
549 Rect
->top
+= GetSystemMetrics(SM_CYCAPTION
);
552 if (menu
&& !(Style
& WS_CHILD
))
554 HDC hDC
= GetWindowDC(hWnd
);
557 RECT CliRect
= *Rect
;
558 CliRect
.bottom
-= OrigRect
.top
;
559 CliRect
.right
-= OrigRect
.left
;
560 CliRect
.left
-= OrigRect
.left
;
561 CliRect
.top
-= OrigRect
.top
;
562 Rect
->top
+= MenuDrawMenuBar(hDC
, &CliRect
, hWnd
, TRUE
);
563 ReleaseDC(hWnd
, hDC
);
567 if (ExStyle
& WS_EX_CLIENTEDGE
)
569 InflateRect(Rect
, -2 * GetSystemMetrics(SM_CXBORDER
),
570 -2 * GetSystemMetrics(SM_CYBORDER
));
573 if(Style
& (WS_VSCROLL
| WS_HSCROLL
))
576 SETSCROLLBARINFO ssbi
;
578 sbi
.cbSize
= sizeof(SCROLLBARINFO
);
579 if((Style
& WS_VSCROLL
) && NtUserGetScrollBarInfo(hWnd
, OBJID_VSCROLL
, &sbi
))
582 LONG sx
= Rect
->right
;
584 sx
-= GetSystemMetrics(SM_CXVSCROLL
);
585 for(i
= 0; i
<= CCHILDREN_SCROLLBAR
; i
++)
586 ssbi
.rgstate
[i
] = sbi
.rgstate
[i
];
588 ssbi
.rgstate
[0] |= STATE_SYSTEM_OFFSCREEN
;
590 ssbi
.rgstate
[0] &= ~STATE_SYSTEM_OFFSCREEN
;
591 NtUserSetScrollBarInfo(hWnd
, OBJID_VSCROLL
, &ssbi
);
592 if(ssbi
.rgstate
[0] & STATE_SYSTEM_OFFSCREEN
)
593 Style
&= ~WS_VSCROLL
;
596 Style
&= ~WS_VSCROLL
;
598 if((Style
& WS_HSCROLL
) && NtUserGetScrollBarInfo(hWnd
, OBJID_HSCROLL
, &sbi
))
601 LONG sy
= Rect
->bottom
;
603 sy
-= GetSystemMetrics(SM_CYHSCROLL
);
604 for(i
= 0; i
<= CCHILDREN_SCROLLBAR
; i
++)
605 ssbi
.rgstate
[i
] = sbi
.rgstate
[i
];
607 ssbi
.rgstate
[0] |= STATE_SYSTEM_OFFSCREEN
;
609 ssbi
.rgstate
[0] &= ~STATE_SYSTEM_OFFSCREEN
;
610 NtUserSetScrollBarInfo(hWnd
, OBJID_HSCROLL
, &ssbi
);
611 if(ssbi
.rgstate
[0] & STATE_SYSTEM_OFFSCREEN
)
612 Style
&= ~WS_HSCROLL
;
615 Style
&= ~WS_HSCROLL
;
618 if ((Style
& WS_VSCROLL
) && (Style
& WS_HSCROLL
))
620 if ((ExStyle
& WS_EX_LEFTSCROLLBAR
) != 0)
621 Rect
->left
+= GetSystemMetrics(SM_CXVSCROLL
);
623 Rect
->right
-= GetSystemMetrics(SM_CXVSCROLL
);
624 Rect
->bottom
-= GetSystemMetrics(SM_CYHSCROLL
);
628 if (Style
& WS_VSCROLL
)
630 if ((ExStyle
& WS_EX_LEFTSCROLLBAR
) != 0)
631 Rect
->left
+= GetSystemMetrics(SM_CXVSCROLL
);
633 Rect
->right
-= GetSystemMetrics(SM_CXVSCROLL
);
635 else if (Style
& WS_HSCROLL
)
636 Rect
->bottom
-= GetSystemMetrics(SM_CYHSCROLL
);
638 if (Rect
->top
> Rect
->bottom
)
639 Rect
->bottom
= Rect
->top
;
640 if (Rect
->left
> Rect
->right
)
641 Rect
->right
= Rect
->left
;
645 Rect
->right
= Rect
->left
;
646 Rect
->bottom
= Rect
->top
;
653 DefWndNCActivate(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
655 PWND Wnd
= ValidateHwnd(hWnd
);
659 /* Lotus Notes draws menu descriptions in the caption of its main
660 * window. When it wants to restore original "system" view, it just
661 * sends WM_NCACTIVATE message to itself. Any optimizations here in
662 * attempt to minimize redrawings lead to a not restored caption.
665 NtUserxSetWindowState(Wnd
, WNDSACTIVEFRAME
);
667 NtUserxClearWindowState(Wnd
, WNDSACTIVEFRAME
);
669 if (Wnd
->state
& WNDS_NONCPAINT
)
672 /* This isn't documented but is reproducible in at least XP SP2 and
673 * Outlook 2007 depends on it
676 // If this parameter is set to -1, DefWindowProc does not repaint the
677 // nonclient area to reflect the state change.
680 DefWndNCPaint(hWnd
, HRGN_WINDOW
, wParam
);
687 * - Check the scrollbar handling
690 DefWndNCHitTest(HWND hWnd
, POINT Point
)
692 RECT WindowRect
, ClientRect
, OrigWndRect
;
695 DWORD Style
= GetWindowLongPtrW(hWnd
, GWL_STYLE
);
696 DWORD ExStyle
= GetWindowLongPtrW(hWnd
, GWL_EXSTYLE
);
698 GetWindowRect(hWnd
, &WindowRect
);
699 if (!PtInRect(&WindowRect
, Point
))
703 OrigWndRect
= WindowRect
;
705 if (UserHasWindowEdge(Style
, ExStyle
))
709 UserGetWindowBorders(Style
, ExStyle
, &WindowBorders
, FALSE
);
710 InflateRect(&WindowRect
, -WindowBorders
.cx
, -WindowBorders
.cy
);
711 XSize
= GetSystemMetrics(SM_CXSIZE
) * GetSystemMetrics(SM_CXBORDER
);
712 YSize
= GetSystemMetrics(SM_CYSIZE
) * GetSystemMetrics(SM_CYBORDER
);
713 if (!PtInRect(&WindowRect
, Point
))
717 ThickFrame
= (Style
& WS_THICKFRAME
);
718 if (Point
.y
< WindowRect
.top
)
720 if(Style
& WS_MINIMIZE
)
724 if (Point
.x
< (WindowRect
.left
+ XSize
))
726 if (Point
.x
>= (WindowRect
.right
- XSize
))
730 if (Point
.y
>= WindowRect
.bottom
)
732 if(Style
& WS_MINIMIZE
)
736 if (Point
.x
< (WindowRect
.left
+ XSize
))
738 if (Point
.x
>= (WindowRect
.right
- XSize
))
739 return HTBOTTOMRIGHT
;
742 if (Point
.x
< WindowRect
.left
)
744 if(Style
& WS_MINIMIZE
)
748 if (Point
.y
< (WindowRect
.top
+ YSize
))
750 if (Point
.y
>= (WindowRect
.bottom
- YSize
))
754 if (Point
.x
>= WindowRect
.right
)
756 if(Style
& WS_MINIMIZE
)
760 if (Point
.y
< (WindowRect
.top
+ YSize
))
762 if (Point
.y
>= (WindowRect
.bottom
- YSize
))
763 return HTBOTTOMRIGHT
;
770 if (ExStyle
& WS_EX_STATICEDGE
)
771 InflateRect(&WindowRect
,
772 -GetSystemMetrics(SM_CXBORDER
),
773 -GetSystemMetrics(SM_CYBORDER
));
774 if (!PtInRect(&WindowRect
, Point
))
778 if ((Style
& WS_CAPTION
) == WS_CAPTION
)
780 if (ExStyle
& WS_EX_TOOLWINDOW
)
781 WindowRect
.top
+= GetSystemMetrics(SM_CYSMCAPTION
);
783 WindowRect
.top
+= GetSystemMetrics(SM_CYCAPTION
);
784 if (!PtInRect(&WindowRect
, Point
))
786 if (Style
& WS_SYSMENU
)
788 if (ExStyle
& WS_EX_TOOLWINDOW
)
790 WindowRect
.right
-= GetSystemMetrics(SM_CXSMSIZE
);
794 if(!(ExStyle
& WS_EX_DLGMODALFRAME
))
795 WindowRect
.left
+= GetSystemMetrics(SM_CXSIZE
);
796 WindowRect
.right
-= GetSystemMetrics(SM_CXSIZE
);
799 if (Point
.x
< WindowRect
.left
)
801 if (WindowRect
.right
<= Point
.x
)
803 if (Style
& WS_MAXIMIZEBOX
|| Style
& WS_MINIMIZEBOX
)
804 WindowRect
.right
-= GetSystemMetrics(SM_CXSIZE
);
805 if (Point
.x
>= WindowRect
.right
)
807 if (Style
& WS_MINIMIZEBOX
)
808 WindowRect
.right
-= GetSystemMetrics(SM_CXSIZE
);
809 if (Point
.x
>= WindowRect
.right
)
815 if(!(Style
& WS_MINIMIZE
))
818 ScreenToClient(hWnd
, &ClientPoint
);
819 GetClientRect(hWnd
, &ClientRect
);
821 if (PtInRect(&ClientRect
, ClientPoint
))
826 if (GetMenu(hWnd
) && !(Style
& WS_CHILD
))
828 if (Point
.x
> 0 && Point
.x
< WindowRect
.right
&& ClientPoint
.y
< 0)
832 if (ExStyle
& WS_EX_CLIENTEDGE
)
834 InflateRect(&WindowRect
, -2 * GetSystemMetrics(SM_CXBORDER
),
835 -2 * GetSystemMetrics(SM_CYBORDER
));
838 if ((Style
& WS_VSCROLL
) && (Style
& WS_HSCROLL
) &&
839 (WindowRect
.bottom
- WindowRect
.top
) > GetSystemMetrics(SM_CYHSCROLL
))
841 RECT ParentRect
, TempRect
= WindowRect
, TempRect2
= WindowRect
;
842 HWND Parent
= GetParent(hWnd
);
844 TempRect
.bottom
-= GetSystemMetrics(SM_CYHSCROLL
);
845 if ((ExStyle
& WS_EX_LEFTSCROLLBAR
) != 0)
846 TempRect
.right
= TempRect
.left
+ GetSystemMetrics(SM_CXVSCROLL
);
848 TempRect
.left
= TempRect
.right
- GetSystemMetrics(SM_CXVSCROLL
);
849 if (PtInRect(&TempRect
, Point
))
852 TempRect2
.top
= TempRect2
.bottom
- GetSystemMetrics(SM_CYHSCROLL
);
853 if ((ExStyle
& WS_EX_LEFTSCROLLBAR
) != 0)
854 TempRect2
.left
+= GetSystemMetrics(SM_CXVSCROLL
);
856 TempRect2
.right
-= GetSystemMetrics(SM_CXVSCROLL
);
857 if (PtInRect(&TempRect2
, Point
))
860 TempRect
.top
= TempRect2
.top
;
861 TempRect
.bottom
= TempRect2
.bottom
;
863 GetClientRect(Parent
, &ParentRect
);
864 if (PtInRect(&TempRect
, Point
) && HASSIZEGRIP(Style
, ExStyle
,
865 GetWindowLongPtrW(Parent
, GWL_STYLE
), OrigWndRect
, ParentRect
))
867 if ((ExStyle
& WS_EX_LEFTSCROLLBAR
) != 0)
870 return HTBOTTOMRIGHT
;
875 if (Style
& WS_VSCROLL
)
877 RECT TempRect
= WindowRect
;
879 if ((ExStyle
& WS_EX_LEFTSCROLLBAR
) != 0)
880 TempRect
.right
= TempRect
.left
+ GetSystemMetrics(SM_CXVSCROLL
);
882 TempRect
.left
= TempRect
.right
- GetSystemMetrics(SM_CXVSCROLL
);
883 if (PtInRect(&TempRect
, Point
))
886 if (Style
& WS_HSCROLL
)
888 RECT TempRect
= WindowRect
;
889 TempRect
.top
= TempRect
.bottom
- GetSystemMetrics(SM_CYHSCROLL
);
890 if (PtInRect(&TempRect
, Point
))
900 DefWndDoButton(HWND hWnd
, WPARAM wParam
)
904 BOOL Pressed
= TRUE
, OldState
;
911 Style
= GetWindowLongPtrW(hWnd
, GWL_STYLE
);
915 hSysMenu
= GetSystemMenu(hWnd
, FALSE
);
916 MenuState
= GetMenuState(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
); /* in case of error MenuState==0xFFFFFFFF */
917 if (!(Style
& WS_SYSMENU
) || (MenuState
& (MF_GRAYED
|MF_DISABLED
)) || (GetClassLongPtrW(hWnd
, GCL_STYLE
) & CS_NOCLOSE
))
919 ButtonType
= DFCS_CAPTIONCLOSE
;
923 if (!(Style
& WS_MINIMIZEBOX
))
925 ButtonType
= DFCS_CAPTIONMIN
;
926 SCMsg
= ((Style
& WS_MINIMIZE
) ? SC_RESTORE
: SC_MINIMIZE
);
929 if (!(Style
& WS_MAXIMIZEBOX
))
931 ButtonType
= DFCS_CAPTIONMAX
;
932 SCMsg
= ((Style
& WS_MAXIMIZE
) ? SC_RESTORE
: SC_MAXIMIZE
);
941 * FIXME: Not sure where to do this, but we must flush the pending
942 * window updates when someone clicks on the close button and at
943 * the same time the window is overlapped with another one. This
944 * looks like a good place for now...
948 WindowDC
= GetWindowDC(hWnd
);
949 UserDrawCaptionButtonWnd(hWnd
, WindowDC
, TRUE
, ButtonType
);
955 if (GetMessageW(&Msg
, 0, WM_MOUSEFIRST
, WM_MOUSELAST
) <= 0)
957 if (CallMsgFilterW( &Msg
, MSGF_MAX
)) continue;
959 if (Msg
.message
== WM_LBUTTONUP
)
962 if (Msg
.message
!= WM_MOUSEMOVE
)
966 Pressed
= (DefWndNCHitTest(hWnd
, Msg
.pt
) == wParam
);
967 if (Pressed
!= OldState
)
968 UserDrawCaptionButtonWnd(hWnd
, WindowDC
, Pressed
, ButtonType
);
972 UserDrawCaptionButtonWnd(hWnd
, WindowDC
, FALSE
, ButtonType
);
974 ReleaseDC(hWnd
, WindowDC
);
976 SendMessageW(hWnd
, WM_SYSCOMMAND
, SCMsg
, MAKELONG(Msg
.pt
.x
,Msg
.pt
.y
));
981 DefWndNCLButtonDown(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
987 HWND hTopWnd
= GetAncestor(hWnd
, GA_ROOT
);
988 if ( NtUserCallHwndLock(hTopWnd
, HWNDLOCK_ROUTINE_SETFOREGROUNDWINDOWMOUSE
) ||
989 GetActiveWindow() == hTopWnd
)
991 SendMessageW(hWnd
, WM_SYSCOMMAND
, SC_MOVE
+ HTCAPTION
, lParam
);
997 LONG style
= GetWindowLongPtrW( hWnd
, GWL_STYLE
);
998 if (style
& WS_SYSMENU
)
1000 SendMessageW(hWnd
, WM_SYSCOMMAND
, SC_MOUSEMENU
+ HTSYSMENU
,
1007 SendMessageW(hWnd
, WM_SYSCOMMAND
, SC_MOUSEMENU
+ HTMENU
, lParam
);
1012 SendMessageW(hWnd
, WM_SYSCOMMAND
, SC_HSCROLL
+ HTHSCROLL
, lParam
);
1017 SendMessageW(hWnd
, WM_SYSCOMMAND
, SC_VSCROLL
+ HTVSCROLL
, lParam
);
1024 DefWndDoButton(hWnd
, wParam
);
1037 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1038 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1040 /* But that is not what WinNT does. Instead it sends this. This
1041 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1042 * SC_MOUSEMENU into wParam.
1044 SendMessageW(hWnd
, WM_SYSCOMMAND
, SC_SIZE
+ wParam
- (HTLEFT
- WMSZ_LEFT
), lParam
);
1055 DefWndNCLButtonDblClk(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
1059 Style
= GetWindowLongPtrW(hWnd
, GWL_STYLE
);
1064 /* Maximize/Restore the window */
1065 if((Style
& WS_CAPTION
) == WS_CAPTION
&& (Style
& WS_MAXIMIZEBOX
))
1067 SendMessageW(hWnd
, WM_SYSCOMMAND
, ((Style
& (WS_MINIMIZE
| WS_MAXIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
), 0);
1073 SendMessageW(hWnd
, WM_SYSCOMMAND
, SC_CLOSE
, 0);
1077 return DefWndNCLButtonDown(hWnd
, wParam
, lParam
);
1082 /***********************************************************************
1083 * NC_HandleNCRButtonDown
1085 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1087 LRESULT
NC_HandleNCRButtonDown( HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1090 INT hittest
= wParam
;
1096 if (!GetSystemMenu( hwnd
, FALSE
)) break;
1101 if (!GetMessageW( &msg
, 0, WM_MOUSEFIRST
, WM_MOUSELAST
)) break;
1102 if (CallMsgFilterW( &msg
, MSGF_MAX
)) continue;
1103 if (msg
.message
== WM_RBUTTONUP
)
1105 hittest
= DefWndNCHitTest( hwnd
, msg
.pt
);
1108 if (hwnd
!= GetCapture()) return 0;
1111 if (hittest
== HTCAPTION
|| hittest
== HTSYSMENU
)
1113 ERR("Msg pt %x and Msg.lParam %x and lParam %x\n",MAKELONG(msg
.pt
.x
,msg
.pt
.y
),msg
.lParam
,lParam
);
1114 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_MOUSEMENU
+ HTSYSMENU
, msg
.lParam
);
1121 /***********************************************************************
1124 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
1125 * but without the borders (if any).
1126 * The rectangle is in window coordinates (for drawing with GetWindowDC()).
1128 static void FASTCALL
1129 NcGetInsideRect(HWND Wnd
, RECT
*Rect
)
1134 GetWindowRect(Wnd
, Rect
);
1135 Rect
->right
= Rect
->right
- Rect
->left
;
1137 Rect
->bottom
= Rect
->bottom
- Rect
->top
;
1140 Style
= GetWindowLongPtrW(Wnd
, GWL_STYLE
);
1141 if (0 != (Style
& WS_ICONIC
))
1146 /* Remove frame from rectangle */
1147 ExStyle
= GetWindowLongPtrW(Wnd
, GWL_EXSTYLE
);
1148 if (HAS_THICKFRAME(Style
, ExStyle
))
1150 InflateRect(Rect
, - GetSystemMetrics(SM_CXFRAME
), - GetSystemMetrics(SM_CYFRAME
));
1152 else if (HAS_DLGFRAME(Style
, ExStyle
))
1154 InflateRect(Rect
, - GetSystemMetrics(SM_CXDLGFRAME
), - GetSystemMetrics(SM_CYDLGFRAME
));
1156 else if (HAS_THINFRAME(Style
, ExStyle
))
1158 InflateRect(Rect
, - GetSystemMetrics(SM_CXBORDER
), - GetSystemMetrics(SM_CYBORDER
));
1161 /* We have additional border information if the window
1162 * is a child (but not an MDI child) */
1163 if (0 != (Style
& WS_CHILD
)
1164 && 0 == (ExStyle
& WS_EX_MDICHILD
))
1166 if (0 != (ExStyle
& WS_EX_CLIENTEDGE
))
1168 InflateRect(Rect
, - GetSystemMetrics(SM_CXEDGE
), - GetSystemMetrics(SM_CYEDGE
));
1170 if (0 != (ExStyle
& WS_EX_STATICEDGE
))
1172 InflateRect(Rect
, - GetSystemMetrics(SM_CXBORDER
), - GetSystemMetrics(SM_CYBORDER
));
1177 /***********************************************************************
1181 NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
)
1187 GetWindowRect(Wnd
, Rect
);
1191 NcGetInsideRect(Wnd
, Rect
);
1192 GetWindowRect(Wnd
, &WindowRect
);
1193 OffsetRect(Rect
, WindowRect
.left
, WindowRect
.top
);
1194 if (0 != (GetWindowLongPtrW(Wnd
, GWL_STYLE
) & WS_CHILD
))
1196 ClientToScreen(GetParent(Wnd
), (POINT
*) Rect
);
1198 Rect
->right
= Rect
->left
+ GetSystemMetrics(SM_CYCAPTION
) - 1;
1199 Rect
->bottom
= Rect
->top
+ GetSystemMetrics(SM_CYCAPTION
) - 1;
1203 /* PUBLIC FUNCTIONS ***********************************************************/
1206 RealAdjustWindowRectEx(LPRECT lpRect
,
1215 lpRect
->top
-= GetSystemMetrics(SM_CYMENU
);
1217 if ((dwStyle
& WS_CAPTION
) == WS_CAPTION
)
1219 if (dwExStyle
& WS_EX_TOOLWINDOW
)
1220 lpRect
->top
-= GetSystemMetrics(SM_CYSMCAPTION
);
1222 lpRect
->top
-= GetSystemMetrics(SM_CYCAPTION
);
1224 UserGetWindowBorders(dwStyle
, dwExStyle
, &BorderSize
, TRUE
);
1237 AdjustWindowRectEx(LPRECT lpRect
,
1242 BOOL Hook
, Ret
= FALSE
;
1246 Hook
= BeginIfHookedUserApiHook();
1248 /* Bypass SEH and go direct. */
1249 if (!Hook
) return RealAdjustWindowRectEx(lpRect
, dwStyle
, bMenu
, dwExStyle
);
1253 Ret
= guah
.AdjustWindowRectEx(lpRect
, dwStyle
, bMenu
, dwExStyle
);
1255 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1270 AdjustWindowRect(LPRECT lpRect
,
1274 return AdjustWindowRectEx(lpRect
, dwStyle
, bMenu
, 0);
1277 // Enabling this will cause captions to draw smoother, but slower:
1278 #define DOUBLE_BUFFER_CAPTION
1284 DrawCaption(HWND hWnd
, HDC hDC
, LPCRECT lprc
, UINT uFlags
)
1286 BOOL Hook
, Ret
= FALSE
;
1290 Hook
= BeginIfHookedUserApiHook();
1292 /* Bypass SEH and go direct. */
1293 if (!Hook
) return NtUserDrawCaption(hWnd
, hDC
, lprc
, uFlags
);
1297 Ret
= guah
.DrawCaption(hWnd
, hDC
, lprc
, uFlags
);
1299 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1324 UNICODE_STRING Text
= {0};
1325 RtlInitUnicodeString(&Text
, str
);
1326 return NtUserDrawCaptionTemp(hWnd
, hDC
, rect
, hFont
, hIcon
, &Text
, uFlags
);
1348 if (!(uFlags
& DC_TEXT
) || !str
)
1349 return DrawCaptionTempW(hwnd
, hdc
, rect
, hFont
, hIcon
, NULL
, uFlags
);
1351 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
1352 if ((strW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
))))
1354 MultiByteToWideChar(CP_ACP
, 0, str
, -1, strW
, len
);
1355 ret
= DrawCaptionTempW(hwnd
, hdc
, rect
, hFont
, hIcon
, strW
, uFlags
);
1356 HeapFree(GetProcessHeap(), 0, strW
);