diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2022-02-21 00:12:34 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2022-02-21 00:12:34 +0200 |
commit | 02fc9553060b4a80e0b5e9c4bdc218dcbb7981c4 (patch) | |
tree | 89d5c6b013873b4feb1595abf5d72deb21ca50fc /src | |
parent | cebc848472629d63cf633973a34df0bc9858efc6 (diff) |
Windows: Fixed dark mode for multiple windows
Diffstat (limited to 'src')
-rw-r--r-- | src/ui/window.c | 1 | ||||
-rw-r--r-- | src/win32.c | 100 |
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 | ||
38 | static 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 | ||
38 | Apparently Microsoft never documented the Win32 functions that control dark mode for | 49 | Apparently Microsoft never documented the Win32 functions that control dark mode for |
@@ -96,12 +107,64 @@ typedef BOOL (WINAPI *AllowDarkModeForWindowFunc)(HWND hWnd, BOOL allow); | |||
96 | static AllowDarkModeForWindowFunc AllowDarkModeForWindow_; | 107 | static AllowDarkModeForWindowFunc AllowDarkModeForWindow_; |
97 | static SetWindowCompositionAttributeFunc SetWindowCompositionAttribute_; | 108 | static SetWindowCompositionAttributeFunc SetWindowCompositionAttribute_; |
98 | 109 | ||
110 | iDeclareType(HandleDarkness) | ||
111 | |||
112 | struct Impl_HandleDarkness { | ||
113 | HWND hwnd; | ||
114 | BOOL isDark; | ||
115 | }; | ||
116 | |||
117 | static int cmp_HandleDarkness_(const void *a, const void *b) { | ||
118 | return iCmp(((const iHandleDarkness *) a)->hwnd, | ||
119 | ((const iHandleDarkness *) b)->hwnd); | ||
120 | } | ||
121 | |||
99 | static DWORD ntBuildNumber_; | 122 | static DWORD ntBuildNumber_; |
100 | static BOOL isDark_; | 123 | static 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 | |||
128 | static void maybeInitDarkness_(void) { | ||
129 | if (!darkness_.cmp) { | ||
130 | init_SortedArray(&darkness_, sizeof(iHandleDarkness), cmp_HandleDarkness_); | ||
131 | } | ||
132 | } | ||
133 | |||
134 | static 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 | |||
143 | static void setIsDark_(HWND hwnd, BOOL isDark) { | ||
144 | maybeInitDarkness_(); | ||
145 | insert_SortedArray(&darkness_, &(iHandleDarkness){ hwnd, isDark }); | ||
146 | } | ||
147 | |||
148 | static 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 | ||
102 | static iBool refreshTitleBarThemeColor_(HWND hwnd) { | 165 | static 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 | ||
179 | static 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 | |||
188 | void useExecutableIconResource_SDLWindow(SDL_Window *win) { | 242 | void 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 | ||
205 | void handleCommand_Win32(const char *cmd) { | 259 | void 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) |