comparison 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
comparison
equal deleted inserted replaced
104:27455104ea37 105:6d8da6e64d61
1 #include "sys/win32/dark_theme.h" 1 #include "sys/win32/dark_theme.h"
2 #include <QApplication>
3 #include <QDebug>
2 #include <QOperatingSystemVersion> 4 #include <QOperatingSystemVersion>
3 #include <QSettings> 5 #include <QSettings>
6 #include <QWidget>
7 #include <iostream>
8 #include <dwmapi.h>
9
10 /* let's make a class wrapper around HINSTANCE,
11 so we don't fuck anything up :). */
12 class Library {
13 public:
14 Library() {}
15 ~Library() {
16 Unload();
17 }
18 void Unload() {
19 if (hInstance)
20 FreeLibrary(hInstance);
21 loaded = false;
22 }
23 void Load(LPCWSTR name) {
24 if (loaded)
25 Unload();
26 hInstance = LoadLibraryW(name);
27 if (hInstance)
28 loaded = true;
29 }
30 HINSTANCE GetInstance() {
31 return hInstance;
32 }
33 bool IsLoaded() {
34 return loaded;
35 }
36 private:
37 HINSTANCE hInstance = nullptr;
38 bool loaded = false;
39 };
40
41 Library dwmapi;
4 42
5 namespace win32 { 43 namespace win32 {
6 44
45 #define GET_FUNCTION(f, i) \
46 reinterpret_cast<decltype(::f)*>(GetProcAddress(i, #f))
47
48 static HRESULT SetWindowAttribute(HWND hWnd, DWORD key, LPCVOID data, DWORD sz_data) {
49 if (!dwmapi.IsLoaded()) {
50 dwmapi.Load(L"dwmapi.dll");
51 if (!dwmapi.IsLoaded())
52 return false;
53 }
54
55 HINSTANCE hInstance = dwmapi.GetInstance();
56 if (!hInstance)
57 return false;
58
59 auto set_wind_attrib = GET_FUNCTION(DwmSetWindowAttribute, hInstance);
60 if (!set_wind_attrib)
61 return false;
62
63 return set_wind_attrib(hWnd, key, data, sz_data);
64 }
65
66 /* Ok, so this doesn't work. Woohoo! :) */
67 bool SetTitleBarToBlack(QWidget* win, bool enabled) {
68 BOOL b = enabled;
69
70 /* MAGIC NUMBERS: 19 and 20 are both DWMWA_USE_IMMERSIVE_DARK_MODE.
71 clarification: it's 20 on newer versions of windows (i.e. win11 and late win10),
72 but it's 19 on very old versions of win10 nobody ought to be using. */
73 {
74 HRESULT result = SetWindowAttribute(reinterpret_cast<HWND>(win->winId()), 20, &b, sizeof(b));
75 if (result == S_OK)
76 return b;
77 }
78
79 {
80 /* It's 19 in older Windows 10 versions. Yeah, stupid. */
81 HRESULT result = SetWindowAttribute(reinterpret_cast<HWND>(win->winId()), 19, &b, sizeof(b));
82 if (result == S_OK)
83 return b;
84 }
85
86 return b;
87 }
88
89 void SetTitleBarsToBlack(bool enabled) {
90 for (QWidget* widget : qApp->topLevelWidgets()) {
91 SetTitleBarToBlack(widget, enabled);
92 }
93 }
94
7 bool DarkThemeAvailable() { 95 bool DarkThemeAvailable() {
8 // dark mode supported Windows 10 1809 10.0.17763 onward
9 // https://stackoverflow.com/questions/53501268/win10-dark-theme-how-to-use-in-winapi
10 const auto& ver = QOperatingSystemVersion::current(); 96 const auto& ver = QOperatingSystemVersion::current();
11 return (ver.majorVersion() > 10) ? true : (ver.majorVersion() == 10 && ver.microVersion() >= 17763); 97 return (ver.majorVersion() > 10) ? true : (ver.majorVersion() == 10 && ver.microVersion() >= 17763);
12 } 98 }
13 99
14 bool IsInDarkTheme() { 100 bool IsInDarkTheme() {