view src/sys/win32/dark_theme.cc @ 105:6d8da6e64d61

theme: add dark stylesheet, make it actually usable win32: make the titlebar black where available
author Paper <mrpapersonic@gmail.com>
date Sun, 05 Nov 2023 03:54:26 -0500
parents 9b2b41f83a5e
children c8c72278f6fd
line wrap: on
line source

#include "sys/win32/dark_theme.h"
#include <QApplication>
#include <QDebug>
#include <QOperatingSystemVersion>
#include <QSettings>
#include <QWidget>
#include <iostream>
#include <dwmapi.h>

/* let's make a class wrapper around HINSTANCE, 
   so we don't fuck anything up :). */
class Library {
	public:
		Library() {}
		~Library() {
			Unload();
		}
		void Unload() {
			if (hInstance)
				FreeLibrary(hInstance);
			loaded = false;
		}
		void Load(LPCWSTR name) {
			if (loaded)
				Unload();
			hInstance = LoadLibraryW(name);
			if (hInstance)
				loaded = true;
		}
		HINSTANCE GetInstance() {
			return hInstance;
		}
		bool IsLoaded() {
			return loaded;
		}
	private:
		HINSTANCE hInstance = nullptr;
		bool loaded = false;
};

Library dwmapi;

namespace win32 {

#define GET_FUNCTION(f, i) \
	reinterpret_cast<decltype(::f)*>(GetProcAddress(i, #f))

static HRESULT SetWindowAttribute(HWND hWnd, DWORD key, LPCVOID data, DWORD sz_data) {
	if (!dwmapi.IsLoaded()) {
		dwmapi.Load(L"dwmapi.dll");
		if (!dwmapi.IsLoaded())
			return false;
	}

	HINSTANCE hInstance = dwmapi.GetInstance();
	if (!hInstance)
		return false;

	auto set_wind_attrib = GET_FUNCTION(DwmSetWindowAttribute, hInstance);
	if (!set_wind_attrib)
		return false;

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

/* Ok, so this doesn't work. Woohoo! :) */
bool SetTitleBarToBlack(QWidget* win, bool enabled) {
	BOOL b = enabled;

	/* MAGIC NUMBERS: 19 and 20 are both DWMWA_USE_IMMERSIVE_DARK_MODE.
	   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. */
	{
		HRESULT result = SetWindowAttribute(reinterpret_cast<HWND>(win->winId()), 20, &b, sizeof(b));
		if (result == S_OK)
			return b;
	}

	{
		/* It's 19 in older Windows 10 versions. Yeah, stupid. */
		HRESULT result = 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