summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2022-02-21 00:12:34 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2022-02-21 00:12:34 +0200
commit02fc9553060b4a80e0b5e9c4bdc218dcbb7981c4 (patch)
tree89d5c6b013873b4feb1595abf5d72deb21ca50fc
parentcebc848472629d63cf633973a34df0bc9858efc6 (diff)
Windows: Fixed dark mode for multiple windows
-rw-r--r--src/ui/window.c1
-rw-r--r--src/win32.c100
2 files changed, 81 insertions, 20 deletions
diff --git a/src/ui/window.c b/src/ui/window.c
index 90588ccf..99dde786 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -1346,6 +1346,7 @@ void draw_MainWindow(iMainWindow *d) {
1346 } 1346 }
1347 } 1347 }
1348 } 1348 }
1349 setCurrent_Window(d);
1349 const int winFlags = SDL_GetWindowFlags(d->base.win); 1350 const int winFlags = SDL_GetWindowFlags(d->base.win);
1350 const iBool gotFocus = (winFlags & SDL_WINDOW_INPUT_FOCUS) != 0; 1351 const iBool gotFocus = (winFlags & SDL_WINDOW_INPUT_FOCUS) != 0;
1351 iPaint p; 1352 iPaint p;
diff --git a/src/win32.c b/src/win32.c
index 05ed2c4b..0a456b45 100644
--- a/src/win32.c
+++ b/src/win32.c
@@ -25,6 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
25#include "ui/command.h" 25#include "ui/command.h"
26#include "prefs.h" 26#include "prefs.h"
27#include "app.h" 27#include "app.h"
28
29#include <the_Foundation/sortedarray.h>
28#include <SDL_syswm.h> 30#include <SDL_syswm.h>
29 31
30#define WIN32_LEAN_AND_MEAN 32#define WIN32_LEAN_AND_MEAN
@@ -33,6 +35,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
33#include <dwmapi.h> 35#include <dwmapi.h>
34#include <d2d1.h> 36#include <d2d1.h>
35 37
38static HWND windowHandle_(SDL_Window *win) {
39 SDL_SysWMinfo wmInfo;
40 SDL_VERSION(&wmInfo.version);
41 if (SDL_GetWindowWMInfo(win, &wmInfo)) {
42 return wmInfo.info.win.window;
43 }
44 return NULL;
45}
46
36/* Windows 10 Dark Mode Support 47/* Windows 10 Dark Mode Support
37 48
38Apparently Microsoft never documented the Win32 functions that control dark mode for 49Apparently Microsoft never documented the Win32 functions that control dark mode for
@@ -96,12 +107,64 @@ typedef BOOL (WINAPI *AllowDarkModeForWindowFunc)(HWND hWnd, BOOL allow);
96static AllowDarkModeForWindowFunc AllowDarkModeForWindow_; 107static AllowDarkModeForWindowFunc AllowDarkModeForWindow_;
97static SetWindowCompositionAttributeFunc SetWindowCompositionAttribute_; 108static SetWindowCompositionAttributeFunc SetWindowCompositionAttribute_;
98 109
110iDeclareType(HandleDarkness)
111
112struct Impl_HandleDarkness {
113 HWND hwnd;
114 BOOL isDark;
115};
116
117static int cmp_HandleDarkness_(const void *a, const void *b) {
118 return iCmp(((const iHandleDarkness *) a)->hwnd,
119 ((const iHandleDarkness *) b)->hwnd);
120}
121
99static DWORD ntBuildNumber_; 122static DWORD ntBuildNumber_;
100static BOOL isDark_; 123static iSortedArray darkness_; /* state tracking; TODO: replace with a flag in MainWindow? */
124
125/* Ugly bit of bookkeeping here, but the idea is that the Windows-specific behavior
126 is invisible outside this source module. */
127
128static void maybeInitDarkness_(void) {
129 if (!darkness_.cmp) {
130 init_SortedArray(&darkness_, sizeof(iHandleDarkness), cmp_HandleDarkness_);
131 }
132}
133
134static BOOL isDark_(HWND hwnd) {
135 maybeInitDarkness_();
136 size_t pos;
137 if (locate_SortedArray(&darkness_, &(iHandleDarkness){ hwnd }, &pos)) {
138 return ((const iHandleDarkness *) at_SortedArray(&darkness_, pos))->isDark;
139 }
140 return FALSE;
141}
142
143static void setIsDark_(HWND hwnd, BOOL isDark) {
144 maybeInitDarkness_();
145 insert_SortedArray(&darkness_, &(iHandleDarkness){ hwnd, isDark });
146}
147
148static void cleanDark_(void) {
149 /* TODO: Just add a flag in MainWindow. */
150 iForEach(Array, i, &darkness_.values) {
151 iHandleDarkness *dark = i.value;
152 iBool exists = iFalse;
153 iConstForEach(PtrArray, iter, mainWindows_App()) {
154 if (windowHandle_(((const iMainWindow *) iter.ptr)->base.win) == dark->hwnd) {
155 exists = iTrue;
156 break;
157 }
158 }
159 if (!exists) {
160 remove_ArrayIterator(&i);
161 }
162 }
163}
101 164
102static iBool refreshTitleBarThemeColor_(HWND hwnd) { 165static iBool refreshTitleBarThemeColor_(HWND hwnd) {
103 BOOL dark = isDark_ColorTheme(prefs_App()->theme); 166 BOOL dark = isDark_ColorTheme(prefs_App()->theme);
104 if (dark == isDark_) { 167 if (dark == isDark_(hwnd)) {
105 return FALSE; 168 return FALSE;
106 } 169 }
107 if (ntBuildNumber_ < 18362) { 170 if (ntBuildNumber_ < 18362) {
@@ -114,7 +177,7 @@ static iBool refreshTitleBarThemeColor_(HWND hwnd) {
114 }; 177 };
115 SetWindowCompositionAttribute_(hwnd, &data); 178 SetWindowCompositionAttribute_(hwnd, &data);
116 } 179 }
117 isDark_ = dark; 180 setIsDark_(hwnd, dark);
118 return TRUE; 181 return TRUE;
119} 182}
120 183
@@ -176,15 +239,6 @@ float desktopDPI_Win32(void) {
176 return ratio; 239 return ratio;
177} 240}
178 241
179static HWND windowHandle_(SDL_Window *win) {
180 SDL_SysWMinfo wmInfo;
181 SDL_VERSION(&wmInfo.version);
182 if (SDL_GetWindowWMInfo(win, &wmInfo)) {
183 return wmInfo.info.win.window;
184 }
185 return NULL;
186}
187
188void useExecutableIconResource_SDLWindow(SDL_Window *win) { 242void useExecutableIconResource_SDLWindow(SDL_Window *win) {
189 HINSTANCE handle = GetModuleHandle(NULL); 243 HINSTANCE handle = GetModuleHandle(NULL);
190 HICON icon = LoadIcon(handle, "IDI_ICON1"); 244 HICON icon = LoadIcon(handle, "IDI_ICON1");
@@ -204,16 +258,22 @@ void enableDarkMode_SDLWindow(SDL_Window *win) {
204 258
205void handleCommand_Win32(const char *cmd) { 259void handleCommand_Win32(const char *cmd) {
206 if (equal_Command(cmd, "theme.changed")) { 260 if (equal_Command(cmd, "theme.changed")) {
207 iMainWindow *mw = get_MainWindow(); 261 iConstForEach(PtrArray, iter, mainWindows_App()) {
208 SDL_Window *win = mw->base.win; 262 iMainWindow *mw = iter.ptr;
209 if (refreshTitleBarThemeColor_(windowHandle_(win)) && 263 SDL_Window *win = mw->base.win;
210 !isFullscreen_MainWindow(mw) && 264 if (refreshTitleBarThemeColor_(windowHandle_(win)) &&
211 !argLabel_Command(cmd, "auto")) { 265 !isFullscreen_MainWindow(mw) &&
212 /* This will ensure that the non-client area is repainted. */ 266 !argLabel_Command(cmd, "auto")) {
213 SDL_MinimizeWindow(win); 267 /* Silly hack, but this will ensure that the non-client area is repainted. */
214 SDL_RestoreWindow(win); 268 SDL_MinimizeWindow(win);
269 SDL_RestoreWindow(win);
270 }
215 } 271 }
216 } 272 }
273 else if (equal_Command(cmd, "window.focus.gained")) {
274 /* Purge old windows from the darkness. */
275 cleanDark_();
276 }
217} 277}
218 278
219#if defined (LAGRANGE_ENABLE_CUSTOM_FRAME) 279#if defined (LAGRANGE_ENABLE_CUSTOM_FRAME)