view src/sys/win32/dark_theme.cc @ 187:9613d72b097e

*: multiple performance improvements like marking `static const` when it makes sense... date: change old stupid heap-based method to a structure which should make copying the thing actually make a copy. also many performance-based changes, like removing the std::tie dependency and forward-declaring nlohmann json *: replace every instance of QString::fromUtf8 to Strings::ToQString. the main difference is that our function will always convert exactly what is in the string, while some other times it would only convert up to the nearest NUL byte
author Paper <mrpapersonic@gmail.com>
date Wed, 06 Dec 2023 13:43:54 -0500
parents bc8d2ccff09c
children f0ff06a45c42
line wrap: on
line source

#include "sys/win32/dark_theme.h"

#include <QApplication>
#include <QOperatingSystemVersion>
#include <QSettings>
#include <QWidget>

#include <iostream>
#include <memory>

#include <dwmapi.h>

struct LibraryDeconstructor {
		using pointer = HINSTANCE;
		void operator()(pointer t) const { ::FreeLibrary(t); };
};

using Library = std::unique_ptr<HINSTANCE, LibraryDeconstructor>;

class Dwmapi {
	public:
		Dwmapi() { library.reset( ::LoadLibraryW(L"dwmapi.dll")); }

		HRESULT SetWindowAttribute(HWND hWnd, DWORD key, LPCVOID data, DWORD sz_data) {
			if (!library.get())
				return E_POINTER;

			/* GCC throws a fit here because C/C++ lacks a "generic" function pointer type.
			   Ignore. */
			auto set_wind_attrib = reinterpret_cast<decltype(::DwmSetWindowAttribute)*>(GetProcAddress(library.get(), "DwmSetWindowAttribute"));
			if (!set_wind_attrib)
				return E_POINTER;

			return set_wind_attrib(hWnd, key, data, sz_data);
		}

	protected:
		Library library = nullptr;
};

Dwmapi dwmapi;

namespace win32 {

/* NOTE: explicit conversion from builtin `bool` and win32 `BOOL` IS allowed. */
bool SetTitleBarToBlack(QWidget* win, bool enabled) {
	BOOL b = enabled;

	/* MAGIC NUMBERS: 19 and 20 are both DWMWA_USE_IMMERSIVE_DARK_MODE.
	   For clarification: it's 20 on newer versions of windows (i.e. win11 and late win10),
	   but it's 19 on very old versions of win10 nobody ought to be using anymore. */
	{
		HRESULT result = dwmapi.SetWindowAttribute(reinterpret_cast<HWND>(win->winId()), 20, &b, sizeof(b));
		if (result == S_OK)
			return b;
	}

	{
		HRESULT result = dwmapi.SetWindowAttribute(reinterpret_cast<HWND>(win->winId()), 19, &b, sizeof(b));
		if (result == S_OK)
			return b;
	}

	return b;
}

void SetTitleBarsToBlack(bool enabled) {
	for (QWidget* widget : qApp->topLevelWidgets()) {
		SetTitleBarToBlack(widget, enabled);
	}
}

bool DarkThemeAvailable() {
	const auto& ver = QOperatingSystemVersion::current();
	return (ver.majorVersion() > 10) ? true : (ver.majorVersion() == 10 && ver.microVersion() >= 17763);
}

bool IsInDarkTheme() {
	QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
	                   QSettings::NativeFormat);
	return settings.value("AppsUseLightTheme", 1).toInt() == 0;
}

} // namespace win32