├── .gitignore ├── Assets └── Noise.png ├── CMakeLists.txt ├── LICENSE ├── README.md ├── app.ico ├── app.manifest ├── app.rc ├── doc ├── dark.png └── light.png ├── main.cpp └── resource.h /.gitignore: -------------------------------------------------------------------------------- 1 | # C++ objects and libs 2 | *.slo 3 | *.lo 4 | *.o 5 | *.a 6 | *.la 7 | *.lai 8 | *.so 9 | *.so.* 10 | *.dll 11 | *.dylib 12 | 13 | # Qt-es 14 | object_script.*.Release 15 | object_script.*.Debug 16 | *_plugin_import.cpp 17 | /.qmake.cache 18 | /.qmake.stash 19 | *.pro.user 20 | *.pro.user.* 21 | *.qbs.user 22 | *.qbs.user.* 23 | *.moc 24 | moc_*.cpp 25 | moc_*.h 26 | qrc_*.cpp 27 | ui_*.h 28 | *.qmlc 29 | *.jsc 30 | Makefile* 31 | *build-* 32 | *.qm 33 | *.prl 34 | 35 | # Qt unit tests 36 | target_wrapper.* 37 | 38 | # QtCreator 39 | *.autosave 40 | 41 | # QtCreator Qml 42 | *.qmlproject.user 43 | *.qmlproject.user.* 44 | 45 | # QtCreator CMake 46 | CMakeLists.txt.user* 47 | 48 | # QtCreator 4.8< compilation database 49 | compile_commands.json 50 | 51 | # QtCreator local machine specific files for imported projects 52 | *creator.user* 53 | -------------------------------------------------------------------------------- /Assets/Noise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangwenx190/d2d-mica/5c61cafbfb844f6035bbf0db28fad30d73ceb536/Assets/Noise.png -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.24) 2 | 3 | project(d2dmica LANGUAGES RC CXX) 4 | 5 | if(NOT MSVC) 6 | message(FATAL_ERROR "This project only supports building with the latest MSVC toolchain!") 7 | endif() 8 | 9 | set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON) 10 | 11 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 12 | 13 | set(CMAKE_CXX_STANDARD 20) 14 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 15 | set(CMAKE_CXX_EXTENSIONS OFF) 16 | 17 | set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded$<$:Debug>) 18 | 19 | string(REGEX REPLACE "[-|/]GR" "/GR-" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) 20 | #string(REGEX REPLACE "[-|/]EHsc" "/EHs-c-" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) 21 | string(REGEX REPLACE "[-|/]W[0|1|2|3|4]" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) 22 | string(REGEX REPLACE "[-|/]Ob[0|1|2|3]" "/Ob3" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) 23 | string(APPEND CMAKE_RC_FLAGS " /c65001 /nologo ") 24 | 25 | add_executable(${PROJECT_NAME} WIN32) 26 | 27 | target_sources(${PROJECT_NAME} PRIVATE 28 | app.rc app.manifest resource.h main.cpp 29 | ) 30 | 31 | target_link_libraries(${PROJECT_NAME} PRIVATE 32 | winmm uxtheme dwmapi d2d1 d3d11 dxgi dxguid 33 | ) 34 | 35 | set(_WIN32_WINNT_WIN10 0x0A00) 36 | set(NTDDI_WIN10_CO 0x0A00000B) 37 | target_compile_definitions(${PROJECT_NAME} PRIVATE 38 | _CRT_NON_CONFORMING_SWPRINTFS _CRT_SECURE_NO_WARNINGS 39 | _ENABLE_EXTENDED_ALIGNED_STORAGE NOMINMAX UNICODE 40 | _UNICODE WIN32_LEAN_AND_MEAN WINRT_LEAN_AND_MEAN 41 | WINVER=${_WIN32_WINNT_WIN10} _WIN32_WINNT=${_WIN32_WINNT_WIN10} 42 | _WIN32_IE=${_WIN32_WINNT_WIN10} NTDDI_VERSION=${NTDDI_WIN10_CO} 43 | ) 44 | 45 | target_compile_options(${PROJECT_NAME} PRIVATE 46 | /await:strict /bigobj /d2FH4 /MP /FS /utf-8 /W4 /WX /permissive- /ZH:SHA_256 47 | /Zc:char8_t,__cplusplus,externC,externConstexpr,hiddenFriend,lambda,preprocessor,referenceBinding,rvalueCast,strictStrings,ternary,throwingNew,trigraphs 48 | $<$:/JMC> 49 | $<$>:/guard:cf /guard:ehcont /GA /GT /Gw /Gy /Oi /Oy /QIntel-jcc-erratum /Qspectre-load /Zc:inline> 50 | ) 51 | 52 | target_link_options(${PROJECT_NAME} PRIVATE 53 | /DYNAMICBASE /HIGHENTROPYVA /LARGEADDRESSAWARE /NXCOMPAT /TSAWARE /WX 54 | $<$>:/CETCOMPAT /GUARD:CF /GUARD:EHCONT /OPT:REF /OPT:ICF> 55 | ) 56 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (C) 2022 by wangwenx190 (Yuhang Zhao) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Homemade Mica Material (Direct2D) 2 | 3 | Homemade Mica Material, using pure Direct2D technology, no XAML Islands, no DirectComposition or Windows.UI.Composition. 4 | 5 | Microsoft Docs: 6 | 7 | ## Screenshots 8 | 9 | ![light](./doc/light.png) 10 | 11 | ![dark](./doc/dark.png) 12 | 13 | ## Requirements 14 | 15 | At least Windows 10. Windows 11 is also supported. Maybe have compatibility issues when running on old Windows 10 versions such as 1607. It's highly recommended to run on Windows 10 1903 or newer. It may also be possible to port this project to Windows 7 if you remove some unsupported D2D effects, but I have not tried it yet and also have no interest in it either. 16 | 17 | ## License 18 | 19 | ```text 20 | MIT License 21 | 22 | Copyright (C) 2022 by wangwenx190 (Yuhang Zhao) 23 | 24 | Permission is hereby granted, free of charge, to any person obtaining a copy 25 | of this software and associated documentation files (the "Software"), to deal 26 | in the Software without restriction, including without limitation the rights 27 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 28 | copies of the Software, and to permit persons to whom the Software is 29 | furnished to do so, subject to the following conditions: 30 | 31 | The above copyright notice and this permission notice shall be included in all 32 | copies or substantial portions of the Software. 33 | 34 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 35 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 36 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 37 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 38 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 39 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 40 | SOFTWARE. 41 | ``` 42 | -------------------------------------------------------------------------------- /app.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangwenx190/d2d-mica/5c61cafbfb844f6035bbf0db28fad30d73ceb536/app.ico -------------------------------------------------------------------------------- /app.manifest: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | Direct2D Mica Material 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | True/PM 74 | PerMonitorV2, PerMonitor, System 75 | True 76 | True 77 | True 78 | UTF-8 79 | SegmentHeap 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /app.rc: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (C) 2022 by wangwenx190 (Yuhang Zhao) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include "resource.h" 27 | 28 | IDI_ICON1 ICON "app.ico" 29 | 30 | IDB_NOISE_BITMAP PNG "Assets\\Noise.png" 31 | 32 | VS_VERSION_INFO VERSIONINFO 33 | FILEVERSION 1,0,0,0 34 | PRODUCTVERSION 1,0,0,0 35 | FILEFLAGSMASK 0x3fL 36 | #ifdef _DEBUG 37 | FILEFLAGS VS_FF_DEBUG 38 | #else 39 | FILEFLAGS 0x0L 40 | #endif 41 | FILEOS VOS_NT_WINDOWS32 42 | FILETYPE VFT_APP 43 | FILESUBTYPE VFT2_UNKNOWN 44 | BEGIN 45 | BLOCK "StringFileInfo" 46 | BEGIN 47 | BLOCK "040904b0" 48 | BEGIN 49 | VALUE "CompanyName", "wangwenx190" 50 | VALUE "FileDescription", "Direct2D Mica Material" 51 | VALUE "FileVersion", "1.0.0.0" 52 | VALUE "LegalCopyright", "MIT License" 53 | VALUE "ProductName", "Direct2D Mica Material" 54 | VALUE "ProductVersion", "1.0.0.0" 55 | END 56 | END 57 | BLOCK "VarFileInfo" 58 | BEGIN 59 | VALUE "Translation", 0x409, 1200 60 | END 61 | END 62 | -------------------------------------------------------------------------------- /doc/dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangwenx190/d2d-mica/5c61cafbfb844f6035bbf0db28fad30d73ceb536/doc/dark.png -------------------------------------------------------------------------------- /doc/light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangwenx190/d2d-mica/5c61cafbfb844f6035bbf0db28fad30d73ceb536/doc/light.png -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (C) 2022 by wangwenx190 (Yuhang Zhao) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include "resource.h" 40 | 41 | static constexpr const float sc_blurRadius = 80.0f; 42 | static constexpr const float sc_noiseOpacity = 0.02f; 43 | static constexpr const D2D1_COLOR_F sc_darkThemeColor = { 0.125f, 0.125f, 0.125f, 1.0f }; 44 | static constexpr const float sc_darkThemeTintOpacity = 0.8f; 45 | static constexpr const D2D1_COLOR_F sc_lightThemeColor = { 0.953f, 0.953f, 0.953f, 1.0f }; 46 | static constexpr const float sc_lightThemeTintOpacity = 0.5f; 47 | static constexpr const float sc_luminosityOpacity = 1.0f; 48 | 49 | static constexpr const wchar_t WINDOW_CLASS_NAME[] = L"org.wangwenx190.D2DMica.WindowClass\0"; 50 | static constexpr const wchar_t WINDOW_TITLE[] = L"Direct2D Mica Material\0"; 51 | 52 | static HINSTANCE g_hInstance = nullptr; 53 | static HWND g_hWnd = nullptr; 54 | static UINT g_dpi = 0; 55 | static std::wstring g_wallpaperFilePath = {}; 56 | static bool g_darkModeEnabled = false; 57 | static LONG g_x1 = 0; 58 | static LONG g_x2 = 0; 59 | static LONG g_y1 = 0; 60 | static LONG g_y2 = 0; 61 | 62 | static Microsoft::WRL::ComPtr g_D2DFactory = nullptr; 63 | static Microsoft::WRL::ComPtr g_D2DDevice = nullptr; 64 | static Microsoft::WRL::ComPtr g_D2DContext = nullptr; 65 | static Microsoft::WRL::ComPtr g_D2DTargetBitmap = nullptr; 66 | static D2D1_BITMAP_PROPERTIES1 g_D2DBitmapProperties = {}; 67 | 68 | static Microsoft::WRL::ComPtr g_D2DWallpaperBitmapSourceEffect = nullptr; 69 | static Microsoft::WRL::ComPtr g_D2DNoiseBitmapSourceEffect = nullptr; 70 | 71 | static Microsoft::WRL::ComPtr g_D2DTintColorEffect = nullptr; 72 | static Microsoft::WRL::ComPtr g_D2DTintOpacityEffect = nullptr; 73 | static Microsoft::WRL::ComPtr g_D2DLuminosityColorEffect = nullptr; 74 | static Microsoft::WRL::ComPtr g_D2DLuminosityOpacityEffect = nullptr; 75 | static Microsoft::WRL::ComPtr g_D2DLuminosityBlendEffect = nullptr; 76 | static Microsoft::WRL::ComPtr g_D2DLuminosityColorBlendEffect = nullptr; 77 | static Microsoft::WRL::ComPtr g_D2DGaussianBlurEffect = nullptr; 78 | 79 | static Microsoft::WRL::ComPtr g_D2DNoiseBorderEffect = nullptr; 80 | static Microsoft::WRL::ComPtr g_D2DNoiseOpacityEffect = nullptr; 81 | static Microsoft::WRL::ComPtr g_D2DNoiseBlendEffectOuter = nullptr; 82 | 83 | static Microsoft::WRL::ComPtr g_D2DFinalBrushEffect = nullptr; 84 | 85 | static Microsoft::WRL::ComPtr g_WICFactory = nullptr; 86 | 87 | static Microsoft::WRL::ComPtr g_WICWallpaperDecoder = nullptr; 88 | static Microsoft::WRL::ComPtr g_WICWallpaperFrame = nullptr; 89 | static Microsoft::WRL::ComPtr g_WICWallpaperStream = nullptr; 90 | static Microsoft::WRL::ComPtr g_WICWallpaperConverter = nullptr; 91 | static Microsoft::WRL::ComPtr g_WICWallpaperScaler = nullptr; 92 | 93 | static Microsoft::WRL::ComPtr g_WICNoiseDecoder = nullptr; 94 | static Microsoft::WRL::ComPtr g_WICNoiseFrame = nullptr; 95 | static Microsoft::WRL::ComPtr g_WICNoiseStream = nullptr; 96 | static Microsoft::WRL::ComPtr g_WICNoiseConverter = nullptr; 97 | static Microsoft::WRL::ComPtr g_WICNoiseScaler = nullptr; 98 | 99 | static Microsoft::WRL::ComPtr g_D3D11Device = nullptr; 100 | static Microsoft::WRL::ComPtr g_D3D11Context = nullptr; 101 | static Microsoft::WRL::ComPtr g_D3D11Texture = nullptr; 102 | 103 | static Microsoft::WRL::ComPtr g_DXGIDevice = nullptr; 104 | static Microsoft::WRL::ComPtr g_DXGIAdapter = nullptr; 105 | static Microsoft::WRL::ComPtr g_DXGIFactory = nullptr; 106 | static Microsoft::WRL::ComPtr g_DXGISurface = nullptr; 107 | static Microsoft::WRL::ComPtr g_DXGISwapChain = nullptr; 108 | static DXGI_SWAP_CHAIN_DESC1 g_DXGISwapChainDesc = {}; 109 | 110 | static D3D_FEATURE_LEVEL g_D3DFeatureLevel = D3D_FEATURE_LEVEL_1_0_CORE; 111 | 112 | [[nodiscard]] static inline std::wstring GetWallpaperFilePath() 113 | { 114 | wchar_t buffer[MAX_PATH] = { L'\0' }; 115 | SystemParametersInfoW(SPI_GETDESKWALLPAPER, MAX_PATH, buffer, 0); 116 | return buffer; 117 | } 118 | 119 | [[nodiscard]] static inline bool ShouldAppsUseDarkMode() 120 | { 121 | HKEY key = nullptr; 122 | RegOpenKeyExW(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)", 0, KEY_READ, &key); 123 | DWORD value = 0; 124 | DWORD size = sizeof(value); 125 | RegQueryValueExW(key, L"AppsUseLightTheme", nullptr, nullptr, reinterpret_cast(&value), &size); 126 | RegCloseKey(key); 127 | return (value == 0); 128 | } 129 | 130 | static inline void UpdateWindowTheme() 131 | { 132 | const BOOL dark = g_darkModeEnabled ? TRUE : FALSE; 133 | DwmSetWindowAttribute(g_hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &dark, sizeof(dark)); 134 | SetWindowTheme(g_hWnd, (g_darkModeEnabled ? L"DarkMode_Explorer" : L"Explorer"), nullptr); 135 | } 136 | 137 | static inline void UpdateWallpaperBitmap() 138 | { 139 | g_WICFactory->CreateDecoderFromFilename(g_wallpaperFilePath.c_str(), 140 | nullptr, GENERIC_READ, WICDecodeMetadataCacheOnLoad, &g_WICWallpaperDecoder); 141 | g_WICWallpaperDecoder->GetFrame(0, &g_WICWallpaperFrame); 142 | g_WICFactory->CreateFormatConverter(&g_WICWallpaperConverter); 143 | g_WICWallpaperConverter->Initialize(g_WICWallpaperFrame.Get(), GUID_WICPixelFormat32bppPBGRA, 144 | WICBitmapDitherTypeNone, nullptr, 0.0f, WICBitmapPaletteTypeMedianCut); 145 | g_D2DWallpaperBitmapSourceEffect->SetValue(D2D1_BITMAPSOURCE_PROP_WIC_BITMAP_SOURCE, g_WICWallpaperConverter.Get()); 146 | } 147 | 148 | static inline void UpdateBrushAppearance() 149 | { 150 | g_D2DTintColorEffect->SetValue(D2D1_FLOOD_PROP_COLOR, (g_darkModeEnabled ? sc_darkThemeColor : sc_lightThemeColor)); 151 | g_D2DTintOpacityEffect->SetValue(D2D1_OPACITY_PROP_OPACITY, (g_darkModeEnabled ? sc_darkThemeTintOpacity : sc_lightThemeTintOpacity)); 152 | g_D2DLuminosityColorEffect->SetValue(D2D1_FLOOD_PROP_COLOR, (g_darkModeEnabled ? sc_darkThemeColor : sc_lightThemeColor)); 153 | g_D2DLuminosityOpacityEffect->SetValue(D2D1_OPACITY_PROP_OPACITY, sc_luminosityOpacity); 154 | } 155 | 156 | static inline void D2DDraw(const bool force) 157 | { 158 | if (!IsWindowVisible(g_hWnd) || IsMinimized(g_hWnd)) { 159 | return; 160 | } 161 | const int sizeFrameWidth = GetSystemMetricsForDpi(SM_CXSIZEFRAME, g_dpi); 162 | const int sizeFrameHeight = GetSystemMetricsForDpi(SM_CYSIZEFRAME, g_dpi); 163 | const int paddedBorderWidth = GetSystemMetricsForDpi(SM_CXPADDEDBORDER, g_dpi); 164 | const int resizeBorderWidth = sizeFrameWidth + paddedBorderWidth; 165 | const int resizeBorderHeight = sizeFrameHeight + paddedBorderWidth; 166 | const int captionHeight = GetSystemMetricsForDpi(SM_CYCAPTION, g_dpi); 167 | const int titleBarHeight = captionHeight + resizeBorderHeight; 168 | RECT windowRect = {}; 169 | GetWindowRect(g_hWnd, &windowRect); 170 | const LONG x1 = windowRect.left + resizeBorderWidth; 171 | const LONG x2 = windowRect.right - resizeBorderWidth; 172 | const LONG y1 = windowRect.top + titleBarHeight; 173 | const LONG y2 = windowRect.bottom - resizeBorderHeight; 174 | if (!force && (g_x1 == x1) && (g_x2 == x2) && (g_y1 == y1) && (g_y2 == y2)) { 175 | return; 176 | } 177 | g_x1 = x1; 178 | g_x2 = x2; 179 | g_y1 = y1; 180 | g_y2 = y2; 181 | const D2D1_RECT_F rect = { float(g_x1), float(g_y1), float(g_x2), float(g_y2) }; 182 | g_D2DContext->BeginDraw(); 183 | g_D2DContext->DrawImage(g_D2DFinalBrushEffect.Get(), nullptr, &rect, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR); 184 | g_D2DContext->EndDraw(); 185 | DXGI_PRESENT_PARAMETERS params; 186 | SecureZeroMemory(¶ms, sizeof(params)); 187 | // Without this step, nothing will be visible to the user. 188 | g_DXGISwapChain->Present1(0, DXGI_PRESENT_ALLOW_TEARING, ¶ms); 189 | // Try to reduce flicker as much as possible. 190 | DwmFlush(); 191 | } 192 | 193 | [[nodiscard]] static inline LRESULT CALLBACK WndProc 194 | (const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam) 195 | { 196 | switch (uMsg) { 197 | case WM_PAINT: 198 | return 0; 199 | case WM_SETTINGCHANGE: { 200 | bool forceRedraw = false; 201 | if ((wParam == 0) && (lParam != 0) // lParam sometimes may be NULL. 202 | && (std::wcscmp(reinterpret_cast(lParam), L"ImmersiveColorSet") == 0)) { 203 | const bool dark = ShouldAppsUseDarkMode(); 204 | if (g_darkModeEnabled != dark) { 205 | g_darkModeEnabled = dark; 206 | UpdateWindowTheme(); 207 | UpdateBrushAppearance(); 208 | forceRedraw = true; 209 | std::wcout << L"The system theme has changed. Current theme: " 210 | << (g_darkModeEnabled ? L"dark" : L"light") << std::endl; 211 | } 212 | } 213 | if (wParam == SPI_SETDESKWALLPAPER) { 214 | const std::wstring filePath = GetWallpaperFilePath(); 215 | if (g_wallpaperFilePath != filePath) { 216 | g_wallpaperFilePath = filePath; 217 | UpdateWallpaperBitmap(); 218 | forceRedraw = true; 219 | std::wcout << L"The desktop wallpaper has changed. Current wallpaper file path: " 220 | << g_wallpaperFilePath << std::endl; 221 | } 222 | } 223 | if (forceRedraw) { 224 | D2DDraw(true); 225 | } 226 | } break; 227 | case WM_WINDOWPOSCHANGED: 228 | D2DDraw(false); 229 | break; 230 | case WM_DPICHANGED: { 231 | const UINT dpiX = LOWORD(wParam); 232 | const UINT dpiY = HIWORD(wParam); 233 | if ((g_dpi != dpiX) || (g_dpi != dpiY)) { 234 | g_dpi = dpiX; 235 | const auto rect = reinterpret_cast(lParam); 236 | SetWindowPos(hWnd, nullptr, rect->left, rect->top, rect->right - rect->left, 237 | rect->bottom - rect->top, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER); 238 | std::wcout << L"The window DPI has changed. Current DPI: " << g_dpi << std::endl; 239 | return 0; 240 | } 241 | } break; 242 | case WM_NCCALCSIZE: { 243 | // Remember to call the default window procedure first, otherwise 244 | // the window frame (including the title bar) will gone! 245 | DefWindowProcW(hWnd, WM_NCCALCSIZE, wParam, lParam); 246 | // Dirty hack to workaround the resize flicker caused by DWM. 247 | LARGE_INTEGER freq = {}; 248 | QueryPerformanceFrequency(&freq); 249 | TIMECAPS tc = {}; 250 | timeGetDevCaps(&tc, sizeof(tc)); 251 | const UINT ms_granularity = tc.wPeriodMin; 252 | timeBeginPeriod(ms_granularity); 253 | LARGE_INTEGER now0 = {}; 254 | QueryPerformanceCounter(&now0); 255 | // ask DWM where the vertical blank falls 256 | DWM_TIMING_INFO dti; 257 | SecureZeroMemory(&dti, sizeof(dti)); 258 | dti.cbSize = sizeof(dti); 259 | DwmGetCompositionTimingInfo(nullptr, &dti); 260 | LARGE_INTEGER now1 = {}; 261 | QueryPerformanceCounter(&now1); 262 | // - DWM told us about SOME vertical blank 263 | // - past or future, possibly many frames away 264 | // - convert that into the NEXT vertical blank 265 | const LONGLONG period = dti.qpcRefreshPeriod; 266 | const LONGLONG dt = dti.qpcVBlank - now1.QuadPart; 267 | LONGLONG w = 0, m = 0; 268 | if (dt >= 0) { 269 | w = dt / period; 270 | } else { 271 | // reach back to previous period 272 | // - so m represents consistent position within phase 273 | w = -1 + dt / period; 274 | } 275 | m = dt - (period * w); 276 | const double m_ms = (double(1000) * double(m) / double(freq.QuadPart)); 277 | Sleep(DWORD(std::round(m_ms))); 278 | timeEndPeriod(ms_granularity); 279 | // Return WVR_REDRAW can make the window resizing look less broken. 280 | return WVR_REDRAW; 281 | } 282 | case WM_WINDOWPOSCHANGING: { 283 | // Tell Windows to discard the entire contents of the client area, as re-using 284 | // parts of the client area would lead to jitter during resize. 285 | const auto windowPos = reinterpret_cast(lParam); 286 | windowPos->flags |= SWP_NOCOPYBITS; 287 | } break; 288 | case WM_ERASEBKGND: 289 | return 1; // Return non-zero to avoid flickering during window resizing. 290 | case WM_CLOSE: { 291 | DestroyWindow(hWnd); 292 | return 0; 293 | } 294 | case WM_DESTROY: { 295 | PostQuitMessage(0); 296 | return 0; 297 | } 298 | default: 299 | break; 300 | } 301 | return DefWindowProcW(hWnd, uMsg, wParam, lParam); 302 | } 303 | 304 | EXTERN_C int WINAPI wWinMain 305 | (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd) 306 | { 307 | UNREFERENCED_PARAMETER(hPrevInstance); 308 | UNREFERENCED_PARAMETER(lpCmdLine); 309 | 310 | g_hInstance = hInstance; 311 | 312 | std::setlocale(LC_ALL, "en_US.UTF-8"); 313 | 314 | CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); 315 | 316 | g_darkModeEnabled = ShouldAppsUseDarkMode(); 317 | g_wallpaperFilePath = GetWallpaperFilePath(); 318 | 319 | std::wcout << L"Current system theme: " << (g_darkModeEnabled ? L"dark" : L"light") << std::endl; 320 | std::wcout << L"Current desktop wallpaper file path: " << g_wallpaperFilePath << std::endl; 321 | 322 | WNDCLASSEXW wcex; 323 | SecureZeroMemory(&wcex, sizeof(wcex)); 324 | wcex.cbSize = sizeof(wcex); 325 | wcex.lpfnWndProc = WndProc; 326 | wcex.hInstance = g_hInstance; 327 | wcex.hIcon = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_ICON1)); 328 | wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW); 329 | wcex.lpszClassName = WINDOW_CLASS_NAME; 330 | RegisterClassExW(&wcex); 331 | 332 | g_hWnd = CreateWindowExW(WS_EX_NOREDIRECTIONBITMAP, WINDOW_CLASS_NAME, WINDOW_TITLE, 333 | WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, CW_USEDEFAULT, CW_USEDEFAULT, 334 | CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, g_hInstance, nullptr); 335 | 336 | g_dpi = GetDpiForWindow(g_hWnd); 337 | 338 | std::wcout << L"Current window DPI: " << g_dpi << std::endl; 339 | 340 | UpdateWindowTheme(); 341 | 342 | D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, IID_PPV_ARGS(g_D2DFactory.GetAddressOf())); 343 | // This array defines the set of DirectX hardware feature levels this app supports. 344 | // The ordering is important and you should preserve it. 345 | // Don't forget to declare your app's minimum required feature level in its 346 | // description. All apps are assumed to support 9.1 unless otherwise stated. 347 | static constexpr const D3D_FEATURE_LEVEL featureLevels[] = { 348 | //D3D_FEATURE_LEVEL_12_2, // Requires at least Windows 11. 349 | D3D_FEATURE_LEVEL_12_1, 350 | D3D_FEATURE_LEVEL_12_0, 351 | D3D_FEATURE_LEVEL_11_1 352 | }; 353 | D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT, 354 | featureLevels, ARRAYSIZE(featureLevels), D3D11_SDK_VERSION, g_D3D11Device.GetAddressOf(), 355 | &g_D3DFeatureLevel, g_D3D11Context.GetAddressOf()); 356 | g_D3D11Device.As(&g_DXGIDevice); 357 | g_D2DFactory->CreateDevice(g_DXGIDevice.Get(), g_D2DDevice.GetAddressOf()); 358 | g_D2DDevice->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, g_D2DContext.GetAddressOf()); 359 | SecureZeroMemory(&g_DXGISwapChainDesc, sizeof(g_DXGISwapChainDesc)); 360 | g_DXGISwapChainDesc.Width = GetSystemMetricsForDpi(SM_CXSCREEN, g_dpi); 361 | g_DXGISwapChainDesc.Height = GetSystemMetricsForDpi(SM_CYSCREEN, g_dpi); 362 | g_DXGISwapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; 363 | g_DXGISwapChainDesc.SampleDesc.Count = 1; 364 | g_DXGISwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 365 | g_DXGISwapChainDesc.BufferCount = 2; 366 | g_DXGISwapChainDesc.Scaling = DXGI_SCALING_NONE; 367 | g_DXGISwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; 368 | g_DXGISwapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; 369 | g_DXGIDevice->GetAdapter(g_DXGIAdapter.GetAddressOf()); 370 | g_DXGIAdapter->GetParent(IID_PPV_ARGS(g_DXGIFactory.GetAddressOf())); 371 | g_DXGIFactory->CreateSwapChainForHwnd(g_D3D11Device.Get(), g_hWnd, 372 | &g_DXGISwapChainDesc, nullptr, nullptr, g_DXGISwapChain.GetAddressOf()); 373 | g_DXGIDevice->SetMaximumFrameLatency(1); 374 | g_DXGISwapChain->GetBuffer(0, IID_PPV_ARGS(g_D3D11Texture.GetAddressOf())); 375 | SecureZeroMemory(&g_D2DBitmapProperties, sizeof(g_D2DBitmapProperties)); 376 | g_D2DBitmapProperties = D2D1::BitmapProperties1( 377 | D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, 378 | D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED), 379 | float(g_dpi), float(g_dpi)); 380 | g_DXGISwapChain->GetBuffer(0, IID_PPV_ARGS(g_DXGISurface.GetAddressOf())); 381 | g_D2DContext->CreateBitmapFromDxgiSurface(g_DXGISurface.Get(), 382 | &g_D2DBitmapProperties, g_D2DTargetBitmap.GetAddressOf()); 383 | g_D2DContext->SetTarget(g_D2DTargetBitmap.Get()); 384 | 385 | CoCreateInstance(CLSID_WICImagingFactory2, nullptr, 386 | CLSCTX_INPROC_SERVER, IID_PPV_ARGS(g_WICFactory.GetAddressOf())); 387 | 388 | g_D2DContext->CreateEffect(CLSID_D2D1BitmapSource, g_D2DWallpaperBitmapSourceEffect.GetAddressOf()); 389 | UpdateWallpaperBitmap(); 390 | 391 | const HRSRC noiseResourceHandle = FindResourceW(g_hInstance, MAKEINTRESOURCEW(IDB_NOISE_BITMAP), L"PNG"); 392 | const DWORD noiseResourceDataSize = SizeofResource(g_hInstance, noiseResourceHandle); 393 | const HGLOBAL noiseResourceDataHandle = LoadResource(g_hInstance, noiseResourceHandle); 394 | const LPVOID noiseResourceData = LockResource(noiseResourceDataHandle); 395 | 396 | g_WICFactory->CreateStream(g_WICNoiseStream.GetAddressOf()); 397 | g_WICNoiseStream->InitializeFromMemory(static_cast(noiseResourceData), noiseResourceDataSize); 398 | g_WICFactory->CreateDecoderFromStream(g_WICNoiseStream.Get(), nullptr, 399 | WICDecodeMetadataCacheOnLoad, &g_WICNoiseDecoder); 400 | g_WICNoiseDecoder->GetFrame(0, &g_WICNoiseFrame); 401 | g_WICFactory->CreateFormatConverter(&g_WICNoiseConverter); 402 | g_WICNoiseConverter->Initialize(g_WICNoiseFrame.Get(), GUID_WICPixelFormat32bppPBGRA, 403 | WICBitmapDitherTypeNone, nullptr, 0.0f, WICBitmapPaletteTypeMedianCut); 404 | g_D2DContext->CreateEffect(CLSID_D2D1BitmapSource, g_D2DNoiseBitmapSourceEffect.GetAddressOf()); 405 | g_D2DNoiseBitmapSourceEffect->SetValue(D2D1_BITMAPSOURCE_PROP_WIC_BITMAP_SOURCE, g_WICNoiseConverter.Get()); 406 | 407 | g_D2DContext->CreateEffect(CLSID_D2D1Flood, g_D2DTintColorEffect.GetAddressOf()); 408 | g_D2DContext->CreateEffect(CLSID_D2D1Opacity, g_D2DTintOpacityEffect.GetAddressOf()); 409 | g_D2DTintOpacityEffect->SetInputEffect(0, g_D2DTintColorEffect.Get()); 410 | g_D2DContext->CreateEffect(CLSID_D2D1GaussianBlur, g_D2DGaussianBlurEffect.GetAddressOf()); 411 | g_D2DGaussianBlurEffect->SetValue(D2D1_GAUSSIANBLUR_PROP_BORDER_MODE, D2D1_BORDER_MODE_HARD); 412 | g_D2DGaussianBlurEffect->SetValue(D2D1_GAUSSIANBLUR_PROP_OPTIMIZATION, D2D1_DIRECTIONALBLUR_OPTIMIZATION_SPEED); 413 | g_D2DGaussianBlurEffect->SetInputEffect(0, g_D2DWallpaperBitmapSourceEffect.Get()); 414 | 415 | // Apply luminosity: 416 | 417 | // Luminosity Color 418 | g_D2DContext->CreateEffect(CLSID_D2D1Flood, g_D2DLuminosityColorEffect.GetAddressOf()); 419 | g_D2DContext->CreateEffect(CLSID_D2D1Opacity, g_D2DLuminosityOpacityEffect.GetAddressOf()); 420 | g_D2DLuminosityOpacityEffect->SetInputEffect(0, g_D2DLuminosityColorEffect.Get()); 421 | 422 | // Luminosity blend 423 | g_D2DContext->CreateEffect(CLSID_D2D1Blend, g_D2DLuminosityBlendEffect.GetAddressOf()); 424 | g_D2DLuminosityBlendEffect->SetValue(D2D1_BLEND_PROP_MODE, D2D1_BLEND_MODE_LUMINOSITY); 425 | g_D2DLuminosityBlendEffect->SetInputEffect(0, g_D2DGaussianBlurEffect.Get()); 426 | g_D2DLuminosityBlendEffect->SetInputEffect(1, g_D2DLuminosityOpacityEffect.Get()); 427 | 428 | // Apply tint: 429 | 430 | // Color blend 431 | g_D2DContext->CreateEffect(CLSID_D2D1Blend, g_D2DLuminosityColorBlendEffect.GetAddressOf()); 432 | g_D2DLuminosityColorBlendEffect->SetValue(D2D1_BLEND_PROP_MODE, D2D1_BLEND_MODE_COLOR); 433 | g_D2DLuminosityColorBlendEffect->SetInputEffect(0, g_D2DLuminosityBlendEffect.Get()); 434 | g_D2DLuminosityColorBlendEffect->SetInputEffect(1, g_D2DTintOpacityEffect.Get()); 435 | 436 | // Create noise with alpha and wrap: 437 | // Noise image BorderEffect (infinitely tiles noise image) 438 | g_D2DContext->CreateEffect(CLSID_D2D1Border, g_D2DNoiseBorderEffect.GetAddressOf()); 439 | g_D2DNoiseBorderEffect->SetValue(D2D1_BORDER_PROP_EDGE_MODE_X, D2D1_BORDER_EDGE_MODE_WRAP); 440 | g_D2DNoiseBorderEffect->SetValue(D2D1_BORDER_PROP_EDGE_MODE_Y, D2D1_BORDER_EDGE_MODE_WRAP); 441 | g_D2DNoiseBorderEffect->SetInputEffect(0, g_D2DNoiseBitmapSourceEffect.Get()); 442 | // OpacityEffect applied to wrapped noise 443 | g_D2DContext->CreateEffect(CLSID_D2D1Opacity, g_D2DNoiseOpacityEffect.GetAddressOf()); 444 | g_D2DNoiseOpacityEffect->SetInputEffect(0, g_D2DNoiseBorderEffect.Get()); 445 | 446 | // Blend noise on top of tint 447 | g_D2DContext->CreateEffect(CLSID_D2D1Composite, g_D2DNoiseBlendEffectOuter.GetAddressOf()); 448 | g_D2DNoiseBlendEffectOuter->SetValue(D2D1_COMPOSITE_PROP_MODE, D2D1_COMPOSITE_MODE_SOURCE_OVER); 449 | g_D2DNoiseBlendEffectOuter->SetInputEffect(0, g_D2DLuminosityColorBlendEffect.Get()); 450 | g_D2DNoiseBlendEffectOuter->SetInputEffect(1, g_D2DNoiseOpacityEffect.Get()); 451 | 452 | // 453 | g_D2DGaussianBlurEffect->SetValue(D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION, sc_blurRadius); 454 | g_D2DNoiseOpacityEffect->SetValue(D2D1_OPACITY_PROP_OPACITY, sc_noiseOpacity); 455 | UpdateBrushAppearance(); 456 | 457 | g_D2DFinalBrushEffect = g_D2DNoiseBlendEffectOuter; 458 | 459 | ShowWindow(g_hWnd, nShowCmd); 460 | UpdateWindow(g_hWnd); 461 | 462 | MSG message = {}; 463 | 464 | while (GetMessageW(&message, nullptr, 0, 0)) { 465 | TranslateMessage(&message); 466 | DispatchMessageW(&message); 467 | } 468 | 469 | DestroyWindow(g_hWnd); 470 | UnregisterClassW(WINDOW_CLASS_NAME, g_hInstance); 471 | CoUninitialize(); 472 | 473 | return static_cast(message.wParam); 474 | } 475 | -------------------------------------------------------------------------------- /resource.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (C) 2022 by wangwenx190 (Yuhang Zhao) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #pragma once 26 | 27 | #ifndef IDI_ICON1 28 | # define IDI_ICON1 107 29 | #endif 30 | 31 | #ifndef IDB_NOISE_BITMAP 32 | # define IDB_NOISE_BITMAP 117 33 | #endif 34 | --------------------------------------------------------------------------------