#include "base/win/dark_mode_support.h"
#include <windows.h>
#include "base/check.h"
#include "base/command_line.h"
#include "base/native_library.h"
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
namespace {
enum class PreferredAppMode {
kDefault,
kAllowDark,
kForceDark,
kForceLight,
kMax
};
using UxThemeAllowDarkModeForAppFunc = bool(WINAPI*)(bool allow);
using UxThemeSetPreferredAppModeFunc =
PreferredAppMode(WINAPI*)(PreferredAppMode app_mode);
using UxThemeAllowDarkModeForWindowFunc = bool(WINAPI*)(HWND hwnd, bool allow);
constexpr WORD kUxThemeAllowDarkModeForAppOrdinal = 135;
constexpr WORD kUxThemeSetPreferredAppModeOrdinal = 135;
constexpr WORD kUxThemeAllowDarkModeForWindowOrdinal = 133;
struct DarkModeSupport {
UxThemeAllowDarkModeForAppFunc allow_dark_mode_for_app = nullptr;
UxThemeSetPreferredAppModeFunc set_preferred_app_mode = nullptr;
UxThemeAllowDarkModeForWindowFunc allow_dark_mode_for_window = nullptr;
};
const DarkModeSupport& GetDarkModeSupport() {
static const DarkModeSupport dark_mode_support = [] {
DarkModeSupport dark_mode_support;
auto* os_info = base::win::OSInfo::GetInstance();
if (os_info->version() >= base::win::Version::WIN10_RS5 &&
base::win::IsUser32AndGdi32Available()) {
base::NativeLibraryLoadError error;
HMODULE ux_theme_lib = base::PinSystemLibrary(L"uxtheme.dll", &error);
DCHECK(!error.code);
if (os_info->version() >= base::win::Version::WIN10_19H1) {
dark_mode_support.set_preferred_app_mode =
reinterpret_cast<UxThemeSetPreferredAppModeFunc>(::GetProcAddress(
ux_theme_lib,
MAKEINTRESOURCEA(kUxThemeSetPreferredAppModeOrdinal)));
} else {
dark_mode_support.allow_dark_mode_for_app =
reinterpret_cast<UxThemeAllowDarkModeForAppFunc>(::GetProcAddress(
ux_theme_lib,
MAKEINTRESOURCEA(kUxThemeAllowDarkModeForAppOrdinal)));
}
dark_mode_support.allow_dark_mode_for_window =
reinterpret_cast<UxThemeAllowDarkModeForWindowFunc>(::GetProcAddress(
ux_theme_lib,
MAKEINTRESOURCEA(kUxThemeAllowDarkModeForWindowOrdinal)));
}
return dark_mode_support;
}();
return dark_mode_support;
}
bool IsForcedLightMode() {
static bool kIsForcedLightMode =
base::CommandLine::ForCurrentProcess()->HasSwitch(
"force-light-mode");
return kIsForcedLightMode;
}
}
namespace base::win {
bool IsDarkModeAvailable() {
if (IsForcedLightMode())
return false;
auto& dark_mode_support = GetDarkModeSupport();
return (dark_mode_support.allow_dark_mode_for_app ||
dark_mode_support.set_preferred_app_mode) &&
dark_mode_support.allow_dark_mode_for_window;
}
void AllowDarkModeForApp(bool allow) {
if (!IsDarkModeAvailable()) {
return;
}
auto& dark_mode_support = GetDarkModeSupport();
if (dark_mode_support.set_preferred_app_mode) {
dark_mode_support.set_preferred_app_mode(
allow ? PreferredAppMode::kAllowDark : PreferredAppMode::kDefault);
} else {
dark_mode_support.allow_dark_mode_for_app(allow);
}
}
bool AllowDarkModeForWindow(HWND hwnd, bool allow) {
if (!IsDarkModeAvailable()) {
return false;
}
return GetDarkModeSupport().allow_dark_mode_for_window(hwnd, allow);
}
}