Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
June 2022
- 68 participants
- 3274 messages
Re: [PATCH v2 3/5] d2d1: Implement property parsing for RegisterEffectFromStream().
by Ziqing Hui
On 6/12/22 4:34 PM, Nikolay Sivov wrote:
>
>
> On 6/12/22 08:31, Ziqing Hui wrote:
>> + if (!wcscmp(name, L"DisplayName")
>> + || !wcscmp(name, L"Author")
>> + || !wcscmp(name, L"Category")
>> + || !wcscmp(name, L"Description"))
>> + {
>> + if (type != D2D1_PROPERTY_TYPE_STRING)
>> + return E_INVALIDARG;
>> + ++reg->system_property_count;
>> + }
>
> That's not going to work for nested properties, that likely can have same names as system ones.
>
Does "nested properties" means sub properties? If it does, I think it's OK because sub properties is ignored. My plan is to ignore sub properties unless we really need them in effect implementation.
So at least for now add_property() will only be called for top level properties.
>> + if (j > entry->property_count)
>> + {
>> + hr = D2DERR_INVALID_PROPERTY;
>> + goto done;
>> + }
> Should it be j == entry->property_count ?
>
June 13, 2022
Re: [PATCH v2 2/5] d2d1: Partially implement RegisterEffectFromStream().
by Ziqing Hui
On 6/12/22 4:30 PM, Nikolay Sivov wrote:
>
>
> On 6/12/22 08:31, Ziqing Hui wrote:
>> + /* Loop inside effect node */
>> + end_node_found = FALSE;
>> + while ((hr = next_xml_node(xml_reader, &node_type, &node_name)) == S_OK)
>> + {
>> + if (node_type == XmlNodeType_Element)
>> + {
>> + if (!wcscmp(node_name, L"Property"))
>> + hr = parse_property(xml_reader, reg);
>> + else if (!wcscmp(node_name, L"Inputs"))
>> + hr = parse_inputs(xml_reader, reg);
>> + else
>> + hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
>> +
>> + if (FAILED(hr))
>> + goto done;
>> + }
>> + else if (node_type == XmlNodeType_EndElement && !wcscmp(node_name, L"Effect"))
>> + {
>> + end_node_found = TRUE;
>> + break;
>> + }
>> + }
>> + hr = (SUCCEEDED(hr) && end_node_found) ? S_OK : E_INVALIDARG;
> I don't think it's necessary to check EndElement name. The structure is always N elements, followed by EndElement. Each element helper should do the same - skip EndElement on return, and skip elements you're not interested in entirely.
>
> Error handling could be better, without SUCCEEDED -> S_OK fixups, or goto's.
>
I'm thinking of failure case. The tests in the PATCH 1 show that if we meet element that are not expected, the function will return a error code (mostly HRESULT_FROM_WIN32(ERROR_NOT_FOUND)).
So I think we should not skip elements we don't interested in, we should return error for them.
Checking EndElement name is for the same reason.
Nikolay, what do you think?
June 13, 2022
Re: [PATCH 4/5] win32u: Move GetDialogBaseUnits implementation from user32.
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=116811
Your paranoid android.
=== debian11 (32 bit WoW report) ===
user32:
menu.c:2324: Test failed: test 25
June 13, 2022
Re: [PATCH 3/5] win32u: Move WM_NCACTIVATE implementation from user32.
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=116810
Your paranoid android.
=== debian11 (64 bit WoW report) ===
user32:
msg.c:6881: Test failed: SetFocus(hwnd) on a button: 5: the msg 0x0138 was expected, but got msg 0x030f instead
msg.c:6881: Test failed: SetFocus(hwnd) on a button: 8: the msg 0x8000 was expected, but got msg 0x0086 instead
msg.c:6881: Test failed: SetFocus(hwnd) on a button: 9: the msg sequence is not complete: expected 0000 - actual 0006
June 13, 2022
Re: [PATCH 2/5] win32u: Move WM_NCPAINT handling from user32.
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=116809
Your paranoid android.
=== debian11 (32 bit WoW report) ===
user32:
menu.c:2324: Test failed: test 25
June 13, 2022
[PATCH 5/5] win32u: Simplify get_text_metr_size.
by Jacek Caban
From: Jacek Caban <jacek(a)codeweavers.com>
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/win32u/sysparams.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c
index 7e43cc2f36f..be8a85bfb9f 100644
--- a/dlls/win32u/sysparams.c
+++ b/dlls/win32u/sysparams.c
@@ -2743,14 +2743,13 @@ static LONG get_char_dimentions( HDC hdc, TEXTMETRICW *metric, LONG *height )
/* get text metrics and/or "average" char width of the specified logfont
* for the specified dc */
-static void get_text_metr_size( HDC hdc, LOGFONTW *plf, TEXTMETRICW *metric, UINT *psz)
+static void get_text_metr_size( HDC hdc, LOGFONTW *lf, TEXTMETRICW *metric, UINT *psz )
{
- ENUMLOGFONTEXDVW exdv = { .elfEnumLogfontEx.elfLogFont = *plf };
HFONT hfont, hfontsav;
TEXTMETRICW tm;
UINT ret;
if (!metric) metric = &tm;
- hfont = NtGdiHfontCreate( &exdv, sizeof(exdv), 0, 0, NULL );
+ hfont = NtGdiHfontCreate( lf, sizeof(*lf), 0, 0, NULL );
if (!hfont || !(hfontsav = NtGdiSelectFont( hdc, hfont )))
{
metric->tmHeight = -1;
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/232
June 13, 2022
[PATCH 4/5] win32u: Move GetDialogBaseUnits implementation from user32.
by Jacek Caban
From: Jacek Caban <jacek(a)codeweavers.com>
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/user32/dialog.c | 17 +-----------
dlls/win32u/sysparams.c | 61 +++++++++++++++++++++++++++++++----------
include/ntuser.h | 6 ++++
3 files changed, 53 insertions(+), 31 deletions(-)
diff --git a/dlls/user32/dialog.c b/dlls/user32/dialog.c
index 66000995861..b804de90df2 100644
--- a/dlls/user32/dialog.c
+++ b/dlls/user32/dialog.c
@@ -1519,22 +1519,7 @@ BOOL WINAPI CheckRadioButton( HWND hwndDlg, int firstID,
*/
DWORD WINAPI GetDialogBaseUnits(void)
{
- static LONG cx, cy;
-
- if (!cx)
- {
- HDC hdc;
-
- if ((hdc = GetDC(0)))
- {
- cx = GdiGetCharDimensions( hdc, NULL, &cy );
- NtUserReleaseDC( 0, hdc );
- }
- TRACE( "base units = %ld,%ld\n", cx, cy );
- }
-
- return MAKELONG( MulDiv( cx, GetDpiForSystem(), USER_DEFAULT_SCREEN_DPI ),
- MulDiv( cy, GetDpiForSystem(), USER_DEFAULT_SCREEN_DPI ));
+ return NtUserGetDialogBaseUnits();
}
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c
index 20b24d9fe86..7e43cc2f36f 100644
--- a/dlls/win32u/sysparams.c
+++ b/dlls/win32u/sysparams.c
@@ -2724,38 +2724,66 @@ static void get_real_fontname( LOGFONTW *lf, WCHAR fullname[LF_FACESIZE] )
lstrcpyW( fullname, lf->lfFaceName );
}
+static LONG get_char_dimentions( HDC hdc, TEXTMETRICW *metric, LONG *height )
+{
+ SIZE sz;
+ static const WCHAR abcdW[] =
+ {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
+ 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
+ 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
+
+ if (metric && !NtGdiGetTextMetricsW( hdc, metric, 0 )) return 0;
+
+ if (!NtGdiGetTextExtentExW( hdc, abcdW, ARRAYSIZE(abcdW), 0, NULL, NULL, &sz, 0 ))
+ return 0;
+
+ if (height) *height = sz.cy;
+ return (sz.cx / 26 + 1) / 2;
+}
+
/* get text metrics and/or "average" char width of the specified logfont
* for the specified dc */
-static void get_text_metr_size( HDC hdc, LOGFONTW *plf, TEXTMETRICW * ptm, UINT *psz)
+static void get_text_metr_size( HDC hdc, LOGFONTW *plf, TEXTMETRICW *metric, UINT *psz)
{
ENUMLOGFONTEXDVW exdv = { .elfEnumLogfontEx.elfLogFont = *plf };
HFONT hfont, hfontsav;
TEXTMETRICW tm;
- if (!ptm) ptm = &tm;
+ UINT ret;
+ if (!metric) metric = &tm;
hfont = NtGdiHfontCreate( &exdv, sizeof(exdv), 0, 0, NULL );
if (!hfont || !(hfontsav = NtGdiSelectFont( hdc, hfont )))
{
- ptm->tmHeight = -1;
+ metric->tmHeight = -1;
if (psz) *psz = 10;
if (hfont) NtGdiDeleteObjectApp( hfont );
return;
}
- NtGdiGetTextMetricsW( hdc, ptm, 0 );
- if (psz)
- {
- SIZE sz;
- static const WCHAR abcdW[] =
- {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
- 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
- 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
- if (NtGdiGetTextExtentExW( hdc, abcdW, ARRAYSIZE(abcdW), 0, NULL, NULL, &sz, 0 ))
- *psz = (sz.cx / 26 + 1) / 2;
- else *psz = 10;
- }
+ ret = get_char_dimentions( hdc, metric, NULL );
+ if (psz) *psz = ret ? ret : 10;
NtGdiSelectFont( hdc, hfontsav );
NtGdiDeleteObjectApp( hfont );
}
+static DWORD get_dialog_base_units(void)
+{
+ static LONG cx, cy;
+
+ if (!cx)
+ {
+ HDC hdc;
+
+ if ((hdc = NtUserGetDCEx( 0, 0, DCX_CACHE | DCX_WINDOW )))
+ {
+ cx = get_char_dimentions( hdc, NULL, &cy );
+ NtUserReleaseDC( 0, hdc );
+ }
+ TRACE( "base units = %d,%d\n", cx, cy );
+ }
+
+ return MAKELONG( muldiv( cx, get_system_dpi(), USER_DEFAULT_SCREEN_DPI ),
+ muldiv( cy, get_system_dpi(), USER_DEFAULT_SCREEN_DPI ));
+}
+
/* adjust some of the raw values found in the registry */
static void normalize_nonclientmetrics( NONCLIENTMETRICSW *pncm)
{
@@ -4681,6 +4709,9 @@ ULONG_PTR WINAPI NtUserCallNoParam( ULONG code )
case NtUserCallNoParam_GetDesktopWindow:
return HandleToUlong( get_desktop_window() );
+ case NtUserCallNoParam_GetDialogBaseUnits:
+ return get_dialog_base_units();
+
case NtUserCallNoParam_GetInputState:
return get_input_state();
diff --git a/include/ntuser.h b/include/ntuser.h
index a918be6b7dd..f2fdab6c0f9 100644
--- a/include/ntuser.h
+++ b/include/ntuser.h
@@ -718,6 +718,7 @@ enum
{
NtUserCallNoParam_DestroyCaret,
NtUserCallNoParam_GetDesktopWindow,
+ NtUserCallNoParam_GetDialogBaseUnits,
NtUserCallNoParam_GetInputState,
NtUserCallNoParam_ReleaseCapture,
/* temporary exports */
@@ -735,6 +736,11 @@ static inline HWND NtUserGetDesktopWindow(void)
return UlongToHandle( NtUserCallNoParam( NtUserCallNoParam_GetDesktopWindow ));
}
+static inline DWORD NtUserGetDialogBaseUnits(void)
+{
+ return NtUserCallNoParam( NtUserCallNoParam_GetDialogBaseUnits );
+};
+
static inline BOOL NtUserGetInputState(void)
{
return NtUserCallNoParam( NtUserCallNoParam_GetInputState );
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/232
June 13, 2022
[PATCH 3/5] win32u: Move WM_NCACTIVATE implementation from user32.
by Jacek Caban
From: Jacek Caban <jacek(a)codeweavers.com>
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/user32/controls.h | 1 -
dlls/user32/defwnd.c | 3 -
dlls/user32/nonclient.c | 305 ----------------------------------------
dlls/win32u/defwnd.c | 27 ++++
4 files changed, 27 insertions(+), 309 deletions(-)
diff --git a/dlls/user32/controls.h b/dlls/user32/controls.h
index b12f56dda6e..83d07e4ad76 100644
--- a/dlls/user32/controls.h
+++ b/dlls/user32/controls.h
@@ -123,7 +123,6 @@ extern void MENU_EndMenu(HWND) DECLSPEC_HIDDEN;
extern HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu ) DECLSPEC_HIDDEN;
/* nonclient area */
-extern LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam ) DECLSPEC_HIDDEN;
extern void NC_HandleNCCalcSize( HWND hwnd, WPARAM wParam, RECT *winRect ) DECLSPEC_HIDDEN;
extern LRESULT NC_HandleNCHitTest( HWND hwnd, POINT pt ) DECLSPEC_HIDDEN;
extern LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam ) DECLSPEC_HIDDEN;
diff --git a/dlls/user32/defwnd.c b/dlls/user32/defwnd.c
index 89bf2c78ce4..9b23d1e6315 100644
--- a/dlls/user32/defwnd.c
+++ b/dlls/user32/defwnd.c
@@ -253,9 +253,6 @@ static LRESULT DEFWND_DefWinProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPa
(short)LOWORD(lParam), (short)HIWORD(lParam), 0, hwnd, NULL );
return 0;
- case WM_NCACTIVATE:
- return NC_HandleNCActivate( hwnd, wParam, lParam );
-
case WM_PRINT:
DEFWND_Print(hwnd, (HDC)wParam, lParam);
return 0;
diff --git a/dlls/user32/nonclient.c b/dlls/user32/nonclient.c
index b8703df8fd1..dab6b73ee1c 100644
--- a/dlls/user32/nonclient.c
+++ b/dlls/user32/nonclient.c
@@ -799,311 +799,6 @@ static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
}
-/******************************************************************************
- *
- * NC_DrawFrame
- *
- * Draw a window frame inside the given rectangle, and update the rectangle.
- *
- * Bugs
- * Many. First, just what IS a frame in Win95? Note that the 3D look
- * on the outer edge is handled by NC_DoNCPaint. As is the inner
- * edge. The inner rectangle just inside the frame is handled by the
- * Caption code.
- *
- * In short, for most people, this function should be a nop (unless
- * you LIKE thick borders in Win95/NT4.0 -- I've been working with
- * them lately, but just to get this code right). Even so, it doesn't
- * appear to be so. It's being worked on...
- *
- *****************************************************************************/
-
-static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
-{
- INT width, height;
-
- /* Firstly the "thick" frame */
- if (style & WS_THICKFRAME)
- {
- width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
- height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
-
- SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
- COLOR_INACTIVEBORDER) );
- /* Draw frame */
- PatBlt( hdc, rect->left, rect->top,
- rect->right - rect->left, height, PATCOPY );
- PatBlt( hdc, rect->left, rect->top,
- width, rect->bottom - rect->top, PATCOPY );
- PatBlt( hdc, rect->left, rect->bottom - 1,
- rect->right - rect->left, -height, PATCOPY );
- PatBlt( hdc, rect->right - 1, rect->top,
- -width, rect->bottom - rect->top, PATCOPY );
-
- InflateRect( rect, -width, -height );
- }
-
- /* Now the other bit of the frame */
- if ((style & (WS_BORDER|WS_DLGFRAME)) ||
- (exStyle & WS_EX_DLGMODALFRAME))
- {
- width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
- height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
- /* This should give a value of 1 that should also work for a border */
-
- SelectObject( hdc, GetSysColorBrush(
- (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
- COLOR_3DFACE :
- (exStyle & WS_EX_STATICEDGE) ?
- COLOR_WINDOWFRAME :
- (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
- COLOR_3DFACE :
- /* else */
- COLOR_WINDOWFRAME));
-
- /* Draw frame */
- PatBlt( hdc, rect->left, rect->top,
- rect->right - rect->left, height, PATCOPY );
- PatBlt( hdc, rect->left, rect->top,
- width, rect->bottom - rect->top, PATCOPY );
- PatBlt( hdc, rect->left, rect->bottom - 1,
- rect->right - rect->left, -height, PATCOPY );
- PatBlt( hdc, rect->right - 1, rect->top,
- -width, rect->bottom - rect->top, PATCOPY );
-
- InflateRect( rect, -width, -height );
- }
-}
-
-
-/******************************************************************************
- *
- * NC_DrawCaption
- *
- * Draw the window caption for windows.
- * The correct pen for the window frame must be selected in the DC.
- *
- *****************************************************************************/
-
-static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
- DWORD exStyle, BOOL active )
-{
- RECT r = *rect;
- WCHAR buffer[256];
- HPEN hPrevPen;
- HMENU hSysMenu;
- BOOL gradient = FALSE;
-
- hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
- ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
- WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
- COLOR_WINDOWFRAME : COLOR_3DFACE) );
- MoveToEx( hdc, r.left, r.bottom - 1, NULL );
- LineTo( hdc, r.right, r.bottom - 1 );
- SelectObject( hdc, hPrevPen );
- r.bottom--;
-
- SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
- NC_DrawCaptionBar (hdc, &r, style, active, gradient);
-
- if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
- if (NC_DrawSysButton (hwnd, hdc, FALSE))
- r.left += GetSystemMetrics(SM_CXSMICON) + 2;
- }
-
- if (style & WS_SYSMENU)
- {
- UINT state;
-
- /* Go get the sysmenu */
- hSysMenu = NtUserGetSystemMenu(hwnd, FALSE);
- state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
-
- /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
- NC_DrawCloseButton (hwnd, hdc, FALSE,
- (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
- r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
-
- if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
- {
- /* In win95 the two buttons are always there */
- /* But if the menu item is not in the menu they're disabled*/
-
- NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
- r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
-
- NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
- r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
- }
- }
-
- if (GetWindowTextW( hwnd, buffer, ARRAY_SIZE( buffer )))
- {
- NONCLIENTMETRICSW nclm;
- HFONT hFont, hOldFont;
- nclm.cbSize = sizeof(nclm);
- SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
- if (exStyle & WS_EX_TOOLWINDOW)
- hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
- else
- hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
- hOldFont = SelectObject (hdc, hFont);
- if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
- else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
- SetBkMode( hdc, TRANSPARENT );
- r.left += 2;
- DrawTextW( hdc, buffer, -1, &r,
- DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
- DeleteObject (SelectObject (hdc, hOldFont));
- }
-}
-
-
-/******************************************************************************
- * NC_DoNCPaint
- *
- * Paint the non-client area for windows.
- */
-static void NC_DoNCPaint( HWND hwnd, HRGN clip )
-{
- HDC hdc;
- RECT rfuzz, rect, rectClip;
- BOOL active;
- WND *wndPtr;
- DWORD dwStyle, dwExStyle;
- WORD flags;
- HRGN hrgn;
- RECT rectClient;
-
- if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
- dwStyle = wndPtr->dwStyle;
- dwExStyle = wndPtr->dwExStyle;
- flags = wndPtr->flags;
- WIN_ReleasePtr( wndPtr );
-
- active = flags & WIN_NCACTIVATED;
-
- TRACE("%p %d\n", hwnd, active );
-
- /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
- the call to GetDCEx implying that it is allowed not to use it either.
- However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
- will cause clipRgn to be deleted after ReleaseDC().
- Now, how is the "system" supposed to tell what happened?
- */
-
- WIN_GetRectangles( hwnd, COORDS_SCREEN, NULL, &rectClient );
- hrgn = CreateRectRgnIndirect( &rectClient );
-
- if (clip > (HRGN)1)
- {
- CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
- hdc = NtUserGetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
- }
- else
- {
- hdc = NtUserGetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
- }
-
- if (!hdc)
- {
- DeleteObject( hrgn );
- return;
- }
-
- WIN_GetRectangles( hwnd, COORDS_WINDOW, &rect, NULL );
- GetClipBox( hdc, &rectClip );
-
- SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
-
- if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
- DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
- }
- else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
- DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
- }
-
- NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
-
- if ((dwStyle & WS_CAPTION) == WS_CAPTION)
- {
- RECT r = rect;
- if (dwExStyle & WS_EX_TOOLWINDOW) {
- r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
- rect.top += GetSystemMetrics(SM_CYSMCAPTION);
- }
- else {
- r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
- rect.top += GetSystemMetrics(SM_CYCAPTION);
- }
- if( IntersectRect( &rfuzz, &r, &rectClip ) )
- NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
- }
-
- if (HAS_MENU( hwnd, dwStyle ))
- {
- RECT r = rect;
- r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
-
- TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
-
- rect.top += MENU_DrawMenuBar( hdc, &r, hwnd ) + 1;
- }
-
- TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
-
- if (dwExStyle & WS_EX_CLIENTEDGE)
- DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
-
- /* Draw the scroll-bars */
- SCROLL_DrawNCScrollBar( hwnd, hdc, dwStyle & WS_HSCROLL, dwStyle & WS_VSCROLL );
-
- /* Draw the "size-box" */
- if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
- {
- RECT r = rect;
- if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
- r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
- else
- r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
- r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
- FillRect( hdc, &r, GetSysColorBrush( COLOR_BTNFACE ) );
- }
-
- NtUserReleaseDC( hwnd, hdc );
-}
-
-
-/***********************************************************************
- * NC_HandleNCActivate
- *
- * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
- */
-LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
-{
- /* Lotus Notes draws menu descriptions in the caption of its main
- * window. When it wants to restore original "system" view, it just
- * sends WM_NCACTIVATE message to itself. Any optimizations here in
- * attempt to minimize redrawings lead to a not restored caption.
- */
- if (wParam) win_set_flags( hwnd, WIN_NCACTIVATED, 0 );
- else win_set_flags( hwnd, 0, WIN_NCACTIVATED );
-
- /* This isn't documented but is reproducible in at least XP SP2 and
- * Outlook 2007 depends on it
- */
- if (lParam != -1)
- {
- NC_DoNCPaint( hwnd, (HRGN)1 );
-
- if (NtUserGetAncestor( hwnd, GA_PARENT ) == GetDesktopWindow())
- PostMessageW( GetDesktopWindow(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd );
- }
-
- return TRUE;
-}
-
-
/***********************************************************************
* NC_HandleSetCursor
*
diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c
index 8d94bbaad90..db8187a3ea1 100644
--- a/dlls/win32u/defwnd.c
+++ b/dlls/win32u/defwnd.c
@@ -1463,6 +1463,30 @@ static LRESULT handle_nc_paint( HWND hwnd , HRGN clip )
return 0;
}
+static LRESULT handle_nc_activate( HWND hwnd, WPARAM wparam, LPARAM lparam )
+{
+ /* Lotus Notes draws menu descriptions in the caption of its main
+ * window. When it wants to restore original "system" view, it just
+ * sends WM_NCACTIVATE message to itself. Any optimizations here in
+ * attempt to minimize redrawings lead to a not restored caption.
+ */
+ if (wparam) win_set_flags( hwnd, WIN_NCACTIVATED, 0 );
+ else win_set_flags( hwnd, 0, WIN_NCACTIVATED );
+
+ /* This isn't documented but is reproducible in at least XP SP2 and
+ * Outlook 2007 depends on it
+ */
+ if (lparam != -1)
+ {
+ nc_paint( hwnd, (HRGN)1 );
+
+ if (NtUserGetAncestor( hwnd, GA_PARENT ) == get_desktop_window())
+ NtUserPostMessage( get_desktop_window(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd );
+ }
+
+ return TRUE;
+}
+
LRESULT default_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL ansi )
{
LRESULT result = 0;
@@ -1493,6 +1517,9 @@ LRESULT default_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
case WM_NCPAINT:
return handle_nc_paint( hwnd, (HRGN)wparam );
+ case WM_NCACTIVATE:
+ return handle_nc_activate( hwnd, wparam, lparam );
+
case WM_WINDOWPOSCHANGING:
return handle_window_pos_changing( hwnd, (WINDOWPOS *)lparam );
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/232
June 13, 2022
[PATCH 2/5] win32u: Move WM_NCPAINT handling from user32.
by Jacek Caban
From: Jacek Caban <jacek(a)codeweavers.com>
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/user32/controls.h | 1 -
dlls/user32/defwnd.c | 20 -
dlls/user32/nonclient.c | 23 -
dlls/user32/user_main.c | 9 +
dlls/win32u/dc.c | 5 +
dlls/win32u/defwnd.c | 786 ++++++++++++++++++++++++++++++++++-
dlls/win32u/font.c | 22 +
dlls/win32u/menu.c | 2 +-
dlls/win32u/ntuser_private.h | 2 +
dlls/win32u/sysparams.c | 6 +-
dlls/win32u/win32u_private.h | 4 +
include/ntgdi.h | 1 +
include/ntuser.h | 11 +
13 files changed, 843 insertions(+), 49 deletions(-)
diff --git a/dlls/user32/controls.h b/dlls/user32/controls.h
index 1e5b1082d50..b12f56dda6e 100644
--- a/dlls/user32/controls.h
+++ b/dlls/user32/controls.h
@@ -123,7 +123,6 @@ extern void MENU_EndMenu(HWND) DECLSPEC_HIDDEN;
extern HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu ) DECLSPEC_HIDDEN;
/* nonclient area */
-extern LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip) DECLSPEC_HIDDEN;
extern LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam ) DECLSPEC_HIDDEN;
extern void NC_HandleNCCalcSize( HWND hwnd, WPARAM wParam, RECT *winRect ) DECLSPEC_HIDDEN;
extern LRESULT NC_HandleNCHitTest( HWND hwnd, POINT pt ) DECLSPEC_HIDDEN;
diff --git a/dlls/user32/defwnd.c b/dlls/user32/defwnd.c
index c4263edac93..89bf2c78ce4 100644
--- a/dlls/user32/defwnd.c
+++ b/dlls/user32/defwnd.c
@@ -159,9 +159,6 @@ static LRESULT DEFWND_DefWinProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPa
{
switch(msg)
{
- case WM_NCPAINT:
- return NC_HandleNCPaint( hwnd, (HRGN)wParam );
-
case WM_NCMOUSEMOVE:
return NC_HandleNCMouseMove( hwnd, wParam, lParam );
@@ -422,15 +419,6 @@ static LRESULT DEFWND_DefWinProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPa
case WM_QUERYENDSESSION:
return 1;
- case WM_SETICON:
- {
- LRESULT res = NtUserMessageCall( hwnd, msg, wParam, lParam,
- 0, NtUserDefWindowProc, FALSE );
- if( (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CAPTION) == WS_CAPTION )
- NC_HandleNCPaint( hwnd , (HRGN)1 ); /* Repaint caption */
- return res;
- }
-
case WM_HELP:
SendMessageW( GetParent(hwnd), msg, wParam, lParam );
break;
@@ -590,8 +578,6 @@ LRESULT WINAPI DefWindowProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam
case WM_SETTEXT:
result = NtUserMessageCall( hwnd, msg, wParam, lParam, 0, NtUserDefWindowProc, TRUE );
- if (result && (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CAPTION) == WS_CAPTION)
- NC_HandleNCPaint( hwnd , (HRGN)1 ); /* Repaint caption */
break;
case WM_IME_CHAR:
@@ -767,12 +753,6 @@ LRESULT WINAPI DefWindowProcW(
}
break;
- case WM_SETTEXT:
- result = NtUserMessageCall( hwnd, msg, wParam, lParam, 0, NtUserDefWindowProc, FALSE );
- if (result && (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CAPTION) == WS_CAPTION)
- NC_HandleNCPaint( hwnd , (HRGN)1 ); /* Repaint caption */
- break;
-
case WM_IME_CHAR:
PostMessageW( hwnd, WM_CHAR, wParam, lParam );
break;
diff --git a/dlls/user32/nonclient.c b/dlls/user32/nonclient.c
index 2ad40b8b116..b8703df8fd1 100644
--- a/dlls/user32/nonclient.c
+++ b/dlls/user32/nonclient.c
@@ -1074,29 +1074,6 @@ static void NC_DoNCPaint( HWND hwnd, HRGN clip )
}
-
-
-/***********************************************************************
- * NC_HandleNCPaint
- *
- * Handle a WM_NCPAINT message. Called from DefWindowProc().
- */
-LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
-{
- HWND parent = NtUserGetAncestor( hwnd, GA_PARENT );
- DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
-
- if( dwStyle & WS_VISIBLE )
- {
- NC_DoNCPaint( hwnd, clip );
-
- if (parent == GetDesktopWindow())
- PostMessageW( parent, WM_PARENTNOTIFY, WM_NCPAINT, (LPARAM)hwnd );
- }
- return 0;
-}
-
-
/***********************************************************************
* NC_HandleNCActivate
*
diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c
index 755fc3d578e..5344dafd359 100644
--- a/dlls/user32/user_main.c
+++ b/dlls/user32/user_main.c
@@ -145,6 +145,8 @@ static const struct user_callbacks user_funcs =
ImmProcessKey,
ImmTranslateMessage,
NtWaitForMultipleObjects,
+ MENU_DrawMenuBar,
+ SCROLL_DrawNCScrollBar,
free_win_ptr,
MENU_GetSysMenu,
MENU_IsMenuActive,
@@ -164,6 +166,12 @@ static NTSTATUS WINAPI User32CopyImage( const struct copy_image_params *params,
return HandleToUlong( ret );
}
+static NTSTATUS WINAPI User32DrawText( const struct draw_text_params *params, ULONG size )
+{
+ size -= FIELD_OFFSET( struct draw_text_params, str );
+ return DrawTextW( params->hdc, params->str, size / sizeof(WCHAR), params->rect, params->flags );
+}
+
static NTSTATUS WINAPI User32LoadImage( const struct load_image_params *params, ULONG size )
{
HANDLE ret = LoadImageW( params->hinst, params->name, params->type,
@@ -198,6 +206,7 @@ static const void *kernel_callback_table[NtUserCallCount] =
User32CallWindowProc,
User32CallWindowsHook,
User32CopyImage,
+ User32DrawText,
User32FreeCachedClipboardData,
User32LoadDriver,
User32LoadImage,
diff --git a/dlls/win32u/dc.c b/dlls/win32u/dc.c
index f50c13d18bb..fc112f0d4b1 100644
--- a/dlls/win32u/dc.c
+++ b/dlls/win32u/dc.c
@@ -966,6 +966,11 @@ BOOL WINAPI NtGdiGetAndSetDCDword( HDC hdc, UINT method, DWORD value, DWORD *pre
dc->attr->rop_mode = value;
break;
+ case NtGdiSetTextAlign:
+ prev = dc->attr->text_align;
+ dc->attr->text_align = value;
+ break;
+
default:
WARN( "unknown method %u\n", method );
ret = FALSE;
diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c
index 3dc0ff1187b..8d94bbaad90 100644
--- a/dlls/win32u/defwnd.c
+++ b/dlls/win32u/defwnd.c
@@ -24,13 +24,43 @@
#pragma makedep unix
#endif
-#include "win32u_private.h"
+#include "ntgdi_private.h"
#include "ntuser_private.h"
#include "wine/server.h"
WINE_DEFAULT_DEBUG_CHANNEL(win);
+static BOOL has_dialog_frame( UINT style, UINT ex_style )
+{
+ return (ex_style & WS_EX_DLGMODALFRAME) || ((style & WS_DLGFRAME) && !(style & WS_THICKFRAME));
+}
+
+static BOOL has_thick_frame( UINT style, UINT ex_style )
+{
+ return (style & WS_THICKFRAME) && (style & (WS_DLGFRAME|WS_BORDER)) != WS_DLGFRAME;
+}
+
+static BOOL has_thin_frame( UINT style )
+{
+ return (style & WS_BORDER) || !(style & (WS_CHILD | WS_POPUP));
+}
+
+static BOOL has_big_frame( UINT style, UINT ex_style )
+{
+ return (style & (WS_THICKFRAME | WS_DLGFRAME)) || (ex_style & WS_EX_DLGMODALFRAME);
+}
+
+static BOOL has_static_outer_frame( UINT ex_style )
+{
+ return (ex_style & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE;
+}
+
+static BOOL has_menu( HWND hwnd, UINT style )
+{
+ return (style & (WS_CHILD | WS_POPUP)) != WS_CHILD && get_menu( hwnd );
+}
+
void fill_rect( HDC dc, const RECT *rect, HBRUSH hbrush )
{
HBRUSH prev_brush;
@@ -66,6 +96,151 @@ static BOOL draw_focus_rect( HDC hdc, const RECT *rc )
return TRUE;
}
+static const signed char lt_inner_normal[] = {
+ -1, -1, -1, -1,
+ -1, COLOR_BTNHIGHLIGHT, COLOR_BTNHIGHLIGHT, -1,
+ -1, COLOR_3DDKSHADOW, COLOR_3DDKSHADOW, -1,
+ -1, -1, -1, -1
+};
+
+static const signed char lt_outer_normal[] = {
+ -1, COLOR_3DLIGHT, COLOR_BTNSHADOW, -1,
+ COLOR_BTNHIGHLIGHT, COLOR_3DLIGHT, COLOR_BTNSHADOW, -1,
+ COLOR_3DDKSHADOW, COLOR_3DLIGHT, COLOR_BTNSHADOW, -1,
+ -1, COLOR_3DLIGHT, COLOR_BTNSHADOW, -1
+};
+
+static const signed char rb_inner_normal[] = {
+ -1, -1, -1, -1,
+ -1, COLOR_BTNSHADOW, COLOR_BTNSHADOW, -1,
+ -1, COLOR_3DLIGHT, COLOR_3DLIGHT, -1,
+ -1, -1, -1, -1
+};
+
+static const signed char rb_outer_normal[] = {
+ -1, COLOR_3DDKSHADOW, COLOR_BTNHIGHLIGHT, -1,
+ COLOR_BTNSHADOW, COLOR_3DDKSHADOW, COLOR_BTNHIGHLIGHT, -1,
+ COLOR_3DLIGHT, COLOR_3DDKSHADOW, COLOR_BTNHIGHLIGHT, -1,
+ -1, COLOR_3DDKSHADOW, COLOR_BTNHIGHLIGHT, -1
+};
+
+static const signed char ltrb_outer_mono[] = {
+ -1, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
+ COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
+ COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
+ COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
+};
+
+static const signed char ltrb_inner_mono[] = {
+ -1, -1, -1, -1,
+ -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
+ -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
+ -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
+};
+
+static BOOL draw_rect_edge( HDC hdc, RECT *rc, UINT type, UINT flags, UINT width )
+{
+ int lbi_offset = 0, lti_offset = 0, rti_offset = 0, rbi_offset = 0;
+ signed char lt_inner, lt_outer, rb_inner, rb_outer;
+ HBRUSH lti_brush, lto_brush, rbi_brush, rbo_brush;
+ RECT inner_rect = *rc, rect;
+ BOOL retval;
+
+ retval = !((type & BDR_INNER) == BDR_INNER || (type & BDR_OUTER) == BDR_OUTER) &&
+ !(flags & (BF_FLAT|BF_MONO));
+
+ lti_brush = lto_brush = rbi_brush = rbo_brush = GetStockObject( NULL_BRUSH );
+
+ /* Determine the colors of the edges */
+ lt_inner = lt_inner_normal[type & (BDR_INNER|BDR_OUTER)];
+ lt_outer = lt_outer_normal[type & (BDR_INNER|BDR_OUTER)];
+ rb_inner = rb_inner_normal[type & (BDR_INNER|BDR_OUTER)];
+ rb_outer = rb_outer_normal[type & (BDR_INNER|BDR_OUTER)];
+
+ if ((flags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT) lbi_offset = width;
+ if ((flags & BF_TOPRIGHT) == BF_TOPRIGHT) rti_offset = width;
+ if ((flags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) rbi_offset = width;
+ if ((flags & BF_TOPLEFT) == BF_TOPLEFT) lti_offset = width;
+
+ if (lt_inner != -1) lti_brush = get_sys_color_brush( lt_inner );
+ if (lt_outer != -1) lto_brush = get_sys_color_brush( lt_outer );
+ if (rb_inner != -1) rbi_brush = get_sys_color_brush( rb_inner );
+ if (rb_outer != -1) rbo_brush = get_sys_color_brush( rb_outer );
+
+ /* Draw the outer edge */
+ if (flags & BF_TOP)
+ {
+ rect = inner_rect;
+ rect.bottom = rect.top + width;
+ fill_rect( hdc, &rect, lto_brush );
+ }
+ if (flags & BF_LEFT)
+ {
+ rect = inner_rect;
+ rect.right = rect.left + width;
+ fill_rect( hdc, &rect, lto_brush );
+ }
+ if (flags & BF_BOTTOM)
+ {
+ rect = inner_rect;
+ rect.top = rect.bottom - width;
+ fill_rect( hdc, &rect, rbo_brush );
+ }
+ if (flags & BF_RIGHT)
+ {
+ rect = inner_rect;
+ rect.left = rect.right - width;
+ fill_rect( hdc, &rect, rbo_brush );
+ }
+
+ /* Draw the inner edge */
+ if (flags & BF_TOP)
+ {
+ SetRect( &rect, inner_rect.left + lti_offset, inner_rect.top + width,
+ inner_rect.right - rti_offset, inner_rect.top + 2 * width );
+ fill_rect( hdc, &rect, lti_brush );
+ }
+ if (flags & BF_LEFT)
+ {
+ SetRect( &rect, inner_rect.left + width, inner_rect.top + lti_offset,
+ inner_rect.left + 2 * width, inner_rect.bottom - lbi_offset );
+ fill_rect( hdc, &rect, lti_brush );
+ }
+ if (flags & BF_BOTTOM)
+ {
+ SetRect( &rect, inner_rect.left + lbi_offset, inner_rect.bottom - 2 * width,
+ inner_rect.right - rbi_offset, inner_rect.bottom - width );
+ fill_rect( hdc, &rect, rbi_brush );
+ }
+ if (flags & BF_RIGHT)
+ {
+ SetRect( &rect, inner_rect.right - 2 * width, inner_rect.top + rti_offset,
+ inner_rect.right - width, inner_rect.bottom - rbi_offset );
+ fill_rect( hdc, &rect, rbi_brush );
+ }
+
+ if (((flags & BF_MIDDLE) && retval) || (flags & BF_ADJUST))
+ {
+ int add = (ltrb_inner_mono[type & (BDR_INNER|BDR_OUTER)] != -1 ? width : 0)
+ + (ltrb_outer_mono[type & (BDR_INNER|BDR_OUTER)] != -1 ? width : 0);
+
+ if (flags & BF_LEFT) inner_rect.left += add;
+ if (flags & BF_RIGHT) inner_rect.right -= add;
+ if (flags & BF_TOP) inner_rect.top += add;
+ if (flags & BF_BOTTOM) inner_rect.bottom -= add;
+
+ if ((flags & BF_MIDDLE) && retval)
+ {
+ fill_rect( hdc, &inner_rect, get_sys_color_brush( flags & BF_MONO ?
+ COLOR_WINDOW : COLOR_BTNFACE ));
+ }
+
+ if (flags & BF_ADJUST) *rc = inner_rect;
+ }
+
+ return retval;
+}
+
/***********************************************************************
* AdjustWindowRectEx (win32u.so)
*/
@@ -686,6 +861,608 @@ static LRESULT handle_sys_command( HWND hwnd, WPARAM wparam, LPARAM lparam )
return 0;
}
+/* Get the 'inside' rectangle of a window, i.e. the whole window rectangle
+ * but without the borders (if any). */
+static void get_inside_rect( HWND hwnd, enum coords_relative relative, RECT *rect,
+ DWORD style, DWORD ex_style )
+{
+ get_window_rects( hwnd, relative, rect, NULL, get_thread_dpi() );
+
+ /* Remove frame from rectangle */
+ if (has_thick_frame( style, ex_style ))
+ {
+ InflateRect( rect, -get_system_metrics( SM_CXFRAME ), -get_system_metrics( SM_CYFRAME ));
+ }
+ else if (has_dialog_frame( style, ex_style ))
+ {
+ InflateRect( rect, -get_system_metrics( SM_CXDLGFRAME ), -get_system_metrics( SM_CYDLGFRAME ));
+ }
+ else if (has_thin_frame( style ))
+ {
+ InflateRect( rect, -get_system_metrics( SM_CXBORDER ), -get_system_metrics( SM_CYBORDER ));
+ }
+
+ /* We have additional border information if the window
+ * is a child (but not an MDI child) */
+ if ((style & WS_CHILD) && !(ex_style & WS_EX_MDICHILD))
+ {
+ if (ex_style & WS_EX_CLIENTEDGE)
+ InflateRect( rect, -get_system_metrics( SM_CXEDGE ), -get_system_metrics( SM_CYEDGE ));
+ if (ex_style & WS_EX_STATICEDGE)
+ InflateRect( rect, -get_system_metrics( SM_CXBORDER ), -get_system_metrics( SM_CYBORDER ));
+ }
+}
+
+/* Draw a window frame inside the given rectangle, and update the rectangle. */
+static void draw_nc_frame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD ex_style )
+{
+ INT width, height;
+
+ if (style & WS_THICKFRAME)
+ {
+ width = get_system_metrics( SM_CXFRAME ) - get_system_metrics( SM_CXDLGFRAME );
+ height = get_system_metrics( SM_CYFRAME ) - get_system_metrics( SM_CYDLGFRAME );
+
+ NtGdiSelectBrush( hdc, get_sys_color_brush( active ? COLOR_ACTIVEBORDER :
+ COLOR_INACTIVEBORDER ));
+ /* Draw frame */
+ NtGdiPatBlt( hdc, rect->left, rect->top, rect->right - rect->left, height, PATCOPY );
+ NtGdiPatBlt( hdc, rect->left, rect->top, width, rect->bottom - rect->top, PATCOPY );
+ NtGdiPatBlt( hdc, rect->left, rect->bottom - 1, rect->right - rect->left, -height, PATCOPY );
+ NtGdiPatBlt( hdc, rect->right - 1, rect->top, -width, rect->bottom - rect->top, PATCOPY );
+
+ InflateRect( rect, -width, -height );
+ }
+
+ /* Now the other bit of the frame */
+ if ((style & (WS_BORDER|WS_DLGFRAME)) || (ex_style & WS_EX_DLGMODALFRAME))
+ {
+ DWORD color;
+
+ width = get_system_metrics( SM_CXDLGFRAME ) - get_system_metrics( SM_CXEDGE );
+ height = get_system_metrics( SM_CYDLGFRAME ) - get_system_metrics( SM_CYEDGE );
+ /* This should give a value of 1 that should also work for a border */
+
+ if (ex_style & (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE)) color = COLOR_3DFACE;
+ else if (ex_style & WS_EX_STATICEDGE) color = COLOR_WINDOWFRAME;
+ else if (style & (WS_DLGFRAME|WS_THICKFRAME)) color = COLOR_3DFACE;
+ else color = COLOR_WINDOWFRAME;
+ NtGdiSelectBrush( hdc, get_sys_color_brush( color ));
+
+ /* Draw frame */
+ NtGdiPatBlt( hdc, rect->left, rect->top,
+ rect->right - rect->left, height, PATCOPY );
+ NtGdiPatBlt( hdc, rect->left, rect->top,
+ width, rect->bottom - rect->top, PATCOPY );
+ NtGdiPatBlt( hdc, rect->left, rect->bottom - 1,
+ rect->right - rect->left, -height, PATCOPY );
+ NtGdiPatBlt( hdc, rect->right - 1, rect->top,
+ -width, rect->bottom - rect->top, PATCOPY );
+
+ InflateRect( rect, -width, -height );
+ }
+}
+
+static HICON get_nc_icon_for_window( HWND hwnd )
+{
+ HICON icon = 0;
+ WND *win = get_win_ptr( hwnd );
+
+ if (win && win != WND_OTHER_PROCESS && win != WND_DESKTOP)
+ {
+ icon = win->hIconSmall;
+ if (!icon) icon = win->hIcon;
+ release_win_ptr( win );
+ }
+ if (!icon) icon = (HICON) get_class_long_ptr( hwnd, GCLP_HICONSM, FALSE );
+ if (!icon) icon = (HICON) get_class_long_ptr( hwnd, GCLP_HICON, FALSE );
+
+ /* If there is no icon specified and this is not a modal dialog, get the default one. */
+ if (!icon && !(get_window_long( hwnd, GWL_EXSTYLE ) & WS_EX_DLGMODALFRAME))
+ icon = LoadImageW( 0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, get_system_metrics( SM_CXSMICON ),
+ get_system_metrics( SM_CYSMICON ), LR_DEFAULTCOLOR | LR_SHARED );
+ return icon;
+}
+
+/* Draws the bar part (ie the big rectangle) of the caption */
+static void draw_caption_bar( HDC hdc, const RECT *rect, DWORD style, BOOL active, BOOL gradient )
+{
+ if (gradient)
+ {
+ TRIVERTEX vertices[4];
+ DWORD left, right;
+ int buttons_size = get_system_metrics( SM_CYCAPTION ) - 1;
+
+ static GRADIENT_RECT mesh[] = {{0, 1}, {1, 2}, {2, 3}};
+
+ left = get_sys_color( active ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION );
+ right = get_sys_color( active ? COLOR_GRADIENTACTIVECAPTION : COLOR_GRADIENTINACTIVECAPTION );
+ vertices[0].Red = vertices[1].Red = GetRValue( left ) << 8;
+ vertices[0].Green = vertices[1].Green = GetGValue( left ) << 8;
+ vertices[0].Blue = vertices[1].Blue = GetBValue( left ) << 8;
+ vertices[0].Alpha = vertices[1].Alpha = 0xff00;
+ vertices[2].Red = vertices[3].Red = GetRValue( right ) << 8;
+ vertices[2].Green = vertices[3].Green = GetGValue( right ) << 8;
+ vertices[2].Blue = vertices[3].Blue = GetBValue( right ) << 8;
+ vertices[2].Alpha = vertices[3].Alpha = 0xff00;
+
+ if ((style & WS_SYSMENU) && ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX)))
+ buttons_size += 2 * (get_system_metrics( SM_CXSIZE ) + 1);
+
+ /* area behind icon; solid filled with left color */
+ vertices[0].x = rect->left;
+ vertices[0].y = rect->top;
+ if (style & WS_SYSMENU)
+ vertices[1].x = min( rect->left + get_system_metrics( SM_CXSMICON ), rect->right );
+ else
+ vertices[1].x = vertices[0].x;
+ vertices[1].y = rect->bottom;
+
+ /* area behind text; gradient */
+ vertices[2].x = max( vertices[1].x, rect->right - buttons_size );
+ vertices[2].y = rect->top;
+
+ /* area behind buttons; solid filled with right color */
+ vertices[3].x = rect->right;
+ vertices[3].y = rect->bottom;
+
+ NtGdiGradientFill( hdc, vertices, 4, mesh, 3, GRADIENT_FILL_RECT_H );
+ }
+ else
+ {
+ DWORD color = active ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION;
+ fill_rect( hdc, rect, get_sys_color_brush( color ));
+ }
+}
+
+/* Draw the system icon */
+static BOOL draw_nc_sys_button( HWND hwnd, HDC hdc, BOOL down )
+{
+ HICON icon = get_nc_icon_for_window( hwnd );
+
+ if (icon)
+ {
+ RECT rect;
+ POINT pt;
+ DWORD style = get_window_long( hwnd, GWL_STYLE );
+ DWORD ex_style = get_window_long( hwnd, GWL_EXSTYLE );
+
+ get_inside_rect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
+ pt.x = rect.left + 2;
+ pt.y = rect.top + (get_system_metrics( SM_CYCAPTION ) - get_system_metrics( SM_CYSMICON )) / 2;
+ NtUserDrawIconEx( hdc, pt.x, pt.y, icon,
+ get_system_metrics( SM_CXSMICON ),
+ get_system_metrics( SM_CYSMICON ), 0, 0, DI_NORMAL );
+ }
+
+ return icon != 0;
+}
+
+/* Create a square rectangle and return its width */
+static int make_square_rect( RECT *src, RECT *dst )
+{
+ int width = src->right - src->left;
+ int height = src->bottom - src->top;
+ int small_diam = width > height ? height : width;
+
+ *dst = *src;
+
+ /* Make it a square box */
+ if (width < height)
+ {
+ dst->top += (height - width) / 2;
+ dst->bottom = dst->top + small_diam;
+ }
+ else if (width > height)
+ {
+ dst->left += (width - height) / 2;
+ dst->right = dst->left + small_diam;
+ }
+
+ return small_diam;
+}
+
+static void draw_checked_rect( HDC dc, RECT *rect )
+{
+ if (get_sys_color( COLOR_BTNHIGHLIGHT ) == RGB( 255, 255, 255 ))
+ {
+ HBRUSH prev_brush;
+ DWORD prev_bg;
+
+ fill_rect( dc, rect, get_sys_color_brush( COLOR_BTNFACE ));
+ NtGdiGetAndSetDCDword( dc, NtGdiSetBkColor, RGB(255, 255, 255), &prev_bg );
+ prev_brush = NtGdiSelectBrush( dc, get_55aa_brush() );
+ NtGdiPatBlt( dc, rect->left, rect->top, rect->right-rect->left,
+ rect->bottom-rect->top, 0x00fa0089 );
+ NtGdiSelectBrush( dc, prev_brush );
+ NtGdiGetAndSetDCDword( dc, NtGdiSetBkColor, prev_bg, NULL );
+ }
+ else
+ {
+ fill_rect( dc, rect, get_sys_color_brush( COLOR_BTNHIGHLIGHT ));
+ }
+}
+
+static BOOL draw_push_button( HDC dc, RECT *r, UINT flags )
+{
+ RECT rect = *r;
+ UINT edge;
+
+ if (flags & (DFCS_PUSHED | DFCS_CHECKED | DFCS_FLAT))
+ edge = EDGE_SUNKEN;
+ else
+ edge = EDGE_RAISED;
+
+ if (flags & DFCS_CHECKED)
+ {
+ if (flags & DFCS_MONO)
+ draw_rect_edge( dc, &rect, edge, BF_MONO|BF_RECT|BF_ADJUST, 1 );
+ else
+ draw_rect_edge( dc, &rect, edge, (flags & DFCS_FLAT)|BF_RECT|BF_SOFT|BF_ADJUST, 1 );
+ if (!(flags & DFCS_TRANSPARENT)) draw_checked_rect( dc, &rect );
+ }
+ else
+ {
+ if (flags & DFCS_MONO)
+ {
+ draw_rect_edge( dc, &rect, edge, BF_MONO|BF_RECT|BF_ADJUST, 1 );
+ if (!(flags & DFCS_TRANSPARENT))
+ fill_rect( dc, &rect, get_sys_color_brush( COLOR_BTNFACE ));
+ }
+ else
+ {
+ UINT edge_flags = BF_RECT | BF_SOFT | (flags & DFCS_FLAT);
+ if (!(flags & DFCS_TRANSPARENT)) edge_flags |= BF_MIDDLE;
+ draw_rect_edge( dc, r, edge, edge_flags, 1 );
+ }
+ }
+
+ /* Adjust rectangle if asked */
+ if (flags & DFCS_ADJUSTRECT) InflateRect( r, -2, -2 );
+ return TRUE;
+}
+
+static BOOL draw_frame_caption( HDC dc, RECT *r, UINT flags )
+{
+ RECT rect;
+ int small_diam = make_square_rect( r, &rect ) - 2;
+ HFONT prev_font, font;
+ int color_idx = flags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
+ int xc = (rect.left + rect.right) / 2;
+ int yc = (rect.top + rect.bottom) / 2;
+ LOGFONTW lf = { 0 };
+ WCHAR str[] = {0, 0};
+ DWORD prev_align, prev_bk;
+ COLORREF prev_color;
+ SIZE size;
+
+ static const WCHAR marlettW[] = {'M','a','r','l','e','t','t',0};
+
+ draw_push_button( dc, r, flags & 0xff00 );
+
+ switch (flags & 0xf)
+ {
+ case DFCS_CAPTIONCLOSE: str[0] = 0x72; break;
+ case DFCS_CAPTIONHELP: str[0] = 0x73; break;
+ case DFCS_CAPTIONMIN: str[0] = 0x30; break;
+ case DFCS_CAPTIONMAX: str[0] = 0x31; break;
+ case DFCS_CAPTIONRESTORE: str[0] = 0x32; break;
+ default:
+ WARN( "Invalid caption; flags=0x%04x\n", flags );
+ return FALSE;
+ }
+
+ lf.lfHeight = -small_diam;
+ lf.lfWeight = FW_NORMAL;
+ lf.lfCharSet = SYMBOL_CHARSET;
+ lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
+ memcpy( lf.lfFaceName, marlettW, sizeof(marlettW) );
+ font = NtGdiHfontCreate( &lf, sizeof(lf), 0, 0, NULL );
+ NtGdiGetAndSetDCDword( dc, NtGdiSetTextAlign, TA_TOP | TA_LEFT, &prev_align );
+ NtGdiGetAndSetDCDword( dc, NtGdiSetBkMode, TRANSPARENT, &prev_bk );
+ NtGdiGetDCDword( dc, NtGdiGetTextColor, &prev_color );
+ prev_font = NtGdiSelectFont( dc, font );
+ NtGdiGetTextExtentExW( dc, str, 1, 0, NULL, NULL, &size, 0 );
+
+ if (flags & DFCS_INACTIVE)
+ {
+ NtGdiGetAndSetDCDword( dc, NtGdiSetTextColor, get_sys_color(COLOR_BTNHIGHLIGHT), NULL );
+ NtGdiExtTextOutW( dc, xc-size.cx/2+1, yc-size.cy/2+1, 0, NULL, str, 1, NULL, 0 );
+ }
+ NtGdiGetAndSetDCDword( dc, NtGdiSetTextColor, get_sys_color( color_idx ), NULL );
+ NtGdiExtTextOutW( dc, xc-size.cx/2, yc-size.cy/2, 0, NULL, str, 1, NULL, 0 );
+
+ NtGdiSelectFont(dc, prev_font);
+ NtGdiGetAndSetDCDword( dc, NtGdiSetTextColor, prev_color, NULL );
+ NtGdiGetAndSetDCDword( dc, NtGdiSetTextAlign, prev_align, NULL );
+ NtGdiGetAndSetDCDword( dc, NtGdiSetBkMode, prev_bk, NULL );
+ NtGdiDeleteObjectApp( font );
+
+ return TRUE;
+}
+
+static void draw_close_button( HWND hwnd, HDC hdc, BOOL down, BOOL grayed )
+{
+ RECT rect;
+ DWORD style = get_window_long( hwnd, GWL_STYLE );
+ DWORD ex_style = get_window_long( hwnd, GWL_EXSTYLE );
+ UINT flags = DFCS_CAPTIONCLOSE;
+
+ get_inside_rect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
+
+ /* A tool window has a smaller Close button */
+ if (ex_style & WS_EX_TOOLWINDOW)
+ {
+ /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE
+ * it uses 11x11 for the close button in tool window */
+ const int bmp_height = 11;
+ const int bmp_width = 11;
+ int caption_height = get_system_metrics( SM_CYSMCAPTION );
+
+ rect.top = rect.top + (caption_height - 1 - bmp_height) / 2;
+ rect.left = rect.right - (caption_height + 1 + bmp_width) / 2;
+ rect.bottom = rect.top + bmp_height;
+ rect.right = rect.left + bmp_width;
+ }
+ else
+ {
+ rect.left = rect.right - get_system_metrics( SM_CXSIZE );
+ rect.bottom = rect.top + get_system_metrics( SM_CYSIZE ) - 2;
+ rect.top += 2;
+ rect.right -= 2;
+ }
+
+ if (down) flags |= DFCS_PUSHED;
+ if (grayed) flags |= DFCS_INACTIVE;
+ draw_frame_caption( hdc, &rect, flags );
+}
+
+static void draw_max_button( HWND hwnd, HDC hdc, BOOL down, BOOL grayed )
+{
+ RECT rect;
+ UINT flags;
+ DWORD style = get_window_long( hwnd, GWL_STYLE );
+ DWORD ex_style = get_window_long( hwnd, GWL_EXSTYLE );
+
+ /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
+ if (ex_style & WS_EX_TOOLWINDOW) return;
+
+ flags = (style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
+
+ get_inside_rect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
+ if (style & WS_SYSMENU) rect.right -= get_system_metrics( SM_CXSIZE );
+ rect.left = rect.right - get_system_metrics( SM_CXSIZE );
+ rect.bottom = rect.top + get_system_metrics( SM_CYSIZE ) - 2;
+ rect.top += 2;
+ rect.right -= 2;
+ if (down) flags |= DFCS_PUSHED;
+ if (grayed) flags |= DFCS_INACTIVE;
+ draw_frame_caption( hdc, &rect, flags );
+}
+
+static void draw_min_button( HWND hwnd, HDC hdc, BOOL down, BOOL grayed )
+{
+ RECT rect;
+ UINT flags;
+ DWORD style = get_window_long( hwnd, GWL_STYLE );
+ DWORD ex_style = get_window_long( hwnd, GWL_EXSTYLE );
+
+ /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
+ if (ex_style & WS_EX_TOOLWINDOW) return;
+
+ flags = (style & WS_MINIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMIN;
+
+ get_inside_rect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
+ if (style & WS_SYSMENU)
+ rect.right -= get_system_metrics( SM_CXSIZE );
+ if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
+ rect.right -= get_system_metrics( SM_CXSIZE ) - 2;
+ rect.left = rect.right - get_system_metrics( SM_CXSIZE );
+ rect.bottom = rect.top + get_system_metrics( SM_CYSIZE ) - 2;
+ rect.top += 2;
+ rect.right -= 2;
+ if (down) flags |= DFCS_PUSHED;
+ if (grayed) flags |= DFCS_INACTIVE;
+ draw_frame_caption( hdc, &rect, flags );
+}
+
+static void draw_nc_caption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
+ DWORD ex_style, BOOL active )
+{
+ RECT r = *rect;
+ WCHAR buffer[256];
+ HPEN prev_pen;
+ HMENU sys_menu;
+ BOOL gradient = FALSE;
+ UINT pen_color = COLOR_3DFACE;
+ int len;
+
+ if ((ex_style & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE)
+ pen_color = COLOR_WINDOWFRAME;
+ prev_pen = NtGdiSelectPen( hdc, get_sys_color_pen( pen_color ));
+ NtGdiMoveTo( hdc, r.left, r.bottom - 1, NULL );
+ NtGdiLineTo( hdc, r.right, r.bottom - 1 );
+ NtGdiSelectPen( hdc, prev_pen );
+ r.bottom--;
+
+ NtUserSystemParametersInfo( SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0 );
+ draw_caption_bar( hdc, &r, style, active, gradient );
+
+ if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW))
+ {
+ if (draw_nc_sys_button( hwnd, hdc, FALSE ))
+ r.left += get_system_metrics( SM_CXSMICON ) + 2;
+ }
+
+ if (style & WS_SYSMENU)
+ {
+ UINT state;
+
+ /* Go get the sysmenu */
+ sys_menu = NtUserGetSystemMenu( hwnd, FALSE );
+ state = get_menu_state( sys_menu, SC_CLOSE, MF_BYCOMMAND );
+
+ /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
+ draw_close_button( hwnd, hdc, FALSE,
+ (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF) );
+ r.right -= get_system_metrics( SM_CYCAPTION ) - 1;
+
+ if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
+ {
+ draw_max_button( hwnd, hdc, FALSE, !(style & WS_MAXIMIZEBOX) );
+ r.right -= get_system_metrics( SM_CXSIZE ) + 1;
+
+ draw_min_button( hwnd, hdc, FALSE, !(style & WS_MINIMIZEBOX) );
+ r.right -= get_system_metrics( SM_CXSIZE ) + 1;
+ }
+ }
+
+ /* FIXME: use packed send message */
+ len = send_message( hwnd, WM_GETTEXT, ARRAY_SIZE( buffer ), (LPARAM)buffer );
+ if (len)
+ {
+ NONCLIENTMETRICSW nclm;
+ HFONT hFont, hOldFont;
+ nclm.cbSize = sizeof(nclm);
+ NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &nclm, 0 );
+ if (ex_style & WS_EX_TOOLWINDOW)
+ hFont = NtGdiHfontCreate( &nclm.lfSmCaptionFont, sizeof(nclm.lfSmCaptionFont), 0, 0, NULL );
+ else
+ hFont = NtGdiHfontCreate( &nclm.lfCaptionFont, sizeof(nclm.lfCaptionFont), 0, 0, NULL );
+ hOldFont = NtGdiSelectFont( hdc, hFont );
+ if (active)
+ NtGdiGetAndSetDCDword( hdc, NtGdiSetTextColor, get_sys_color( COLOR_CAPTIONTEXT ), NULL );
+ else
+ NtGdiGetAndSetDCDword( hdc, NtGdiSetTextColor, get_sys_color( COLOR_INACTIVECAPTIONTEXT ), NULL );
+ NtGdiGetAndSetDCDword( hdc, NtGdiSetBkMode, TRANSPARENT, NULL );
+ r.left += 2;
+ DrawTextW( hdc, buffer, -1, &r,
+ DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
+ NtGdiDeleteObjectApp( NtGdiSelectFont( hdc, hOldFont ));
+ }
+}
+
+/* Paint the non-client area for windows */
+static void nc_paint( HWND hwnd, HRGN clip )
+{
+ HDC hdc;
+ RECT rfuzz, rect, clip_rect;
+ BOOL active;
+ WND *win;
+ DWORD style, ex_style;
+ WORD flags;
+ HRGN hrgn;
+ RECT rectClient;
+
+ if (!(win = get_win_ptr( hwnd )) || win == WND_OTHER_PROCESS) return;
+ style = win->dwStyle;
+ ex_style = win->dwExStyle;
+ flags = win->flags;
+ release_win_ptr( win );
+
+ active = flags & WIN_NCACTIVATED;
+
+ TRACE( "%p %d\n", hwnd, active );
+
+ get_window_rects( hwnd, COORDS_SCREEN, NULL, &rectClient, get_thread_dpi() );
+ hrgn = NtGdiCreateRectRgn( rectClient.left, rectClient.top,
+ rectClient.right, rectClient.bottom );
+
+ if (clip > (HRGN)1)
+ {
+ NtGdiCombineRgn( hrgn, clip, hrgn, RGN_DIFF );
+ hdc = NtUserGetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
+ }
+ else
+ {
+ hdc = NtUserGetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
+ }
+
+ if (!hdc)
+ {
+ NtGdiDeleteObjectApp( hrgn );
+ return;
+ }
+
+ get_window_rects( hwnd, COORDS_WINDOW, &rect, NULL, get_thread_dpi() );
+ NtGdiGetAppClipBox( hdc, &clip_rect );
+
+ NtGdiSelectPen( hdc, get_sys_color_pen( COLOR_WINDOWFRAME ));
+
+ if (has_static_outer_frame( ex_style ))
+ draw_rect_edge( hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST, 1 );
+ else if (has_big_frame( style, ex_style ))
+ draw_rect_edge( hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST, 1 );
+
+ draw_nc_frame( hdc, &rect, active, style, ex_style );
+
+ if ((style & WS_CAPTION) == WS_CAPTION)
+ {
+ RECT r = rect;
+ if (ex_style & WS_EX_TOOLWINDOW)
+ {
+ r.bottom = rect.top + get_system_metrics( SM_CYSMCAPTION );
+ rect.top += get_system_metrics( SM_CYSMCAPTION );
+ }
+ else {
+ r.bottom = rect.top + get_system_metrics( SM_CYCAPTION );
+ rect.top += get_system_metrics( SM_CYCAPTION );
+ }
+
+ if (intersect_rect( &rfuzz, &r, &clip_rect ))
+ draw_nc_caption( hdc, &r, hwnd, style, ex_style, active );
+ }
+
+ if (has_menu( hwnd, style ))
+ {
+ RECT r = rect;
+ r.bottom = rect.top + get_system_metrics( SM_CYMENU );
+
+ TRACE( "drawing menu with rect %s\n", wine_dbgstr_rect( &r ));
+
+ if (user_callbacks)
+ rect.top += user_callbacks->draw_menu( hdc, &r, hwnd ) + 1;
+ }
+
+ TRACE( "rect after menu %s\n", wine_dbgstr_rect( &rect ));
+
+ if (ex_style & WS_EX_CLIENTEDGE)
+ draw_rect_edge( hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST, 1 );
+
+ /* Draw the scroll-bars */
+ if (user_callbacks)
+ user_callbacks->draw_nc_scrollbar( hwnd, hdc, style & WS_HSCROLL, style & WS_VSCROLL );
+
+ /* Draw the "size-box" */
+ if ((style & WS_VSCROLL) && (style & WS_HSCROLL))
+ {
+ RECT r = rect;
+ if ((ex_style & WS_EX_LEFTSCROLLBAR) != 0)
+ r.right = r.left + get_system_metrics( SM_CXVSCROLL ) + 1;
+ else
+ r.left = r.right - get_system_metrics( SM_CXVSCROLL ) + 1;
+ r.top = r.bottom - get_system_metrics( SM_CYHSCROLL ) + 1;
+ fill_rect( hdc, &r, get_sys_color_brush( COLOR_BTNFACE ) );
+ }
+
+ NtUserReleaseDC( hwnd, hdc );
+}
+
+static LRESULT handle_nc_paint( HWND hwnd , HRGN clip )
+{
+ HWND parent = NtUserGetAncestor( hwnd, GA_PARENT );
+ DWORD style = get_window_long( hwnd, GWL_STYLE );
+
+ if (style & WS_VISIBLE)
+ {
+ nc_paint( hwnd, clip );
+
+ if (parent == get_desktop_window())
+ NtUserPostMessage( parent, WM_PARENTNOTIFY, WM_NCPAINT, (LPARAM)hwnd );
+ }
+ return 0;
+}
+
LRESULT default_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL ansi )
{
LRESULT result = 0;
@@ -713,6 +1490,9 @@ LRESULT default_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
break;
}
+ case WM_NCPAINT:
+ return handle_nc_paint( hwnd, (HRGN)wparam );
+
case WM_WINDOWPOSCHANGING:
return handle_window_pos_changing( hwnd, (WINDOWPOS *)lparam );
@@ -804,10 +1584,14 @@ LRESULT default_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
case WM_SETTEXT:
result = set_window_text( hwnd, (void *)lparam, ansi );
+ if (result && (get_window_long( hwnd, GWL_STYLE ) & WS_CAPTION) == WS_CAPTION)
+ handle_nc_paint( hwnd , (HRGN)1 ); /* repaint caption */
break;
case WM_SETICON:
result = (LRESULT)set_window_icon( hwnd, wparam, (HICON)lparam );
+ if ((get_window_long( hwnd, GWL_STYLE ) & WS_CAPTION) == WS_CAPTION)
+ handle_nc_paint( hwnd , (HRGN)1 ); /* repaint caption */
break;
case WM_GETICON:
diff --git a/dlls/win32u/font.c b/dlls/win32u/font.c
index 6aa46e0949a..39b195fe25a 100644
--- a/dlls/win32u/font.c
+++ b/dlls/win32u/font.c
@@ -6573,3 +6573,25 @@ BOOL WINAPI NtGdiGetCharWidthInfo( HDC hdc, struct char_width_info *info )
release_dc_ptr(dc);
return ret;
}
+
+/***********************************************************************
+ * DrawTextW (win32u.so)
+ */
+INT WINAPI DrawTextW( HDC hdc, const WCHAR *str, INT count, RECT *rect, UINT flags )
+{
+ struct draw_text_params *params;
+ ULONG ret_len, size;
+ void *ret_ptr;
+ int ret;
+
+ if (count == -1) count = wcslen( str );
+ size = FIELD_OFFSET( struct draw_text_params, str[count] );
+ if (!(params = malloc( size ))) return 0;
+ params->hdc = hdc;
+ params->rect = rect;
+ params->flags = flags;
+ if (count) memcpy( params->str, str, count * sizeof(WCHAR) );
+ ret = KeUserModeCallback( NtUserDrawText, params, size, &ret_ptr, &ret_len );
+ free( params );
+ return ret;
+}
diff --git a/dlls/win32u/menu.c b/dlls/win32u/menu.c
index a6aeae045e2..4622105ddf1 100644
--- a/dlls/win32u/menu.c
+++ b/dlls/win32u/menu.c
@@ -824,7 +824,7 @@ static BOOL set_menu_item_info( MENUITEM *menu, const MENUITEMINFOW *info )
}
/* see GetMenuState */
-static UINT get_menu_state( HMENU handle, UINT item_id, UINT flags )
+UINT get_menu_state( HMENU handle, UINT item_id, UINT flags )
{
POPUPMENU *menu;
UINT state, pos;
diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h
index e39e3f54169..6fc1c1423bd 100644
--- a/dlls/win32u/ntuser_private.h
+++ b/dlls/win32u/ntuser_private.h
@@ -36,6 +36,8 @@ struct user_callbacks
BOOL (WINAPI *pImmProcessKey)(HWND, HKL, UINT, LPARAM, DWORD);
BOOL (WINAPI *pImmTranslateMessage)(HWND, UINT, WPARAM, LPARAM);
NTSTATUS (WINAPI *pNtWaitForMultipleObjects)(ULONG,const HANDLE*,BOOLEAN,BOOLEAN,const LARGE_INTEGER*);
+ UINT (CDECL *draw_menu)( HDC hDC, LPRECT lprect, HWND hwnd );
+ void (CDECL *draw_nc_scrollbar)( HWND hwnd, HDC hdc, BOOL draw_horizontal, BOOL draw_vertical );
void (CDECL *free_win_ptr)( struct tagWND *win );
HMENU (CDECL *get_sys_menu)( HWND hwnd, HMENU popup );
HWND (CDECL *is_menu_active)(void);
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c
index 902cd7ddb0c..20b24d9fe86 100644
--- a/dlls/win32u/sysparams.c
+++ b/dlls/win32u/sysparams.c
@@ -4499,7 +4499,7 @@ static int get_system_metrics_for_dpi( int index, unsigned int dpi )
}
}
-static COLORREF get_sys_color( int index )
+COLORREF get_sys_color( int index )
{
COLORREF ret = 0;
@@ -4508,7 +4508,7 @@ static COLORREF get_sys_color( int index )
return ret;
}
-static HBRUSH get_55aa_brush(void)
+HBRUSH get_55aa_brush(void)
{
static const WORD pattern[] = { 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa };
static HBRUSH brush_55aa;
@@ -4546,7 +4546,7 @@ HBRUSH get_sys_color_brush( unsigned int index )
return system_colors[index].brush;
}
-static HPEN get_sys_color_pen( unsigned int index )
+HPEN get_sys_color_pen( unsigned int index )
{
if (index >= ARRAY_SIZE( system_colors )) return 0;
diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h
index 957d930d9da..be15dac62e7 100644
--- a/dlls/win32u/win32u_private.h
+++ b/dlls/win32u/win32u_private.h
@@ -394,6 +394,7 @@ extern BOOL draw_menu_bar( HWND hwnd ) DECLSPEC_HIDDEN;
extern HMENU get_menu( HWND hwnd ) DECLSPEC_HIDDEN;
extern BOOL get_menu_info( HMENU handle, MENUINFO *info ) DECLSPEC_HIDDEN;
extern INT get_menu_item_count( HMENU handle ) DECLSPEC_HIDDEN;
+extern UINT get_menu_state( HMENU handle, UINT item_id, UINT flags ) DECLSPEC_HIDDEN;
extern BOOL set_window_menu( HWND hwnd, HMENU handle ) DECLSPEC_HIDDEN;
/* message.c */
@@ -411,12 +412,15 @@ extern LRESULT send_message_timeout( HWND hwnd, UINT msg, WPARAM wparam, LPARAM
/* sysparams.c */
extern BOOL enable_thunk_lock DECLSPEC_HIDDEN;
+extern HBRUSH get_55aa_brush(void) DECLSPEC_HIDDEN;
extern RECT get_display_rect( const WCHAR *display ) DECLSPEC_HIDDEN;
extern UINT get_monitor_dpi( HMONITOR monitor ) DECLSPEC_HIDDEN;
extern BOOL get_monitor_info( HMONITOR handle, MONITORINFO *info ) DECLSPEC_HIDDEN;
extern UINT get_win_monitor_dpi( HWND hwnd ) DECLSPEC_HIDDEN;
extern RECT get_primary_monitor_rect( UINT dpi ) DECLSPEC_HIDDEN;
+extern COLORREF get_sys_color( int index ) DECLSPEC_HIDDEN;
extern HBRUSH get_sys_color_brush( unsigned int index ) DECLSPEC_HIDDEN;
+extern HPEN get_sys_color_pen( unsigned int index ) DECLSPEC_HIDDEN;
extern UINT get_system_dpi(void) DECLSPEC_HIDDEN;
extern int get_system_metrics( int index ) DECLSPEC_HIDDEN;
extern UINT get_thread_dpi(void) DECLSPEC_HIDDEN;
diff --git a/include/ntgdi.h b/include/ntgdi.h
index 61ee94071a9..8fd4c5b1214 100644
--- a/include/ntgdi.h
+++ b/include/ntgdi.h
@@ -115,6 +115,7 @@ enum
NtGdiSetDCPenColor,
NtGdiSetGraphicsMode,
NtGdiSetROP2,
+ NtGdiSetTextAlign,
};
/* NtGdiGetDCDword parameter, not compatible with Windows */
diff --git a/include/ntuser.h b/include/ntuser.h
index 8320a83800f..a918be6b7dd 100644
--- a/include/ntuser.h
+++ b/include/ntuser.h
@@ -33,6 +33,7 @@ enum
NtUserCallWinProc,
NtUserCallWindowsHook,
NtUserCopyImage,
+ NtUserDrawText,
NtUserFreeCachedClipboardData,
NtUserLoadDriver,
NtUserLoadImage,
@@ -158,6 +159,16 @@ struct copy_image_params
UINT flags;
};
+/* NtUserDrawText params */
+struct draw_text_params
+{
+ HDC hdc;
+ int count;
+ RECT *rect; /* FIXME: Use NtCallbackReturn instead */
+ UINT flags;
+ WCHAR str[1];
+};
+
/* NtUserFreeCachedClipboardData params */
struct free_cached_data_params
{
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/232
June 13, 2022
[PATCH 1/5] win32u: Allow passing simple LOGFONTW to NtGdiHfontCreate.
by Jacek Caban
From: Jacek Caban <jacek(a)codeweavers.com>
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/win32u/font.c | 29 +++++++++++++++++++----------
dlls/wow64win/gdi.c | 4 ++--
include/ntgdi.h | 2 +-
3 files changed, 22 insertions(+), 13 deletions(-)
diff --git a/dlls/win32u/font.c b/dlls/win32u/font.c
index 571379976a5..6aa46e0949a 100644
--- a/dlls/win32u/font.c
+++ b/dlls/win32u/font.c
@@ -4478,26 +4478,35 @@ UINT WINAPI NtGdiGetTextCharsetInfo( HDC hdc, FONTSIGNATURE *fs, DWORD flags )
/***********************************************************************
* NtGdiHfontCreate (win32u.@)
*/
-HFONT WINAPI NtGdiHfontCreate( const ENUMLOGFONTEXDVW *penumex, ULONG size, ULONG type,
+HFONT WINAPI NtGdiHfontCreate( const void *logfont, ULONG size, ULONG type,
ULONG flags, void *data )
{
HFONT hFont;
FONTOBJ *fontPtr;
const LOGFONTW *plf;
- if (!penumex) return 0;
+ if (!logfont) return 0;
- if (penumex->elfEnumLogfontEx.elfFullName[0] ||
- penumex->elfEnumLogfontEx.elfStyle[0] ||
- penumex->elfEnumLogfontEx.elfScript[0])
+ if (size == sizeof(ENUMLOGFONTEXDVW) || size == sizeof(ENUMLOGFONTEXW))
{
- FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
- debugstr_w(penumex->elfEnumLogfontEx.elfFullName),
- debugstr_w(penumex->elfEnumLogfontEx.elfStyle),
- debugstr_w(penumex->elfEnumLogfontEx.elfScript));
+ const ENUMLOGFONTEXW *lfex = logfont;
+
+ if (lfex->elfFullName[0] || lfex->elfStyle[0] || lfex->elfScript[0])
+ {
+ FIXME( "some fields ignored. fullname=%s, style=%s, script=%s\n",
+ debugstr_w( lfex->elfFullName ), debugstr_w( lfex->elfStyle ),
+ debugstr_w( lfex->elfScript ));
+ }
+
+ plf = &lfex->elfLogFont;
+ }
+ else if (size != sizeof(LOGFONTW))
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return 0;
}
+ else plf = logfont;
- plf = &penumex->elfEnumLogfontEx.elfLogFont;
if (!(fontPtr = malloc( sizeof(*fontPtr) ))) return 0;
fontPtr->logfont = *plf;
diff --git a/dlls/wow64win/gdi.c b/dlls/wow64win/gdi.c
index c821b90122e..5fdc9906a02 100644
--- a/dlls/wow64win/gdi.c
+++ b/dlls/wow64win/gdi.c
@@ -403,13 +403,13 @@ NTSTATUS WINAPI wow64_NtGdiSetTextJustification( UINT *args )
NTSTATUS WINAPI wow64_NtGdiHfontCreate( UINT *args )
{
- const ENUMLOGFONTEXDVW *enumex = get_ptr( &args );
+ const void *logfont = get_ptr( &args );
ULONG unk2 = get_ulong( &args );
ULONG unk3 = get_ulong( &args );
ULONG unk4 = get_ulong( &args );
void *data = get_ptr( &args );
- return HandleToUlong( NtGdiHfontCreate( enumex, unk2, unk3, unk4, data ));
+ return HandleToUlong( NtGdiHfontCreate( logfont, unk2, unk3, unk4, data ));
}
NTSTATUS WINAPI wow64_NtGdiGetFontFileData( UINT *args )
diff --git a/include/ntgdi.h b/include/ntgdi.h
index 14b1dde45d5..61ee94071a9 100644
--- a/include/ntgdi.h
+++ b/include/ntgdi.h
@@ -371,7 +371,7 @@ BOOL WINAPI NtGdiGetTextMetricsW( HDC hdc, TEXTMETRICW *metrics, ULONG flags
BOOL WINAPI NtGdiGetTransform( HDC hdc, DWORD which, XFORM *xform );
BOOL WINAPI NtGdiGradientFill( HDC hdc, TRIVERTEX *vert_array, ULONG nvert,
void *grad_array, ULONG ngrad, ULONG mode );
-HFONT WINAPI NtGdiHfontCreate( const ENUMLOGFONTEXDVW *enumex, ULONG unk2, ULONG unk3,
+HFONT WINAPI NtGdiHfontCreate( const void *logfont, ULONG unk2, ULONG unk3,
ULONG unk4, void *data );
DWORD WINAPI NtGdiInitSpool(void);
INT WINAPI NtGdiIntersectClipRect( HDC hdc, INT left, INT top, INT right, INT bottom );
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/232
June 13, 2022