summaryrefslogtreecommitdiff
path: root/vcl/win
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2022-03-12 20:38:21 +0000
committerCaolán McNamara <caolanm@redhat.com>2022-03-16 22:16:01 +0100
commita3f400886768bf95fbd8e6b236e11d7aac393b96 (patch)
tree29d71aed9e5ca0e6045cac00aaba5e415acc53a5 /vcl/win
parent45f9c1862bd205f620ce21663a8cd91119b9b2d5 (diff)
Related: tdf#118320 enable some windows dark theme support
If experimental mode is enabled and only for windows >= 10.0.18362 Toggling from dark to light mode is detected, and getting some suitable colors for dark mode works. The titlebar will toggle into dark/light mode successfully. DrawThemeBackground does something sensible for buttons and scrollbar at least, comboboxes can be forced to work. SpinButtons are less successful. Menubar and toolbar just bodged to draw a solid backcolor. Notebooks/TabControls don't respect the theme. Its possible it makes more sense to not try and use the windows control drawings apis and just set some dark colors and draw with the old built-in vcl widget rendering or alternative. Change-Id: Ic7927fb9af7ec94444d9de6e0204560e2789be46 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131453 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Diffstat (limited to 'vcl/win')
-rw-r--r--vcl/win/app/salinst.cxx49
-rw-r--r--vcl/win/gdi/salnativewidgets-luna.cxx61
-rw-r--r--vcl/win/window/salframe.cxx107
3 files changed, 200 insertions, 17 deletions
diff --git a/vcl/win/app/salinst.cxx b/vcl/win/app/salinst.cxx
index e9d8e73f8a5e..a322046d66bf 100644
--- a/vcl/win/app/salinst.cxx
+++ b/vcl/win/app/salinst.cxx
@@ -318,6 +318,43 @@ SalData::~SalData()
Gdiplus::GdiplusShutdown(gdiplusToken);
}
+bool OSSupportsDarkMode()
+{
+ bool bRet = false;
+ if (HMODULE h_ntdll = GetModuleHandleW(L"ntdll.dll"))
+ {
+ typedef LONG(WINAPI* RtlGetVersion_t)(PRTL_OSVERSIONINFOW);
+ if (auto RtlGetVersion
+ = reinterpret_cast<RtlGetVersion_t>(GetProcAddress(h_ntdll, "RtlGetVersion")))
+ {
+ RTL_OSVERSIONINFOW vi2{};
+ vi2.dwOSVersionInfoSize = sizeof(vi2);
+ if (RtlGetVersion(&vi2) == 0)
+ {
+ if (vi2.dwMajorVersion > 10)
+ bRet = true;
+ else if (vi2.dwMajorVersion == 10)
+ {
+ if (vi2.dwMinorVersion > 0)
+ bRet = true;
+ else if (vi2.dwBuildNumber >= 18362)
+ bRet = true;
+ }
+ }
+ }
+ }
+ return bRet;
+}
+
+enum PreferredAppMode
+{
+ Default,
+ AllowDark,
+ ForceDark,
+ ForceLight,
+ Max
+};
+
extern "C" {
VCLPLUG_WIN_PUBLIC SalInstance* create_SalInstance()
{
@@ -331,6 +368,18 @@ VCLPLUG_WIN_PUBLIC SalInstance* create_SalInstance()
pSalData->mnAppThreadId = GetCurrentThreadId();
+ static bool bSetAllowDarkMode = OSSupportsDarkMode(); // too early to additionally check LibreOffice's config
+ if (bSetAllowDarkMode)
+ {
+ typedef PreferredAppMode(WINAPI* SetPreferredAppMode_t)(PreferredAppMode);
+ if (HINSTANCE hUxthemeLib = LoadLibraryExW(L"uxtheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32))
+ {
+ if (auto SetPreferredAppMode = reinterpret_cast<SetPreferredAppMode_t>(GetProcAddress(hUxthemeLib, MAKEINTRESOURCEA(135))))
+ SetPreferredAppMode(AllowDark);
+ FreeLibrary(hUxthemeLib);
+ }
+ }
+
// register frame class
WNDCLASSEXW aWndClassEx;
aWndClassEx.cbSize = sizeof( aWndClassEx );
diff --git a/vcl/win/gdi/salnativewidgets-luna.cxx b/vcl/win/gdi/salnativewidgets-luna.cxx
index 8e754d129580..c4113b877f1f 100644
--- a/vcl/win/gdi/salnativewidgets-luna.cxx
+++ b/vcl/win/gdi/salnativewidgets-luna.cxx
@@ -36,6 +36,7 @@
#include <osl/diagnose.h>
#include <osl/module.h>
#include <o3tl/char16_t2wchar_t.hxx>
+#include <officecfg/Office/Common.hxx>
#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>
@@ -395,6 +396,26 @@ static bool implDrawNativeMenuMark(HDC hDC, HTHEME hTheme, RECT rc, ControlPart
return ImplDrawTheme(hTheme, hDC, MENU_POPUPCHECK, iState, rc, aCaption);
}
+bool UseDarkMode()
+{
+ static bool bExperimental = officecfg::Office::Common::Misc::ExperimentalMode::get();
+ if (!bExperimental)
+ return false;
+
+ HINSTANCE hUxthemeLib = LoadLibraryExW(L"uxtheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
+ if (!hUxthemeLib)
+ return false;
+
+ bool bRet = false;
+ typedef bool(WINAPI* ShouldAppsUseDarkMode_t)();
+ if (auto ShouldAppsUseDarkMode = reinterpret_cast<ShouldAppsUseDarkMode_t>(GetProcAddress(hUxthemeLib, MAKEINTRESOURCEA(132))))
+ bRet = ShouldAppsUseDarkMode();
+
+ FreeLibrary(hUxthemeLib);
+
+ return bRet;
+}
+
static bool ImplDrawNativeControl( HDC hDC, HTHEME hTheme, RECT rc,
ControlType nType,
ControlPart nPart,
@@ -819,6 +840,17 @@ static bool ImplDrawNativeControl( HDC hDC, HTHEME hTheme, RECT rc,
rc.top = 0; // extend potential gradient to cover menu bar as well
}
+ // menubar in main window gets drawn in white in "darkmode", so bodge this here
+ if (UseDarkMode())
+ {
+ Color aColor(Application::GetSettings().GetStyleSettings().GetWindowColor());
+ ScopedHBRUSH hbrush(CreateSolidBrush(RGB(aColor.GetRed(),
+ aColor.GetGreen(),
+ aColor.GetBlue())));
+ FillRect(hDC, &rc, hbrush.get());
+ return true;
+ }
+
// make it more compatible with Aero
if( ImplGetSVData()->maNWFData.mbDockingAreaAvoidTBFrames )
{
@@ -839,6 +871,17 @@ static bool ImplDrawNativeControl( HDC hDC, HTHEME hTheme, RECT rc,
const MenubarValue *pValue = static_cast<const MenubarValue*>(&aValue);
rc.bottom += pValue->maTopDockingAreaHeight; // extend potential gradient to cover docking area as well
+ // menubar in main window gets drawn in white in "darkmode", so bodge this here
+ if (UseDarkMode())
+ {
+ Color aColor(Application::GetSettings().GetStyleSettings().GetWindowColor());
+ ScopedHBRUSH hbrush(CreateSolidBrush(RGB(aColor.GetRed(),
+ aColor.GetGreen(),
+ aColor.GetBlue())));
+ FillRect(hDC, &rc, hbrush.get());
+ return true;
+ }
+
// make it more compatible with Aero
if( ImplGetSVData()->maNWFData.mbDockingAreaAvoidTBFrames )
{
@@ -1045,6 +1088,10 @@ bool WinSalGraphics::drawNativeControl( ControlType nType,
return true;
}
+ const bool bUseDarkMode = UseDarkMode();
+ if (bUseDarkMode)
+ SetWindowTheme(mhWnd, L"Explorer", nullptr);
+
switch( nType )
{
case ControlType::Pushbutton:
@@ -1059,7 +1106,11 @@ bool WinSalGraphics::drawNativeControl( ControlType nType,
if( nPart == ControlPart::Entire )
hTheme = getThemeHandle(mhWnd, L"Edit", mpImpl.get());
else if( nPart == ControlPart::ButtonDown )
+ {
+ if (bUseDarkMode)
+ SetWindowTheme(mhWnd, L"CFD", nullptr);
hTheme = getThemeHandle(mhWnd, L"Combobox", mpImpl.get());
+ }
break;
case ControlType::Spinbox:
if( nPart == ControlPart::Entire )
@@ -1078,7 +1129,11 @@ bool WinSalGraphics::drawNativeControl( ControlType nType,
if( nPart == ControlPart::Entire || nPart == ControlPart::ListboxWindow )
hTheme = getThemeHandle(mhWnd, L"Listview", mpImpl.get());
else if( nPart == ControlPart::ButtonDown )
+ {
+ if (bUseDarkMode)
+ SetWindowTheme(mhWnd, L"CFD", nullptr);
hTheme = getThemeHandle(mhWnd, L"Combobox", mpImpl.get());
+ }
break;
case ControlType::TabPane:
case ControlType::TabBody:
@@ -1129,7 +1184,11 @@ bool WinSalGraphics::drawNativeControl( ControlType nType,
}
if( !hTheme )
+ {
+ if (bUseDarkMode)
+ SetWindowTheme(mhWnd, nullptr, nullptr);
return false;
+ }
RECT rc;
rc.left = buttonRect.Left();
@@ -1167,6 +1226,8 @@ bool WinSalGraphics::drawNativeControl( ControlType nType,
}
}
+ if (bUseDarkMode)
+ SetWindowTheme(mhWnd, nullptr, nullptr);
return bOk;
}
diff --git a/vcl/win/window/salframe.cxx b/vcl/win/window/salframe.cxx
index 95b9a36693ad..5965e9225058 100644
--- a/vcl/win/window/salframe.cxx
+++ b/vcl/win/window/salframe.cxx
@@ -94,10 +94,13 @@
# define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
+#include <dwmapi.h>
#include <shobjidl.h>
#include <propkey.h>
#include <propvarutil.h>
#include <shellapi.h>
+#include <uxtheme.h>
+#include <Vssym32.h>
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
@@ -277,6 +280,33 @@ void ImplSalGetWorkArea( HWND hWnd, RECT *pRect, const RECT *pParentRect )
}
}
+static void UpdateDarkMode(HWND hWnd)
+{
+ static bool bExperimental = officecfg::Office::Common::Misc::ExperimentalMode::get();
+ if (!bExperimental)
+ return;
+ static bool bOSSupportsDarkMode = OSSupportsDarkMode();
+ if (!bOSSupportsDarkMode)
+ return;
+
+ HINSTANCE hUxthemeLib = LoadLibraryExW(L"uxtheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
+ if (!hUxthemeLib)
+ return;
+
+ typedef void(WINAPI* AllowDarkModeForWindow_t)(HWND, BOOL);
+ if (auto AllowDarkModeForWindow = reinterpret_cast<AllowDarkModeForWindow_t>(GetProcAddress(hUxthemeLib, MAKEINTRESOURCEA(133))))
+ AllowDarkModeForWindow(hWnd, TRUE);
+
+ typedef bool(WINAPI* ShouldAppsUseDarkMode_t)();
+ if (auto ShouldAppsUseDarkMode = reinterpret_cast<ShouldAppsUseDarkMode_t>(GetProcAddress(hUxthemeLib, MAKEINTRESOURCEA(132))))
+ {
+ BOOL bDarkMode = ShouldAppsUseDarkMode();
+ DwmSetWindowAttribute(hWnd, 20, &bDarkMode, sizeof(bDarkMode));
+ }
+
+ FreeLibrary(hUxthemeLib);
+}
+
SalFrame* ImplSalCreateFrame( WinSalInstance* pInst,
HWND hWndParent, SalFrameStyleFlags nSalFrameStyle )
{
@@ -2627,7 +2657,61 @@ void WinSalFrame::UpdateSettings( AllSettings& rSettings )
aStyleSettings.SetActiveBorderColor( ImplWinColorToSal( GetSysColor( COLOR_ACTIVEBORDER ) ) );
aStyleSettings.SetDeactiveBorderColor( ImplWinColorToSal( GetSysColor( COLOR_INACTIVEBORDER ) ) );
aStyleSettings.SetDeactiveColor( ImplWinColorToSal( GetSysColor( COLOR_GRADIENTINACTIVECAPTION ) ) );
- aStyleSettings.SetFaceColor( ImplWinColorToSal( GetSysColor( COLOR_3DFACE ) ) );
+
+ Color aControlTextColor;
+ Color aMenuBarTextColor;
+ Color aMenuBarRolloverTextColor;
+
+ if (UseDarkMode())
+ {
+ SetWindowTheme(mhWnd, L"Explorer", nullptr);
+
+ HTHEME hTheme = OpenThemeData(nullptr, L"ItemsView");
+ COLORREF color;
+ GetThemeColor(hTheme, 0, 0, TMT_FILLCOLOR, &color);
+ aStyleSettings.SetFaceColor( ImplWinColorToSal( color ) );
+ aStyleSettings.SetWindowColor( ImplWinColorToSal( color ) );
+ GetThemeColor(hTheme, 0, 0, TMT_TEXTCOLOR, &color);
+ aStyleSettings.SetWindowTextColor( ImplWinColorToSal( color ) );
+ CloseThemeData(hTheme);
+
+ hTheme = OpenThemeData(mhWnd, L"Button");
+ GetThemeColor(hTheme, BP_PUSHBUTTON, MBI_NORMAL, TMT_TEXTCOLOR, &color);
+ aControlTextColor = ImplWinColorToSal(color);
+ GetThemeColor(hTheme, BP_CHECKBOX, MBI_NORMAL, TMT_TEXTCOLOR, &color);
+ aStyleSettings.SetRadioCheckTextColor( ImplWinColorToSal( color ) );
+ CloseThemeData(hTheme);
+
+ SetWindowTheme(mhWnd, nullptr, nullptr);
+
+ hTheme = OpenThemeData(mhWnd, L"Menu");
+ GetThemeColor(hTheme, MENU_POPUPITEM, MBI_NORMAL, TMT_TEXTCOLOR, &color);
+ aStyleSettings.SetMenuTextColor( ImplWinColorToSal( color ) );
+ aMenuBarTextColor = ImplWinColorToSal( color );
+ aMenuBarRolloverTextColor = ImplWinColorToSal( color );
+ CloseThemeData(hTheme);
+ }
+ else
+ {
+ aStyleSettings.SetFaceColor( ImplWinColorToSal( GetSysColor( COLOR_3DFACE ) ) );
+ aStyleSettings.SetWindowColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOW ) ) );
+ aStyleSettings.SetWindowTextColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOWTEXT ) ) );
+ aControlTextColor = ImplWinColorToSal(GetSysColor(COLOR_BTNTEXT));
+ aStyleSettings.SetRadioCheckTextColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOWTEXT ) ) );
+ aStyleSettings.SetMenuTextColor( ImplWinColorToSal( GetSysColor( COLOR_MENUTEXT ) ) );
+ aMenuBarTextColor = ImplWinColorToSal( GetSysColor( COLOR_MENUTEXT ) );
+ aMenuBarRolloverTextColor = ImplWinColorToSal( GetSysColor( COLOR_HIGHLIGHTTEXT ) );
+ }
+
+ if ( std::optional<Color> aColor = aStyleSettings.GetPersonaMenuBarTextColor() )
+ {
+ aMenuBarTextColor = *aColor;
+ aMenuBarRolloverTextColor = *aColor;
+ }
+
+ aStyleSettings.SetMenuBarTextColor( aMenuBarTextColor );
+ aStyleSettings.SetMenuBarRolloverTextColor( aMenuBarRolloverTextColor );
+
aStyleSettings.SetInactiveTabColor( aStyleSettings.GetFaceColor() );
aStyleSettings.SetLightColor( ImplWinColorToSal( GetSysColor( COLOR_3DHILIGHT ) ) );
aStyleSettings.SetLightBorderColor( ImplWinColorToSal( GetSysColor( COLOR_3DLIGHT ) ) );
@@ -2636,8 +2720,6 @@ void WinSalFrame::UpdateSettings( AllSettings& rSettings )
aStyleSettings.SetHelpColor( ImplWinColorToSal( GetSysColor( COLOR_INFOBK ) ) );
aStyleSettings.SetHelpTextColor( ImplWinColorToSal( GetSysColor( COLOR_INFOTEXT ) ) );
- Color aControlTextColor(ImplWinColorToSal(GetSysColor(COLOR_BTNTEXT)));
-
aStyleSettings.SetDialogColor(aStyleSettings.GetFaceColor());
aStyleSettings.SetDialogTextColor(aControlTextColor);
@@ -2661,12 +2743,9 @@ void WinSalFrame::UpdateSettings( AllSettings& rSettings )
aStyleSettings.SetTabRolloverTextColor(aControlTextColor);
aStyleSettings.SetTabHighlightTextColor(aControlTextColor);
- aStyleSettings.SetRadioCheckTextColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOWTEXT ) ) );
aStyleSettings.SetGroupTextColor( aStyleSettings.GetRadioCheckTextColor() );
aStyleSettings.SetLabelTextColor( aStyleSettings.GetRadioCheckTextColor() );
- aStyleSettings.SetWindowColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOW ) ) );
aStyleSettings.SetActiveTabColor( aStyleSettings.GetWindowColor() );
- aStyleSettings.SetWindowTextColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOWTEXT ) ) );
aStyleSettings.SetToolTextColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOWTEXT ) ) );
aStyleSettings.SetFieldColor( aStyleSettings.GetWindowColor() );
aStyleSettings.SetFieldTextColor( aStyleSettings.GetWindowTextColor() );
@@ -2692,17 +2771,6 @@ void WinSalFrame::UpdateSettings( AllSettings& rSettings )
aStyleSettings.SetMenuBorderColor( aStyleSettings.GetLightBorderColor() ); // overridden below for flat menus
aStyleSettings.SetUseFlatBorders( false );
aStyleSettings.SetUseFlatMenus( false );
- aStyleSettings.SetMenuTextColor( ImplWinColorToSal( GetSysColor( COLOR_MENUTEXT ) ) );
- if ( std::optional<Color> aColor = aStyleSettings.GetPersonaMenuBarTextColor() )
- {
- aStyleSettings.SetMenuBarTextColor( *aColor );
- aStyleSettings.SetMenuBarRolloverTextColor( *aColor );
- }
- else
- {
- aStyleSettings.SetMenuBarTextColor( ImplWinColorToSal( GetSysColor( COLOR_MENUTEXT ) ) );
- aStyleSettings.SetMenuBarRolloverTextColor( ImplWinColorToSal( GetSysColor( COLOR_HIGHLIGHTTEXT ) ) );
- }
aStyleSettings.SetMenuBarHighlightTextColor(aStyleSettings.GetMenuHighlightTextColor());
aStyleSettings.SetActiveColor( ImplWinColorToSal( GetSysColor( COLOR_ACTIVECAPTION ) ) );
aStyleSettings.SetActiveTextColor( ImplWinColorToSal( GetSysColor( COLOR_CAPTIONTEXT ) ) );
@@ -4107,6 +4175,8 @@ static void ImplHandleSettingsChangeMsg( HWND hWnd, UINT nMsg,
aSalShlData.mnWheelScrollLines = ImplSalGetWheelScrollLines();
else if( wParam == SPI_SETWHEELSCROLLCHARS )
aSalShlData.mnWheelScrollChars = ImplSalGetWheelScrollChars();
+ UpdateDarkMode(hWnd);
+ GetSalData()->mbThemeChanged = true;
}
if ( WM_SYSCOLORCHANGE == nMsg && GetSalData()->mhDitherPal )
@@ -5499,6 +5569,9 @@ static LRESULT CALLBACK SalFrameWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LP
if ( pFrame != nullptr )
{
SetWindowPtr( hWnd, pFrame );
+
+ UpdateDarkMode(hWnd);
+
// Set HWND already here, as data might be used already
// when messages are being sent by CreateWindow()
pFrame->mhWnd = hWnd;