comparison win/dw.c @ 1969:2322769acf88

Win: More Dark Mode work, code based on information found on github... https://github.com/ysc3839/win32-darkmode/tree/master/win32-darkmode
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Fri, 02 Aug 2019 00:44:52 +0000
parents d510e9bb61c2
children 8cf330e1e331
comparison
equal deleted inserted replaced
1968:abb949dd3bb3 1969:2322769acf88
206 #endif 206 #endif
207 207
208 #ifdef AEROGLASS 208 #ifdef AEROGLASS
209 HRESULT (WINAPI *_DwmExtendFrameIntoClientArea)(HWND hWnd, const MARGINS *pMarInset) = 0; 209 HRESULT (WINAPI *_DwmExtendFrameIntoClientArea)(HWND hWnd, const MARGINS *pMarInset) = 0;
210 HRESULT (WINAPI *_DwmIsCompositionEnabled)(BOOL *pfEnabled) = 0; 210 HRESULT (WINAPI *_DwmIsCompositionEnabled)(BOOL *pfEnabled) = 0;
211 HRESULT (WINAPI *_DwmSetWindowAttribute)(HWND, DWORD, LPCVOID, DWORD) = 0;
211 HTHEME (WINAPI *_OpenThemeData)(HWND hwnd, LPCWSTR pszClassList) = 0; 212 HTHEME (WINAPI *_OpenThemeData)(HWND hwnd, LPCWSTR pszClassList) = 0;
212 HPAINTBUFFER (WINAPI *_BeginBufferedPaint)(HDC hdcTarget, const RECT *prcTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS *pPaintParams, HDC *phdc) = 0; 213 HPAINTBUFFER (WINAPI *_BeginBufferedPaint)(HDC hdcTarget, const RECT *prcTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS *pPaintParams, HDC *phdc) = 0;
213 HRESULT (WINAPI *_BufferedPaintSetAlpha)(HPAINTBUFFER hBufferedPaint, const RECT *prc, BYTE alpha) = 0; 214 HRESULT (WINAPI *_BufferedPaintSetAlpha)(HPAINTBUFFER hBufferedPaint, const RECT *prc, BYTE alpha) = 0;
214 HRESULT (WINAPI *_DrawThemeTextEx)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwFlags, LPRECT pRect, const DTTOPTS *pOptions) = 0; 215 HRESULT (WINAPI *_DrawThemeTextEx)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwFlags, LPRECT pRect, const DTTOPTS *pOptions) = 0;
215 HRESULT (WINAPI *_EndBufferedPaint)(HPAINTBUFFER hBufferedPaint, BOOL fUpdateTarget) = 0; 216 HRESULT (WINAPI *_EndBufferedPaint)(HPAINTBUFFER hBufferedPaint, BOOL fUpdateTarget) = 0;
669 } 670 }
670 return NULL; 671 return NULL;
671 } 672 }
672 #endif 673 #endif
673 674
675 #ifdef AEROGLASS
674 int _DW_DARK_MODE_ALLOWED = FALSE; 676 int _DW_DARK_MODE_ALLOWED = FALSE;
675 677 int _DW_DARK_MODE_SUPPORTED = FALSE;
676 /* Call this on a window to apply the style */ 678 int _DW_DARK_MODE_ENABLED = FALSE;
677 BOOL CALLBACK _set_child_window_theme(HWND window, LPARAM lParam) 679
678 { 680 typedef enum IMMERSIVE_HC_CACHE_MODE
679 static int initialized = FALSE; 681 {
680 static BOOL (WINAPI * AllowDarkModeForWindow)(HWND a_HWND, BOOL a_Allow) = NULL; 682 IHCM_USE_CACHED_VALUE,
681 683 IHCM_REFRESH
682 if(initialized == FALSE && dwVersion) 684 } IMMERSIVE_HC_CACHE_MODE;
685
686 typedef enum _PreferredAppMode
687 {
688 _Default,
689 _AllowDark,
690 _ForceDark,
691 _ForceLight,
692 _Max
693 } _PreferredAppMode;
694
695 HTHEME (WINAPI * _OpenNcThemeData)(HWND, LPCWSTR) = NULL;
696 VOID (WINAPI * _RefreshImmersiveColorPolicyState)(VOID) = NULL;
697 BOOL (WINAPI * _GetIsImmersiveColorUsingHighContrast)(IMMERSIVE_HC_CACHE_MODE) = NULL;
698 BOOL (WINAPI * _ShouldAppsUseDarkMode)(VOID) = NULL;
699 BOOL (WINAPI * _AllowDarkModeForWindow)(HWND, BOOL) = NULL;
700 BOOL (WINAPI * _AllowDarkModeForApp)(BOOL) = NULL;
701 _PreferredAppMode (WINAPI * _SetPreferredAppMode)(_PreferredAppMode) = NULL;
702 BOOL (WINAPI * _IsDarkModeAllowedForWindow)(HWND) = NULL;
703 BOOL (WINAPI * _ShouldSystemUseDarkMode)(VOID) = NULL;
704
705 void _dw_init_dark_mode(void)
706 {
707 if(_DW_DARK_MODE_ALLOWED && dwVersion && huxtheme)
683 { 708 {
684 /* Dark mode is introduced in Windows 10 (1809) build 17763 */ 709 /* Dark mode is introduced in Windows 10 (1809) build 17763 */
685 if(LOBYTE(LOWORD(dwVersion)) >= 10 && HIWORD(dwVersion) >= 17763) 710 if(LOBYTE(LOWORD(dwVersion)) >= 10 && HIWORD(dwVersion) >= 17763)
686 AllowDarkModeForWindow = (BOOL (WINAPI *)(HWND, BOOL))GetProcAddress(huxtheme, MAKEINTRESOURCEA(133)); 711 {
687 initialized = TRUE; 712 _OpenNcThemeData = (HTHEME (WINAPI *)(HWND, LPCWSTR))GetProcAddress(huxtheme, MAKEINTRESOURCEA(49));
688 } 713 _RefreshImmersiveColorPolicyState = (VOID (WINAPI *)(VOID))GetProcAddress(huxtheme, MAKEINTRESOURCEA(104));
689 if(AllowDarkModeForWindow) 714 _GetIsImmersiveColorUsingHighContrast = (BOOL (WINAPI *)(IMMERSIVE_HC_CACHE_MODE))GetProcAddress(huxtheme, MAKEINTRESOURCEA(106));
690 { 715 _ShouldAppsUseDarkMode = (BOOL (WINAPI *)(VOID))GetProcAddress(huxtheme, MAKEINTRESOURCEA(132));
691 AllowDarkModeForWindow(window, _DW_DARK_MODE_ALLOWED); 716 _AllowDarkModeForWindow = (BOOL (WINAPI *)(HWND, BOOL))GetProcAddress(huxtheme, MAKEINTRESOURCEA(133));
692 if(_DW_DARK_MODE_ALLOWED && _SetWindowTheme) 717 if(HIWORD(dwVersion) < 18334)
693 { 718 _AllowDarkModeForApp = (BOOL (WINAPI *)(BOOL))GetProcAddress(huxtheme, MAKEINTRESOURCEA(135));
694 _SetWindowTheme(window, L"DarkMode_Explorer", NULL); 719 else
695 } 720 _SetPreferredAppMode = (_PreferredAppMode (WINAPI *)(_PreferredAppMode))GetProcAddress(huxtheme, MAKEINTRESOURCEA(135));
696 } 721 _IsDarkModeAllowedForWindow = (BOOL (WINAPI *)(HWND))GetProcAddress(huxtheme, MAKEINTRESOURCEA(137));
722 _ShouldSystemUseDarkMode = (BOOL (WINAPI *)(VOID))GetProcAddress(huxtheme, MAKEINTRESOURCEA(138));
723 }
724 /* Make sure we were able to load all the Dark Mode functions */
725 if(_OpenNcThemeData && _RefreshImmersiveColorPolicyState && _ShouldAppsUseDarkMode && _AllowDarkModeForWindow &&
726 (_AllowDarkModeForApp || _SetPreferredAppMode) && _IsDarkModeAllowedForWindow && _DwmSetWindowAttribute)
727 {
728 _DW_DARK_MODE_SUPPORTED = TRUE;
729 _AllowDarkModeForApp(TRUE);
730 _RefreshImmersiveColorPolicyState();
731 }
732 }
733 }
734
735 BOOL AllowDarkModeForWindow(HWND window, BOOL allow)
736 {
737 if(_DW_DARK_MODE_SUPPORTED)
738 return _AllowDarkModeForWindow(window, allow);
739 return FALSE;
740 }
741
742 BOOL IsHighContrast(VOID)
743 {
744 HIGHCONTRASTW highContrast = { sizeof(highContrast) };
745 if(SystemParametersInfoW(SPI_GETHIGHCONTRAST, sizeof(highContrast), &highContrast, FALSE))
746 return highContrast.dwFlags & HCF_HIGHCONTRASTON;
747 return FALSE;
748 }
749
750 BOOL IsColorSchemeChangeMessage(LPARAM lParam)
751 {
752 BOOL is = FALSE;
753 if(lParam && CompareStringOrdinal((LPCWCH)lParam, -1, L"ImmersiveColorSet", -1, TRUE) == CSTR_EQUAL)
754 {
755 _RefreshImmersiveColorPolicyState();
756 is = TRUE;
757 }
758 _GetIsImmersiveColorUsingHighContrast(IHCM_REFRESH);
759 return is;
760 }
761
762 void RefreshTitleBarThemeColor(HWND window)
763 {
764 BOOL dark = FALSE;
765 if (_IsDarkModeAllowedForWindow(window) && _ShouldAppsUseDarkMode() && !IsHighContrast())
766 dark = TRUE;
767 _DwmSetWindowAttribute(window, 19, &dark, sizeof(dark));
768 }
769
770 /* Call this on a window to apply the style */
771 BOOL CALLBACK _dw_set_child_window_theme(HWND window, LPARAM lParam)
772 {
773 if(_DW_DARK_MODE_SUPPORTED)
774 AllowDarkModeForWindow(window, _DW_DARK_MODE_ENABLED);
697 return TRUE; 775 return TRUE;
698 } 776 }
777 #endif
699 778
700 /* This function adds a signal handler callback into the linked list. 779 /* This function adds a signal handler callback into the linked list.
701 */ 780 */
702 void _new_signal(ULONG message, HWND window, int id, void *signalfunction, void *discfunc, void *data) 781 void _new_signal(ULONG message, HWND window, int id, void *signalfunction, void *discfunc, void *data)
703 { 782 {
2221 if(_DwmExtendFrameIntoClientArea) 2300 if(_DwmExtendFrameIntoClientArea)
2222 _DwmExtendFrameIntoClientArea(hWnd, &mar); 2301 _DwmExtendFrameIntoClientArea(hWnd, &mar);
2223 } 2302 }
2224 } 2303 }
2225 break; 2304 break;
2305 case WM_SETTINGCHANGE:
2306 {
2307 if(_DW_DARK_MODE_SUPPORTED && IsColorSchemeChangeMessage(mp2))
2308 SendMessageW(hWnd, WM_THEMECHANGED, 0, 0);
2309 }
2310 break;
2311 case WM_THEMECHANGED:
2312 {
2313 if(_DW_DARK_MODE_SUPPORTED)
2314 {
2315 _AllowDarkModeForWindow(hWnd, _DW_DARK_MODE_ENABLED);
2316 if(GetParent(hWnd) == HWND_DESKTOP)
2317 RefreshTitleBarThemeColor(hWnd);
2318 }
2319 }
2320 break;
2226 #endif 2321 #endif
2227 #ifdef AEROGLASS1 2322 #ifdef AEROGLASS1
2228 case WM_ERASEBKGND: 2323 case WM_ERASEBKGND:
2229 if(_dw_composition && (GetWindowLongPtr(hWnd, GWL_EXSTYLE) & WS_EX_LAYERED)) 2324 if(_dw_composition && (GetWindowLongPtr(hWnd, GWL_EXSTYLE) & WS_EX_LAYERED))
2230 { 2325 {
2231 static HBRUSH hbrush = 0; 2326 static HBRUSH hbrush = 0;
2232 RECT rect; 2327 RECT rect;
2237 GetClientRect(hWnd, &rect); 2332 GetClientRect(hWnd, &rect);
2238 FillRect((HDC)mp1, &rect, hbrush); 2333 FillRect((HDC)mp1, &rect, hbrush);
2239 return TRUE; 2334 return TRUE;
2240 } 2335 }
2241 break; 2336 break;
2242 #endif 2337 #endif
2243 case WM_PAINT: 2338 case WM_PAINT:
2244 { 2339 {
2245 PAINTSTRUCT ps; 2340 PAINTSTRUCT ps;
2246 2341
2247 BeginPaint(hWnd, &ps); 2342 BeginPaint(hWnd, &ps);
3994 #ifdef AEROGLASS 4089 #ifdef AEROGLASS
3995 /* Attempt to load the Desktop Window Manager and Theme library */ 4090 /* Attempt to load the Desktop Window Manager and Theme library */
3996 if(huxtheme && (hdwm = LoadLibrary(TEXT("dwmapi")))) 4091 if(huxtheme && (hdwm = LoadLibrary(TEXT("dwmapi"))))
3997 { 4092 {
3998 _DwmExtendFrameIntoClientArea = (HRESULT (WINAPI *)(HWND, const MARGINS *))GetProcAddress(hdwm, "DwmExtendFrameIntoClientArea"); 4093 _DwmExtendFrameIntoClientArea = (HRESULT (WINAPI *)(HWND, const MARGINS *))GetProcAddress(hdwm, "DwmExtendFrameIntoClientArea");
4094 _DwmSetWindowAttribute = (HRESULT (WINAPI *)(HWND, DWORD, LPCVOID, DWORD))GetProcAddress(hdwm, "DwmSetWindowAttribute");
3999 if((_DwmIsCompositionEnabled = (HRESULT (WINAPI *)(BOOL *))GetProcAddress(hdwm, "DwmIsCompositionEnabled"))) 4095 if((_DwmIsCompositionEnabled = (HRESULT (WINAPI *)(BOOL *))GetProcAddress(hdwm, "DwmIsCompositionEnabled")))
4000 _DwmIsCompositionEnabled(&_dw_composition); 4096 _DwmIsCompositionEnabled(&_dw_composition);
4001 _OpenThemeData = (HTHEME (WINAPI *)(HWND, LPCWSTR))GetProcAddress(huxtheme, "OpenThemeData"); 4097 _OpenThemeData = (HTHEME (WINAPI *)(HWND, LPCWSTR))GetProcAddress(huxtheme, "OpenThemeData");
4002 _BeginBufferedPaint = (HPAINTBUFFER (WINAPI *)(HDC, const RECT *, BP_BUFFERFORMAT, BP_PAINTPARAMS *, HDC *))GetProcAddress(huxtheme, "BeginBufferedPaint"); 4098 _BeginBufferedPaint = (HPAINTBUFFER (WINAPI *)(HDC, const RECT *, BP_BUFFERFORMAT, BP_PAINTPARAMS *, HDC *))GetProcAddress(huxtheme, "BeginBufferedPaint");
4003 _BufferedPaintSetAlpha = (HRESULT (WINAPI *)(HPAINTBUFFER, const RECT *, BYTE))GetProcAddress(huxtheme, "BufferedPaintSetAlpha"); 4099 _BufferedPaintSetAlpha = (HRESULT (WINAPI *)(HPAINTBUFFER, const RECT *, BYTE))GetProcAddress(huxtheme, "BufferedPaintSetAlpha");
4004 _DrawThemeTextEx = (HRESULT (WINAPI *)(HTHEME, HDC, int, int, LPCWSTR, int, DWORD, LPRECT, const DTTOPTS *))GetProcAddress(huxtheme, "DrawThemeTextEx"); 4100 _DrawThemeTextEx = (HRESULT (WINAPI *)(HTHEME, HDC, int, int, LPCWSTR, int, DWORD, LPRECT, const DTTOPTS *))GetProcAddress(huxtheme, "DrawThemeTextEx");
4005 _EndBufferedPaint = (HRESULT (WINAPI *)(HPAINTBUFFER, BOOL))GetProcAddress(huxtheme, "EndBufferedPaint"); 4101 _EndBufferedPaint = (HRESULT (WINAPI *)(HPAINTBUFFER, BOOL))GetProcAddress(huxtheme, "EndBufferedPaint");
4006 _CloseThemeData = (HRESULT (WINAPI *)(HTHEME))GetProcAddress(huxtheme, "CloseThemeData"); 4102 _CloseThemeData = (HRESULT (WINAPI *)(HTHEME))GetProcAddress(huxtheme, "CloseThemeData");
4103 _dw_init_dark_mode();
4007 } 4104 }
4008 /* In case of error close the library if needed */ 4105 /* In case of error close the library if needed */
4009 else if(hdwm) 4106 else if(hdwm)
4010 { 4107 {
4011 FreeLibrary(hdwm); 4108 FreeLibrary(hdwm);
4271 { 4368 {
4272 int rc; 4369 int rc;
4273 RECT rect; 4370 RECT rect;
4274 4371
4275 /* Try to enable dark mode support if our OS supports it */ 4372 /* Try to enable dark mode support if our OS supports it */
4276 _set_child_window_theme(handle, 0); 4373 _dw_set_child_window_theme(handle, 0);
4277 EnumChildWindows(handle, _set_child_window_theme, 0); 4374 EnumChildWindows(handle, _dw_set_child_window_theme, 0);
4278 4375
4279 GetClientRect(handle, &rect); 4376 GetClientRect(handle, &rect);
4280 4377
4281 /* If the client area is 0x0 then call the autosize routine */ 4378 /* If the client area is 0x0 then call the autosize routine */
4282 if((rect.bottom - rect.top) == 0 || (rect.right - rect.left) == 0) 4379 if((rect.bottom - rect.top) == 0 || (rect.right - rect.left) == 0)