summaryrefslogtreecommitdiff
path: root/wx+/darkmode.cpp
blob: c8a7ea2883179137ac5212cf5ce90c37d4c97faf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// *****************************************************************************
// * 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)
        {
            const auto& [rh, rl] = hexify(c.Red  ());
            const auto& [gh, gl] = hexify(c.Green());
            const auto& [bh, bl] = hexify(c.Blue ());
            const auto& [ah, al] = hexify(c.Alpha());
            return "#" + std::string({rh, rl, gh, gl, bh, bl, ah, al});
        };
        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_WINDOWTEXT),
                        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()); }
}
bgstack15