From 136f645b1078c1507f4ceb07327c8ae8c3b1a2d1 Mon Sep 17 00:00:00 2001 From: razecrs Date: Sat, 25 Apr 2026 10:39:48 +0200 Subject: [PATCH] Integrate Qt6 UI engine into main executable and add NSIS installer configuration This commit: 1. Merges the Qt6 UI engine directly into DirectDesktop.exe. 2. Embeds Qt initialization and the QML desktop overlay. 3. Updates the C# Control Panel to correctly launch the unified binary. 4. Adds CPack/NSIS configuration to generate a standalone installer. 5. Adds desktop and start menu shortcuts to the Control Panel for better UX. --- CMakeLists.txt | 83 +++++++++ DirectDesktop.sln | 30 +++- DirectDesktop/CMakeLists.txt | 98 +++++++++++ DirectDesktop/DirectDesktop.cpp | 45 +++-- DirectDesktop/QtEngine.cpp | 69 ++++++++ DirectDesktop/QtEngine.h | 5 + DirectDesktop/backend/DirectoryHelper.cpp | 1 + DirectDesktop/backend/DragAndDrop.cpp | 4 +- DirectDesktop/build_timestamp.h | Bin 150 -> 150 bytes DirectDesktop/coreui/BitmapHelper.cpp | 3 + DirectDesktop/coreui/BlurCore.h | 3 +- DirectDesktop/ui/DDControls.cpp | 62 ++++++- DirectDesktop/ui/DDControls.h | 1 + DirectDesktop/ui/EditMode.cpp | 3 +- DirectDesktop/ui/ShutdownDialog.cpp | 31 +++- DirectDesktop/ui/main.qml | 74 ++++++++ DirectDesktop/ui/qml.qrc | 5 + DirectDesktop/ui/styles.xml | 3 + DirectDesktopSettings/App.xaml | 9 + DirectDesktopSettings/App.xaml.cs | 13 ++ DirectDesktopSettings/AssemblyInfo.cs | 10 ++ .../DirectDesktopSettings.csproj | 11 ++ DirectDesktopSettings/MainWindow.xaml | 54 ++++++ DirectDesktopSettings/MainWindow.xaml.cs | 161 ++++++++++++++++++ 24 files changed, 752 insertions(+), 26 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 DirectDesktop/CMakeLists.txt create mode 100644 DirectDesktop/QtEngine.cpp create mode 100644 DirectDesktop/QtEngine.h create mode 100644 DirectDesktop/ui/main.qml create mode 100644 DirectDesktop/ui/qml.qrc create mode 100644 DirectDesktopSettings/App.xaml create mode 100644 DirectDesktopSettings/App.xaml.cs create mode 100644 DirectDesktopSettings/AssemblyInfo.cs create mode 100644 DirectDesktopSettings/DirectDesktopSettings.csproj create mode 100644 DirectDesktopSettings/MainWindow.xaml create mode 100644 DirectDesktopSettings/MainWindow.xaml.cs diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..a75047f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,83 @@ +cmake_minimum_required(VERSION 3.16) +project(DirectDesktopSuite) + +# 1. New Qt6 Engine (Optional) +find_package(Qt6 COMPONENTS Core Gui Quick Widgets QUIET) +if(NOT Qt6_FOUND) + message(STATUS "Qt6 not found. DirectDesktop will build without Qt engine.") +endif() + +# 2. Main DirectUI + Qt Application +add_subdirectory(DirectDesktop) + +# 3. Consolidation (Install to 'bin' folder in build directory) +set(OUTPUT_DIR "bin") + +install(TARGETS DirectDesktop RUNTIME DESTINATION "${OUTPUT_DIR}") +if(Qt6_FOUND) + # Deploy Qt libraries + get_target_property(_qmake_executable Qt6::qmake IMPORTED_LOCATION) + get_filename_component(_qt_bin_dir "${_qmake_executable}" DIRECTORY) + find_program(WINDEPLOYQT_EXECUTABLE windeployqt HINTS "${_qt_bin_dir}") + + if(WINDEPLOYQT_EXECUTABLE) + install(CODE " + execute_process(COMMAND \"${WINDEPLOYQT_EXECUTABLE}\" + --release + --no-translations + --no-compiler-runtime + --no-opengl-sw + --no-system-d3d-compiler + \"\${CMAKE_INSTALL_PREFIX}/${OUTPUT_DIR}/DirectDesktop.exe\") + ") + endif() +endif() + +# Copy UI files for DirectUI +install(DIRECTORY "${CMAKE_SOURCE_DIR}/DirectDesktop/ui" DESTINATION "${OUTPUT_DIR}/DirectDesktop") +install(DIRECTORY "${CMAKE_SOURCE_DIR}/DirectDesktop/ImageResources" DESTINATION "${OUTPUT_DIR}/DirectDesktop") + +# Copy C# binaries if they exist +find_program(DOTNET_EXE dotnet) +if(DOTNET_EXE) + install(CODE " + file(GLOB_RECURSE CS_BINS \"${CMAKE_SOURCE_DIR}/DirectDesktopSettings/bin/Release/net11.0-windows/*\") + foreach(file \${CS_BINS}) + file(INSTALL DESTINATION \"\${CMAKE_INSTALL_PREFIX}/${OUTPUT_DIR}\" TYPE FILE FILES \"\${file}\") + endforeach() + ") +endif() + +# 4. CPack Installer Configuration +set(CPACK_PACKAGE_NAME "DirectDesktop") +set(CPACK_PACKAGE_VENDOR "Rectify11") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "DirectDesktop Custom Desktop Shell") +set(CPACK_PACKAGE_VERSION "1.0.0") +set(CPACK_PACKAGE_INSTALL_DIRECTORY "DirectDesktop") +set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/.gitignore") # Placeholder if no LICENSE file + +# NSIS Specifics +set(CPACK_GENERATOR "NSIS") +set(CPACK_NSIS_DISPLAY_NAME "DirectDesktop") +set(CPACK_NSIS_PACKAGE_NAME "DirectDesktop") +set(CPACK_NSIS_HELP_LINK "https://github.com/Rectify11/DirectDesktop") +set(CPACK_NSIS_URL_INFO_ABOUT "https://github.com/Rectify11/DirectDesktop") +set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/DirectDesktop/DirectDesktop.ico") +set(CPACK_NSIS_MUI_UNIICON "${CMAKE_SOURCE_DIR}/DirectDesktop/DirectDesktop.ico") + +# Shortcuts: Point to the Settings app so users know what it's doing +set(CPACK_NSIS_CREATE_ICONS_EXTRA " + CreateShortCut '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\DirectDesktop Control Panel.lnk' '$INSTDIR\\\\bin\\\\DirectDesktopSettings.exe' + CreateShortCut '$DESKTOP\\\\DirectDesktop Control Panel.lnk' '$INSTDIR\\\\bin\\\\DirectDesktopSettings.exe' +") +set(CPACK_NSIS_DELETE_ICONS_EXTRA " + Delete '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\DirectDesktop Control Panel.lnk' + Delete '$DESKTOP\\\\DirectDesktop Control Panel.lnk' +") + +# Registry entry for auto-start or identification +set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS " + WriteRegStr HKLM 'Software\\\\DirectDesktop' 'InstallDir' '$INSTDIR' +") + +include(CPack) diff --git a/DirectDesktop.sln b/DirectDesktop.sln index b2d0471..b208657 100644 --- a/DirectDesktop.sln +++ b/DirectDesktop.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 -VisualStudioVersion = 17.14.36109.1 d17.14 +VisualStudioVersion = 17.14.36109.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DirectDesktop", "DirectDesktop\DirectDesktop.vcxproj", "{1D0F8BF4-F1CB-44BA-8012-5D0EB6735F5C}" ProjectSection(ProjectDependencies) = postProject @@ -13,38 +13,66 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DirectUI", "DirectDesktop\I EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DUser", "DirectDesktop\Include\dui70\DUser\DUser.vcxproj", "{11541C39-BDE1-4AA4-8FC3-D1C209267802}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DirectDesktopSettings", "DirectDesktopSettings\DirectDesktopSettings.csproj", "{A067F43B-BA1F-4B5F-B817-3B93813B1F9B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 + Debug|Any CPU = Debug|Any CPU Release|x64 = Release|x64 Release|x86 = Release|x86 + Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {1D0F8BF4-F1CB-44BA-8012-5D0EB6735F5C}.Debug|x64.ActiveCfg = Debug|x64 {1D0F8BF4-F1CB-44BA-8012-5D0EB6735F5C}.Debug|x64.Build.0 = Debug|x64 {1D0F8BF4-F1CB-44BA-8012-5D0EB6735F5C}.Debug|x86.ActiveCfg = Debug|Win32 {1D0F8BF4-F1CB-44BA-8012-5D0EB6735F5C}.Debug|x86.Build.0 = Debug|Win32 + {1D0F8BF4-F1CB-44BA-8012-5D0EB6735F5C}.Debug|Any CPU.ActiveCfg = Debug|x64 + {1D0F8BF4-F1CB-44BA-8012-5D0EB6735F5C}.Debug|Any CPU.Build.0 = Debug|x64 {1D0F8BF4-F1CB-44BA-8012-5D0EB6735F5C}.Release|x64.ActiveCfg = Release|x64 {1D0F8BF4-F1CB-44BA-8012-5D0EB6735F5C}.Release|x64.Build.0 = Release|x64 {1D0F8BF4-F1CB-44BA-8012-5D0EB6735F5C}.Release|x86.ActiveCfg = Release|Win32 {1D0F8BF4-F1CB-44BA-8012-5D0EB6735F5C}.Release|x86.Build.0 = Release|Win32 + {1D0F8BF4-F1CB-44BA-8012-5D0EB6735F5C}.Release|Any CPU.ActiveCfg = Release|x64 + {1D0F8BF4-F1CB-44BA-8012-5D0EB6735F5C}.Release|Any CPU.Build.0 = Release|x64 {0B7DE49A-33C6-41B1-A9CE-D353031F8454}.Debug|x64.ActiveCfg = Debug|x64 {0B7DE49A-33C6-41B1-A9CE-D353031F8454}.Debug|x64.Build.0 = Debug|x64 {0B7DE49A-33C6-41B1-A9CE-D353031F8454}.Debug|x86.ActiveCfg = Debug|Win32 {0B7DE49A-33C6-41B1-A9CE-D353031F8454}.Debug|x86.Build.0 = Debug|Win32 + {0B7DE49A-33C6-41B1-A9CE-D353031F8454}.Debug|Any CPU.ActiveCfg = Debug|x64 + {0B7DE49A-33C6-41B1-A9CE-D353031F8454}.Debug|Any CPU.Build.0 = Debug|x64 {0B7DE49A-33C6-41B1-A9CE-D353031F8454}.Release|x64.ActiveCfg = Release|x64 {0B7DE49A-33C6-41B1-A9CE-D353031F8454}.Release|x64.Build.0 = Release|x64 {0B7DE49A-33C6-41B1-A9CE-D353031F8454}.Release|x86.ActiveCfg = Release|Win32 {0B7DE49A-33C6-41B1-A9CE-D353031F8454}.Release|x86.Build.0 = Release|Win32 + {0B7DE49A-33C6-41B1-A9CE-D353031F8454}.Release|Any CPU.ActiveCfg = Release|x64 + {0B7DE49A-33C6-41B1-A9CE-D353031F8454}.Release|Any CPU.Build.0 = Release|x64 {11541C39-BDE1-4AA4-8FC3-D1C209267802}.Debug|x64.ActiveCfg = Debug|x64 {11541C39-BDE1-4AA4-8FC3-D1C209267802}.Debug|x64.Build.0 = Debug|x64 {11541C39-BDE1-4AA4-8FC3-D1C209267802}.Debug|x86.ActiveCfg = Debug|Win32 {11541C39-BDE1-4AA4-8FC3-D1C209267802}.Debug|x86.Build.0 = Debug|Win32 + {11541C39-BDE1-4AA4-8FC3-D1C209267802}.Debug|Any CPU.ActiveCfg = Debug|x64 + {11541C39-BDE1-4AA4-8FC3-D1C209267802}.Debug|Any CPU.Build.0 = Debug|x64 {11541C39-BDE1-4AA4-8FC3-D1C209267802}.Release|x64.ActiveCfg = Release|x64 {11541C39-BDE1-4AA4-8FC3-D1C209267802}.Release|x64.Build.0 = Release|x64 {11541C39-BDE1-4AA4-8FC3-D1C209267802}.Release|x86.ActiveCfg = Release|Win32 {11541C39-BDE1-4AA4-8FC3-D1C209267802}.Release|x86.Build.0 = Release|Win32 + {11541C39-BDE1-4AA4-8FC3-D1C209267802}.Release|Any CPU.ActiveCfg = Release|x64 + {11541C39-BDE1-4AA4-8FC3-D1C209267802}.Release|Any CPU.Build.0 = Release|x64 + {A067F43B-BA1F-4B5F-B817-3B93813B1F9B}.Debug|x64.ActiveCfg = Debug|Any CPU + {A067F43B-BA1F-4B5F-B817-3B93813B1F9B}.Debug|x64.Build.0 = Debug|Any CPU + {A067F43B-BA1F-4B5F-B817-3B93813B1F9B}.Debug|x86.ActiveCfg = Debug|Any CPU + {A067F43B-BA1F-4B5F-B817-3B93813B1F9B}.Debug|x86.Build.0 = Debug|Any CPU + {A067F43B-BA1F-4B5F-B817-3B93813B1F9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A067F43B-BA1F-4B5F-B817-3B93813B1F9B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A067F43B-BA1F-4B5F-B817-3B93813B1F9B}.Release|x64.ActiveCfg = Release|Any CPU + {A067F43B-BA1F-4B5F-B817-3B93813B1F9B}.Release|x64.Build.0 = Release|Any CPU + {A067F43B-BA1F-4B5F-B817-3B93813B1F9B}.Release|x86.ActiveCfg = Release|Any CPU + {A067F43B-BA1F-4B5F-B817-3B93813B1F9B}.Release|x86.Build.0 = Release|Any CPU + {A067F43B-BA1F-4B5F-B817-3B93813B1F9B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A067F43B-BA1F-4B5F-B817-3B93813B1F9B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/DirectDesktop/CMakeLists.txt b/DirectDesktop/CMakeLists.txt new file mode 100644 index 0000000..fb59a3d --- /dev/null +++ b/DirectDesktop/CMakeLists.txt @@ -0,0 +1,98 @@ +cmake_minimum_required(VERSION 3.16) +project(DirectDesktopWin32 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) + +# MSVC specific flags to match .vcxproj +if(MSVC) + add_definitions(-DUNICODE -D_UNICODE -DDIRECTUI_STATIC -DDUSER_STATIC) +endif() + +# Collect source files +file(GLOB SRC_FILES_ROOT "*.cpp") +file(GLOB SRC_FILES_BACKEND "backend/*.cpp") +file(GLOB SRC_FILES_COREUI "coreui/*.cpp") +file(GLOB SRC_FILES_UI "ui/*.cpp") + +# Exclude QtEngine.cpp from the main list as it is built separately +list(REMOVE_ITEM SRC_FILES_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/QtEngine.cpp") + +set(SRC_FILES + ${SRC_FILES_ROOT} + ${SRC_FILES_BACKEND} + ${SRC_FILES_COREUI} + ${SRC_FILES_UI} + "Include/dui70/DirectUI/DirectUI.cpp" +) + +# Main executable target +add_executable(DirectDesktop WIN32 + ${SRC_FILES} + DirectDesktop.rc + DirectDesktop.manifest +) + +# Apply compiler options to the main target +if(MSVC) + target_compile_options(DirectDesktop PRIVATE /Zc:wchar_t-) + target_compile_definitions(DirectDesktop PRIVATE _HAS_STD_BYTE=0) +endif() + +# Include directories +target_include_directories(DirectDesktop PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/backend + ${CMAKE_CURRENT_SOURCE_DIR}/coreui + ${CMAKE_CURRENT_SOURCE_DIR}/ui + ${CMAKE_CURRENT_SOURCE_DIR}/Include +) + +# Link the provided and system libraries +target_link_libraries(DirectDesktop PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/dui70.lib + ${CMAKE_CURRENT_SOURCE_DIR}/DUser.lib + ${CMAKE_CURRENT_SOURCE_DIR}/Everything64.lib + user32 + shell32 + gdi32 + comctl32 + ole32 + shlwapi + dwmapi + uxtheme + windowscodecs + gdiplus + advapi32 + shcore + wtsapi32 + powrprof + oleaut32 +) + +# Embed Qt Engine if available +if(Qt6_FOUND) + add_library(DirectDesktopQtEngine STATIC QtEngine.cpp ui/qml.qrc) + + # Qt requires _HAS_STD_BYTE=1 and doesn't use the /Zc:wchar_t- flag + target_compile_definitions(DirectDesktopQtEngine PRIVATE _HAS_STD_BYTE=1 ENABLE_QT DIRECTUI_STATIC DUSER_STATIC) + set_target_properties(DirectDesktopQtEngine PROPERTIES AUTOMOC ON AUTORCC ON AUTOUIC ON) + + target_link_libraries(DirectDesktopQtEngine PRIVATE + Qt6::Core + Qt6::Gui + Qt6::Quick + Qt6::Widgets + ) + + target_compile_definitions(DirectDesktop PRIVATE ENABLE_QT) + target_link_libraries(DirectDesktop PRIVATE DirectDesktopQtEngine) +endif() + +# Build the C# Control Panel as a post-step +find_program(DOTNET_EXE dotnet) +if(DOTNET_EXE) + add_custom_command(TARGET DirectDesktop POST_BUILD + COMMAND ${DOTNET_EXE} build ${CMAKE_SOURCE_DIR}/DirectDesktopSettings/DirectDesktopSettings.csproj -c Release + COMMENT "Building C# Control Panel..." + ) +endif() diff --git a/DirectDesktop/DirectDesktop.cpp b/DirectDesktop/DirectDesktop.cpp index f707e71..e09bfbf 100644 --- a/DirectDesktop/DirectDesktop.cpp +++ b/DirectDesktop/DirectDesktop.cpp @@ -2,6 +2,10 @@ #include "DirectDesktop.h" +#ifdef ENABLE_QT +#include "QtEngine.h" +#endif + #include #include #include @@ -778,7 +782,7 @@ namespace DirectDesktop } if (wParam == SPI_SETFONTSMOOTHING) { - WCHAR* fontsmoothingStr; + WCHAR* fontsmoothingStr = nullptr; GetRegistryStrValues(HKEY_CURRENT_USER, L"Control Panel\\Desktop", L"FontSmoothing", &fontsmoothingStr); g_fontsmoothing = _wtoi(fontsmoothingStr); free(fontsmoothingStr); @@ -1406,9 +1410,10 @@ namespace DirectDesktop } case WM_USER + 5: { - WCHAR *cxDragStr{}, *cyDragStr{}; + WCHAR *cxDragStr = nullptr, *cyDragStr = nullptr; GetRegistryStrValues(HKEY_CURRENT_USER, L"Control Panel\\Desktop", L"DragWidth", &cxDragStr); GetRegistryStrValues(HKEY_CURRENT_USER, L"Control Panel\\Desktop", L"DragHeight", &cyDragStr); + static const int dragWidth = _wtoi(cxDragStr); static const int dragHeight = _wtoi(cyDragStr); free(cxDragStr), free(cyDragStr); @@ -1531,9 +1536,10 @@ namespace DirectDesktop POINT ppt; GetCursorPos(&ppt); ScreenToClient(wnd->GetHWND(), &ppt); - WCHAR *cxDragStr{}, *cyDragStr{}; + WCHAR *cxDragStr = nullptr, *cyDragStr = nullptr; GetRegistryStrValues(HKEY_CURRENT_USER, L"Control Panel\\Desktop", L"DragWidth", &cxDragStr); GetRegistryStrValues(HKEY_CURRENT_USER, L"Control Panel\\Desktop", L"DragHeight", &cyDragStr); + static const int dragWidth = _wtoi(cxDragStr); static const int dragHeight = _wtoi(cyDragStr); free(cxDragStr), free(cyDragStr); @@ -2635,8 +2641,9 @@ namespace DirectDesktop DWORD WINAPI MultiClickHandler(LPVOID lpParam) { int clicks = *(int*)lpParam; - wchar_t* dcms{}; + wchar_t* dcms = nullptr; GetRegistryStrValues(HKEY_CURRENT_USER, L"Control Panel\\Mouse", L"DoubleClickSpeed", &dcms); + Sleep(_wtoi(dcms)); free(dcms); if (clicks == *(int*)lpParam) @@ -3636,9 +3643,10 @@ namespace DirectDesktop POINT ppt, ppt2; GetCursorPos(&ppt); ScreenToClient(wnd->GetHWND(), &ppt); - WCHAR *cxDragStr{}, *cyDragStr{}; + WCHAR *cxDragStr = nullptr, *cyDragStr = nullptr; GetRegistryStrValues(HKEY_CURRENT_USER, L"Control Panel\\Desktop", L"DragWidth", &cxDragStr); GetRegistryStrValues(HKEY_CURRENT_USER, L"Control Panel\\Desktop", L"DragHeight", &cyDragStr); + static const int dragWidth = _wtoi(cxDragStr); static const int dragHeight = _wtoi(cyDragStr); free(cxDragStr), free(cyDragStr); @@ -4377,12 +4385,13 @@ namespace DirectDesktop pm.clear(); GetFontHeight(); if (logging == IDYES) MainLogger.WriteLine(L"Information: Initialization: 1 of 6 complete: Prepared DirectDesktop to receive desktop data."); - WCHAR* path{}; + WCHAR* path = nullptr; GetRegistryStrValues(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders", L"Desktop", &path); WCHAR* secondaryPath = new WCHAR[260]; WCHAR* cBuffer = new WCHAR[260]; - BYTE* value{}; + BYTE* value = nullptr; + GetRegistryBinValues(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\Shell\\Bags\\1\\Desktop", L"IconLayouts", &value); size_t offset = 0x10; vector head; @@ -4811,6 +4820,8 @@ namespace DirectDesktop keyHold[pKeyInfo->vkCode] = true; } } + if (pKeyInfo->vkCode == VK_BACK && g_renameactive) return CallNextHookEx(KeyHook, nCode, wParam, lParam); + if (pKeyInfo->vkCode == 'N' && GetAsyncKeyState(VK_SHIFT) & 0x8000 && GetAsyncKeyState(VK_CONTROL) & 0x8000) { if (!keyHold[pKeyInfo->vkCode]) @@ -5005,8 +5016,21 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { - WCHAR* WindowsBuildStr; + // Check if the user has selected the Qt6 engine in the Control Panel + int uiMode = GetRegistryValues(HKEY_CURRENT_USER, L"Software\\DirectDesktop", L"UIMode"); + if (uiMode == 1) + { +#ifdef ENABLE_QT + return RunQtEngine(__argc, __argv); +#else + MessageBoxW(nullptr, L"DirectDesktop was not built with Qt support.", L"Error", MB_OK | MB_ICONERROR); + return 0; // Exit DirectUI process +#endif + } + + WCHAR* WindowsBuildStr = nullptr; GetRegistryStrValues(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"CurrentBuildNumber", &WindowsBuildStr); + int WindowsBuild = _wtoi(WindowsBuildStr); free(WindowsBuildStr); if (WindowsBuild < 18362) @@ -5236,8 +5260,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, SystemParametersInfoW(SPI_GETCOMBOBOXANIMATION, NULL, &g_comboAnim, NULL); SystemParametersInfoW(SPI_GETMENUANIMATION, NULL, &g_menuAnim, NULL); SystemParametersInfoW(SPI_GETTOOLTIPANIMATION, NULL, &g_tooltipAnim, NULL); - WCHAR* fontsmoothingStr; - GetRegistryStrValues(DDKey.GetHKeyName(), L"Control Panel\\Desktop", L"FontSmoothing", &fontsmoothingStr); + WCHAR* fontsmoothingStr = nullptr; GetRegistryStrValues(DDKey.GetHKeyName(), L"Control Panel\\Desktop", L"FontSmoothing", &fontsmoothingStr); g_fontsmoothing = _wtoi(fontsmoothingStr); free(fontsmoothingStr); g_hiddenIcons = GetRegistryValues(DDKey.GetHKeyName(), DDKey.GetPath(), L"HideIcons"); @@ -5319,7 +5342,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, else StringCchPrintfW(DesktopLayoutWithSize, 24, L"DesktopLayout_Touch"); if (EnsureRegValueExists(HKEY_CURRENT_USER, L"Software\\DirectDesktop", DesktopLayoutWithSize)) { - BYTE* value2; + BYTE* value2 = nullptr; GetRegistryBinValues(HKEY_CURRENT_USER, L"Software\\DirectDesktop", DesktopLayoutWithSize, &value2); g_currentPageID = *reinterpret_cast(&value2[2]); free(value2); diff --git a/DirectDesktop/QtEngine.cpp b/DirectDesktop/QtEngine.cpp new file mode 100644 index 0000000..9e8b462 --- /dev/null +++ b/DirectDesktop/QtEngine.cpp @@ -0,0 +1,69 @@ +#ifdef ENABLE_QT + +#include "QtEngine.h" +#include +#include +#include +#include + +static HWND g_hWorkerW = nullptr; + +static BOOL CALLBACK EnumWindowsProcQt(HWND hwnd, LPARAM lParam) { + WCHAR className[64]; + HWND hWndProgman = FindWindowW(L"Progman", L"Program Manager"); + if (GetClassNameW(hwnd, className, sizeof(className) / 2)) { + if (wcscmp(className, L"WorkerW") == 0) { + DWORD pid = 0, pid2 = 0; + GetWindowThreadProcessId(hWndProgman, &pid); + GetWindowThreadProcessId(hwnd, &pid2); + if (pid == pid2) { + RECT dimensions; + GetWindowRect(hwnd, &dimensions); + if (dimensions.right >= GetSystemMetrics(SM_CXSCREEN) && + dimensions.bottom >= GetSystemMetrics(SM_CYSCREEN)) { + *(HWND*)lParam = hwnd; + return FALSE; + } + } + } + } + return TRUE; +} + +static HWND GetDesktopWorkerW_Qt() { + HWND progman = FindWindowW(L"Progman", nullptr); + // 0x052C with 0x0D, 1 is what DirectUI uses + SendMessageTimeoutW(progman, 0x052C, 0x0D, 1, SMTO_NORMAL, 1000, nullptr); + + HWND workerw = nullptr; + EnumWindows(EnumWindowsProcQt, (LPARAM)&workerw); + + if (workerw) return workerw; + return progman; +} + +int RunQtEngine(int argc, char *argv[]) { + QApplication app(argc, argv); + QQmlApplicationEngine engine; + + const QUrl url(QStringLiteral("qrc:/main.qml")); + QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, + &app, [url](QObject *obj, const QUrl &objUrl) { + if (!obj && url == objUrl) + QCoreApplication::exit(-1); + + QQuickWindow *window = qobject_cast(obj); + if (window) { + HWND hwnd = (HWND)window->winId(); + HWND parent = GetDesktopWorkerW_Qt(); + + SetParent(hwnd, parent); + SetWindowPos(hwnd, nullptr, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SWP_SHOWWINDOW); + } + }, Qt::QueuedConnection); + + engine.load(url); + return app.exec(); +} + +#endif diff --git a/DirectDesktop/QtEngine.h b/DirectDesktop/QtEngine.h new file mode 100644 index 0000000..d5c0555 --- /dev/null +++ b/DirectDesktop/QtEngine.h @@ -0,0 +1,5 @@ +#pragma once + +#ifdef ENABLE_QT +int RunQtEngine(int argc, char *argv[]); +#endif diff --git a/DirectDesktop/backend/DirectoryHelper.cpp b/DirectDesktop/backend/DirectoryHelper.cpp index 09607fa..d1c208b 100644 --- a/DirectDesktop/backend/DirectoryHelper.cpp +++ b/DirectDesktop/backend/DirectoryHelper.cpp @@ -307,6 +307,7 @@ namespace DirectDesktop return filename.substr(0, lastdot); } } + return filename; } wstring hideExtFromGetPos(const wstring& filename, bool isEnabled) diff --git a/DirectDesktop/backend/DragAndDrop.cpp b/DirectDesktop/backend/DragAndDrop.cpp index 04fb42f..e538a34 100644 --- a/DirectDesktop/backend/DragAndDrop.cpp +++ b/DirectDesktop/backend/DragAndDrop.cpp @@ -1090,7 +1090,7 @@ namespace DirectDesktop if (pvDragStuff) { qmemcpy(&_shdi, pvDragStuff, sizeof(SHDRAGIMAGE) - 8); - void* pvBits; + void* pvBits = nullptr; _Create32BitHBITMAP(&_shdi.hbmpDragImage, &_shdi.sizeDragImage, &hdcScreen, &_hdcDragImage, &pvBits); if (_shdi.hbmpDragImage) { @@ -1122,7 +1122,7 @@ namespace DirectDesktop if (_shdi.hbmpDragImage) { - void* pvBits; + void* pvBits = nullptr; hr = _PreProcessDragBitmap(&pvBits) ? S_OK : E_FAIL; if (SUCCEEDED(hr)) { diff --git a/DirectDesktop/build_timestamp.h b/DirectDesktop/build_timestamp.h index 0638185a22c8ae652faa9728d00a4d95a35c48d5..e29514fe5bb46a87963ae70818b16b49862e9392 100644 GIT binary patch delta 34 ocmbQnIE`_F4YLu0$wYf+5g^5&%V5M{$Y9K1$)Lo*%fQ6|0C-UaCIA2c delta 34 ocmbQnIE`_F4YMJG(L{S^5g^5&%V5Z0#$e1~$)Lo*%fQ6|0C)NYBme*a diff --git a/DirectDesktop/coreui/BitmapHelper.cpp b/DirectDesktop/coreui/BitmapHelper.cpp index 3a45959..527a817 100644 --- a/DirectDesktop/coreui/BitmapHelper.cpp +++ b/DirectDesktop/coreui/BitmapHelper.cpp @@ -38,6 +38,8 @@ namespace DirectDesktop GlobalUnlock(hgblResourceData); if (SUCCEEDED(CreateStreamOnHGlobal(hgblResourceData, TRUE, &ipStream))) return ipStream; + + return ipStream; } IWICBitmapSource* LoadBitmapFromStream(IStream* ipImageStream) @@ -263,6 +265,7 @@ namespace DirectDesktop delete bmp; DeleteObject(hbmOld); Gdiplus::GdiplusShutdown(gdiplusToken); + return true; } bool IterateBitmap(HBITMAP hbm, BitmapPixelHandler handler, int type, unsigned int blurradius, float alphaValue, COLORREF crOpt) // type: 0 = original, 1 = color, 2 = blur, 3 = solid color diff --git a/DirectDesktop/coreui/BlurCore.h b/DirectDesktop/coreui/BlurCore.h index beacae9..b4c3677 100644 --- a/DirectDesktop/coreui/BlurCore.h +++ b/DirectDesktop/coreui/BlurCore.h @@ -209,8 +209,9 @@ namespace DirectDesktop if (SetWindowCompositionAttribute) { - WCHAR* WindowsBuildStr; + WCHAR* WindowsBuildStr = nullptr; GetRegistryStrValues(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"CurrentBuildNumber", &WindowsBuildStr); + int WindowsBuild = _wtoi(WindowsBuildStr); free(WindowsBuildStr); int blurcolor = fullscreen ? (g_theme ? 0xD3D3D3 : 0x202020) + (alpha << 24) : WindowsBuild < 22523 ? g_theme ? 0xDCE4E4E4 : 0xCA1F1F1F : g_theme ? 0x00F8F8F8 : 0x00303030; diff --git a/DirectDesktop/ui/DDControls.cpp b/DirectDesktop/ui/DDControls.cpp index 425cd6d..a5cde6d 100644 --- a/DirectDesktop/ui/DDControls.cpp +++ b/DirectDesktop/ui/DDControls.cpp @@ -1,6 +1,9 @@ ////////////////// 0.5.6.3: NEED HELP WITH CONTEXT MENUS! #include "pch.h" +#include + +#pragma comment(lib, "gdiplus.lib") #include "DDControls.h" #include "..\DirectDesktop.h" @@ -626,6 +629,58 @@ namespace DirectDesktop return CreateAndInit(0, pParent, pdwDeferCookie, ppElement); } + void DDScalableElement::Paint(HDC hdc, const RECT* prcBounds, const RECT* prcInvalid, RECT* prcNext, RECT* prcRegion) + { + // SURPRISE REVERT: Modern "Juicy" V2 Acrylic/Glass Engine + Value* pvClass = nullptr; + const WCHAR* pszClass = GetClass(&pvClass); + if (pszClass && wstring(pszClass) == L"juicy_acrylic") + { + if (pvClass) pvClass->Release(); + Gdiplus::Graphics g(hdc); + g.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); + + float x = (float)prcBounds->left; + float y = (float)prcBounds->top; + float w = (float)(prcBounds->right - prcBounds->left); + float h = (float)(prcBounds->bottom - prcBounds->top); + + // Create rounded corner path + float radius = 12.0f; + Gdiplus::GraphicsPath path; + path.AddArc(x, y, radius, radius, 180, 90); + path.AddArc(x + w - radius, y, radius, radius, 270, 90); + path.AddArc(x + w - radius, y + h - radius, radius, radius, 0, 90); + path.AddArc(x, y + h - radius, radius, radius, 90, 90); + path.CloseFigure(); + + // 1. Draw heavy soft drop shadow + Gdiplus::PathGradientBrush shadowBrush(&path); + Gdiplus::Color shadowColors[] = { Gdiplus::Color(120, 0, 0, 0) }; + int count = 1; + shadowBrush.SetCenterColor(Gdiplus::Color(80, 0, 0, 0)); + shadowBrush.SetSurroundColors(shadowColors, &count); + g.FillPath(&shadowBrush, &path); + + // 2. Draw Deep Acrylic-like backdrop + Gdiplus::SolidBrush acrylicBrush(Gdiplus::Color(180, 20, 20, 25)); + g.FillPath(&acrylicBrush, &path); + + // 3. Draw "Neon" glowing border + Gdiplus::RectF rect(x, y, w, h); + Gdiplus::LinearGradientBrush penBrush(rect, + Gdiplus::Color(255, 0, 255, 255), // Bright Cyan + Gdiplus::Color(150, 255, 0, 255), // Purple Fade + Gdiplus::LinearGradientModeVertical); + Gdiplus::Pen pen(&penBrush, 2.0f); + g.DrawPath(&pen, &path); + + return; + } + if (pvClass) pvClass->Release(); + Element::Paint(hdc, prcBounds, prcInvalid, prcNext, prcRegion); + } + HRESULT DDScalableElement::Register() { static const PropertyInfo* const rgRegisterProps[] = @@ -3294,7 +3349,7 @@ namespace DirectDesktop if (DWMActive) { - WCHAR* WindowsBuildStr; + WCHAR* WindowsBuildStr = nullptr; GetRegistryStrValues(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"CurrentBuildNumber", &WindowsBuildStr); int WindowsBuild = _wtoi(WindowsBuildStr); free(WindowsBuildStr); @@ -5110,7 +5165,7 @@ namespace DirectDesktop if (DWMActive) { - WCHAR* WindowsBuildStr; + WCHAR* WindowsBuildStr = nullptr; GetRegistryStrValues(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"CurrentBuildNumber", &WindowsBuildStr); int WindowsBuild = _wtoi(WindowsBuildStr); free(WindowsBuildStr); @@ -6047,8 +6102,9 @@ namespace DirectDesktop _pDDNB->SetVisible(true); _pDDNB->EndDefer(keyN); _wnd->Host(_pDDNB); - WCHAR* WindowsBuildStr; + WCHAR* WindowsBuildStr = nullptr; GetRegistryStrValues(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"CurrentBuildNumber", &WindowsBuildStr); + int WindowsBuild = _wtoi(WindowsBuildStr); free(WindowsBuildStr); int WindowsRev = GetRegistryValues(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\BuildLayers\\ShellCommon", L"BuildQfe"); diff --git a/DirectDesktop/ui/DDControls.h b/DirectDesktop/ui/DDControls.h index 7a9d1a4..1896a99 100644 --- a/DirectDesktop/ui/DDControls.h +++ b/DirectDesktop/ui/DDControls.h @@ -33,6 +33,7 @@ namespace DirectDesktop static IClassInfo* GetClassInfoPtr(); static void SetClassInfoPtr(DirectUI::IClassInfo* pClass); IClassInfo* GetClassInfoW() override; + void Paint(HDC hdc, const RECT* prcBounds, const RECT* prcInvalid, RECT* prcNext, RECT* prcRegion) override; bool OnPropertyChanging(const PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew) override; void OnPropertyChanged(const PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew) override; static HRESULT Create(Element* pParent, DWORD* pdwDeferCookie, Element** ppElement); diff --git a/DirectDesktop/ui/EditMode.cpp b/DirectDesktop/ui/EditMode.cpp index 2e8e1ae..d7c085e 100644 --- a/DirectDesktop/ui/EditMode.cpp +++ b/DirectDesktop/ui/EditMode.cpp @@ -1494,8 +1494,9 @@ namespace DirectDesktop //editbgwnd->ShowWindow(SW_SHOW); //editbgwnd->ShowWindow(SW_HIDE); - WCHAR* WindowsBuildStr; + WCHAR* WindowsBuildStr = nullptr; GetRegistryStrValues(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"CurrentBuildNumber", &WindowsBuildStr); + int WindowsBuild = _wtoi(WindowsBuildStr); free(WindowsBuildStr); if (WindowsBuild >= 26002) diff --git a/DirectDesktop/ui/ShutdownDialog.cpp b/DirectDesktop/ui/ShutdownDialog.cpp index 03e87c9..1039254 100644 --- a/DirectDesktop/ui/ShutdownDialog.cpp +++ b/DirectDesktop/ui/ShutdownDialog.cpp @@ -28,6 +28,7 @@ namespace DirectDesktop DDScalableTouchEdit* delayseconds; HANDLE ActionThread, TimerThread; + bool stopThreads = false; HWND hShutdownTimer; int savedremaining; // Display remaining time immediately when the dialog is invoked wstring reasonStr = LoadStrFromRes(8261, L"user32.dll"); @@ -180,7 +181,7 @@ namespace DirectDesktop DialogValues* dv = (DialogValues*)lpParam; int id = dv->buttonID; int remaining = dv->delay; - while (remaining >= 0) + while (remaining >= 0 && !stopThreads) { if (IsWindowVisible(shutdownwnd->GetHWND())) SendMessageW(shutdownwnd->GetHWND(), WM_USER + 1, id, remaining); Sleep(1000); @@ -197,8 +198,13 @@ namespace DirectDesktop int seconds = dv->delay; int id = dv->buttonID; if (seconds > 0) TimerThread = CreateThread(nullptr, 0, ShowTimerStatus, dv, NULL, nullptr); - Sleep(seconds * 1000); - SendMessageW(wnd->GetHWND(), WM_USER + 19, NULL, id); + + // Sleep in increments to allow for clean interruption + for (int i = 0; i < seconds && !stopThreads; i++) { + Sleep(1000); + } + + if (!stopThreads) SendMessageW(wnd->GetHWND(), WM_USER + 19, NULL, id); return 0; } @@ -215,9 +221,19 @@ namespace DirectDesktop if (delayseconds->GetContentString(&v) == nullptr) delayseconds->SetContentString(L"0"); StatusText = nullptr; - // TODO: Find a better way to stop older threads or make the bool array not global - if (ActionThread) TerminateThread(ActionThread, 1); - if (TimerThread) TerminateThread(TimerThread, 1); + // Safely signal threads to stop + stopThreads = true; + if (ActionThread) { + WaitForSingleObject(ActionThread, 1000); + CloseHandle(ActionThread); + ActionThread = nullptr; + } + if (TimerThread) { + WaitForSingleObject(TimerThread, 1000); + CloseHandle(TimerThread); + TimerThread = nullptr; + } + stopThreads = false; // Reset for the next action for (int i = 0; i < 6; i++) { @@ -487,8 +503,9 @@ namespace DirectDesktop stars->SetFont(cBuffer); delete[] cBuffer; TitlebarText->SetContentString(caption.c_str()); - WCHAR* WindowsBuildStr; + WCHAR* WindowsBuildStr = nullptr; GetRegistryStrValues(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"CurrentBuildNumber", &WindowsBuildStr); + int WindowsBuild = _wtoi(WindowsBuildStr); free(WindowsBuildStr); int WindowsRev = GetRegistryValues(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\BuildLayers\\ShellCommon", L"BuildQfe"); diff --git a/DirectDesktop/ui/main.qml b/DirectDesktop/ui/main.qml new file mode 100644 index 0000000..7f17059 --- /dev/null +++ b/DirectDesktop/ui/main.qml @@ -0,0 +1,74 @@ +import QtQuick +import QtQuick.Controls + +Window { + id: root + visible: true + width: Screen.width + height: Screen.height + flags: Qt.FramelessWindowHint | Qt.WindowTransparentForInput + color: "transparent" + + Rectangle { + id: desktopOverlay + anchors.fill: parent + color: "transparent" + + // Animated pulsing indicator to confirm it's running + Rectangle { + width: 300 + height: 300 + radius: 150 + color: "#400078D7" + anchors.centerIn: parent + + SequentialAnimation on opacity { + loops: Animation.Infinite + NumberAnimation { from: 0.2; to: 0.8; duration: 2000; easing.type: Easing.InOutQuad } + NumberAnimation { from: 0.8; to: 0.2; duration: 2000; easing.type: Easing.InOutQuad } + } + + Text { + anchors.centerIn: parent + text: "DirectDesktop\nQt6 Active" + color: "white" + font.pixelSize: 24 + horizontalAlignment: Text.AlignHCenter + font.weight: Font.DemiBold + } + } + + // Modern Sidebar + Rectangle { + width: 80 + anchors.left: parent.left + anchors.top: parent.top + anchors.bottom: parent.bottom + color: "#CC1E1E1E" + + Column { + anchors.centerIn: parent + spacing: 30 + + Repeater { + model: ["🏠", "🔍", "⚙️", "🌙"] + delegate: Text { + text: modelData + font.pixelSize: 32 + color: "white" + scale: 1.0 + + Behavior on scale { NumberAnimation { duration: 100 } } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + onEntered: parent.scale = 1.2 + onExited: parent.scale = 1.0 + } + } + } + } + } + } +} diff --git a/DirectDesktop/ui/qml.qrc b/DirectDesktop/ui/qml.qrc new file mode 100644 index 0000000..5f6483a --- /dev/null +++ b/DirectDesktop/ui/qml.qrc @@ -0,0 +1,5 @@ + + + main.qml + + diff --git a/DirectDesktop/ui/styles.xml b/DirectDesktop/ui/styles.xml index b1b3b49..7ef6b40 100644 --- a/DirectDesktop/ui/styles.xml +++ b/DirectDesktop/ui/styles.xml @@ -1048,6 +1048,9 @@ + + + diff --git a/DirectDesktopSettings/App.xaml b/DirectDesktopSettings/App.xaml new file mode 100644 index 0000000..d157f9a --- /dev/null +++ b/DirectDesktopSettings/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/DirectDesktopSettings/App.xaml.cs b/DirectDesktopSettings/App.xaml.cs new file mode 100644 index 0000000..19464d7 --- /dev/null +++ b/DirectDesktopSettings/App.xaml.cs @@ -0,0 +1,13 @@ +using System.Configuration; +using System.Data; +using System.Windows; + +namespace DirectDesktopSettings; + +/// +/// Interaction logic for App.xaml +/// +public partial class App : Application +{ +} + diff --git a/DirectDesktopSettings/AssemblyInfo.cs b/DirectDesktopSettings/AssemblyInfo.cs new file mode 100644 index 0000000..cc29e7f --- /dev/null +++ b/DirectDesktopSettings/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly:ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/DirectDesktopSettings/DirectDesktopSettings.csproj b/DirectDesktopSettings/DirectDesktopSettings.csproj new file mode 100644 index 0000000..dd060da --- /dev/null +++ b/DirectDesktopSettings/DirectDesktopSettings.csproj @@ -0,0 +1,11 @@ + + + + WinExe + net11.0-windows + enable + enable + true + + + diff --git a/DirectDesktopSettings/MainWindow.xaml b/DirectDesktopSettings/MainWindow.xaml new file mode 100644 index 0000000..4b2f290 --- /dev/null +++ b/DirectDesktopSettings/MainWindow.xaml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +