Replaces #26053.
https://github.com/wxWidgets/wxWidgets/pull/26182
(9 files)
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@vadz pushed 1 commit.
—
View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@PBfordev commented on this pull request.
> + if ( win )
+ {
+ wxUxThemeHandle hTheme
+ (
+ win,
+ L"LightMode_ImmersiveStart::Menu;MENU",
+ L"DarkMode_ImmersiveStart::Menu;DarkMode::Menu;MENU"
+ );
+ colBorder = hTheme.GetColour(MENU_POPUPBORDERS, TMT_FILLCOLORHINT);
+ }
+
+ if ( !colBorder.IsOk() )
+ colBorder = wxSystemSettings::GetColour(wxSYS_COLOUR_ACTIVEBORDER);
+
+ DWORD color = static_cast<DWORD>(wxColourToRGB(colBorder));
+ dwmSetWinAttr(hwnd, DWMWA_BORDER_COLOR, &color, sizeof(color));
IIRC, it was this line to which I referred in the original PR, making the menus to have very light borders, as shown in the screenshots there.
IME, such borders are not common for dark menus on MSW.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
> @@ -579,6 +586,22 @@ HandleMenuMessage(WXLRESULT* result,
switch ( nMsg )
{
+ case WM_MENUBAR_INITMENU:
+ // Menu them is turned off in high contrast mode.
+ if ( wxMSWImpl::IsHighContrast() )
+ break;
+
+ // Enable rounded corners for UAH menus
+ if ( auto* const pUahMenu = (MenuBarDrawMenu*)lParam )
+ {
+ if ( pUahMenu->dwReserved & 0x4000001 )
Should not code like this have a comment, but perhaps this magic is too dark... TBH, I don't even know what UAH menu means here...
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@vadz commented on this pull request.
> + if ( win )
+ {
+ wxUxThemeHandle hTheme
+ (
+ win,
+ L"LightMode_ImmersiveStart::Menu;MENU",
+ L"DarkMode_ImmersiveStart::Menu;DarkMode::Menu;MENU"
+ );
+ colBorder = hTheme.GetColour(MENU_POPUPBORDERS, TMT_FILLCOLORHINT);
+ }
+
+ if ( !colBorder.IsOk() )
+ colBorder = wxSystemSettings::GetColour(wxSYS_COLOUR_ACTIVEBORDER);
+
+ DWORD color = static_cast<DWORD>(wxColourToRGB(colBorder));
+ dwmSetWinAttr(hwnd, DWMWA_BORDER_COLOR, &color, sizeof(color));
What colour do they use for border under Windows 11?
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
> @@ -579,6 +586,22 @@ HandleMenuMessage(WXLRESULT* result,
switch ( nMsg )
{
+ case WM_MENUBAR_INITMENU:
+ // Menu them is turned off in high contrast mode.
+ if ( wxMSWImpl::IsHighContrast() )
+ break;
+
+ // Enable rounded corners for UAH menus
+ if ( auto* const pUahMenu = (MenuBarDrawMenu*)lParam )
+ {
+ if ( pUahMenu->dwReserved & 0x4000001 )
Unfortunately I have no idea what does this mean either so I can't write a meaningful comment for it. @memoarfaa If you have any suggestions, they would be very welcome.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@PBfordev commented on this pull request.
> + if ( win )
+ {
+ wxUxThemeHandle hTheme
+ (
+ win,
+ L"LightMode_ImmersiveStart::Menu;MENU",
+ L"DarkMode_ImmersiveStart::Menu;DarkMode::Menu;MENU"
+ );
+ colBorder = hTheme.GetColour(MENU_POPUPBORDERS, TMT_FILLCOLORHINT);
+ }
+
+ if ( !colBorder.IsOk() )
+ colBorder = wxSystemSettings::GetColour(wxSYS_COLOUR_ACTIVEBORDER);
+
+ DWORD color = static_cast<DWORD>(wxColourToRGB(colBorder));
+ dwmSetWinAttr(hwnd, DWMWA_BORDER_COLOR, &color, sizeof(color));
Well, what is the reference? Here are few examples from applications shipped with Windows.
Explorer
darkmenu-explorer.png (view on web)
Edge
darkmenu-edge.png (view on web)
Notepad
darkmenu-notepad.png (view on web)
Microsoft 365 uses light border, but its menu are different from the rest, e.g., the width of the divider:
darkmenu-office.png (view on web)
FWIW, the only Win32 application with dark mode support I use is Notepad++ which does not have a light border and nor does have it MSVS 2026.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Ugh, I've tried testing myself under Windows 11 (it's a pretty old version, 10.0.22621.3155) and it looks like dark mode is totally broken there, this is how menu sample looks for me with master (it's almost the same with this PR):
image.png (view on web)@PBfordev Do you not see this? It still works fine under Windows 10 (10.0.19044.3803) for me:
image.png (view on web)but something is very wrong under 11...
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@MaartenBent commented on this pull request.
In include/wx/msw/private/menu.h:
> @@ -15,6 +15,7 @@ namespace wxMSWMenuImpl // Definitions for undocumented messages and structs used in this code. constexpr int WM_MENUBAR_DRAWMENU = 0x91; +constexpr int WM_MENUBAR_INITMENU = 0x93;
93 after 92
> @@ -788,3 +811,51 @@ HandleMenuMessage(WXLRESULT* WXUNUSED(result),
} // namespace wxMSWDarkMode
#endif // wxUSE_DARK_MODE/!wxUSE_DARK_MODE
+
+void wxMSWImpl::EnableRoundCorners(HWND hwnd)
+{
+ const auto dwmSetWinAttr = wxDarkModeModule::GetDwmSetWindowAttribute();
+ if ( !dwmSetWinAttr )
+ return;
+
+ constexpr DWORD DWMWA_WINDOW_CORNER_PREFERENCE = 33;
+ constexpr DWORD DWMWA_BORDER_COLOR = 34;
+ constexpr int WindowCornerPreference = 3; // DWMWCP_ROUNDSMALL
+
+ // Apply rounded corners
+ HRESULT hr = dwmSetWinAttr(hwnd, DWMWA_WINDOW_CORNER_PREFERENCE,
On Windows 10, every time I open a menu the debugger logs the following:
clientcore\windows\dwm\dwmapi\attribute.cpp(185)\dwmapi.dll!00007FFFA9F62C57: (caller: 00007FFEDA0A29C1) ReturnHr(29) tid(2ef8) 80070057 The parameter is incorrect.
I don't think it supports rounded corners. Maybe limit it to Windows 11 only? Like it is already done in HandleEnterIdle.
> +
+ if ( FAILED(hr) )
+ return;
+
+ // Clean up conflicting styles like drop shadows.
+ DWORD style = ::GetClassLongPtr(hwnd, GCL_STYLE);
+ if ( style & CS_DROPSHADOW )
+ {
+ style &= ~CS_DROPSHADOW;
+ ::SetClassLongPtr(hwnd, GCL_STYLE, style);
+ }
+
+ // Determine the appropriate border colour for the current theme.
+ wxColor colBorder;
+
+ wxWindow* const win = wxTheApp ? wxTheApp->GetTopWindow() : nullptr;
You can pass a wxWindow to this function, instead of getting the main app window.
> @@ -579,6 +586,22 @@ HandleMenuMessage(WXLRESULT* result,
switch ( nMsg )
{
+ case WM_MENUBAR_INITMENU:
+ // Menu them is turned off in high contrast mode.
them -> theme
> + constexpr DWORD DWMWA_WINDOW_CORNER_PREFERENCE = 33; + constexpr DWORD DWMWA_BORDER_COLOR = 34;
To be safe, maybe these should get a WX prefix. So they won't clash with the enum values from dwmapi.h.
> + &WindowCornerPreference,
+ sizeof(WindowCornerPreference));
+
+ if ( FAILED(hr) )
+ return;
+
+ // Clean up conflicting styles like drop shadows.
+ DWORD style = ::GetClassLongPtr(hwnd, GCL_STYLE);
+ if ( style & CS_DROPSHADOW )
+ {
+ style &= ~CS_DROPSHADOW;
+ ::SetClassLongPtr(hwnd, GCL_STYLE, style);
+ }
+
+ // Determine the appropriate border colour for the current theme.
+ wxColor colBorder;
wxColour
In src/msw/menu.cpp:
> @@ -938,6 +947,31 @@ WXHMENU wxMenuBar::Create()
wxLogLastError(wxT("AppendMenu"));
}
}
+
+#if wxUSE_OWNER_DRAWN
+ // Set menu background color
+ wxUxThemeHandle hTheme
+ (
+ GetFrame()->AsWindow(),
+ L"LightMode_ImmersiveStart::Menu;Menu",
+ L"DarkMode_ImmersiveStart::Menu;Menu"
+ );
+ wxColor colMenu = hTheme.GetColour(MENU_POPUPBACKGROUND, TMT_FILLCOLOR);
wxColour
> @@ -1261,7 +1340,18 @@ void wxMenuItem::GetColourToUse(wxODStatus stat, wxColour& colText, wxColour& co
{
colText = GetTextColour();
if ( !colText.IsOk() )
- wxRGBToColour(colText, ::GetThemeSysColor(hTheme, COLOR_MENUTEXT));
+ {
+ if ( wxMSWDarkMode::IsActive() )
+ {
+ colText = hTheme.GetColour(MENU_POPUPITEM, TMT_TEXTCOLOR, MS_NORMAL);
I think this should be MPI_NORMAL instead of MS_NORMAL (both are 1). The definition at the start of this file can then be removed.
See the states for MENU_POPUPITEM in https://learn.microsoft.com/en-us/windows/win32/controls/parts-and-states
> @@ -579,6 +586,22 @@ HandleMenuMessage(WXLRESULT* result,
switch ( nMsg )
{
+ case WM_MENUBAR_INITMENU:
+ // Menu them is turned off in high contrast mode.
+ if ( wxMSWImpl::IsHighContrast() )
+ break;
+
+ // Enable rounded corners for UAH menus
+ if ( auto* const pUahMenu = (MenuBarDrawMenu*)lParam )
+ {
+ if ( pUahMenu->dwReserved & 0x4000001 )
UAH is mentioned in darkmode.cpp with a link. It seems to be a common name for the Windows messages and structs used for custom menu drawing. But I cannot find a clear definition either.
dwReserved (or dwFlags as it is called elsewhere) doesn't seem to have any documentation. But I noticed these two bits are always set when the menu is opened, and never when the menu is closed.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Ugh, I've tried testing myself under Windows 11 (it's a pretty old version, 10.0.22621.3155) and it looks like dark mode is totally broken there
Looks fine in Windows 11 25H2.
I do not have those light borders.
Screenshot.2026-02-12.123234.png (view on web)
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
I can also confirm the menus are not broken in Win11 25H2 (I don't have access to an older version) dark mode both in the master and with this PR.
The light menu border is not present any longer (unlike in the original PR), sorry.
EDIT: The menus in the PR version do not handle switching between the dark and light mode well, they DO look broken after doing that. Does not happen in the master.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@memoarfaa commented on this pull request.
> @@ -579,6 +586,22 @@ HandleMenuMessage(WXLRESULT* result,
switch ( nMsg )
{
+ case WM_MENUBAR_INITMENU:
+ // Menu them is turned off in high contrast mode.
+ if ( wxMSWImpl::IsHighContrast() )
+ break;
+
+ // Enable rounded corners for UAH menus
+ if ( auto* const pUahMenu = (MenuBarDrawMenu*)lParam )
+ {
+ if ( pUahMenu->dwReserved & 0x4000001 )
Hi @vadz , @MaartenBent , @PBfordev
UAH stands for User32 Api Hook interface and support functions.
Simple and None Completed Open Source Win NT refrences
Reactos usrapihk
Reactos themehooks
⚠️ Note: This is an ongoing investigation based on observed behavior. These flags are undocumented and may not be complete or 100% accurate. Use for educational purposes only.
| Flag Value | Type Bit 0 | State/Op | Messages Observed | Description | Themed | Non-Themed |
|---|---|---|---|---|---|---|
| 0x00000001 | Popup (1) | CREATE | WM_MENUBAR_INITMENU (0x93) | Popup menu object created | ✅ | ✅ |
| 0x00000200 | MenuBar (0) | INIT_FIRST | WM_MENUBAR_INITMENU (0x93) | First menu initialization | ✅ | ✅ |
| 0x00000A00 | MenuBar (0) | MEASURE | WM_MENUBAR_INITMENU (0x93) WM_MENUBAR_DRAWMENU (0x91) WM_MENUBAR_DRAWMENUITEM (0x92) WM_MENUBAR_MEASUREMENUITEM (0x94) |
Measuring/drawing items | ✅ | ✅ |
| 0x00000A10 | MenuBar (0) | INACTIVE | WM_MENUBAR_INITMENU (0x93) WM_MENUBAR_DRAWMENU (0x91) WM_MENUBAR_DRAWMENUITEM (0x92) |
Menu bar inactive state | ✅ | ❌ |
| 0x00000800 | MenuBar (0) | HOT | WM_MENUBAR_DRAWMENUITEM (0x92) WM_MENUBAR_DRAWMENU (0x91) |
Hot tracking | ✅ | ❌ |
| 0x00000810 | MenuBar (0) | HOT_INACTIVE | WM_MENUBAR_DRAWMENUITEM (0x92) | Hot + inactive | ✅ | ❌ |
| 0x00000100 | MenuBar (0) | NORMAL | WM_MENUBAR_DRAWMENUITEM (0x92) | Normal drawing | ✅ | ✅ |
| 0x00000101 | Popup (1) | SELECTED | WM_MENUBAR_DRAWMENUITEM (0x92) | Selected state (rare) | ✅ | ❌ |
| 0x00000140 | MenuBar (0) | HOT | WM_MENUBAR_DRAWMENUITEM (0x92) | Hot drawing | ✅ | ❌ |
| 0x00000180 | MenuBar (0) | INACTIVE | WM_MENUBAR_DRAWMENUITEM (0x92) | Inactive drawing | ✅ | ❌ |
| 0x000001C0 | MenuBar (0) | HOT_INACTIVE | WM_MENUBAR_DRAWMENUITEM (0x92) | Hot + inactive drawing | ✅ | ❌ |
| 0x04000001 | Popup (1) | POPUP_INIT | WM_MENUBAR_INITMENU (0x93) | Popup menu initialization (after click) | ✅ | ✅ |
| 0x04000801 | Popup (1) | POPUP_MEASURE | WM_MENUBAR_MEASUREMENUITEM (0x94) | Measuring popup menu items | ✅ | ✅ |
| Message | Flag Values Observed |
|---|---|
| WM_MENUBAR_INITMENU (0x93) | 0x00000200, 0x00000A00, 0x00000A10, 0x00000001, 0x04000001 |
| WM_MENUBAR_DRAWMENU (0x91) | 0x00000A00, 0x00000A10, 0x00000800 |
| WM_MENUBAR_DRAWMENUITEM (0x92) | 0x00000A00, 0x00000A10, 0x00000800, 0x00000810, 0x00000100, 0x00000101, 0x00000140, 0x00000180, 0x000001C0 |
| WM_MENUBAR_MEASUREMENUITEM (0x94) | 0x00000A00, 0x04000801 |
0x00000001 - Popup creation0x00000200 - First initialization0x00000A00 - Measurement/drawing (menu bar)0x00000100 - Normal drawing0x04000001 - Popup initialization (appears when submenu opens)0x04000801 - Popup measurement (appears when submenu items are measured)0x00000A10 - Menu bar inactive state0x00000800 - Hot tracking on menu bar0x00000810 - Hot tracking when window inactive0x00000101 - Selected/pressed state0x00000140 - Drawing hot state0x00000180 - Drawing inactive state0x000001C0 - Drawing hot+inactive state—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
EDIT 2: And a nitpick: In the PR, the menu item separator is not always drawn at full menu width (minus bitmaps). This is different from light mode and the master dark mode. Not sure if by design (this is not uniform, see the screenshots in my previous post). It happens only in the Menu menu in the menu sample (the one that has
Break()called upon).
If this by design? the answer is Yes.
The owner's drawing menu contains a MENU_POPUPGUTER Part and it's better to keep It as it's.
contextpopup.png (view on web)
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
> @@ -788,3 +811,51 @@ HandleMenuMessage(WXLRESULT* WXUNUSED(result),
} // namespace wxMSWDarkMode
#endif // wxUSE_DARK_MODE/!wxUSE_DARK_MODE
+
+void wxMSWImpl::EnableRoundCorners(HWND hwnd)
+{
+ const auto dwmSetWinAttr = wxDarkModeModule::GetDwmSetWindowAttribute();
+ if ( !dwmSetWinAttr )
+ return;
+
+ constexpr DWORD DWMWA_WINDOW_CORNER_PREFERENCE = 33;
+ constexpr DWORD DWMWA_BORDER_COLOR = 34;
+ constexpr int WindowCornerPreference = 3; // DWMWCP_ROUNDSMALL
+
+ // Apply rounded corners
+ HRESULT hr = dwmSetWinAttr(hwnd, DWMWA_WINDOW_CORNER_PREFERENCE,
On Windows 10, every time I open a menu the debugger logs the following:
clientcore\windows\dwm\dwmapi\attribute.cpp(185)\dwmapi.dll!00007FFFA9F62C57: (caller: 00007FFEDA0A29C1) ReturnHr(29) tid(2ef8) 80070057 The parameter is incorrect.I don't think it supports rounded corners. Maybe limit it to Windows 11 only? Like it is already done in
HandleEnterIdle.
Yes this is true.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
EDIT 2: And a nitpick: In the PR, the menu item separator is not always drawn at full menu width (minus bitmaps). This is different from light mode and the master dark mode. Not sure if by design (this is not uniform, see the screenshots in my previous post). It happens only in the Menu menu in the menu sample (the one that has
Break()called upon).If this by design? the answer is Yes. The owner's drawing menu contains a MENU_POPUPGUTER Part and it's better to keep It as it's.
I don't really care either way. But I find surprising it is not consistent: As I wrote, in the menu sample it can be seen that the separators are full width for menus File, Menubar, and Test (and they have bitmaps, checks and radios) but not for menu Menu (which calls Break() and has two columns).
BTW, I hope you understand I appreciate your work here, this is just a review, not an attempt to annoy you.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@vadz commented on this pull request.
> + if ( win )
+ {
+ wxUxThemeHandle hTheme
+ (
+ win,
+ L"LightMode_ImmersiveStart::Menu;MENU",
+ L"DarkMode_ImmersiveStart::Menu;DarkMode::Menu;MENU"
+ );
+ colBorder = hTheme.GetColour(MENU_POPUPBORDERS, TMT_FILLCOLORHINT);
+ }
+
+ if ( !colBorder.IsOk() )
+ colBorder = wxSystemSettings::GetColour(wxSYS_COLOUR_ACTIVEBORDER);
+
+ DWORD color = static_cast<DWORD>(wxColourToRGB(colBorder));
+ dwmSetWinAttr(hwnd, DWMWA_BORDER_COLOR, &color, sizeof(color));
@memoarfaa What do you think of using a different colour here? It looks like light border is not typically used for the menus.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
> @@ -579,6 +586,22 @@ HandleMenuMessage(WXLRESULT* result,
switch ( nMsg )
{
+ case WM_MENUBAR_INITMENU:
+ // Menu them is turned off in high contrast mode.
+ if ( wxMSWImpl::IsHighContrast() )
+ break;
+
+ // Enable rounded corners for UAH menus
+ if ( auto* const pUahMenu = (MenuBarDrawMenu*)lParam )
+ {
+ if ( pUahMenu->dwReserved & 0x4000001 )
Thanks, this is very useful, but according to this table, shouldn't we test for dwReserved == 0x4000001? I.e. why do we call EnableRoundCorners() twice, for both POPUP_INIT and POPUP_MEASURE, is this intentional?
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@vadz commented on this pull request.
> @@ -579,6 +586,22 @@ HandleMenuMessage(WXLRESULT* result,
switch ( nMsg )
{
+ case WM_MENUBAR_INITMENU:
+ // Menu them is turned off in high contrast mode.
+ if ( wxMSWImpl::IsHighContrast() )
+ break;
+
+ // Enable rounded corners for UAH menus
+ if ( auto* const pUahMenu = (MenuBarDrawMenu*)lParam )
+ {
+ if ( pUahMenu->dwReserved & 0x4000001 )
P.S. As I still can't test this myself, could someone (sorry @PBfordev if it means you again) please test if replacing & with == still works?
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
> @@ -788,3 +811,51 @@ HandleMenuMessage(WXLRESULT* WXUNUSED(result),
} // namespace wxMSWDarkMode
#endif // wxUSE_DARK_MODE/!wxUSE_DARK_MODE
+
+void wxMSWImpl::EnableRoundCorners(HWND hwnd)
+{
+ const auto dwmSetWinAttr = wxDarkModeModule::GetDwmSetWindowAttribute();
+ if ( !dwmSetWinAttr )
+ return;
+
+ constexpr DWORD DWMWA_WINDOW_CORNER_PREFERENCE = 33;
+ constexpr DWORD DWMWA_BORDER_COLOR = 34;
+ constexpr int WindowCornerPreference = 3; // DWMWCP_ROUNDSMALL
+
+ // Apply rounded corners
+ HRESULT hr = dwmSetWinAttr(hwnd, DWMWA_WINDOW_CORNER_PREFERENCE,
Added, thanks.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
> + constexpr DWORD DWMWA_WINDOW_CORNER_PREFERENCE = 33; + constexpr DWORD DWMWA_BORDER_COLOR = 34;
This would make them inconsistent with DWMWA_USE_IMMERSIVE_DARK_MODE. Let's leave them like this for now and maybe change them all at once later if/when we start including dwmapi.h.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@vadz commented on this pull request.
> @@ -1261,7 +1340,18 @@ void wxMenuItem::GetColourToUse(wxODStatus stat, wxColour& colText, wxColour& co
{
colText = GetTextColour();
if ( !colText.IsOk() )
- wxRGBToColour(colText, ::GetThemeSysColor(hTheme, COLOR_MENUTEXT));
+ {
+ if ( wxMSWDarkMode::IsActive() )
+ {
+ colText = hTheme.GetColour(MENU_POPUPITEM, TMT_TEXTCOLOR, MS_NORMAL);
Thanks, you're right, of course.
I still wonder what is this (from tmschema.h) about though:
BEGIN_TM_PART_STATES(MENU) TM_STATE(1,MS,NORMAL) TM_STATE(2,MS,SELECTED) TM_STATE(3,MS,DEMOTED) END_TM_PART_STATES()
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@vadz commented on this pull request.
> + if ( win )
+ {
+ wxUxThemeHandle hTheme
+ (
+ win,
+ L"LightMode_ImmersiveStart::Menu;MENU",
+ L"DarkMode_ImmersiveStart::Menu;DarkMode::Menu;MENU"
+ );
+ colBorder = hTheme.GetColour(MENU_POPUPBORDERS, TMT_FILLCOLORHINT);
+ }
+
+ if ( !colBorder.IsOk() )
+ colBorder = wxSystemSettings::GetColour(wxSYS_COLOUR_ACTIVEBORDER);
+
+ DWORD color = static_cast<DWORD>(wxColourToRGB(colBorder));
+ dwmSetWinAttr(hwnd, DWMWA_BORDER_COLOR, &color, sizeof(color));
Oops, after reading to the end, I see that @PBfordev doesn't see the light borders any longer, apparently, so this is probably good as it is, finally, sorry.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
> +
+ if ( FAILED(hr) )
+ return;
+
+ // Clean up conflicting styles like drop shadows.
+ DWORD style = ::GetClassLongPtr(hwnd, GCL_STYLE);
+ if ( style & CS_DROPSHADOW )
+ {
+ style &= ~CS_DROPSHADOW;
+ ::SetClassLongPtr(hwnd, GCL_STYLE, style);
+ }
+
+ // Determine the appropriate border colour for the current theme.
+ wxColor colBorder;
+
+ wxWindow* const win = wxTheApp ? wxTheApp->GetTopWindow() : nullptr;
I think you meant HWND, right? If so, I've modified the code to do it like this now, thanks. If not, please let me know what did you mean.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@vadz pushed 3 commits.
—
View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@MaartenBent commented on this pull request.
> +
+ if ( FAILED(hr) )
+ return;
+
+ // Clean up conflicting styles like drop shadows.
+ DWORD style = ::GetClassLongPtr(hwnd, GCL_STYLE);
+ if ( style & CS_DROPSHADOW )
+ {
+ style &= ~CS_DROPSHADOW;
+ ::SetClassLongPtr(hwnd, GCL_STYLE, style);
+ }
+
+ // Determine the appropriate border colour for the current theme.
+ wxColor colBorder;
+
+ wxWindow* const win = wxTheApp ? wxTheApp->GetTopWindow() : nullptr;
That's not what I meant, but maybe that works as well. Though I don't know if a hwnd of a menu is fine, or if it should be a window.
My original idea was this:
include/wx/msw/private/darkmode.h | 2 +- src/msw/darkmode.cpp | 5 ++--- src/msw/window.cpp | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/include/wx/msw/private/darkmode.h b/include/wx/msw/private/darkmode.h index 56db19a7a7b..cc523ce30bf 100644 --- a/include/wx/msw/private/darkmode.h +++ b/include/wx/msw/private/darkmode.h @@ -72,7 +72,7 @@ namespace wxMSWImpl // This function is not dark mode specific but reuses the code in darkmode.cpp, // so it's implemented there as well. -void EnableRoundCorners(HWND hwnd); +void EnableRoundCorners(wxWindow* win, HWND menuHwnd); } // namespace wxMSWImpl diff --git a/src/msw/darkmode.cpp b/src/msw/darkmode.cpp index 73b56c882be..f8b41b4eeac 100644 --- a/src/msw/darkmode.cpp +++ b/src/msw/darkmode.cpp @@ -597,7 +597,7 @@ HandleMenuMessage(WXLRESULT* result, if ( pUahMenu->dwReserved & 0x4000001 ) { if ( HWND hWndMenu = ::WindowFromDC(pUahMenu->hdc) ) - wxMSWImpl::EnableRoundCorners(hWndMenu); + wxMSWImpl::EnableRoundCorners(w, hWndMenu); } } break; @@ -812,7 +812,7 @@ HandleMenuMessage(WXLRESULT* WXUNUSED(result), #endif // wxUSE_DARK_MODE/!wxUSE_DARK_MODE -void wxMSWImpl::EnableRoundCorners(HWND hwnd) +void wxMSWImpl::EnableRoundCorners(wxWindow* win, HWND hwnd) { const auto dwmSetWinAttr = wxDarkModeModule::GetDwmSetWindowAttribute(); if ( !dwmSetWinAttr ) @@ -841,7 +841,6 @@ void wxMSWImpl::EnableRoundCorners(HWND hwnd) // Determine the appropriate border colour for the current theme. wxColor colBorder; - wxWindow* const win = wxTheApp ? wxTheApp->GetTopWindow() : nullptr; if ( win ) { wxUxThemeHandle hTheme diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 0522e6e7d9e..eb519aa3d07 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -4300,7 +4300,7 @@ bool wxWindowMSW::HandleEnterIdle(WXWPARAM wParam, WXLPARAM lParam) if ( !wxMSWDarkMode::IsActive() && !wxMSWImpl::IsHighContrast() ) { - wxMSWImpl::EnableRoundCorners(reinterpret_cast<HWND>(lParam)); + wxMSWImpl::EnableRoundCorners(this, reinterpret_cast<HWND>(lParam)); } #else wxUnusedVar(wParam);
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@MaartenBent commented on this pull request.
> @@ -1261,7 +1340,18 @@ void wxMenuItem::GetColourToUse(wxODStatus stat, wxColour& colText, wxColour& co
{
colText = GetTextColour();
if ( !colText.IsOk() )
- wxRGBToColour(colText, ::GetThemeSysColor(hTheme, COLOR_MENUTEXT));
+ {
+ if ( wxMSWDarkMode::IsActive() )
+ {
+ colText = hTheme.GetColour(MENU_POPUPITEM, TMT_TEXTCOLOR, MS_NORMAL);
I don't have this header at all. Is it from the Windows 7 SDK?
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@vadz commented on this pull request.
> +
+ if ( FAILED(hr) )
+ return;
+
+ // Clean up conflicting styles like drop shadows.
+ DWORD style = ::GetClassLongPtr(hwnd, GCL_STYLE);
+ if ( style & CS_DROPSHADOW )
+ {
+ style &= ~CS_DROPSHADOW;
+ ::SetClassLongPtr(hwnd, GCL_STYLE, style);
+ }
+
+ // Determine the appropriate border colour for the current theme.
+ wxColor colBorder;
+
+ wxWindow* const win = wxTheApp ? wxTheApp->GetTopWindow() : nullptr;
Ah, I see, sorry for misunderstanding.
I'm not sure which window is needed here either (and it's possible that it doesn't even matter...). Does the latest version work for you under Windows 11? If so, I'd probably leave it as is.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@vadz commented on this pull request.
> @@ -1261,7 +1340,18 @@ void wxMenuItem::GetColourToUse(wxODStatus stat, wxColour& colText, wxColour& co
{
colText = GetTextColour();
if ( !colText.IsOk() )
- wxRGBToColour(colText, ::GetThemeSysColor(hTheme, COLOR_MENUTEXT));
+ {
+ if ( wxMSWDarkMode::IsActive() )
+ {
+ colText = hTheme.GetColour(MENU_POPUPITEM, TMT_TEXTCOLOR, MS_NORMAL);
No, it's from MinGW-w64 (I only copy symbol values for the stuff we use in wx from there, not from SDK directly, just in case...).
Under Debian, it's /usr/share/mingw-w64/include/tmschema.h from mingw-w64-common package.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@MaartenBent commented on this pull request.
> +
+ if ( FAILED(hr) )
+ return;
+
+ // Clean up conflicting styles like drop shadows.
+ DWORD style = ::GetClassLongPtr(hwnd, GCL_STYLE);
+ if ( style & CS_DROPSHADOW )
+ {
+ style &= ~CS_DROPSHADOW;
+ ::SetClassLongPtr(hwnd, GCL_STYLE, style);
+ }
+
+ // Determine the appropriate border colour for the current theme.
+ wxColor colBorder;
+
+ wxWindow* const win = wxTheApp ? wxTheApp->GetTopWindow() : nullptr;
Border color still looks correct in dark and light mode when using hwnd directly.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
I do see the problem that @PBfordev mentioned. After switching from light to dark mode in Windows settings, with the app open, the 'normal' menus get broken. The owner-drawn menu stays light. I didn't test if this already happens before this PR.
Screenshot.2026-02-14.174347.png (view on web) Screenshot.2026-02-14.174409.png (view on web)
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
My guess would be that it doesn't work correctly in master either, but it would be nice to test this, if possible...
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
My guess would be that it doesn't work correctly in master either, but it would be nice to test this, if possible...
As I wrote, it does NOT happen in the master with menus. OTOH, both are broken in many other ways:
In the menu sample basically everything besides the menubar stays dark. E.g., the frame caption and background, the edit control and the status bar.
Some things improve after moving the frame to another monitor, the frame remains dark, and there are artifacts on the status bar (frame gripper?) and the edit control (black border):
image.png (view on web)
And one more nitpick related to this PR, the checkmark bitmap background seems different from the normal menu and two-column menu (with Break() called upon it, i.e., similar as with the separator width):
image.png (view on web)
vs
image.png (view on web)
Sorry for all these not-so-great news.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
I guess we should still merge it as the behaviour when changing between light and dark mode dynamically is broken anyhow, while this, at least, improves things when dark mode is already turned on when the application launches.
Do you agree?
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@memoarfaa commented on this pull request.
>
Sorry for all these not-so-great news.
Ok @PBfordev these is old news .
I guess we should still merge it as the behaviour when changing between light and dark mode dynamically is broken anyhow, while this, at least, improves things when dark mode is already turned on when the application launches.
Do you agree?
I say give me some time for this.
#26053 (comment)
But I'm busy these days, so let's help each other get this over with by tomorrow, including your Windows 11 system issue.
In the menu sample basically everything besides the menubar stays dark. E.g., the frame caption and background, the edit control and the status bar.
Some things improve after moving the frame to another monitor, the frame remains dark, and there are artifacts on the status bar (frame gripper?) and the edit control (black border):
// Responds to colour changes: passes event on to children.
void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event))
{
// update the menu background colour to match the current theme as otherwise
wxString strTheme = wxMSWDarkMode::IsActive() ? L"DarkMode_ImmersiveStart::Menu;MENU" : L"LightMode_ImmersiveStart::Menu;Menu";
wxUxThemeHandle hTheme = wxUxThemeHandle::NewAtStdDPI(strTheme.c_str());
wxColour wxMenuColor = hTheme.GetColour(MENU_POPUPBACKGROUND, TMT_FILLCOLOR);
if (wxMenuColor.IsOk())
{
COLORREF crMenu = wxColourToRGB(wxMenuColor);
LOGBRUSH lbr;
memset(&lbr, 0, sizeof(LOGBRUSH));
lbr.lbColor = crMenu;
HBRUSH GBRUSH = CreateBrushIndirect(&lbr);
WinStruct<MENUINFO> mi;
HWND hWnd = GetHwnd();
HMENU hMenu = ::GetMenu(hWnd);
if (hMenu)
{
MENUINFO MenuInfo = { 0};
memset(&MenuInfo, 0, sizeof(MENUINFO));
MenuInfo.cbSize = sizeof(mi);
GetMenuInfo(hMenu, &mi);
mi.fMask = MIM_BACKGROUND | MIM_APPLYTOSUBMENUS;
mi.hbrBack = (HBRUSH)wxTheBrushList->FindOrCreateBrush(crMenu)->GetResourceHandle();
if (!::SetMenuInfo(hMenu, &mi))
{
wxLogLastError(wxT("SetMenuInfo(MIM_BACKGROUND)"));
}
}
}
// the top level window also reset the standard colour map as it might have
// changed (there is no need to do it for the non top level windows as we
// only have to do it once)
if ( IsTopLevel() )
{
// FIXME-MT
gs_hasStdCmap = false;
}
wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
while ( node )
{
// Only propagate to non-top-level windows because Windows already
// sends this event to all top-level ones
wxWindow *win = node->GetData();
if ( !win->IsTopLevel() )
{
// we need to send the real WM_SYSCOLORCHANGE and not just trigger
// EVT_SYS_COLOUR_CHANGED call because the latter wouldn't work for
// the standard controls
::SendMessage(GetHwndOf(win), WM_SYSCOLORCHANGE, 0, 0);
}
node = node->GetNext();
}
}
https://github.com/user-attachments/assets/ad5eb386-7206-4941-b81f-f0f80869c600
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
I don't really care either way. But I find surprising it is not consistent: As I wrote, in the menu sample it can be seen that the separators are full width for menus File, Menubar, and Test (and they have bitmaps, checks and radios) but not for menu Menu (which calls
Break()and has two columns).
BTW, I hope you understand I appreciate your work here, this is just a review, not an attempt to annoy you.
I understand and know that there is no attempt to upset me; we are all here to make an improvement.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Ugh, I've tried testing myself under Windows 11 (it's a pretty old version, 10.0.22621.3155) and it looks like dark mode is totally broken there, this is how menu sample looks for me with master (it's almost the same with this PR):
P.S. As I still can't test this myself, could someone (sorry @PBfordev if it means you again) please test if replacing & with == still works?
but something is very wrong under 11...
Regarding your Windows 11 version, 10.0.22621.3155, I have an almost identical version (an ISO file containing all versions) and dark mode works perfectly for me with Rounded Corner at Hyper-V.
https://github.com/user-attachments/assets/1d6ba93b-7e5c-4288-ab90-0dab408d4663
1- Your Window scrollbar is not themed.
2- Window without rounded corners.
3- Menubar can't draw menu Items text.
Screenshot.2026-02-15.075231.png (view on web)
1- Incorrect use of the SetWindowTheme function with a class that does not exist in Aero Msstyles theme (Aero.Msstyles).
can turn off SetWindowTheme in code.
2- Cutome Aero.Msstyles.
can use this exe to list darkMode Classes
My be your Windows 11 has difference windows edition. My edition is pro What's your edition?
1-my be beacuase of Incorrect use of the SetWindowTheme.
2- my be beacuase of Running in Hyper-V.
Enfoce Round Corners at Hyper-V
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Dwm]
"ForceEffectMode"=dword:00000002
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
I wouldn't worry much about the problem in my very old Windows 11 VM, nobody is probably running it any longer but, just in case, this is also a Pro version, here is the information copy-pasted from "System » About":
Edition Windows 11 Pro
Version 22H2
Installed on 9 Feb 2023
OS build 22621.4317
Experience Windows Feature Experience Pack 1000.22700.1041.0
The only problem is that I can't update it (I had installed it using old version of QEMU where TPM passthrough worked without problems, but somehow it doesn't work any more and I can't upgrade without working TPM...) and so can't currently test anything myself.
Setting ForceEffectMode doesn't do anything for me. Of course, the weird thing is that Windows itself works just fine and menus in e.g. notepad have round corners, it's only wx which has problems on this system.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
I wouldn't worry much about the problem in my very old Windows 11 VM
Well, maybe I should. I've made TPM work with QEMU again and updated to the latest version
Edition Windows 11 Pro
Version 25H2
Installed on 15 Feb 2026
OS build 26200.7840
Experience Windows Feature Experience Pack 1000.26100.291.0
and I still have the same problems.
So on one hand this is probably still not that bad because it's clearly something broken in my VM and not more generally, but OTOH it's very inconvenient because I still can't test dark mode support under Windows 11 and I don't know what to do about it.
Maybe the problem is that my VM doesn't have any dedicated GPU? But then it never did and yet dark mode worked fine in it some (long) time ago...
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
We need to decide whether this should be merged or not. I still can't test this myself, so I'm not sure, but I think it's better to improve dark mode support even if it makes switching between modes work even worse — but then it's already broken, so this is arguably less important...
What do the others think?
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Well, wxWidgets does not handle the switching between dark and light modes well, but AFAICT, the controls remain usable.
When switching from the light to dark mode with the PR, the menus are unreadable:
wxmenu-switch-light.png (view on web)
The menus are barely readable (dark text on dark background) when switching the other direction. I understand that people don't switch the mode often.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@memoarfaa Any chance you could improve this to avoid regressions when switching between modes soon, i.e. before the end of the month?
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()