Currently, WM_SYSCOLORCHANGE is caught also to indicate a change between dark and light mode. That does not work because wxMSWDarkMode::IsActive() has not changed yet (still false when changing to dark mode). Instead, we need to use WM_SETTINGCHANGE as that is sent afterwards. I changed HandleSettingChange() to send out a WM_SYSCOLORCHANGE to all child windows as that is the current API and update the own window before, see below. This corrects dark/light mode changes in all test scenarios I found, with the exception of the background of menus, which stay white in dark mode and are then unreadable.
I realize that this might trigger a redraw under other circumstances when a WM_SETTINGCHANGE message is sent, but I habve not actually seen that.
bool wxWindowMSW::HandleSettingChange(WXWPARAM wParam, WXLPARAM lParam)
{
// Another special case: event with this wParam value is sent when the user
// changes the mouse pointer size in the Control Panel.
if ( wParam == 0x2029 )
{
WXUpdateCursor();
wxSysMetricChangedEvent event(wxSysMetric::CursorSize);
event.SetEventObject(this);
(void)HandleWindowEvent(event);
}
MSWSetDarkOrLightMode(SetMode::Change);
// despite MSDN saying "(This message cannot be sent directly to a window.)"
// we need to send this to child windows (it is only sent to top-level
// windows) so {list,tree}ctrls can adjust their font size if necessary
// this is exactly how explorer does it to enable the font size changes
wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
while ( node )
{
// top-level windows already get this message from the system
wxWindow *win = node->GetData();
if ( !win->IsTopLevel() )
{
::SendMessage(GetHwndOf(win), WM_SETTINGCHANGE, wParam, lParam);
// Send WM_SYSCOLORCHANGE to inform child windows about dark/light mode
::SendMessage(GetHwndOf(win), WM_SYSCOLORCHANGE, 0, 0);
}
node = node->GetNext();
}
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
The dark/light switch is indicated by Windows with a WM_SETTINGCHANGE message with the "ImmersiveColorSet" argument. Windows does not send WM_SYSCOLORCHANGE upon dark/light switch, at least not with the latest Windows 11. When Windows switches between light and dark mode, there are two such WM_SETTINGCHANGE messages. The first occurs before the switch and the second after. So wxMSWDarkMode::IsActive() appears to return a wrong answer when called during the first message WM_SETTINGCHANGE.
When wxWidgets receives WM_SETTINGCHANGE with "ImmersiveColorSet", it converts this into a system colour change event, here: https://github.com/wxWidgets/wxWidgets/blob/52eee93edb66f59d0516a09a5f5e3335262356a8/src/msw/window.cpp#L3558
After that conversion, all the dark/light mode switching is handled as a system color change event.
With all that in mind, what is the symptom of the problem you see? How can I reproduce it? When running the samples, such as the widgets sample, everything looks pretty good to me when switching between light and dark modes, including menus.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
I add to minimal.cpp in OnInit()
#ifdef WXMSW
MSWEnableDarkMode(wxApp::DarkMode_Auto);
#endif
and then switch between dark and light mode using the system preferences. The below screenshot shows this after switching back to light mode: the system preferences dialog in now light, but the minimal sample is dark. I use MingW64 using the latest TRUNK on an unmodified, uptodate Windows 11
image.png (view on web)—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
Furthermore, when I change the code like below, wxMSWDarkMode::IsActive() is always reverted. When I change to dark, wxMSWDarkMode::IsActive() is false and vice versa. I assume wxIsSystemColourChange() is doing something wrong, which I need to check later.
case WM_SETTINGCHANGE:
// Check for the special case of the message which notifies about
// the colours change.
if ( wxIsSystemColourChange(lParam) )
{
if (wxMSWDarkMode::IsActive())
wxLogWarning( "WM_SETTINGCHANGE IsActive = true" );
else
wxLogWarning( "WM_SETTINGCHANGE IsActive = false" );
processed = HandleSysColorChange();
}
else
processed = HandleSettingChange(wParam, lParam);
break;
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
Here we go again: on my system, I get two WM_SETTINGCHANGE messages. The first with lParam being "ImmersiveColorSet" but at this stage, wxMSWDarkMode::IsActive() is still "wrong", during the second message lParam is not "ImmersiveColorSet" but isActive returns the right value.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
This "patch" eats the first WM_SETTINGCHANGE message and then waits for the second. This reduces redraw, works in all my test cases and also redraws the menus correctly. I had to add a flag to the wxWindowMSW class. I don't know if Windows sends these two messages in all versions of Windows, but I am not the only one reporting it. Indeed, the second message also seems to have a string as lParam:
Assuming that we can finally make this work, I wonder if
MSWEnableDarkMode(wxApp::DarkMode_Auto);
should become the default and if we can support setting dark mode in the app from now on as well, like in the other ports.
in msw\window.h
bool m_lastChangeSettingMessageWasImmersiveColorSet:1;
in msw\window.cpp
case WM_SETTINGCHANGE:
// Check for the special case of the message which notifies about
// the colours change.
if (m_lastChangeSettingMessageWasImmersiveColorSet)
{
processed = HandleSysColorChange();
m_lastChangeSettingMessageWasImmersiveColorSet = false;
}
else
{
if (wxIsSystemColourChange(lParam))
{
m_lastChangeSettingMessageWasImmersiveColorSet = true;
processed = true;
}
else
processed = HandleSettingChange(wParam, lParam);
}
break;
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()