Files
free-file-sync-mirror/wx+/darkmode.cpp
2025-12-10 14:38:26 -08:00

103 lines
3.6 KiB
C++

// *****************************************************************************
// * This file is part of the FreeFileSync project. It is distributed under *
// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 *
// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
// *****************************************************************************
#include "darkmode.h"
#include <zen/sys_version.h>
#include <wx/settings.h>
#include "color_tools.h"
#include <gtk/gtk.h>
using namespace zen;
bool zen::darkModeAvailable()
{
#if GTK_MAJOR_VERSION == 2
return false;
#elif GTK_MAJOR_VERSION >= 3
return true;
#else
#error unknown GTK version!
#endif
}
namespace
{
class SysColorsHook : public wxColorHook
{
public:
wxColor getColor(wxSystemColour index) const override
{
//fix contrast e.g. Ubuntu's Adwaita-Dark theme and macOS dark mode:
if (index == wxSYS_COLOUR_GRAYTEXT)
return colGreyTextEnhContrast_;
#if 0
auto colToString = [](wxColor c) { return utfTo<std::string>(c.GetAsString(wxC2S_HTML_SYNTAX)); /* #RRGGBB(AA) */ };
std::cerr << "wxSYS_COLOUR_GRAYTEXT " << colToString(wxSystemSettingsNative::GetColour(wxSYS_COLOUR_GRAYTEXT)) << "\n";
#endif
return wxSystemSettingsNative::GetColour(index); //fallback
}
private:
const wxColor colGreyTextEnhContrast_ =
enhanceContrast(wxSystemSettingsNative::GetColour(wxSYS_COLOUR_GRAYTEXT),
wxSystemSettingsNative::GetColour(wxSYS_COLOUR_WINDOW), 4.5 /*contrastRatioMin*/); //W3C recommends >= 4.5
};
std::optional<bool> globalDefaultThemeIsDark;
}
void zen::colorThemeInit(wxApp& app, ColorTheme colTheme) //throw FileError
{
assert(!refGlobalColorHook());
globalDefaultThemeIsDark = wxSystemSettings::GetAppearance().AreAppsDark();
ZEN_ON_SCOPE_EXIT(if (!refGlobalColorHook()) refGlobalColorHook() = std::make_unique<SysColorsHook>()); //*after* SetAppearance() and despite errors
//caveat: on macOS there are more themes than light/dark: https://developer.apple.com/documentation/appkit/nsappearance/name-swift.struct
if (colTheme != ColorTheme::System && //"System" is already the default for macOS/Linux(GTK3)
darkModeAvailable())
changeColorTheme(colTheme); //throw FileError
}
void zen::colorThemeCleanup()
{
assert(refGlobalColorHook());
refGlobalColorHook().reset();
}
bool zen::equalAppearance(ColorTheme colTheme1, ColorTheme colTheme2)
{
if (colTheme1 == ColorTheme::System) colTheme1 = *globalDefaultThemeIsDark ? ColorTheme::Dark : ColorTheme::Light;
if (colTheme2 == ColorTheme::System) colTheme2 = *globalDefaultThemeIsDark ? ColorTheme::Dark : ColorTheme::Light;
return colTheme1 == colTheme2;
}
void zen::changeColorTheme(ColorTheme colTheme) //throw FileError
{
if (colTheme == ColorTheme::System) //SetAppearance(System) isn't working reliably! surprise!?
colTheme = *globalDefaultThemeIsDark ? ColorTheme::Dark : ColorTheme::Light;
try
{
ZEN_ON_SCOPE_SUCCESS(refGlobalColorHook() = std::make_unique<SysColorsHook>()); //*after* SetAppearance()
if (wxApp::AppearanceResult rv = wxTheApp->SetAppearance(colTheme);
rv != wxApp::AppearanceResult::Ok)
throw SysError(formatSystemError("wxApp::SetAppearance",
rv == wxApp::AppearanceResult::CannotChange ? L"CannotChange" : L"Failure", L"" /*errorMsg*/));
}
catch (const SysError& e) { throw FileError(_("Failed to update the color theme."), e.toString()); }
}