From 4480e140a49f6ab23cb9a32bd98bee363f4b35e0 Mon Sep 17 00:00:00 2001 From: Elias Bachaalany Date: Sat, 2 May 2026 09:13:14 -0700 Subject: [PATCH 1/3] [build] replace legacy dev tool projects with CMake --- CMakeLists.txt | 6 + cmake/sal_dev_tools.cmake | 87 ++++++++ doc/DEV.md | 16 ++ .../vcproj2015_manison/lang_portables.props | 13 -- .../vcproj2015_manison/lang_portables.vcxproj | 129 ------------ .../vcproj2015_manison/portables.props | 15 -- .../vcproj2015_manison/portables.sln | 48 ----- .../vcproj2015_manison/portables.vcxproj | 191 ------------------ .../portables.vcxproj.filters | 170 ---------------- src/reglib/!clear.bat | 6 - src/reglib/REGLIBA.vcxproj | 142 ------------- src/reglib/REGLIBA.vcxproj.filters | 50 ----- src/reglib/regliba.sln | 22 -- tools/salbreak/!clear.bat | 6 - tools/salbreak/salbreak.sln | 22 -- tools/salbreak/salbreak.vcxproj | 130 ------------ tools/salbreak/salbreak.vcxproj.filters | 58 ------ tools/utfnames/utfnames.vcxproj | 153 -------------- 18 files changed, 109 insertions(+), 1155 deletions(-) create mode 100644 cmake/sal_dev_tools.cmake delete mode 100644 src/plugins/portables/vcproj2015_manison/lang_portables.props delete mode 100644 src/plugins/portables/vcproj2015_manison/lang_portables.vcxproj delete mode 100644 src/plugins/portables/vcproj2015_manison/portables.props delete mode 100644 src/plugins/portables/vcproj2015_manison/portables.sln delete mode 100644 src/plugins/portables/vcproj2015_manison/portables.vcxproj delete mode 100644 src/plugins/portables/vcproj2015_manison/portables.vcxproj.filters delete mode 100644 src/reglib/!clear.bat delete mode 100644 src/reglib/REGLIBA.vcxproj delete mode 100644 src/reglib/REGLIBA.vcxproj.filters delete mode 100644 src/reglib/regliba.sln delete mode 100644 tools/salbreak/!clear.bat delete mode 100644 tools/salbreak/salbreak.sln delete mode 100644 tools/salbreak/salbreak.vcxproj delete mode 100644 tools/salbreak/salbreak.vcxproj.filters delete mode 100644 tools/utfnames/utfnames.vcxproj diff --git a/CMakeLists.txt b/CMakeLists.txt index 83f469b30..e8f1b4d1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -581,6 +581,12 @@ set_target_properties(salext PROPERTIES add_subdirectory(src/plugins) +# ============================================================================== +# Optional Developer Tools +# ============================================================================== + +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/sal_dev_tools.cmake) + # ============================================================================== # Installation Rules # ============================================================================== diff --git a/cmake/sal_dev_tools.cmake b/cmake/sal_dev_tools.cmake new file mode 100644 index 000000000..3d0d88a34 --- /dev/null +++ b/cmake/sal_dev_tools.cmake @@ -0,0 +1,87 @@ +# Optional developer tools for Sally. +# These targets are intentionally excluded from the default build and release packaging. + +include_guard(GLOBAL) + +if(NOT WIN32) + return() +endif() + +set(SAL_DEVTOOLS_OUTPUT_DIR "${SAL_OUTPUT_BASE}/$_${SAL_PLATFORM}/devtools") + +function(sal_configure_dev_tool TARGET_NAME) + set_target_properties(${TARGET_NAME} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${SAL_DEVTOOLS_OUTPUT_DIR}" + ARCHIVE_OUTPUT_DIRECTORY "${SAL_DEVTOOLS_OUTPUT_DIR}/lib" + LIBRARY_OUTPUT_DIRECTORY "${SAL_DEVTOOLS_OUTPUT_DIR}/bin" + ) + + if(MSVC) + target_compile_options(${TARGET_NAME} PRIVATE /MP /W3 /J) + target_link_options(${TARGET_NAME} PRIVATE /MANIFEST:NO) + endif() +endfunction() + +# utfnames: utility for creating and inspecting non-well-formed UTF-16 filenames. +set(SAL_UTFNAMES_MANIFEST_RC "${CMAKE_CURRENT_BINARY_DIR}/devtools/utfnames_manifest.rc") +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/devtools") +file(WRITE "${SAL_UTFNAMES_MANIFEST_RC}" + "#include \n" + "CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST \"${SAL_ROOT}/tools/utfnames/utfnames.manifest\"\n" +) + +add_executable(utfnames EXCLUDE_FROM_ALL + "${SAL_ROOT}/tools/utfnames/utfnames.cpp" + "${SAL_UTFNAMES_MANIFEST_RC}" +) +target_compile_features(utfnames PRIVATE cxx_std_20) +target_compile_definitions(utfnames PRIVATE + _CONSOLE + WIN32 + WINVER=0x0601 + _WIN32_WINNT=0x0601 + $<$:_DEBUG> + $<${SAL_IS_RELEASE}:NDEBUG> +) +target_link_libraries(utfnames PRIVATE ntdll) +sal_configure_dev_tool(utfnames) + +# salbreak: hidden hotkey helper that asks running Sally instances to break. +add_executable(salbreak WIN32 EXCLUDE_FROM_ALL + "${SAL_ROOT}/tools/salbreak/md5.cpp" + "${SAL_ROOT}/tools/salbreak/salbreak.cpp" + "${SAL_ROOT}/tools/salbreak/tasklist.cpp" + "${SAL_ROOT}/tools/salbreak/salbreak.rc" +) +target_include_directories(salbreak PRIVATE "${SAL_ROOT}/tools/salbreak") +target_compile_definitions(salbreak PRIVATE + WIN32 + _WINDOWS + WINVER=0x0601 + _WIN32_WINNT=0x0601 + $<$:_DEBUG> + $<${SAL_IS_RELEASE}:NDEBUG> +) +target_link_libraries(salbreak PRIVATE advapi32) +if(MSVC) + set_target_properties(salbreak PROPERTIES + MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>" + ) +endif() +sal_configure_dev_tool(salbreak) + +# RegParser: standalone registry file parser/dumper built from reglib. +add_executable(regparser EXCLUDE_FROM_ALL + "${SAL_SRC}/reglib/src/tester.cpp" + "${SAL_SRC}/reglib/src/regparser.rc" +) +set_target_properties(regparser PROPERTIES OUTPUT_NAME "RegParser") +target_include_directories(regparser PRIVATE "${SAL_SRC}/reglib/src") +target_compile_definitions(regparser PRIVATE + _CONSOLE + ${SAL_COMMON_DEFINES} + $<$:${SAL_DEBUG_DEFINES}> + $<${SAL_IS_RELEASE}:${SAL_RELEASE_DEFINES}> +) +target_link_libraries(regparser PRIVATE reglib) +sal_configure_dev_tool(regparser) diff --git a/doc/DEV.md b/doc/DEV.md index 0981bd797..fa202ddab 100644 --- a/doc/DEV.md +++ b/doc/DEV.md @@ -41,6 +41,22 @@ A few Altap Salamander 4.0 plugins are either not included or cannot be compiled All source code uses UTF-8-BOM encoding and is formatted with `clang-format`. Refer to the `\tools\normalize.ps1` script for more information. +## Developer Tool Targets + +The CMake build keeps a few standalone maintenance utilities as explicit targets only. They are not part of default builds, `populate`, installs, or release packages. These targets replace old first-party `.vcxproj` files that were preserved from the Open Salamander tree: + +- `utfnames`: creates and lists unusual NTFS names, including names with invalid UTF-16 sequences. +- `salbreak`: hidden hotkey helper that asks running Sally instances to trigger their break/report path. +- `regparser`: builds `RegParser.exe`, a standalone parser/dumper for `.reg` files using `src/reglib`. + +```bash +cmake --build build --config Debug --target utfnames salbreak regparser +``` + +The resulting executables are written under `build/out/sally/_/devtools/`. + +The old Portables plugin Visual Studio project was removed without a separate dev-tool replacement because the normal CMake plugin build already covers `plugin_portables` and its English language file. `packages.config` is still used by `cmake/sal_nuget.cmake` to restore the WebView2 SDK for the CMake build. + ## Localization For the supported Translator workflow, generated workspaces, and contribution steps, see `doc/LOCALIZATION.md`. diff --git a/src/plugins/portables/vcproj2015_manison/lang_portables.props b/src/plugins/portables/vcproj2015_manison/lang_portables.props deleted file mode 100644 index 1426bc978..000000000 --- a/src/plugins/portables/vcproj2015_manison/lang_portables.props +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - portables - - - - $(ShortProjectName) - - - \ No newline at end of file diff --git a/src/plugins/portables/vcproj2015_manison/lang_portables.vcxproj b/src/plugins/portables/vcproj2015_manison/lang_portables.vcxproj deleted file mode 100644 index 71ec90212..000000000 --- a/src/plugins/portables/vcproj2015_manison/lang_portables.vcxproj +++ /dev/null @@ -1,129 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - 16.0 - {ABFAEF56-F1E6-4B1C-B1D3-1A759D84B910} - lang_portables - 10.0.14393.0 - Win32Proj - lang_portables - - - -v140 - DynamicLibrary - - -v140 - DynamicLibrary - - -v140 - DynamicLibrary - - -v140 - DynamicLibrary - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .slg - english - - - .slg - english - - - english - .slg - - - - - - - - - true - - - - - - - - - - true - - - - - - - - - - - - - RC - - - - - - - - - diff --git a/src/plugins/portables/vcproj2015_manison/portables.props b/src/plugins/portables/vcproj2015_manison/portables.props deleted file mode 100644 index 201958d9c..000000000 --- a/src/plugins/portables/vcproj2015_manison/portables.props +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - WINVER=0x0601;_WIN32_WINNT=0x0601;_WIN32_IE=0x0800;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT;%(PreprocessorDefinitions) - - - WINVER=0x0600;%(PreprocessorDefinitions) - - - - \ No newline at end of file diff --git a/src/plugins/portables/vcproj2015_manison/portables.sln b/src/plugins/portables/vcproj2015_manison/portables.sln deleted file mode 100644 index 0ab06ede8..000000000 --- a/src/plugins/portables/vcproj2015_manison/portables.sln +++ /dev/null @@ -1,48 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portables", "portables.vcxproj", "{21EC6980-0206-421C-BE36-FD169EC2D654}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lang_portables", "lang_portables.vcxproj", "{ABFAEF56-F1E6-4B1C-B1D3-1A759D84B910}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - SDK|x64 = SDK|x64 - SDK|x86 = SDK|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {21EC6980-0206-421C-BE36-FD169EC2D654}.Debug|x64.ActiveCfg = Debug|x64 - {21EC6980-0206-421C-BE36-FD169EC2D654}.Debug|x64.Build.0 = Debug|x64 - {21EC6980-0206-421C-BE36-FD169EC2D654}.Debug|x86.ActiveCfg = Debug|Win32 - {21EC6980-0206-421C-BE36-FD169EC2D654}.Debug|x86.Build.0 = Debug|Win32 - {21EC6980-0206-421C-BE36-FD169EC2D654}.Release|x64.ActiveCfg = Release|x64 - {21EC6980-0206-421C-BE36-FD169EC2D654}.Release|x64.Build.0 = Release|x64 - {21EC6980-0206-421C-BE36-FD169EC2D654}.Release|x86.ActiveCfg = Release|Win32 - {21EC6980-0206-421C-BE36-FD169EC2D654}.Release|x86.Build.0 = Release|Win32 - {21EC6980-0206-421C-BE36-FD169EC2D654}.SDK|x64.ActiveCfg = SDK|x64 - {21EC6980-0206-421C-BE36-FD169EC2D654}.SDK|x64.Build.0 = SDK|x64 - {21EC6980-0206-421C-BE36-FD169EC2D654}.SDK|x86.ActiveCfg = SDK|Win32 - {21EC6980-0206-421C-BE36-FD169EC2D654}.SDK|x86.Build.0 = SDK|Win32 - {ABFAEF56-F1E6-4B1C-B1D3-1A759D84B910}.Debug|x64.ActiveCfg = Debug|x64 - {ABFAEF56-F1E6-4B1C-B1D3-1A759D84B910}.Debug|x64.Build.0 = Debug|x64 - {ABFAEF56-F1E6-4B1C-B1D3-1A759D84B910}.Debug|x86.ActiveCfg = Debug|Win32 - {ABFAEF56-F1E6-4B1C-B1D3-1A759D84B910}.Debug|x86.Build.0 = Debug|Win32 - {ABFAEF56-F1E6-4B1C-B1D3-1A759D84B910}.Release|x64.ActiveCfg = Release|x64 - {ABFAEF56-F1E6-4B1C-B1D3-1A759D84B910}.Release|x64.Build.0 = Release|x64 - {ABFAEF56-F1E6-4B1C-B1D3-1A759D84B910}.Release|x86.ActiveCfg = Release|Win32 - {ABFAEF56-F1E6-4B1C-B1D3-1A759D84B910}.Release|x86.Build.0 = Release|Win32 - {ABFAEF56-F1E6-4B1C-B1D3-1A759D84B910}.SDK|x64.ActiveCfg = SDK|x64 - {ABFAEF56-F1E6-4B1C-B1D3-1A759D84B910}.SDK|x64.Build.0 = SDK|x64 - {ABFAEF56-F1E6-4B1C-B1D3-1A759D84B910}.SDK|x86.ActiveCfg = SDK|Win32 - {ABFAEF56-F1E6-4B1C-B1D3-1A759D84B910}.SDK|x86.Build.0 = SDK|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/src/plugins/portables/vcproj2015_manison/portables.vcxproj b/src/plugins/portables/vcproj2015_manison/portables.vcxproj deleted file mode 100644 index f5c2a3c14..000000000 --- a/src/plugins/portables/vcproj2015_manison/portables.vcxproj +++ /dev/null @@ -1,191 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - 16.0 - {21ec6980-0206-421c-be36-fd169ec2d654} - portables - 10.0.14393.0 - portables - - - -v140 - DynamicLibrary - - -v140 - DynamicLibrary - - -v140 - DynamicLibrary - - -v140 - DynamicLibrary - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .spl - - - .spl - - - .spl - - - - - - true - kernel32.lib;user32.lib;comctl32.lib;gdi32.lib;ole32.lib - false - - - MultiThreadedDebug - false - - - - - - - true - false - salrtl9.lib - - - - - - - false - kernel32.lib;user32.lib;comctl32.lib;gdi32.lib;ole32.lib;advapi32.lib - - - - false - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RC - - - - - - - - - - - - - - - diff --git a/src/plugins/portables/vcproj2015_manison/portables.vcxproj.filters b/src/plugins/portables/vcproj2015_manison/portables.vcxproj.filters deleted file mode 100644 index 0944fed79..000000000 --- a/src/plugins/portables/vcproj2015_manison/portables.vcxproj.filters +++ /dev/null @@ -1,170 +0,0 @@ - - - - - {fca60546-50be-4543-959b-31871a48be15} - - - {8026bbeb-7cef-401f-9576-faf17fd495f1} - - - {4a3a15a1-96a9-4761-9e60-45b1d25a70de} - - - {33d35887-058a-450e-8dfa-246d83c9ca8c} - - - {8beedec5-09a2-418c-8eb8-7a076cb79947} - - - {4db6c2bc-f2e0-4687-8508-60c208ff1032} - - - - - cpp - - - cpp - - - cpp\shared - - - cpp\shared - - - cpp - - - cpp\shared - - - cpp - - - cpp - - - cpp - - - cpp\fx - - - cpp\fx - - - cpp - - - cpp - - - cpp - - - cpp - - - - - h - - - h\shared - - - h\shared - - - h\shared - - - h\shared - - - h\shared - - - h\shared - - - h\shared - - - h\shared - - - h\shared - - - h\shared - - - h - - - h - - - h\shared - - - h - - - h - - - h - - - h - - - h\fx - - - h\fx - - - h - - - h - - - h - - - h - - - h - - - h\fx - - - - - - - - - - h\fx - - - h\fx - - - - - - - - - - \ No newline at end of file diff --git a/src/reglib/!clear.bat b/src/reglib/!clear.bat deleted file mode 100644 index ecb785493..000000000 --- a/src/reglib/!clear.bat +++ /dev/null @@ -1,6 +0,0 @@ -@rmdir /s /q Debug -@rmdir /s /q Release -@rmdir /s /q .vs - -@del REGLIBA.vcxproj.user -@del src\REGPARSER.APS diff --git a/src/reglib/REGLIBA.vcxproj b/src/reglib/REGLIBA.vcxproj deleted file mode 100644 index fcffd7329..000000000 --- a/src/reglib/REGLIBA.vcxproj +++ /dev/null @@ -1,142 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {6B5D0336-74E9-48B7-8C3C-891E1CF6DCC5} - regliba - - - - Application - true - v142 - false - - - Application - false - v142 - false - - - - - - - - - - - - - Release\ - Release\ - false - false - false - - - Debug\ - Debug\ - false - true - false - - - - MaxSpeed - true - src;%(AdditionalIncludeDirectories) - SAFE_ALLOC;NDEBUG;MESSAGES_DISABLE;_MT;WIN32;_CONSOLE;WINVER=0x0601;_WIN32_WINNT=0x0601;_WIN32_IE=0x0800;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT;%(PreprocessorDefinitions) - MultiThreadedDLL - true - /J - Use - precomp.h - Release/REGLIBA.pch - Level3 - true - - - NDEBUG;%(PreprocessorDefinitions) - 0x0409 - - - false - - - Release/REGLIBA.exe - false - true - Release/REGLIBA.pdb - Console - 3145728 - true - true - true - MachineX86 - - - - - Disabled - src;%(AdditionalIncludeDirectories) - _ALLOW_RTCc_IN_STL;SAFE_ALLOC;_DEBUG;__DEBUG_WINLIB;TRACE_ENABLE;HANDLES_ENABLE;MESSAGES_DEBUG;MULTITHREADED_TRACE_ENABLE;MULTITHREADED_MESSAGES_ENABLE;MULTITHREADED_HANDLES_ENABLE;_CRTDBG_MAP_ALLOC;_MT;WIN32;_CONSOLE;WINVER=0x0601;_WIN32_WINNT=0x0601;_WIN32_IE=0x0800;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT;%(PreprocessorDefinitions) - true - MultiThreadedDebugDLL - /J - Use - precomp.h - Debug/REGLIBA.pch - Level3 - - - _DEBUG;%(PreprocessorDefinitions) - 0x0409 - - - false - Debug/REGLIBA.exe - true - Debug/REGLIBA.pdb - Console - 3145728 - false - ..\plugins\shared\baseaddr_x86.txt,$(ProjectName) - MachineX86 - - - false - - - - - Create - Create - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/reglib/REGLIBA.vcxproj.filters b/src/reglib/REGLIBA.vcxproj.filters deleted file mode 100644 index 947bdcb9d..000000000 --- a/src/reglib/REGLIBA.vcxproj.filters +++ /dev/null @@ -1,50 +0,0 @@ - - - - - {95d91a3d-1bf8-4da4-b8c9-0fa180621ec7} - CPP - - - {4531b38d-f131-4ad4-9379-fee0c623963f} - H - - - {392b7344-c65d-404a-a25f-524254641250} - RC;ICO;BMP - - - - - CPP - - - CPP - - - CPP - - - CPP - - - CPP - - - CPP - - - - - H - - - H - - - - - RC - - - \ No newline at end of file diff --git a/src/reglib/regliba.sln b/src/reglib/regliba.sln deleted file mode 100644 index c8dba0a3b..000000000 --- a/src/reglib/regliba.sln +++ /dev/null @@ -1,22 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.40629.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "REGLIBA", "REGLIBA.vcxproj", "{6B5D0336-74E9-48B7-8C3C-891E1CF6DCC5}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6B5D0336-74E9-48B7-8C3C-891E1CF6DCC5}.Debug|Win32.ActiveCfg = Debug|Win32 - {6B5D0336-74E9-48B7-8C3C-891E1CF6DCC5}.Debug|Win32.Build.0 = Debug|Win32 - {6B5D0336-74E9-48B7-8C3C-891E1CF6DCC5}.Release|Win32.ActiveCfg = Release|Win32 - {6B5D0336-74E9-48B7-8C3C-891E1CF6DCC5}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/tools/salbreak/!clear.bat b/tools/salbreak/!clear.bat deleted file mode 100644 index c5aa69f3f..000000000 --- a/tools/salbreak/!clear.bat +++ /dev/null @@ -1,6 +0,0 @@ -@rmdir /s /q Debug -@rmdir /s /q Release -@rmdir /s /q .vs - -@del salbreak.aps -@del salbreak.vcxproj.user diff --git a/tools/salbreak/salbreak.sln b/tools/salbreak/salbreak.sln deleted file mode 100644 index d9bea2364..000000000 --- a/tools/salbreak/salbreak.sln +++ /dev/null @@ -1,22 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.40629.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "salbreak", "SALBREAK.vcxproj", "{C16525FC-1009-4BEA-B0DA-3EC714B55775}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C16525FC-1009-4BEA-B0DA-3EC714B55775}.Debug|Win32.ActiveCfg = Debug|Win32 - {C16525FC-1009-4BEA-B0DA-3EC714B55775}.Debug|Win32.Build.0 = Debug|Win32 - {C16525FC-1009-4BEA-B0DA-3EC714B55775}.Release|Win32.ActiveCfg = Release|Win32 - {C16525FC-1009-4BEA-B0DA-3EC714B55775}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/tools/salbreak/salbreak.vcxproj b/tools/salbreak/salbreak.vcxproj deleted file mode 100644 index 6f2bb6934..000000000 --- a/tools/salbreak/salbreak.vcxproj +++ /dev/null @@ -1,130 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - 16.0 - {C16525FC-1009-4BEA-B0DA-3EC714B55775} - Win32Proj - salbreak - salbreak - 10.0 - - - - Application - true - v143 - MultiByte - - - Application - false - v143 - true - MultiByte - - - - - - - - - - - - - .\Release\ - .\Release\ - false - false - - - .\Debug\ - .\Debug\ - false - false - - - - MaxSpeed - true - WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) - MultiThreaded - false - true - Level3 - - - NDEBUG;%(PreprocessorDefinitions) - 0x0405 - - - .\Release/salbreak.exe - .\Release/salbreak.pdb - Windows - true - MachineX86 - true - true - - - call ..\..\tools\codesign\sign_with_retry.cmd "$(TargetPath)" - - - - - Disabled - WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) - true - MultiThreadedDebug - Level3 - - - _DEBUG;%(PreprocessorDefinitions) - 0x0405 - - - .\Debug/salbreak.exe - true - .\Debug/salbreak.pdb - Windows - false - ..\..\src\plugins\shared\baseaddr_x86.txt,$(ProjectName) - MachineX86 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/tools/salbreak/salbreak.vcxproj.filters b/tools/salbreak/salbreak.vcxproj.filters deleted file mode 100644 index aad672852..000000000 --- a/tools/salbreak/salbreak.vcxproj.filters +++ /dev/null @@ -1,58 +0,0 @@ - - - - - {b2b9e36a-77af-4b76-88fc-f8eee7e2a9e5} - cpp;c;cxx;rc;def;r;odl;idl;hpj;bat - - - {2eec3ac7-6491-47fe-8696-1de36b59f567} - h;hpp;hxx;hm;inl - - - {ec5c9e8b-43d7-4430-b7db-9027ea3e2b0b} - ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - - Resource Files - - - - - - \ No newline at end of file diff --git a/tools/utfnames/utfnames.vcxproj b/tools/utfnames/utfnames.vcxproj deleted file mode 100644 index 798ba31cd..000000000 --- a/tools/utfnames/utfnames.vcxproj +++ /dev/null @@ -1,153 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 18.0 - Win32Proj - {bfd34b42-c72c-4d87-a6a2-1016c499a6d3} - badutf16filename - 10.0 - - - - Application - true - v143 - MultiByte - - - Application - false - v143 - true - MultiByte - - - Application - true - v143 - MultiByte - - - Application - false - v143 - true - MultiByte - - - - - - - - - - - - - - - - - - - - - utfnames.manifest - - - - Level3 - true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp20 - - - Console - true - - - utfnames.manifest - - - - - Level3 - true - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp20 - - - Console - true - - - utfnames.manifest - - - - - Level3 - true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp20 - - - Console - true - - - utfnames.manifest - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp20 - - - Console - true - - - utfnames.manifest - - - - - - - - - - - - \ No newline at end of file From b222ecfeeca99d76ad134a354950d195de05e9b5 Mon Sep 17 00:00:00 2001 From: Elias Bachaalany Date: Sun, 3 May 2026 08:05:50 -0700 Subject: [PATCH 2/3] darkmode: clean up remaining chrome edges --- src/darkmode.cpp | 21 ++- src/editwnd.cpp | 44 ++++- src/files_box_header_bottom_bar.cpp | 3 +- src/files_box_view.cpp | 34 +++- src/files_window_navigation.cpp | 1 + src/main_window_commands_help.cpp | 259 ++++++++++++++++++++++++++-- src/salamander_entry_lifecycle.cpp | 1 + src/stswnd.cpp | 36 +++- src/toolbar_layout_draw.cpp | 63 +++++-- 9 files changed, 427 insertions(+), 35 deletions(-) diff --git a/src/darkmode.cpp b/src/darkmode.cpp index 28fbaceb6..3b79f0dd4 100644 --- a/src/darkmode.cpp +++ b/src/darkmode.cpp @@ -20,11 +20,13 @@ BOOL InitSupportLogged = FALSE; BOOL SupportWarningLogged = FALSE; BOOL CaptionColorAttrSupported = TRUE; BOOL TextColorAttrSupported = TRUE; +BOOL BorderColorAttrSupported = TRUE; thread_local int ListTreeThemeApplyDepth = 0; thread_local int GroupBoxThemeApplyDepth = 0; const DWORD DWMWA_USE_IMMERSIVE_DARK_MODE_NEW = 20; // Win10 1903+ const DWORD DWMWA_USE_IMMERSIVE_DARK_MODE_OLD = 19; // older Win10 builds +const DWORD DWMWA_BORDER_COLOR = 34; const DWORD DWMWA_CAPTION_COLOR = 35; const DWORD DWMWA_TEXT_COLOR = 36; const COLORREF DWMWA_COLOR_DEFAULT = 0xFFFFFFFF; @@ -748,14 +750,24 @@ void DarkMode_ApplyTitleBar(HWND hwnd) int normalizedTheme = NormalizeThemeMode(ThemeMode); COLORREF captionColor = DWMWA_COLOR_DEFAULT; COLORREF textColor = DWMWA_COLOR_DEFAULT; + COLORREF borderColor = DWMWA_COLOR_DEFAULT; if (normalizedTheme == THEME_MODE_DARK) { captionColor = RGB(32, 32, 32); textColor = RGB(255, 255, 255); } + if (useDark) + borderColor = MAINFRAME_DARK_LINE_DARK; HRESULT hrCaption = S_OK; HRESULT hrText = S_OK; + HRESULT hrBorder = S_OK; + if (BorderColorAttrSupported) + { + hrBorder = DwmSetWindowAttributePtr(hwnd, DWMWA_BORDER_COLOR, &borderColor, sizeof(borderColor)); + if (FAILED(hrBorder)) + BorderColorAttrSupported = FALSE; + } if (CaptionColorAttrSupported) { hrCaption = DwmSetWindowAttributePtr(hwnd, DWMWA_CAPTION_COLOR, &captionColor, sizeof(captionColor)); @@ -768,11 +780,12 @@ void DarkMode_ApplyTitleBar(HWND hwnd) if (FAILED(hrText)) TextColorAttrSupported = FALSE; } - if (FAILED(hrCaption) || FAILED(hrText)) + if (FAILED(hrBorder) || FAILED(hrCaption) || FAILED(hrText)) { - TRACE_I("DarkMode: caption/text color attributes not available or failed, hwnd=" << hwnd - << ", hrCaption=" << std::hex << hrCaption - << ", hrText=" << std::hex << hrText); + TRACE_I("DarkMode: border/caption/text color attributes not available or failed, hwnd=" << hwnd + << ", hrBorder=" << std::hex << hrBorder + << ", hrCaption=" << std::hex << hrCaption + << ", hrText=" << std::hex << hrText); } } diff --git a/src/editwnd.cpp b/src/editwnd.cpp index d7bd90cd1..71f08726a 100644 --- a/src/editwnd.cpp +++ b/src/editwnd.cpp @@ -22,8 +22,8 @@ const COLORREF EDITWND_DARK_BG = RGB(45, 45, 48); const COLORREF EDITWND_DARK_INPUT_BG = RGB(30, 30, 30); const COLORREF EDITWND_DARK_TEXT = RGB(232, 232, 232); const COLORREF EDITWND_DARK_DISABLED_TEXT = RGB(140, 140, 140); -const COLORREF EDITWND_DARK_BORDER_OUTER = RGB(75, 75, 75); -const COLORREF EDITWND_DARK_BORDER_INNER = RGB(95, 95, 95); +const COLORREF EDITWND_DARK_BORDER_OUTER = RGB(45, 45, 48); +const COLORREF EDITWND_DARK_BORDER_INNER = RGB(62, 62, 66); const COLORREF EDITWND_DARK_BUTTON_BG = RGB(52, 52, 56); static void FillRectSolid(HDC hDC, const RECT* rect, COLORREF color) @@ -35,6 +35,28 @@ static void FillRectSolid(HDC hDC, const RECT* rect, COLORREF color) SelectObject(hDC, oldBrush); } +static void DrawDarkComboFrame(HWND hwnd, HDC hDC) +{ + RECT r; + GetWindowRect(hwnd, &r); + OffsetRect(&r, -r.left, -r.top); + + HGDIOBJ oldPen = SelectObject(hDC, GetStockObject(DC_PEN)); + HGDIOBJ oldBrush = SelectObject(hDC, GetStockObject(NULL_BRUSH)); + + SetDCPenColor(hDC, EDITWND_DARK_BORDER_OUTER); + Rectangle(hDC, r.left, r.top, r.right, r.bottom); + + if (r.right - r.left > 3 && r.bottom - r.top > 3) + { + SetDCPenColor(hDC, EDITWND_DARK_BORDER_INNER); + Rectangle(hDC, r.left + 1, r.top + 1, r.right - 1, r.bottom - 1); + } + + SelectObject(hDC, oldBrush); + SelectObject(hDC, oldPen); +} + } // namespace //***************************************************************************** @@ -1779,6 +1801,21 @@ CEditWindow::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) return result; } + case WM_NCPAINT: + { + if (DarkMode_ShouldUseDark()) + { + HDC hDC = HANDLES(GetWindowDC(HWindow)); + if (hDC != NULL) + { + DrawDarkComboFrame(HWindow, hDC); + HANDLES(ReleaseDC(HWindow, hDC)); + } + return 0; + } + break; + } + case WM_DESTROY: { if (EditLine != NULL) @@ -1893,7 +1930,8 @@ CEditWindow::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) if (r.right > r.left && r.bottom > r.top) ValidateRect(HWindow, &r); - break; + ValidateRect(HWindow, NULL); + return 0; } // ensure the 2-pixel frame around the combo is not cleared during painting diff --git a/src/files_box_header_bottom_bar.cpp b/src/files_box_header_bottom_bar.cpp index 684848193..e28b86b4e 100644 --- a/src/files_box_header_bottom_bar.cpp +++ b/src/files_box_header_bottom_bar.cpp @@ -313,7 +313,7 @@ void CHeaderLine::PaintItem(HDC hDC, int index, int x) if (useDarkChrome) { HGDIOBJ oldPen = SelectObject(ItemBitmap.HMemDC, GetStockObject(DC_PEN)); - SetDCPenColor(ItemBitmap.HMemDC, palette.LineLight); + SetDCPenColor(ItemBitmap.HMemDC, palette.LineDark); MoveToEx(ItemBitmap.HMemDC, r.left, r.top, NULL); LineTo(ItemBitmap.HMemDC, r.right, r.top); if (first) @@ -327,7 +327,6 @@ void CHeaderLine::PaintItem(HDC hDC, int index, int x) LineTo(ItemBitmap.HMemDC, r.left, r.bottom - 2); } - SetDCPenColor(ItemBitmap.HMemDC, palette.LineDark); MoveToEx(ItemBitmap.HMemDC, r.left, r.bottom - 1, NULL); LineTo(ItemBitmap.HMemDC, r.right, r.bottom - 1); if (!last) diff --git a/src/files_box_view.cpp b/src/files_box_view.cpp index 7153513be..e45c6f747 100644 --- a/src/files_box_view.cpp +++ b/src/files_box_view.cpp @@ -17,6 +17,23 @@ const char* CFILESBOX_CLASSNAME = "SalamanderItemsBox"; +static void DrawDarkSunkenFrame(HDC hDC, const RECT* r, const DarkModeMainFramePalette& palette) +{ + HGDIOBJ oldPen = SelectObject(hDC, GetStockObject(DC_PEN)); + + SetDCPenColor(hDC, palette.LineDark); + MoveToEx(hDC, r->left, r->bottom - 1, NULL); + LineTo(hDC, r->left, r->top); + LineTo(hDC, r->right - 1, r->top); + + SetDCPenColor(hDC, palette.Border); + MoveToEx(hDC, r->right - 1, r->top, NULL); + LineTo(hDC, r->right - 1, r->bottom - 1); + LineTo(hDC, r->left - 1, r->bottom - 1); + + SelectObject(hDC, oldPen); +} + //**************************************************************************** // // CFilesBox @@ -1365,14 +1382,27 @@ CFilesBox::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) GetClientRect(HWindow, &r); r.right += 2; r.bottom += 2; - DrawEdge(hdc, &r, BDR_SUNKENOUTER, BF_RECT); + DarkModeMainFramePalette palette; + BOOL useDarkPalette = DarkMode_GetMainFramePalette(&palette); + if (useDarkPalette) + DrawDarkSunkenFrame(hdc, &r, palette); + else + DrawEdge(hdc, &r, BDR_SUNKENOUTER, BF_RECT); if (Parent->StatusLine != NULL && Parent->StatusLine->HWindow != NULL) { r.left = 0; r.top = r.bottom - 1; r.right = 1; r.bottom = r.top + 1; - FillRect(hdc, &r, HMenuGrayTextBrush); + if (useDarkPalette) + { + HGDIOBJ oldBrush = SelectObject(hdc, GetStockObject(DC_BRUSH)); + SetDCBrushColor(hdc, palette.LineDark); + FillRect(hdc, &r, (HBRUSH)GetStockObject(DC_BRUSH)); + SelectObject(hdc, oldBrush); + } + else + FillRect(hdc, &r, HMenuGrayTextBrush); } HANDLES(ReleaseDC(HWindow, hdc)); return 0; diff --git a/src/files_window_navigation.cpp b/src/files_window_navigation.cpp index 042c3b9f4..8711ab0fc 100644 --- a/src/files_window_navigation.cpp +++ b/src/files_window_navigation.cpp @@ -3328,6 +3328,7 @@ void CFilesWindow::OnColorsChanged() // A color/theme switch can happen after the panel was already painted. // Force a full panel repaint so stale light pixels are not left behind // until the user moves selection or scrolls. + RedrawWindow(ListBox->HWindow, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_NOCHILDREN); InvalidateRect(ListBox->HWindow, &ListBox->FilesRect, FALSE); if (ListBox->HeaderLine.HWindow != NULL) InvalidateRect(ListBox->HeaderLine.HWindow, NULL, TRUE); diff --git a/src/main_window_commands_help.cpp b/src/main_window_commands_help.cpp index bca83229c..ae724e30f 100644 --- a/src/main_window_commands_help.cpp +++ b/src/main_window_commands_help.cpp @@ -93,6 +93,238 @@ extern BOOL CacheNextSetFocus; BOOL MainFrameIsActive = FALSE; +const UINT_PTR MAIN_REBAR_DARK_SUBCLASS_ID = 1; +static BOOL ApplyingMainRebarDarkStyle = FALSE; + +static void ApplyMainRebarDarkStyle(HWND hwnd) +{ + if (hwnd == NULL) + return; + + DarkModeMainFramePalette palette; + BOOL useDark = DarkMode_GetMainFramePalette(&palette); + + LONG_PTR style = GetWindowLongPtr(hwnd, GWL_STYLE); + LONG_PTR newStyle; + if (useDark) + newStyle = style & ~(WS_BORDER | RBS_BANDBORDERS); + else + newStyle = style | WS_BORDER | RBS_BANDBORDERS; + + if (newStyle != style) + { + SetWindowLongPtr(hwnd, GWL_STYLE, newStyle); + SetWindowPos(hwnd, NULL, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | + SWP_NOZORDER | SWP_FRAMECHANGED); + } + + int bandCount = (int)SendMessage(hwnd, RB_GETBANDCOUNT, 0, 0); + for (int i = 0; i < bandCount; i++) + { + REBARBANDINFO rbbi; + ZeroMemory(&rbbi, sizeof(rbbi)); + rbbi.cbSize = sizeof(rbbi); + rbbi.fMask = RBBIM_STYLE | RBBIM_ID | RBBIM_HEADERSIZE; + if (!SendMessage(hwnd, RB_GETBANDINFO, (WPARAM)i, (LPARAM)&rbbi)) + continue; + + DWORD originalStyle = rbbi.fStyle; + UINT originalHeader = rbbi.cxHeader; + BOOL forceNoGrip = useDark || + rbbi.wID == BANDID_DRIVEBAR2 || + rbbi.wID == BANDID_WORKER; + + if (forceNoGrip || !Configuration.GripsVisible) + { + rbbi.fStyle &= ~RBBS_GRIPPERALWAYS; + rbbi.fStyle |= RBBS_NOGRIPPER; + if (useDark || rbbi.wID == BANDID_DRIVEBAR2 || rbbi.wID == BANDID_WORKER) + rbbi.cxHeader = 0; + else if (rbbi.cxHeader == 0) + rbbi.cxHeader = 2; + } + else + { + rbbi.fStyle &= ~RBBS_NOGRIPPER; + rbbi.fStyle |= RBBS_GRIPPERALWAYS; + } + + if (rbbi.fStyle != originalStyle || rbbi.cxHeader != originalHeader) + { + rbbi.fMask = RBBIM_STYLE | RBBIM_HEADERSIZE; + ApplyingMainRebarDarkStyle = TRUE; + SendMessage(hwnd, RB_SETBANDINFO, (WPARAM)i, (LPARAM)&rbbi); + ApplyingMainRebarDarkStyle = FALSE; + } + } +} + +static void DrawDarkRebarLine(HDC hdc, int x1, int y1, int x2, int y2, COLORREF color) +{ + SetDCPenColor(hdc, color); + MoveToEx(hdc, x1, y1, NULL); + LineTo(hdc, x2, y2); +} + +static void PaintDarkRebarClientLines(HWND hwnd, HDC hdc) +{ + DarkModeMainFramePalette palette; + if (!DarkMode_GetMainFramePalette(&palette)) + return; + + RECT client; + GetClientRect(hwnd, &client); + if (client.right <= client.left || client.bottom <= client.top) + return; + + HGDIOBJ oldPen = SelectObject(hdc, GetStockObject(DC_PEN)); + + int bandCount = (int)SendMessage(hwnd, RB_GETBANDCOUNT, 0, 0); + for (int i = 0; i < bandCount; i++) + { + RECT band; + if (!SendMessage(hwnd, RB_GETRECT, (WPARAM)i, (LPARAM)&band)) + continue; + + if (band.top > client.top && band.top < client.bottom) + DrawDarkRebarLine(hdc, client.left, band.top, client.right, band.top, palette.LineDark); + } + + SelectObject(hdc, oldPen); +} + +static void PaintDarkRebarClient(HWND hwnd, HDC hdc) +{ + DarkModeMainFramePalette palette; + if (!DarkMode_GetMainFramePalette(&palette)) + return; + + RECT client; + GetClientRect(hwnd, &client); + if (client.right <= client.left || client.bottom <= client.top) + return; + + HGDIOBJ oldBrush = SelectObject(hdc, GetStockObject(DC_BRUSH)); + SetDCBrushColor(hdc, palette.Fill); + FillRect(hdc, &client, (HBRUSH)GetStockObject(DC_BRUSH)); + SelectObject(hdc, oldBrush); + + PaintDarkRebarClientLines(hwnd, hdc); +} + +static void PaintDarkRebarNonClientFrame(HWND hwnd) +{ + DarkModeMainFramePalette palette; + if (!DarkMode_GetMainFramePalette(&palette)) + return; + + HDC hdc = HANDLES(GetWindowDC(hwnd)); + if (hdc == NULL) + return; + + RECT r; + GetWindowRect(hwnd, &r); + OffsetRect(&r, -r.left, -r.top); + + HGDIOBJ oldBrush = SelectObject(hdc, GetStockObject(DC_BRUSH)); + SetDCBrushColor(hdc, palette.Fill); + FillRect(hdc, &r, (HBRUSH)GetStockObject(DC_BRUSH)); + SelectObject(hdc, oldBrush); + + HGDIOBJ oldPen = SelectObject(hdc, GetStockObject(DC_PEN)); + + SetDCPenColor(hdc, palette.Fill); + MoveToEx(hdc, r.left, r.top, NULL); + LineTo(hdc, r.right - 1, r.top); + LineTo(hdc, r.right - 1, r.bottom - 1); + LineTo(hdc, r.left, r.bottom - 1); + LineTo(hdc, r.left, r.top); + + SelectObject(hdc, oldPen); + HANDLES(ReleaseDC(hwnd, hdc)); +} + +static LRESULT CALLBACK MainRebarDarkSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, + UINT_PTR uIdSubclass, DWORD_PTR dwRefData) +{ + switch (uMsg) + { + case WM_ERASEBKGND: + { + DarkModeMainFramePalette palette; + if (DarkMode_GetMainFramePalette(&palette)) + { + RECT r; + GetClientRect(hwnd, &r); + HGDIOBJ oldBrush = SelectObject((HDC)wParam, GetStockObject(DC_BRUSH)); + SetDCBrushColor((HDC)wParam, palette.Fill); + FillRect((HDC)wParam, &r, (HBRUSH)GetStockObject(DC_BRUSH)); + SelectObject((HDC)wParam, oldBrush); + return 1; + } + break; + } + + case WM_PAINT: + { + if (DarkMode_ShouldUseDark()) + { + PAINTSTRUCT ps; + HDC hdc = HANDLES(BeginPaint(hwnd, &ps)); + PaintDarkRebarClient(hwnd, hdc); + HANDLES(EndPaint(hwnd, &ps)); + return 0; + } + return DefSubclassProc(hwnd, uMsg, wParam, lParam); + } + + case WM_NCPAINT: + { + if (DarkMode_ShouldUseDark()) + { + PaintDarkRebarNonClientFrame(hwnd); + return 0; + } + LRESULT result = DefSubclassProc(hwnd, uMsg, wParam, lParam); + PaintDarkRebarNonClientFrame(hwnd); + return result; + } + + case WM_THEMECHANGED: + case WM_SYSCOLORCHANGE: + case WM_SETTINGCHANGE: + ApplyMainRebarDarkStyle(hwnd); + RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN); + break; + + case RB_INSERTBAND: + { + LRESULT result = DefSubclassProc(hwnd, uMsg, wParam, lParam); + ApplyMainRebarDarkStyle(hwnd); + RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN); + return result; + } + + case RB_SETBANDINFO: + { + LRESULT result = DefSubclassProc(hwnd, uMsg, wParam, lParam); + if (!ApplyingMainRebarDarkStyle) + { + ApplyMainRebarDarkStyle(hwnd); + RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN); + } + return result; + } + + case WM_NCDESTROY: + RemoveWindowSubclass(hwnd, MainRebarDarkSubclassProc, uIdSubclass); + break; + } + + return DefSubclassProc(hwnd, uMsg, wParam, lParam); +} + // code for testing time losses /* const char *s1 = "aj hjka sakjSJKAHS AJKSH JKDSHFJSDH FJS HDFJSD HFJS"; @@ -1078,10 +1310,8 @@ MENU_TEMPLATE_ITEM AddToSystemMenu[] = // disable them SetWindowTheme(HTopRebar, (L" "), (L" ")); - // enforce WS_BORDER which somehow "disappeared" - DWORD style = (DWORD)GetWindowLongPtr(HTopRebar, GWL_STYLE); - style |= WS_BORDER; - SetWindowLongPtr(HTopRebar, GWL_STYLE, style); + SetWindowSubclass(HTopRebar, MainRebarDarkSubclassProc, MAIN_REBAR_DARK_SUBCLASS_ID, 0); + ApplyMainRebarDarkStyle(HTopRebar); MenuBar = new CMenuBar(&MainMenu, HWindow); if (MenuBar == NULL) @@ -6767,14 +6997,23 @@ MENU_TEMPLATE_ITEM AddToSystemMenu[] = RECT r; if (TopToolBar->HWindow != NULL) { - MoveToEx(dc, 0, 0, NULL); - LineTo(dc, WindowWidth + 1, 0); if (useDarkPalette) - SetDCPenColor(dc, palette.LineLight); + { + r.left = 0; + r.top = 0; + r.right = WindowWidth; + r.bottom = 2; + SetDCBrushColor(dc, palette.Fill); + FillRect(dc, &r, (HBRUSH)GetStockObject(DC_BRUSH)); + } else + { + MoveToEx(dc, 0, 0, NULL); + LineTo(dc, WindowWidth + 1, 0); SelectObject(dc, BtnHilightPen); - MoveToEx(dc, 0, 1, NULL); - LineTo(dc, WindowWidth + 1, 1); + MoveToEx(dc, 0, 1, NULL); + LineTo(dc, WindowWidth + 1, 1); + } } if (PanelsHeight > 0) @@ -6793,7 +7032,7 @@ MENU_TEMPLATE_ITEM AddToSystemMenu[] = { SetDCBrushColor(dc, palette.Fill); FillRect(dc, &r, (HBRUSH)GetStockObject(DC_BRUSH)); - SetDCPenColor(dc, palette.Border); + SetDCPenColor(dc, palette.LineDark); } else { diff --git a/src/salamander_entry_lifecycle.cpp b/src/salamander_entry_lifecycle.cpp index 47c9c920c..81ccb1bcc 100644 --- a/src/salamander_entry_lifecycle.cpp +++ b/src/salamander_entry_lifecycle.cpp @@ -3241,6 +3241,7 @@ void ColorsChanged(BOOL refresh, BOOL colorsOnly, BOOL reloadUMIcons) SendMessage(MainWindow->HTopRebar, RB_SETBKCOLOR, 0, (LPARAM)palette.Fill); else SendMessage(MainWindow->HTopRebar, RB_SETBKCOLOR, 0, (LPARAM)GetSysColor(COLOR_BTNFACE)); + RedrawWindow(MainWindow->HTopRebar, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN); } if (refresh && MainWindow != NULL) diff --git a/src/stswnd.cpp b/src/stswnd.cpp index a9dcfa7de..b7953f3d7 100644 --- a/src/stswnd.cpp +++ b/src/stswnd.cpp @@ -58,6 +58,23 @@ static void FillRectSolid(HDC hDC, const RECT* rect, COLORREF color) SelectObject(hDC, oldBrush); } +static void DrawDarkSunkenFrame(HDC hDC, const RECT* r, const DarkModeMainFramePalette& palette) +{ + HGDIOBJ oldPen = SelectObject(hDC, GetStockObject(DC_PEN)); + + SetDCPenColor(hDC, palette.LineDark); + MoveToEx(hDC, r->left, r->bottom - 1, NULL); + LineTo(hDC, r->left, r->top); + LineTo(hDC, r->right - 1, r->top); + + SetDCPenColor(hDC, palette.Border); + MoveToEx(hDC, r->right - 1, r->top, NULL); + LineTo(hDC, r->right - 1, r->bottom - 1); + LineTo(hDC, r->left - 1, r->bottom - 1); + + SelectObject(hDC, oldPen); +} + // // **************************************************************************** // CStatusWindow @@ -740,7 +757,8 @@ void CStatusWindow::Paint(HDC hdc, BOOL highlightText, BOOL highlightHotTrackOnl HDC dc = ItemBitmap.HMemDC; BOOL isDirectoryLine = (Border & blTop) != 0; - BOOL useDark = DarkMode_ShouldUseDark(); + DarkModeMainFramePalette palette; + BOOL useDark = DarkMode_GetMainFramePalette(&palette); RECT r; r.left = 0; @@ -767,7 +785,10 @@ void CStatusWindow::Paint(HDC hdc, BOOL highlightText, BOOL highlightHotTrackOnl RECT textR = r; textR.top += 2; textR.bottom -= 2; - DrawEdge(dc, &textR, BDR_SUNKENOUTER, BF_RECT); + if (useDark) + DrawDarkSunkenFrame(dc, &textR, palette); + else + DrawEdge(dc, &textR, BDR_SUNKENOUTER, BF_RECT); // fill area under text (active/inactive) textR.left++; @@ -2153,12 +2174,19 @@ CStatusWindow::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) HDC dc = (HDC)wParam; if (Border != blNone) { - HPEN oldPen = (HPEN)SelectObject(dc, BtnShadowPen); + DarkModeMainFramePalette palette; + BOOL useDark = DarkMode_GetMainFramePalette(&palette); + HGDIOBJ oldPen = SelectObject(dc, useDark ? GetStockObject(DC_PEN) : BtnShadowPen); if (Border & blBottom) { + if (useDark) + SetDCPenColor(dc, palette.LineDark); MoveToEx(dc, r.left, r.top, NULL); LineTo(dc, r.left, r.bottom); - SelectObject(dc, BtnHilightPen); + if (useDark) + SetDCPenColor(dc, palette.Border); + else + SelectObject(dc, BtnHilightPen); MoveToEx(dc, r.right - 1, r.top, NULL); LineTo(dc, r.right - 1, r.bottom); MoveToEx(dc, r.left, r.bottom - 1, NULL); diff --git a/src/toolbar_layout_draw.cpp b/src/toolbar_layout_draw.cpp index c51b9a06d..58291394d 100644 --- a/src/toolbar_layout_draw.cpp +++ b/src/toolbar_layout_draw.cpp @@ -27,6 +27,37 @@ static void FillRectWithColor(HDC hDC, const RECT* r, COLORREF color) SelectObject(hDC, oldBrush); } +static void DrawDarkToolbarFrame(HDC hDC, const RECT* r, BOOL pressed) +{ + HGDIOBJ oldPen = SelectObject(hDC, GetStockObject(DC_PEN)); + + COLORREF upperLeft = pressed ? RGB(28, 28, 28) : RGB(62, 62, 66); + COLORREF lowerRight = pressed ? RGB(62, 62, 66) : RGB(28, 28, 28); + COLORREF border = RGB(62, 62, 66); + + SetDCPenColor(hDC, border); + MoveToEx(hDC, r->left, r->top, NULL); + LineTo(hDC, r->right - 1, r->top); + LineTo(hDC, r->right - 1, r->bottom - 1); + LineTo(hDC, r->left, r->bottom - 1); + LineTo(hDC, r->left, r->top); + + if (r->right - r->left > 2 && r->bottom - r->top > 2) + { + SetDCPenColor(hDC, upperLeft); + MoveToEx(hDC, r->left + 1, r->bottom - 2, NULL); + LineTo(hDC, r->left + 1, r->top + 1); + LineTo(hDC, r->right - 2, r->top + 1); + + SetDCPenColor(hDC, lowerRight); + MoveToEx(hDC, r->right - 2, r->top + 1, NULL); + LineTo(hDC, r->right - 2, r->bottom - 2); + LineTo(hDC, r->left + 1, r->bottom - 2); + } + + SelectObject(hDC, oldPen); +} + static COLORREF GetToolBarBkColor() { return DarkMode_ShouldUseDark() ? RGB(45, 45, 48) : GetSysColor(COLOR_BTNFACE); @@ -490,8 +521,8 @@ void CToolBar::DrawItem(HDC hDC, int index) if (item->Style & TLBI_STYLE_SEPARATOR) { - COLORREF separatorDark = useDarkToolbar ? RGB(70, 70, 70) : GetSysColor(COLOR_BTNSHADOW); - COLORREF separatorLight = useDarkToolbar ? RGB(95, 95, 95) : GetSysColor(COLOR_BTNHIGHLIGHT); + COLORREF separatorDark = useDarkToolbar ? RGB(28, 28, 28) : GetSysColor(COLOR_BTNSHADOW); + COLORREF separatorLight = useDarkToolbar ? RGB(45, 45, 48) : GetSysColor(COLOR_BTNHIGHLIGHT); if (vertical) { int y = height / 2 - 1; @@ -499,9 +530,12 @@ void CToolBar::DrawItem(HDC hDC, int index) SetDCPenColor(CacheBitmap->HMemDC, separatorDark); MoveToEx(CacheBitmap->HMemDC, 1, y, NULL); LineTo(CacheBitmap->HMemDC, Width - 1, y); - SetDCPenColor(CacheBitmap->HMemDC, separatorLight); - MoveToEx(CacheBitmap->HMemDC, 1, y + 1, NULL); - LineTo(CacheBitmap->HMemDC, Width - 1, y + 1); + if (!useDarkToolbar) + { + SetDCPenColor(CacheBitmap->HMemDC, separatorLight); + MoveToEx(CacheBitmap->HMemDC, 1, y + 1, NULL); + LineTo(CacheBitmap->HMemDC, Width - 1, y + 1); + } SelectObject(CacheBitmap->HMemDC, hOldPen); } else @@ -511,9 +545,12 @@ void CToolBar::DrawItem(HDC hDC, int index) SetDCPenColor(CacheBitmap->HMemDC, separatorDark); MoveToEx(CacheBitmap->HMemDC, x, 1, NULL); LineTo(CacheBitmap->HMemDC, x, Height - 1); - SetDCPenColor(CacheBitmap->HMemDC, separatorLight); - MoveToEx(CacheBitmap->HMemDC, x + 1, 1, NULL); - LineTo(CacheBitmap->HMemDC, x + 1, Height - 1); + if (!useDarkToolbar) + { + SetDCPenColor(CacheBitmap->HMemDC, separatorLight); + MoveToEx(CacheBitmap->HMemDC, x + 1, 1, NULL); + LineTo(CacheBitmap->HMemDC, x + 1, Height - 1); + } SelectObject(CacheBitmap->HMemDC, hOldPen); } } @@ -592,7 +629,10 @@ void CToolBar::DrawItem(HDC hDC, int index) // frame around body DWORD mode = bodyDown ? BDR_SUNKENOUTER : BDR_RAISEDINNER; - DrawEdge(CacheBitmap->HMemDC, &r, mode, BF_RECT); + if (useDarkToolbar) + DrawDarkToolbarFrame(CacheBitmap->HMemDC, &r, bodyDown); + else + DrawEdge(CacheBitmap->HMemDC, &r, mode, BF_RECT); if (HotIndex == index && outterDropPresent) { @@ -600,7 +640,10 @@ void CToolBar::DrawItem(HDC hDC, int index) r.left = r.right; r.right = width; mode = dropDown ? BDR_SUNKENOUTER : BDR_RAISEDINNER; - DrawEdge(CacheBitmap->HMemDC, &r, mode, BF_RECT); + if (useDarkToolbar) + DrawDarkToolbarFrame(CacheBitmap->HMemDC, &r, dropDown); + else + DrawEdge(CacheBitmap->HMemDC, &r, mode, BF_RECT); } } From 7f0d02f58fd95f628c43f3ebe235d59bceb94333 Mon Sep 17 00:00:00 2001 From: Elias Bachaalany Date: Sun, 3 May 2026 09:12:27 -0700 Subject: [PATCH 3/3] darkmode: post-review polish - Restore the dropdown arrow glyph in CEditWindow's dark WM_PAINT path (the short-circuit added in b222ecfe stopped the default ComboBox paint from drawing it). - Hoist the duplicated DrawDarkSunkenFrame helper into darkmode.cpp as DarkMode_DrawSunkenFrame; drop the static copies in stswnd.cpp and files_box_view.cpp. - Drop the unreachable second PaintDarkRebarNonClientFrame call in the light branch of MainRebarDarkSubclassProc::WM_NCPAINT. --- src/darkmode.cpp | 17 +++++++++++++++++ src/darkmode.h | 1 + src/editwnd.cpp | 21 +++++++++++++++++++++ src/files_box_view.cpp | 19 +------------------ src/main_window_commands_help.cpp | 4 +--- src/stswnd.cpp | 19 +------------------ 6 files changed, 42 insertions(+), 39 deletions(-) diff --git a/src/darkmode.cpp b/src/darkmode.cpp index 3b79f0dd4..709abc217 100644 --- a/src/darkmode.cpp +++ b/src/darkmode.cpp @@ -707,6 +707,23 @@ BOOL DarkMode_OnSettingChange(LPARAM lParam) return changed; } +void DarkMode_DrawSunkenFrame(HDC hDC, const RECT* r, const DarkModeMainFramePalette& palette) +{ + HGDIOBJ oldPen = SelectObject(hDC, GetStockObject(DC_PEN)); + + SetDCPenColor(hDC, palette.LineDark); + MoveToEx(hDC, r->left, r->bottom - 1, NULL); + LineTo(hDC, r->left, r->top); + LineTo(hDC, r->right - 1, r->top); + + SetDCPenColor(hDC, palette.Border); + MoveToEx(hDC, r->right - 1, r->top, NULL); + LineTo(hDC, r->right - 1, r->bottom - 1); + LineTo(hDC, r->left - 1, r->bottom - 1); + + SelectObject(hDC, oldPen); +} + void DarkMode_ApplyTitleBar(HWND hwnd) { EnsureInitialized(); diff --git a/src/darkmode.h b/src/darkmode.h index cf6e34604..adc9335e7 100644 --- a/src/darkmode.h +++ b/src/darkmode.h @@ -52,3 +52,4 @@ void DarkMode_ApplyTitleBar(HWND hwnd); void DarkMode_ApplyToThreadTopLevelWindows(DWORD threadId); void DarkMode_ApplyListTreeThemeRecursive(HWND root); void DarkMode_ApplyGroupBoxThemeRecursive(HWND root); +void DarkMode_DrawSunkenFrame(HDC hDC, const RECT* r, const DarkModeMainFramePalette& palette); diff --git a/src/editwnd.cpp b/src/editwnd.cpp index 71f08726a..f604b042e 100644 --- a/src/editwnd.cpp +++ b/src/editwnd.cpp @@ -1878,8 +1878,29 @@ CEditWindow::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) btnArea.right = cr.right - 3; btnArea.bottom = cr.bottom - 3; if (btnArea.right > btnArea.left && btnArea.bottom > btnArea.top) + { FillRectSolid(hDC, &btnArea, EDITWND_DARK_BUTTON_BG); + // The default combo WM_PAINT no longer runs in this branch, + // so the dropdown arrow glyph must be drawn here. + int centerX = (btnArea.left + btnArea.right) / 2; + int centerY = (btnArea.top + btnArea.bottom) / 2; + POINT arrow[3] = { + {centerX - 3, centerY - 1}, + {centerX + 4, centerY - 1}, + {centerX, centerY + 3}, + }; + HPEN hArrowPen = HANDLES(CreatePen(PS_SOLID, 1, EDITWND_DARK_TEXT)); + HBRUSH hArrowBrush = HANDLES(CreateSolidBrush(EDITWND_DARK_TEXT)); + HGDIOBJ oldArrowPen = SelectObject(hDC, hArrowPen); + HGDIOBJ oldArrowBrush = SelectObject(hDC, hArrowBrush); + Polygon(hDC, arrow, 3); + SelectObject(hDC, oldArrowBrush); + SelectObject(hDC, oldArrowPen); + HANDLES(DeleteObject(hArrowBrush)); + HANDLES(DeleteObject(hArrowPen)); + } + HGDIOBJ oldPen = SelectObject(hDC, GetStockObject(DC_PEN)); HGDIOBJ oldBrush = SelectObject(hDC, GetStockObject(NULL_BRUSH)); COLORREF oldPenColor = SetDCPenColor(hDC, EDITWND_DARK_BORDER_OUTER); diff --git a/src/files_box_view.cpp b/src/files_box_view.cpp index e45c6f747..eee6a603d 100644 --- a/src/files_box_view.cpp +++ b/src/files_box_view.cpp @@ -17,23 +17,6 @@ const char* CFILESBOX_CLASSNAME = "SalamanderItemsBox"; -static void DrawDarkSunkenFrame(HDC hDC, const RECT* r, const DarkModeMainFramePalette& palette) -{ - HGDIOBJ oldPen = SelectObject(hDC, GetStockObject(DC_PEN)); - - SetDCPenColor(hDC, palette.LineDark); - MoveToEx(hDC, r->left, r->bottom - 1, NULL); - LineTo(hDC, r->left, r->top); - LineTo(hDC, r->right - 1, r->top); - - SetDCPenColor(hDC, palette.Border); - MoveToEx(hDC, r->right - 1, r->top, NULL); - LineTo(hDC, r->right - 1, r->bottom - 1); - LineTo(hDC, r->left - 1, r->bottom - 1); - - SelectObject(hDC, oldPen); -} - //**************************************************************************** // // CFilesBox @@ -1385,7 +1368,7 @@ CFilesBox::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) DarkModeMainFramePalette palette; BOOL useDarkPalette = DarkMode_GetMainFramePalette(&palette); if (useDarkPalette) - DrawDarkSunkenFrame(hdc, &r, palette); + DarkMode_DrawSunkenFrame(hdc, &r, palette); else DrawEdge(hdc, &r, BDR_SUNKENOUTER, BF_RECT); if (Parent->StatusLine != NULL && Parent->StatusLine->HWindow != NULL) diff --git a/src/main_window_commands_help.cpp b/src/main_window_commands_help.cpp index ae724e30f..87daa764e 100644 --- a/src/main_window_commands_help.cpp +++ b/src/main_window_commands_help.cpp @@ -286,9 +286,7 @@ static LRESULT CALLBACK MainRebarDarkSubclassProc(HWND hwnd, UINT uMsg, WPARAM w PaintDarkRebarNonClientFrame(hwnd); return 0; } - LRESULT result = DefSubclassProc(hwnd, uMsg, wParam, lParam); - PaintDarkRebarNonClientFrame(hwnd); - return result; + return DefSubclassProc(hwnd, uMsg, wParam, lParam); } case WM_THEMECHANGED: diff --git a/src/stswnd.cpp b/src/stswnd.cpp index b7953f3d7..13d534b51 100644 --- a/src/stswnd.cpp +++ b/src/stswnd.cpp @@ -58,23 +58,6 @@ static void FillRectSolid(HDC hDC, const RECT* rect, COLORREF color) SelectObject(hDC, oldBrush); } -static void DrawDarkSunkenFrame(HDC hDC, const RECT* r, const DarkModeMainFramePalette& palette) -{ - HGDIOBJ oldPen = SelectObject(hDC, GetStockObject(DC_PEN)); - - SetDCPenColor(hDC, palette.LineDark); - MoveToEx(hDC, r->left, r->bottom - 1, NULL); - LineTo(hDC, r->left, r->top); - LineTo(hDC, r->right - 1, r->top); - - SetDCPenColor(hDC, palette.Border); - MoveToEx(hDC, r->right - 1, r->top, NULL); - LineTo(hDC, r->right - 1, r->bottom - 1); - LineTo(hDC, r->left - 1, r->bottom - 1); - - SelectObject(hDC, oldPen); -} - // // **************************************************************************** // CStatusWindow @@ -786,7 +769,7 @@ void CStatusWindow::Paint(HDC hdc, BOOL highlightText, BOOL highlightHotTrackOnl textR.top += 2; textR.bottom -= 2; if (useDark) - DrawDarkSunkenFrame(dc, &textR, palette); + DarkMode_DrawSunkenFrame(dc, &textR, palette); else DrawEdge(dc, &textR, BDR_SUNKENOUTER, BF_RECT);