From fc1195dc9c4370f228a86893c66815ab83425a45 Mon Sep 17 00:00:00 2001 From: Noraa Junker Date: Thu, 12 Feb 2026 02:40:54 +0100 Subject: [PATCH] Move runnerv2 to appropriate location and remove old runner --- PowerToys.slnx | 20 +- .../Assets/PowerToysDark.ico | Bin .../Assets/PowerToysLight.ico | Bin .../Extensions/PackageVersionExtensions.cs | 0 .../RunnerV2 => Runner}/Helpers/AIHelper.cs | 0 .../Helpers/AutoStartHelper.cs | 0 .../RunnerV2 => Runner}/Helpers/COMUtils.cs | 0 .../Helpers/CentralizedKeyboardHookManager.cs | 0 .../Helpers/ElevationHelper.cs | 0 .../Helpers/HotkeyConflictsManager.cs | 0 .../Helpers/NotificationHelper.cs | 0 .../Helpers/PackageHelper.cs | 0 .../Helpers/ProcessHelper.cs | 0 .../Helpers/QuickAccessHelper.cs | 0 .../Helpers/SettingsHelper.cs | 0 .../Helpers/TrayIconManager.cs | 0 .../Models/IPowerToysModule.cs | 0 .../IPowerToysModuleCustomActionsProvider.cs | 0 ...owerToysModuleSettingsChangedSubscriber.cs | 0 .../IPowerToysModuleShortcutsProvider.cs | 0 .../Models/ProcessModuleAbstractClass.cs | 0 .../Models/RegistryChangeSet.cs | 0 .../Models/RegistryValueChange.cs | 0 .../RunnerV2 => Runner}/Models/SpecialMode.cs | 0 .../AdvancedPasteModuleInterface.cs | 0 .../AlwaysOnTopModuleInterface.cs | 0 .../ModuleInterfaces/AwakeModuleInterface.cs | 0 .../CmdNotFoundModuleInterface.cs | 0 .../ColorPickerModuleInterface.cs | 0 .../CommandPaletteModuleInterface.cs | 0 .../CropAndLockModuleInterface.cs | 0 .../CursorWrapModuleInterface.cs | 0 .../EnvironmentVariablesModuleInterface.cs | 0 .../FancyZonesModuleInterface.cs | 0 .../FileExplorerModuleInterface.cs | 0 .../FileLocksmithModuleInterface.cs | 0 .../FindMyMouseModuleInterface.cs | 0 .../ModuleInterfaces/HostsModuleInterface.cs | 0 .../ImageResizerModuleInterface.cs | 0 .../KeyboardManagerModuleInterface.cs | 0 .../LightSwitchModuleInterface.cs | 0 .../MeasureToolModuleInterface.cs | 0 .../MouseHighlighterModuleInterface.cs | 0 .../MouseJumpModuleInterface.cs | 0 .../MousePointerCrosshairsModuleInterface.cs | 0 .../MouseWithoutBordersModuleInterface.cs | 0 .../NewPlusModuleInterface.cs | 0 .../ModuleInterfaces/PeekModuleInterface.cs | 0 .../PowerAccentModuleInterface.cs | 0 .../PowerDisplayModuleInterface.cs | 0 .../PowerOCRModuleInterface.cs | 0 .../PowerRenameModuleInterface.cs | 0 .../PowerToysRunModuleInterface.cs | 0 .../RegistryPreviewModuleInterface.cs | 0 .../ShortcutGuideModuleInterface.cs | 0 .../WorkspacesModuleInterface.cs | 0 .../ModuleInterfaces/ZoomItModuleInterface.cs | 0 .../RunnerV2 => Runner}/NativeMethods.cs | 0 src/{RunnerV2/RunnerV2 => Runner}/Program.cs | 0 src/{RunnerV2/RunnerV2 => Runner}/Runner.cs | 0 .../RunnerV2 => Runner}/RunnerV2.csproj | 18 +- .../RunnerV2 => Runner}/app.manifest | 0 src/{RunnerV2/RunnerV2 => Runner}/icon.ico | Bin src/runner/ActionRunnerUtils.h | 9 - src/runner/PowerToys.exe.manifest | 16 - src/runner/Resources.resx | 200 ---- src/runner/RestartManagement.cpp | 37 - src/runner/RestartManagement.h | 5 - src/runner/UpdateUtils.cpp | 308 ------ src/runner/UpdateUtils.h | 20 - src/runner/ai_detection.h | 11 - src/runner/auto_start_helper.cpp | 397 -------- src/runner/auto_start_helper.h | 5 - src/runner/bug_report.cpp | 90 -- src/runner/bug_report.h | 43 - src/runner/centralized_hotkeys.cpp | 121 --- src/runner/centralized_hotkeys.h | 47 - src/runner/centralized_kb_hook.cpp | 276 ----- src/runner/centralized_kb_hook.h | 15 - src/runner/general_settings.cpp | 588 ----------- src/runner/general_settings.h | 42 - src/runner/hotkey_conflict_detector.cpp | 471 --------- src/runner/hotkey_conflict_detector.h | 100 -- src/runner/main.cpp | 643 ------------ src/runner/pch.cpp | 1 - src/runner/pch.h | 34 - src/runner/powertoy_module.cpp | 115 --- src/runner/powertoy_module.h | 61 -- src/runner/quick_access_host.cpp | 296 ------ src/runner/quick_access_host.h | 12 - src/runner/resource.base.h | 23 - src/runner/restart_elevated.cpp | 63 -- src/runner/restart_elevated.h | 7 - src/runner/runner.base.rc | Bin 3118 -> 0 bytes src/runner/runner.vcxproj | 179 ---- src/runner/runner.vcxproj.filters | 145 --- src/runner/settings_telemetry.cpp | 93 -- src/runner/settings_telemetry.h | 7 - src/runner/settings_window.cpp | 960 ------------------ src/runner/settings_window.h | 49 - src/runner/svgs/PowerToysDark.ico | Bin 37916 -> 0 bytes src/runner/svgs/PowerToysWhite.ico | Bin 37822 -> 0 bytes src/runner/svgs/icon.ico | Bin 53114 -> 0 bytes src/runner/trace.cpp | 116 --- src/runner/trace.h | 21 - src/runner/tray_icon.cpp | 513 ---------- src/runner/tray_icon.h | 24 - src/runner/unhandled_exception_handler.cpp | 182 ---- src/runner/unhandled_exception_handler.h | 4 - 109 files changed, 10 insertions(+), 6377 deletions(-) rename src/{RunnerV2/RunnerV2 => Runner}/Assets/PowerToysDark.ico (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Assets/PowerToysLight.ico (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Extensions/PackageVersionExtensions.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Helpers/AIHelper.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Helpers/AutoStartHelper.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Helpers/COMUtils.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Helpers/CentralizedKeyboardHookManager.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Helpers/ElevationHelper.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Helpers/HotkeyConflictsManager.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Helpers/NotificationHelper.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Helpers/PackageHelper.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Helpers/ProcessHelper.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Helpers/QuickAccessHelper.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Helpers/SettingsHelper.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Helpers/TrayIconManager.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Models/IPowerToysModule.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Models/IPowerToysModuleCustomActionsProvider.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Models/IPowerToysModuleSettingsChangedSubscriber.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Models/IPowerToysModuleShortcutsProvider.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Models/ProcessModuleAbstractClass.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Models/RegistryChangeSet.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Models/RegistryValueChange.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Models/SpecialMode.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/AdvancedPasteModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/AlwaysOnTopModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/AwakeModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/CmdNotFoundModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/ColorPickerModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/CommandPaletteModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/CropAndLockModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/CursorWrapModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/EnvironmentVariablesModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/FancyZonesModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/FileExplorerModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/FileLocksmithModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/FindMyMouseModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/HostsModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/ImageResizerModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/KeyboardManagerModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/LightSwitchModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/MeasureToolModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/MouseHighlighterModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/MouseJumpModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/MousePointerCrosshairsModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/MouseWithoutBordersModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/NewPlusModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/PeekModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/PowerAccentModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/PowerDisplayModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/PowerOCRModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/PowerRenameModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/PowerToysRunModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/RegistryPreviewModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/ShortcutGuideModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/WorkspacesModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/ModuleInterfaces/ZoomItModuleInterface.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/NativeMethods.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Program.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/Runner.cs (100%) rename src/{RunnerV2/RunnerV2 => Runner}/RunnerV2.csproj (54%) rename src/{RunnerV2/RunnerV2 => Runner}/app.manifest (100%) rename src/{RunnerV2/RunnerV2 => Runner}/icon.ico (100%) delete mode 100644 src/runner/ActionRunnerUtils.h delete mode 100644 src/runner/PowerToys.exe.manifest delete mode 100644 src/runner/Resources.resx delete mode 100644 src/runner/RestartManagement.cpp delete mode 100644 src/runner/RestartManagement.h delete mode 100644 src/runner/UpdateUtils.cpp delete mode 100644 src/runner/UpdateUtils.h delete mode 100644 src/runner/ai_detection.h delete mode 100644 src/runner/auto_start_helper.cpp delete mode 100644 src/runner/auto_start_helper.h delete mode 100644 src/runner/bug_report.cpp delete mode 100644 src/runner/bug_report.h delete mode 100644 src/runner/centralized_hotkeys.cpp delete mode 100644 src/runner/centralized_hotkeys.h delete mode 100644 src/runner/centralized_kb_hook.cpp delete mode 100644 src/runner/centralized_kb_hook.h delete mode 100644 src/runner/general_settings.cpp delete mode 100644 src/runner/general_settings.h delete mode 100644 src/runner/hotkey_conflict_detector.cpp delete mode 100644 src/runner/hotkey_conflict_detector.h delete mode 100644 src/runner/main.cpp delete mode 100644 src/runner/pch.cpp delete mode 100644 src/runner/pch.h delete mode 100644 src/runner/powertoy_module.cpp delete mode 100644 src/runner/powertoy_module.h delete mode 100644 src/runner/quick_access_host.cpp delete mode 100644 src/runner/quick_access_host.h delete mode 100644 src/runner/resource.base.h delete mode 100644 src/runner/restart_elevated.cpp delete mode 100644 src/runner/restart_elevated.h delete mode 100644 src/runner/runner.base.rc delete mode 100644 src/runner/runner.vcxproj delete mode 100644 src/runner/runner.vcxproj.filters delete mode 100644 src/runner/settings_telemetry.cpp delete mode 100644 src/runner/settings_telemetry.h delete mode 100644 src/runner/settings_window.cpp delete mode 100644 src/runner/settings_window.h delete mode 100644 src/runner/svgs/PowerToysDark.ico delete mode 100644 src/runner/svgs/PowerToysWhite.ico delete mode 100644 src/runner/svgs/icon.ico delete mode 100644 src/runner/trace.cpp delete mode 100644 src/runner/trace.h delete mode 100644 src/runner/tray_icon.cpp delete mode 100644 src/runner/tray_icon.h delete mode 100644 src/runner/unhandled_exception_handler.cpp delete mode 100644 src/runner/unhandled_exception_handler.h diff --git a/PowerToys.slnx b/PowerToys.slnx index e0bbf9820d..53eb43de15 100644 --- a/PowerToys.slnx +++ b/PowerToys.slnx @@ -1028,25 +1028,7 @@ - - - - - - - - - - - - - - - - - - - + diff --git a/src/RunnerV2/RunnerV2/Assets/PowerToysDark.ico b/src/Runner/Assets/PowerToysDark.ico similarity index 100% rename from src/RunnerV2/RunnerV2/Assets/PowerToysDark.ico rename to src/Runner/Assets/PowerToysDark.ico diff --git a/src/RunnerV2/RunnerV2/Assets/PowerToysLight.ico b/src/Runner/Assets/PowerToysLight.ico similarity index 100% rename from src/RunnerV2/RunnerV2/Assets/PowerToysLight.ico rename to src/Runner/Assets/PowerToysLight.ico diff --git a/src/RunnerV2/RunnerV2/Extensions/PackageVersionExtensions.cs b/src/Runner/Extensions/PackageVersionExtensions.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Extensions/PackageVersionExtensions.cs rename to src/Runner/Extensions/PackageVersionExtensions.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/AIHelper.cs b/src/Runner/Helpers/AIHelper.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/AIHelper.cs rename to src/Runner/Helpers/AIHelper.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/AutoStartHelper.cs b/src/Runner/Helpers/AutoStartHelper.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/AutoStartHelper.cs rename to src/Runner/Helpers/AutoStartHelper.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/COMUtils.cs b/src/Runner/Helpers/COMUtils.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/COMUtils.cs rename to src/Runner/Helpers/COMUtils.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/CentralizedKeyboardHookManager.cs b/src/Runner/Helpers/CentralizedKeyboardHookManager.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/CentralizedKeyboardHookManager.cs rename to src/Runner/Helpers/CentralizedKeyboardHookManager.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/ElevationHelper.cs b/src/Runner/Helpers/ElevationHelper.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/ElevationHelper.cs rename to src/Runner/Helpers/ElevationHelper.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/HotkeyConflictsManager.cs b/src/Runner/Helpers/HotkeyConflictsManager.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/HotkeyConflictsManager.cs rename to src/Runner/Helpers/HotkeyConflictsManager.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/NotificationHelper.cs b/src/Runner/Helpers/NotificationHelper.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/NotificationHelper.cs rename to src/Runner/Helpers/NotificationHelper.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/PackageHelper.cs b/src/Runner/Helpers/PackageHelper.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/PackageHelper.cs rename to src/Runner/Helpers/PackageHelper.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/ProcessHelper.cs b/src/Runner/Helpers/ProcessHelper.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/ProcessHelper.cs rename to src/Runner/Helpers/ProcessHelper.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/QuickAccessHelper.cs b/src/Runner/Helpers/QuickAccessHelper.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/QuickAccessHelper.cs rename to src/Runner/Helpers/QuickAccessHelper.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/SettingsHelper.cs b/src/Runner/Helpers/SettingsHelper.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/SettingsHelper.cs rename to src/Runner/Helpers/SettingsHelper.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/TrayIconManager.cs b/src/Runner/Helpers/TrayIconManager.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/TrayIconManager.cs rename to src/Runner/Helpers/TrayIconManager.cs diff --git a/src/RunnerV2/RunnerV2/Models/IPowerToysModule.cs b/src/Runner/Models/IPowerToysModule.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Models/IPowerToysModule.cs rename to src/Runner/Models/IPowerToysModule.cs diff --git a/src/RunnerV2/RunnerV2/Models/IPowerToysModuleCustomActionsProvider.cs b/src/Runner/Models/IPowerToysModuleCustomActionsProvider.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Models/IPowerToysModuleCustomActionsProvider.cs rename to src/Runner/Models/IPowerToysModuleCustomActionsProvider.cs diff --git a/src/RunnerV2/RunnerV2/Models/IPowerToysModuleSettingsChangedSubscriber.cs b/src/Runner/Models/IPowerToysModuleSettingsChangedSubscriber.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Models/IPowerToysModuleSettingsChangedSubscriber.cs rename to src/Runner/Models/IPowerToysModuleSettingsChangedSubscriber.cs diff --git a/src/RunnerV2/RunnerV2/Models/IPowerToysModuleShortcutsProvider.cs b/src/Runner/Models/IPowerToysModuleShortcutsProvider.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Models/IPowerToysModuleShortcutsProvider.cs rename to src/Runner/Models/IPowerToysModuleShortcutsProvider.cs diff --git a/src/RunnerV2/RunnerV2/Models/ProcessModuleAbstractClass.cs b/src/Runner/Models/ProcessModuleAbstractClass.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Models/ProcessModuleAbstractClass.cs rename to src/Runner/Models/ProcessModuleAbstractClass.cs diff --git a/src/RunnerV2/RunnerV2/Models/RegistryChangeSet.cs b/src/Runner/Models/RegistryChangeSet.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Models/RegistryChangeSet.cs rename to src/Runner/Models/RegistryChangeSet.cs diff --git a/src/RunnerV2/RunnerV2/Models/RegistryValueChange.cs b/src/Runner/Models/RegistryValueChange.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Models/RegistryValueChange.cs rename to src/Runner/Models/RegistryValueChange.cs diff --git a/src/RunnerV2/RunnerV2/Models/SpecialMode.cs b/src/Runner/Models/SpecialMode.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Models/SpecialMode.cs rename to src/Runner/Models/SpecialMode.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/AdvancedPasteModuleInterface.cs b/src/Runner/ModuleInterfaces/AdvancedPasteModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/AdvancedPasteModuleInterface.cs rename to src/Runner/ModuleInterfaces/AdvancedPasteModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/AlwaysOnTopModuleInterface.cs b/src/Runner/ModuleInterfaces/AlwaysOnTopModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/AlwaysOnTopModuleInterface.cs rename to src/Runner/ModuleInterfaces/AlwaysOnTopModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/AwakeModuleInterface.cs b/src/Runner/ModuleInterfaces/AwakeModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/AwakeModuleInterface.cs rename to src/Runner/ModuleInterfaces/AwakeModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/CmdNotFoundModuleInterface.cs b/src/Runner/ModuleInterfaces/CmdNotFoundModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/CmdNotFoundModuleInterface.cs rename to src/Runner/ModuleInterfaces/CmdNotFoundModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/ColorPickerModuleInterface.cs b/src/Runner/ModuleInterfaces/ColorPickerModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/ColorPickerModuleInterface.cs rename to src/Runner/ModuleInterfaces/ColorPickerModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/CommandPaletteModuleInterface.cs b/src/Runner/ModuleInterfaces/CommandPaletteModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/CommandPaletteModuleInterface.cs rename to src/Runner/ModuleInterfaces/CommandPaletteModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/CropAndLockModuleInterface.cs b/src/Runner/ModuleInterfaces/CropAndLockModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/CropAndLockModuleInterface.cs rename to src/Runner/ModuleInterfaces/CropAndLockModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/CursorWrapModuleInterface.cs b/src/Runner/ModuleInterfaces/CursorWrapModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/CursorWrapModuleInterface.cs rename to src/Runner/ModuleInterfaces/CursorWrapModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/EnvironmentVariablesModuleInterface.cs b/src/Runner/ModuleInterfaces/EnvironmentVariablesModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/EnvironmentVariablesModuleInterface.cs rename to src/Runner/ModuleInterfaces/EnvironmentVariablesModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/FancyZonesModuleInterface.cs b/src/Runner/ModuleInterfaces/FancyZonesModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/FancyZonesModuleInterface.cs rename to src/Runner/ModuleInterfaces/FancyZonesModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/FileExplorerModuleInterface.cs b/src/Runner/ModuleInterfaces/FileExplorerModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/FileExplorerModuleInterface.cs rename to src/Runner/ModuleInterfaces/FileExplorerModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/FileLocksmithModuleInterface.cs b/src/Runner/ModuleInterfaces/FileLocksmithModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/FileLocksmithModuleInterface.cs rename to src/Runner/ModuleInterfaces/FileLocksmithModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/FindMyMouseModuleInterface.cs b/src/Runner/ModuleInterfaces/FindMyMouseModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/FindMyMouseModuleInterface.cs rename to src/Runner/ModuleInterfaces/FindMyMouseModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/HostsModuleInterface.cs b/src/Runner/ModuleInterfaces/HostsModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/HostsModuleInterface.cs rename to src/Runner/ModuleInterfaces/HostsModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/ImageResizerModuleInterface.cs b/src/Runner/ModuleInterfaces/ImageResizerModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/ImageResizerModuleInterface.cs rename to src/Runner/ModuleInterfaces/ImageResizerModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/KeyboardManagerModuleInterface.cs b/src/Runner/ModuleInterfaces/KeyboardManagerModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/KeyboardManagerModuleInterface.cs rename to src/Runner/ModuleInterfaces/KeyboardManagerModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/LightSwitchModuleInterface.cs b/src/Runner/ModuleInterfaces/LightSwitchModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/LightSwitchModuleInterface.cs rename to src/Runner/ModuleInterfaces/LightSwitchModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/MeasureToolModuleInterface.cs b/src/Runner/ModuleInterfaces/MeasureToolModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/MeasureToolModuleInterface.cs rename to src/Runner/ModuleInterfaces/MeasureToolModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/MouseHighlighterModuleInterface.cs b/src/Runner/ModuleInterfaces/MouseHighlighterModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/MouseHighlighterModuleInterface.cs rename to src/Runner/ModuleInterfaces/MouseHighlighterModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/MouseJumpModuleInterface.cs b/src/Runner/ModuleInterfaces/MouseJumpModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/MouseJumpModuleInterface.cs rename to src/Runner/ModuleInterfaces/MouseJumpModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/MousePointerCrosshairsModuleInterface.cs b/src/Runner/ModuleInterfaces/MousePointerCrosshairsModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/MousePointerCrosshairsModuleInterface.cs rename to src/Runner/ModuleInterfaces/MousePointerCrosshairsModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/MouseWithoutBordersModuleInterface.cs b/src/Runner/ModuleInterfaces/MouseWithoutBordersModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/MouseWithoutBordersModuleInterface.cs rename to src/Runner/ModuleInterfaces/MouseWithoutBordersModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/NewPlusModuleInterface.cs b/src/Runner/ModuleInterfaces/NewPlusModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/NewPlusModuleInterface.cs rename to src/Runner/ModuleInterfaces/NewPlusModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/PeekModuleInterface.cs b/src/Runner/ModuleInterfaces/PeekModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/PeekModuleInterface.cs rename to src/Runner/ModuleInterfaces/PeekModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/PowerAccentModuleInterface.cs b/src/Runner/ModuleInterfaces/PowerAccentModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/PowerAccentModuleInterface.cs rename to src/Runner/ModuleInterfaces/PowerAccentModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/PowerDisplayModuleInterface.cs b/src/Runner/ModuleInterfaces/PowerDisplayModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/PowerDisplayModuleInterface.cs rename to src/Runner/ModuleInterfaces/PowerDisplayModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/PowerOCRModuleInterface.cs b/src/Runner/ModuleInterfaces/PowerOCRModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/PowerOCRModuleInterface.cs rename to src/Runner/ModuleInterfaces/PowerOCRModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/PowerRenameModuleInterface.cs b/src/Runner/ModuleInterfaces/PowerRenameModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/PowerRenameModuleInterface.cs rename to src/Runner/ModuleInterfaces/PowerRenameModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/PowerToysRunModuleInterface.cs b/src/Runner/ModuleInterfaces/PowerToysRunModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/PowerToysRunModuleInterface.cs rename to src/Runner/ModuleInterfaces/PowerToysRunModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/RegistryPreviewModuleInterface.cs b/src/Runner/ModuleInterfaces/RegistryPreviewModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/RegistryPreviewModuleInterface.cs rename to src/Runner/ModuleInterfaces/RegistryPreviewModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/ShortcutGuideModuleInterface.cs b/src/Runner/ModuleInterfaces/ShortcutGuideModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/ShortcutGuideModuleInterface.cs rename to src/Runner/ModuleInterfaces/ShortcutGuideModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/WorkspacesModuleInterface.cs b/src/Runner/ModuleInterfaces/WorkspacesModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/WorkspacesModuleInterface.cs rename to src/Runner/ModuleInterfaces/WorkspacesModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/ZoomItModuleInterface.cs b/src/Runner/ModuleInterfaces/ZoomItModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/ZoomItModuleInterface.cs rename to src/Runner/ModuleInterfaces/ZoomItModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/NativeMethods.cs b/src/Runner/NativeMethods.cs similarity index 100% rename from src/RunnerV2/RunnerV2/NativeMethods.cs rename to src/Runner/NativeMethods.cs diff --git a/src/RunnerV2/RunnerV2/Program.cs b/src/Runner/Program.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Program.cs rename to src/Runner/Program.cs diff --git a/src/RunnerV2/RunnerV2/Runner.cs b/src/Runner/Runner.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Runner.cs rename to src/Runner/Runner.cs diff --git a/src/RunnerV2/RunnerV2/RunnerV2.csproj b/src/Runner/RunnerV2.csproj similarity index 54% rename from src/RunnerV2/RunnerV2/RunnerV2.csproj rename to src/Runner/RunnerV2.csproj index 47b57bf1de..3dea14f5a2 100644 --- a/src/RunnerV2/RunnerV2/RunnerV2.csproj +++ b/src/Runner/RunnerV2.csproj @@ -1,11 +1,11 @@  - - + + WinExe PowerToys Runner PowerToys - ..\..\..\$(Platform)\$(Configuration) + ..\..\$(Platform)\$(Configuration) enable false false @@ -14,12 +14,12 @@ - - - - - - + + + + + + diff --git a/src/RunnerV2/RunnerV2/app.manifest b/src/Runner/app.manifest similarity index 100% rename from src/RunnerV2/RunnerV2/app.manifest rename to src/Runner/app.manifest diff --git a/src/RunnerV2/RunnerV2/icon.ico b/src/Runner/icon.ico similarity index 100% rename from src/RunnerV2/RunnerV2/icon.ico rename to src/Runner/icon.ico diff --git a/src/runner/ActionRunnerUtils.h b/src/runner/ActionRunnerUtils.h deleted file mode 100644 index a0c59761c6..0000000000 --- a/src/runner/ActionRunnerUtils.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#define WIN32_LEAN_AND_MEAN -#include - -namespace cmdArg -{ - const inline wchar_t* RUN_NONELEVATED = L"-run-non-elevated"; -} diff --git a/src/runner/PowerToys.exe.manifest b/src/runner/PowerToys.exe.manifest deleted file mode 100644 index ce82aa752f..0000000000 --- a/src/runner/PowerToys.exe.manifest +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - true/PM - PerMonitorV2 - - - diff --git a/src/runner/Resources.resx b/src/runner/Resources.resx deleted file mode 100644 index b94f84714e..0000000000 --- a/src/runner/Resources.resx +++ /dev/null @@ -1,200 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - PowerToys Error - - - Could not start PowerToys as a user! - - - Could not start PowerToys as an administrator! - - - PowerToys is already running. - - - PowerToys was successfully updated! - - - An older version of PowerToys is already running. - - - Couldn't download PowerToys update! Please report the issue on GitHub. - - - An older MSIX version of PowerToys was uninstalled. - - - PowerToys was updated successfully! - - - This setting has been disabled by your administrator. - - - This setting has been disabled manually via <a href="https://ms_settings_startupapps" target="_blank">Startup Settings</a>. - - - An update to PowerToys is available. - - - Update now - - - An update to PowerToys is available. Visit our GitHub page to update. - - - More info... - - - PowerToys Update - - - Quick access\tLeft-click - Don't localize "\t" as that is what separates the click portion to be right aligned in the menu. - - - Settings\tDouble-click - Don't localize "\t" as that is what separates the click portion to be right aligned in the menu. - - - Settings\tLeft-click - Don't localize "\t" as that is what separates the click portion to be right aligned in the menu. This is shown when Quick Access is disabled. - - - Documentation - - - Report bug - - - Bug report .zip file has been created on your Desktop. - - - A new PowerToys version has been installed. Please restart the computer, when possible, to fully reload File Explorer extensions. - File Explorer refers to the Windows File Explorer application. - - - Administrator - - - Close - Close as a verb, as in Close the application - - \ No newline at end of file diff --git a/src/runner/RestartManagement.cpp b/src/runner/RestartManagement.cpp deleted file mode 100644 index 8fc11338fc..0000000000 --- a/src/runner/RestartManagement.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "pch.h" -#include "RestartManagement.h" - -#include -#include - -#include - -void RestartProcess(const std::wstring& processName) -{ - DWORD sessionHandle{}; - WCHAR sessionKey[CCH_RM_SESSION_KEY + 1]; - if (RmStartSession(&sessionHandle, 0, sessionKey) != ERROR_SUCCESS) - { - return; - } - auto processHandles = getProcessHandlesByName(processName, PROCESS_QUERY_INFORMATION); - std::vector pInfo; - for (const auto& hProcess : processHandles) - { - FILETIME creationTime{}; - FILETIME _{}; - if (GetProcessTimes(hProcess.get(), &creationTime, &_, &_, &_)) - { - pInfo.emplace_back(RM_UNIQUE_PROCESS{ GetProcessId(hProcess.get()), creationTime }); - } - } - - if (pInfo.empty() || - RmRegisterResources(sessionHandle, 0, nullptr, sizeof(pInfo), pInfo.data(), 0, nullptr) != ERROR_SUCCESS) - { - return; - } - RmShutdown(sessionHandle, RmForceShutdown, nullptr); - RmRestart(sessionHandle, 0, nullptr); - RmEndSession(sessionHandle); -} diff --git a/src/runner/RestartManagement.h b/src/runner/RestartManagement.h deleted file mode 100644 index 92c60004c8..0000000000 --- a/src/runner/RestartManagement.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include - -void RestartProcess(const std::wstring& processName); diff --git a/src/runner/UpdateUtils.cpp b/src/runner/UpdateUtils.cpp deleted file mode 100644 index 820b926984..0000000000 --- a/src/runner/UpdateUtils.cpp +++ /dev/null @@ -1,308 +0,0 @@ -#include "pch.h" - -#include "Generated Files/resource.h" - -#include "ActionRunnerUtils.h" -#include "general_settings.h" -#include "trace.h" -#include "UpdateUtils.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace -{ - constexpr int64_t UPDATE_CHECK_INTERVAL_MINUTES = 60 * 24; - constexpr int64_t UPDATE_CHECK_AFTER_FAILED_INTERVAL_MINUTES = 60 * 2; - - // How many minor versions to suspend the toast notification (example: installed=0.60.0, suspend=2, next notification=0.63.*) - // Attention: When changing this value please update the ADML file to. - const int UPDATE_NOTIFICATION_TOAST_SUSPEND_MINOR_VERSION_COUNT = 2; -} -using namespace notifications; -using namespace updating; - -std::wstring CurrentVersionToNextVersion(const new_version_download_info& info) -{ - auto result = VersionHelper{ VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION }.toWstring(); - result += L" \u2192 "; // Right arrow - result += info.version.toWstring(); - return result; -} - -void ShowNewVersionAvailable(const new_version_download_info& info) -{ - remove_toasts_by_tag(UPDATING_PROCESS_TOAST_TAG); - - toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false }; - std::wstring contents = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_AVAILABLE); - contents += L'\n'; - contents += CurrentVersionToNextVersion(info); - - show_toast_with_activations(std::move(contents), - GET_RESOURCE_STRING(IDS_TOAST_TITLE), - {}, - { link_button{ GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_UPDATE_NOW), - L"powertoys://update_now/" }, - link_button{ GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_MORE_INFO), - L"powertoys://open_overview/" } }, - std::move(toast_params), - L"powertoys://open_overview/"); -} - -void ShowOpenSettingsForUpdate() -{ - remove_toasts_by_tag(UPDATING_PROCESS_TOAST_TAG); - - toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false }; - - std::vector actions = { - link_button{ GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_MORE_INFO), - L"powertoys://open_overview/" }, - }; - show_toast_with_activations(GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_AVAILABLE), - GET_RESOURCE_STRING(IDS_TOAST_TITLE), - {}, - std::move(actions), - std::move(toast_params), - L"powertoys://open_overview/"); -} - -SHELLEXECUTEINFOW LaunchPowerToysUpdate(const wchar_t* cmdline) -{ - std::wstring powertoysUpdaterPath; - powertoysUpdaterPath = get_module_folderpath(); - - powertoysUpdaterPath += L"\\PowerToys.Update.exe"; - SHELLEXECUTEINFOW sei{ sizeof(sei) }; - sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS }; - sei.lpFile = powertoysUpdaterPath.c_str(); - sei.nShow = SW_SHOWNORMAL; - sei.lpParameters = cmdline; - ShellExecuteExW(&sei); - return sei; -} - -bool IsMeteredConnection() -{ - using namespace winrt::Windows::Networking::Connectivity; - ConnectionProfile internetConnectionProfile = NetworkInformation::GetInternetConnectionProfile(); - if (!internetConnectionProfile) - { - return false; - } - - if (internetConnectionProfile.IsWwanConnectionProfile()) - { - return true; - } - - ConnectionCost connectionCost = internetConnectionProfile.GetConnectionCost(); - if (connectionCost.Roaming() - || connectionCost.OverDataLimit() - || connectionCost.NetworkCostType() == NetworkCostType::Fixed - || connectionCost.NetworkCostType() == NetworkCostType::Variable) - { - return true; - } - - return false; -} - -void ProcessNewVersionInfo(const github_version_info& version_info, - UpdateState& state, - const bool download_update, - bool show_notifications) -{ - state.githubUpdateLastCheckedDate.emplace(timeutil::now()); - if (std::holds_alternative(version_info)) - { - state.state = UpdateState::upToDate; - state.releasePageUrl = {}; - state.downloadedInstallerFilename = {}; - Logger::trace(L"Version is up to date"); - return; - } - const auto new_version_info = std::get(version_info); - state.releasePageUrl = new_version_info.release_page_uri.ToString().c_str(); - Logger::trace(L"Discovered new version {}", new_version_info.version.toWstring()); - - const bool already_downloaded = state.state == UpdateState::readyToInstall && state.downloadedInstallerFilename == new_version_info.installer_filename; - if (already_downloaded) - { - Logger::trace(L"New version is already downloaded"); - return; - } - - // Check toast notification GPOs and settings. (We check only if notifications are allowed. This is the case if we are triggered by the periodic check.) - // Disable notification GPO or setting - bool disable_notification_setting = get_general_settings().showNewUpdatesToastNotification == false; - if (show_notifications && (disable_notification_setting || powertoys_gpo::getDisableNewUpdateToastValue() == powertoys_gpo::gpo_rule_configured_enabled)) - { - Logger::info(L"There is a new update available or ready to install. But the toast notification is disabled by setting or GPO."); - show_notifications = false; - } - // Suspend notification GPO - else if (show_notifications && powertoys_gpo::getSuspendNewUpdateToastValue() == powertoys_gpo::gpo_rule_configured_enabled) - { - Logger::info(L"GPO to suspend new update toast notification is enabled."); - if (new_version_info.version.major <= VERSION_MAJOR && new_version_info.version.minor - VERSION_MINOR <= UPDATE_NOTIFICATION_TOAST_SUSPEND_MINOR_VERSION_COUNT) - { - Logger::info(L"The difference between the installed version and the newer version is within the allowed period. The toast notification is not shown."); - show_notifications = false; - } - else - { - Logger::info(L"The installed version is older than allowed for suspending the toast notification. The toast notification is shown."); - } - } - - if (download_update) - { - Logger::trace(L"Downloading installer for a new version"); - - // Cleanup old updates before downloading the latest - updating::cleanup_updates(); - - if (download_new_version(new_version_info).get()) - { - state.state = UpdateState::readyToInstall; - state.downloadedInstallerFilename = new_version_info.installer_filename; - Trace::UpdateDownloadCompleted(true, new_version_info.version.toWstring()); - if (show_notifications) - { - ShowNewVersionAvailable(new_version_info); - } - } - else - { - state.state = UpdateState::errorDownloading; - state.downloadedInstallerFilename = {}; - Trace::UpdateDownloadCompleted(false, new_version_info.version.toWstring()); - Logger::error("Couldn't download new installer"); - } - } - else - { - Logger::trace(L"New version is ready to download, showing notification"); - state.state = UpdateState::readyToDownload; - state.downloadedInstallerFilename = {}; - if (show_notifications) - { - ShowOpenSettingsForUpdate(); - } - } -} - -void PeriodicUpdateWorker() -{ - for (;;) - { - auto state = UpdateState::read(); - int64_t sleep_minutes_till_next_update = UPDATE_CHECK_AFTER_FAILED_INTERVAL_MINUTES; - if (state.githubUpdateLastCheckedDate.has_value()) - { - int64_t last_checked_minutes_ago = timeutil::diff::in_minutes(timeutil::now(), *state.githubUpdateLastCheckedDate); - if (last_checked_minutes_ago < 0) - { - last_checked_minutes_ago = UPDATE_CHECK_INTERVAL_MINUTES; - } - sleep_minutes_till_next_update = max(0, UPDATE_CHECK_INTERVAL_MINUTES - last_checked_minutes_ago); - } - - std::this_thread::sleep_for(std::chrono::minutes{ sleep_minutes_till_next_update }); - - // Auto download setting. - bool download_update = !IsMeteredConnection() && get_general_settings().downloadUpdatesAutomatically; - if (powertoys_gpo::getDisableAutomaticUpdateDownloadValue() == powertoys_gpo::gpo_rule_configured_enabled) - { - Logger::info(L"Automatic download of updates is disabled by GPO."); - download_update = false; - } - - bool version_info_obtained = false; - try - { - const auto new_version_info = get_github_version_info_async().get(); - if (new_version_info.has_value()) - { - version_info_obtained = true; - bool updateAvailable = std::holds_alternative(*new_version_info); - std::wstring fromVersion = get_product_version(); - std::wstring toVersion = updateAvailable ? std::get(*new_version_info).version.toWstring() : L""; - Trace::UpdateCheckCompleted(true, updateAvailable, fromVersion, toVersion); - ProcessNewVersionInfo(*new_version_info, state, download_update, true); - } - else - { - Trace::UpdateCheckCompleted(false, false, get_product_version(), L""); - Logger::error(L"Couldn't obtain version info from github: {}", new_version_info.error()); - } - } - catch (...) - { - Logger::error("periodic_update_worker: error while processing version info"); - } - - if (version_info_obtained) - { - UpdateState::store([&](UpdateState& v) { - v = std::move(state); - }); - } - else - { - std::this_thread::sleep_for(std::chrono::minutes{ UPDATE_CHECK_AFTER_FAILED_INTERVAL_MINUTES }); - } - } -} - -void CheckForUpdatesCallback() -{ - Logger::trace(L"Check for updates callback invoked"); - auto state = UpdateState::read(); - try - { - auto new_version_info = get_github_version_info_async().get(); - if (!new_version_info) - { - // We couldn't get a new version from github for some reason, log error - state.state = UpdateState::networkError; - Trace::UpdateCheckCompleted(false, false, get_product_version(), L""); - Logger::error(L"Couldn't obtain version info from github: {}", new_version_info.error()); - } - else - { - // Auto download setting - bool download_update = !IsMeteredConnection() && get_general_settings().downloadUpdatesAutomatically; - if (powertoys_gpo::getDisableAutomaticUpdateDownloadValue() == powertoys_gpo::gpo_rule_configured_enabled) - { - Logger::info(L"Automatic download of updates is disabled by GPO."); - download_update = false; - } - - bool updateAvailable = std::holds_alternative(*new_version_info); - std::wstring fromVersion = get_product_version(); - std::wstring toVersion = updateAvailable ? std::get(*new_version_info).version.toWstring() : L""; - Trace::UpdateCheckCompleted(true, updateAvailable, fromVersion, toVersion); - ProcessNewVersionInfo(*new_version_info, state, download_update, false); - } - - UpdateState::store([&](UpdateState& v) { - v = std::move(state); - }); - } - catch (...) - { - Logger::error("CheckForUpdatesCallback: error while processing version info"); - } -} diff --git a/src/runner/UpdateUtils.h b/src/runner/UpdateUtils.h deleted file mode 100644 index 83437c8f80..0000000000 --- a/src/runner/UpdateUtils.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -void PeriodicUpdateWorker(); -void CheckForUpdatesCallback(); - -namespace cmdArg -{ - // Starts first stage of the PowerToys auto-update process, which involves copying action runner to a temp path and - // restarting it from there, so it doesn't interfere with the installation process. - const inline wchar_t* UPDATE_NOW_LAUNCH_STAGE1 = L"-update_now"; - // Stage 2 consists of starting the installer and optionally launching newly installed PowerToys binary. - // That's indicated by the following 2 flags. - const inline wchar_t* UPDATE_NOW_LAUNCH_STAGE2 = L"-update_now_stage_2"; - const inline wchar_t* UPDATE_STAGE2_RESTART_PT = L"restart"; - const inline wchar_t* UPDATE_STAGE2_DONT_START_PT = L"dont_start"; - - const inline wchar_t* UPDATE_REPORT_SUCCESS = L"-report_update_success"; -} - -SHELLEXECUTEINFOW LaunchPowerToysUpdate(const wchar_t* cmdline); \ No newline at end of file diff --git a/src/runner/ai_detection.h b/src/runner/ai_detection.h deleted file mode 100644 index 41aa1dc328..0000000000 --- a/src/runner/ai_detection.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -// Detect AI capabilities by calling ImageResizer in detection mode. -// This runs in a background thread to avoid blocking. -// ImageResizer writes the result to a cache file that it reads on normal startup. -// -// Parameters: -// skipSettingsCheck - If true, skip checking if ImageResizer is enabled in settings. -// Use this when called from apply_general_settings where we know -// ImageResizer is being enabled but settings file may not be saved yet. -void DetectAiCapabilitiesAsync(bool skipSettingsCheck = false); diff --git a/src/runner/auto_start_helper.cpp b/src/runner/auto_start_helper.cpp deleted file mode 100644 index ac1ae45afe..0000000000 --- a/src/runner/auto_start_helper.cpp +++ /dev/null @@ -1,397 +0,0 @@ -#include "pch.h" -#include "auto_start_helper.h" - -#include - -#include -#include -#include - -// Helper macros from wix. -#define ExitOnFailure(x, s, ...) \ - if (FAILED(x)) \ - { \ - Logger::error(s, ##__VA_ARGS__); \ - goto LExit; \ - } -#define ExitWithLastError(x, s, ...) \ - { \ - DWORD util_err = ::GetLastError(); \ - x = HRESULT_FROM_WIN32(util_err); \ - if (!FAILED(x)) \ - { \ - x = E_FAIL; \ - } \ - Logger::error(s, ##__VA_ARGS__); \ - goto LExit; \ - } -#define ExitFunction() \ - { \ - goto LExit; \ - } - -const DWORD USERNAME_DOMAIN_LEN = DNLEN + UNLEN + 2; // Domain Name + '\' + User Name + '\0' -const DWORD USERNAME_LEN = UNLEN + 1; // User Name + '\0' - -bool create_auto_start_task_for_this_user(bool runElevated) -{ - HRESULT hr = S_OK; - - WCHAR username_domain[USERNAME_DOMAIN_LEN]; - WCHAR username[USERNAME_LEN]; - - std::wstring wstrTaskName; - - ITaskService* pService = NULL; - ITaskFolder* pTaskFolder = NULL; - ITaskDefinition* pTask = NULL; - IRegistrationInfo* pRegInfo = NULL; - ITaskSettings* pSettings = NULL; - ITriggerCollection* pTriggerCollection = NULL; - IRegisteredTask* pRegisteredTask = NULL; - - // ------------------------------------------------------ - // Get the Domain/Username for the trigger. - if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) - { - ExitWithLastError(hr, "Getting username failed: {:x}", hr); - } - if (!GetEnvironmentVariable(L"USERDOMAIN", username_domain, USERNAME_DOMAIN_LEN)) - { - ExitWithLastError(hr, "Getting the user's domain failed: {:x}", hr); - } - wcscat_s(username_domain, L"\\"); - wcscat_s(username_domain, username); - - // Task Name. - wstrTaskName = L"Autorun for "; - wstrTaskName += username; - - // Get the executable path passed to the custom action. - WCHAR wszExecutablePath[MAX_PATH]; - GetModuleFileName(NULL, wszExecutablePath, MAX_PATH); - - // ------------------------------------------------------ - // Create an instance of the Task Service. - hr = CoCreateInstance(CLSID_TaskScheduler, - NULL, - CLSCTX_INPROC_SERVER, - IID_ITaskService, - reinterpret_cast(&pService)); - ExitOnFailure(hr, "Failed to create an instance of ITaskService: {:x}", hr); - - // Connect to the task service. - hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t()); - ExitOnFailure(hr, "ITaskService::Connect failed: {:x}", hr); - - // ------------------------------------------------------ - // Get the PowerToys task folder. Creates it if it doesn't exist. - hr = pService->GetFolder(_bstr_t(L"\\PowerToys"), &pTaskFolder); - if (FAILED(hr)) - { - // Folder doesn't exist. Get the Root folder and create the PowerToys subfolder. - ITaskFolder* pRootFolder = NULL; - hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder); - ExitOnFailure(hr, "Cannot get Root Folder pointer: {:x}", hr); - hr = pRootFolder->CreateFolder(_bstr_t(L"\\PowerToys"), _variant_t(L""), &pTaskFolder); - if (FAILED(hr)) - { - pRootFolder->Release(); - ExitOnFailure(hr, "Cannot create PowerToys task folder: {:x}", hr); - } - } - - // If the task exists, just enable it. - { - IRegisteredTask* pExistingRegisteredTask = NULL; - hr = pTaskFolder->GetTask(_bstr_t(wstrTaskName.c_str()), &pExistingRegisteredTask); - if (SUCCEEDED(hr)) - { - // Task exists, try enabling it. - hr = pExistingRegisteredTask->put_Enabled(VARIANT_TRUE); - pExistingRegisteredTask->Release(); - if (SUCCEEDED(hr)) - { - // Function enable. Sounds like a success. - ExitFunction(); - } - } - } - - // Create the task builder object to create the task. - hr = pService->NewTask(0, &pTask); - ExitOnFailure(hr, "Failed to create a task definition: {:x}", hr); - - // ------------------------------------------------------ - // Get the registration info for setting the identification. - hr = pTask->get_RegistrationInfo(&pRegInfo); - ExitOnFailure(hr, "Cannot get identification pointer: {:x}", hr); - hr = pRegInfo->put_Author(_bstr_t(username_domain)); - ExitOnFailure(hr, "Cannot put identification info: {:x}", hr); - - // ------------------------------------------------------ - // Create the settings for the task - hr = pTask->get_Settings(&pSettings); - ExitOnFailure(hr, "Cannot get settings pointer: {:x}", hr); - - hr = pSettings->put_StartWhenAvailable(VARIANT_FALSE); - ExitOnFailure(hr, "Cannot put_StartWhenAvailable setting info: {:x}", hr); - hr = pSettings->put_StopIfGoingOnBatteries(VARIANT_FALSE); - ExitOnFailure(hr, "Cannot put_StopIfGoingOnBatteries setting info: {:x}", hr); - hr = pSettings->put_ExecutionTimeLimit(_bstr_t(L"PT0S")); //Unlimited - ExitOnFailure(hr, "Cannot put_ExecutionTimeLimit setting info: {:x}", hr); - hr = pSettings->put_DisallowStartIfOnBatteries(VARIANT_FALSE); - ExitOnFailure(hr, "Cannot put_DisallowStartIfOnBatteries setting info: {:x}", hr); - hr = pSettings->put_Priority(4); - ExitOnFailure(hr, "Cannot put_Priority setting info : {:x}", hr); - - // ------------------------------------------------------ - // Get the trigger collection to insert the logon trigger. - hr = pTask->get_Triggers(&pTriggerCollection); - ExitOnFailure(hr, "Cannot get trigger collection: {:x}", hr); - - // Add the logon trigger to the task. - { - ITrigger* pTrigger = NULL; - ILogonTrigger* pLogonTrigger = NULL; - hr = pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger); - ExitOnFailure(hr, "Cannot create the trigger: {:x}", hr); - - hr = pTrigger->QueryInterface( - IID_ILogonTrigger, reinterpret_cast(&pLogonTrigger)); - pTrigger->Release(); - ExitOnFailure(hr, "QueryInterface call failed for ILogonTrigger: {:x}", hr); - - hr = pLogonTrigger->put_Id(_bstr_t(L"Trigger1")); - - // Timing issues may make explorer not be started when the task runs. - // Add a little delay to mitigate this. - hr = pLogonTrigger->put_Delay(_bstr_t(L"PT03S")); - - // Define the user. The task will execute when the user logs on. - // The specified user must be a user on this computer. - hr = pLogonTrigger->put_UserId(_bstr_t(username_domain)); - pLogonTrigger->Release(); - ExitOnFailure(hr, "Cannot add user ID to logon trigger: {:x}", hr); - } - - // ------------------------------------------------------ - // Add an Action to the task. This task will execute the path passed to this custom action. - { - IActionCollection* pActionCollection = NULL; - IAction* pAction = NULL; - IExecAction* pExecAction = NULL; - - // Get the task action collection pointer. - hr = pTask->get_Actions(&pActionCollection); - ExitOnFailure(hr, "Cannot get Task collection pointer: {:x}", hr); - - // Create the action, specifying that it is an executable action. - hr = pActionCollection->Create(TASK_ACTION_EXEC, &pAction); - pActionCollection->Release(); - ExitOnFailure(hr, "Cannot create the action: {:x}", hr); - - // QI for the executable task pointer. - hr = pAction->QueryInterface( - IID_IExecAction, reinterpret_cast(&pExecAction)); - pAction->Release(); - ExitOnFailure(hr, "QueryInterface call failed for IExecAction: {:x}", hr); - - // Set the path of the executable to PowerToys (passed as CustomActionData). - hr = pExecAction->put_Path(_bstr_t(wszExecutablePath)); - pExecAction->Release(); - ExitOnFailure(hr, "Cannot set path of executable: {:x}", hr); - } - - // ------------------------------------------------------ - // Create the principal for the task - { - IPrincipal* pPrincipal = NULL; - hr = pTask->get_Principal(&pPrincipal); - ExitOnFailure(hr, "Cannot get principal pointer: {:x}", hr); - - // Set up principal information: - hr = pPrincipal->put_Id(_bstr_t(L"Principal1")); - - hr = pPrincipal->put_UserId(_bstr_t(username_domain)); - - hr = pPrincipal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN); - - if (runElevated) - { - hr = pPrincipal->put_RunLevel(_TASK_RUNLEVEL::TASK_RUNLEVEL_HIGHEST); - } - else - { - hr = pPrincipal->put_RunLevel(_TASK_RUNLEVEL::TASK_RUNLEVEL_LUA); - } - pPrincipal->Release(); - ExitOnFailure(hr, "Cannot put principal run level: {:x}", hr); - } - // ------------------------------------------------------ - // Save the task in the PowerToys folder. - { - _variant_t SDDL_FULL_ACCESS_FOR_EVERYONE = L"D:(A;;FA;;;WD)"; - hr = pTaskFolder->RegisterTaskDefinition( - _bstr_t(wstrTaskName.c_str()), - pTask, - TASK_CREATE_OR_UPDATE, - _variant_t(username_domain), - _variant_t(), - TASK_LOGON_INTERACTIVE_TOKEN, - SDDL_FULL_ACCESS_FOR_EVERYONE, - &pRegisteredTask); - ExitOnFailure(hr, "Error saving the Task : {:x}", hr); - } - -LExit: - if (pService) - pService->Release(); - if (pTaskFolder) - pTaskFolder->Release(); - if (pTask) - pTask->Release(); - if (pRegInfo) - pRegInfo->Release(); - if (pSettings) - pSettings->Release(); - if (pTriggerCollection) - pTriggerCollection->Release(); - if (pRegisteredTask) - pRegisteredTask->Release(); - - return (SUCCEEDED(hr)); -} - -bool delete_auto_start_task_for_this_user() -{ - HRESULT hr = S_OK; - - WCHAR username[USERNAME_LEN]; - std::wstring wstrTaskName; - - ITaskService* pService = NULL; - ITaskFolder* pTaskFolder = NULL; - - // ------------------------------------------------------ - // Get the Username for the task. - if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) - { - ExitWithLastError(hr, "Getting username failed: {:x}", hr); - } - - // Task Name. - wstrTaskName = L"Autorun for "; - wstrTaskName += username; - - // ------------------------------------------------------ - // Create an instance of the Task Service. - hr = CoCreateInstance(CLSID_TaskScheduler, - NULL, - CLSCTX_INPROC_SERVER, - IID_ITaskService, - reinterpret_cast(&pService)); - ExitOnFailure(hr, "Failed to create an instance of ITaskService: {:x}", hr); - - // Connect to the task service. - hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t()); - ExitOnFailure(hr, "ITaskService::Connect failed: {:x}", hr); - - // ------------------------------------------------------ - // Get the PowerToys task folder. - hr = pService->GetFolder(_bstr_t(L"\\PowerToys"), &pTaskFolder); - if (FAILED(hr)) - { - // Folder doesn't exist. No need to disable a non-existing task. - hr = S_OK; - ExitFunction(); - } - - // ------------------------------------------------------ - // If the task exists, disable. - { - IRegisteredTask* pExistingRegisteredTask = NULL; - hr = pTaskFolder->GetTask(_bstr_t(wstrTaskName.c_str()), &pExistingRegisteredTask); - if (SUCCEEDED(hr)) - { - // Task exists, try disabling it. - hr = pTaskFolder->DeleteTask(_bstr_t(wstrTaskName.c_str()), 0); - } - } - -LExit: - if (pService) - pService->Release(); - if (pTaskFolder) - pTaskFolder->Release(); - - return (SUCCEEDED(hr)); -} - -bool is_auto_start_task_active_for_this_user() -{ - HRESULT hr = S_OK; - - WCHAR username[USERNAME_LEN]; - std::wstring wstrTaskName; - - ITaskService* pService = NULL; - ITaskFolder* pTaskFolder = NULL; - - // ------------------------------------------------------ - // Get the Username for the task. - if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) - { - ExitWithLastError(hr, "Getting username failed: {:x}", hr); - } - - // Task Name. - wstrTaskName = L"Autorun for "; - wstrTaskName += username; - - // ------------------------------------------------------ - // Create an instance of the Task Service. - hr = CoCreateInstance(CLSID_TaskScheduler, - NULL, - CLSCTX_INPROC_SERVER, - IID_ITaskService, - reinterpret_cast(&pService)); - ExitOnFailure(hr, "Failed to create an instance of ITaskService: {:x}", hr); - - // Connect to the task service. - hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t()); - ExitOnFailure(hr, "ITaskService::Connect failed: {:x}", hr); - - // ------------------------------------------------------ - // Get the PowerToys task folder. - hr = pService->GetFolder(_bstr_t(L"\\PowerToys"), &pTaskFolder); - ExitOnFailure(hr, "ITaskFolder doesn't exist: {:x}", hr); - - // ------------------------------------------------------ - // If the task exists, disable. - { - IRegisteredTask* pExistingRegisteredTask = NULL; - hr = pTaskFolder->GetTask(_bstr_t(wstrTaskName.c_str()), &pExistingRegisteredTask); - if (SUCCEEDED(hr)) - { - // Task exists, get its value. - VARIANT_BOOL is_enabled; - hr = pExistingRegisteredTask->get_Enabled(&is_enabled); - pExistingRegisteredTask->Release(); - if (SUCCEEDED(hr)) - { - // Got the value. Return it. - hr = (is_enabled == VARIANT_TRUE) ? S_OK : E_FAIL; // Fake success or fail to return the value. - ExitFunction(); - } - } - } - -LExit: - if (pService) - pService->Release(); - if (pTaskFolder) - pTaskFolder->Release(); - - return (SUCCEEDED(hr)); -} diff --git a/src/runner/auto_start_helper.h b/src/runner/auto_start_helper.h deleted file mode 100644 index fb2b68fadf..0000000000 --- a/src/runner/auto_start_helper.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -bool is_auto_start_task_active_for_this_user(); -bool create_auto_start_task_for_this_user(bool runElevated); -bool delete_auto_start_task_for_this_user(); diff --git a/src/runner/bug_report.cpp b/src/runner/bug_report.cpp deleted file mode 100644 index 697bf518f7..0000000000 --- a/src/runner/bug_report.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "pch.h" -#include "bug_report.h" -#include "Generated files/resource.h" -#include -#include - -BugReportManager& BugReportManager::instance() -{ - static BugReportManager instance; - return instance; -} - -void BugReportManager::register_callback(const BugReportCallback& callback) -{ - std::lock_guard lock(m_callbacksMutex); - m_callbacks.push_back(callback); -} - -void BugReportManager::clear_callbacks() -{ - std::lock_guard lock(m_callbacksMutex); - m_callbacks.clear(); -} - -void BugReportManager::notify_observers(bool isRunning) -{ - std::lock_guard lock(m_callbacksMutex); - for (const auto& callback : m_callbacks) - { - try - { - callback(isRunning); - } - catch (...) - { - // Ignore callback exceptions to prevent one bad callback from affecting others - } - } -} - -void BugReportManager::launch_bug_report() noexcept -{ - std::wstring bug_report_path = get_module_folderpath(); - bug_report_path += L"\\Tools\\PowerToys.BugReportTool.exe"; - - bool expected_isBugReportRunning = false; - if (m_isBugReportRunning.compare_exchange_strong(expected_isBugReportRunning, true)) - { - // Notify observers that bug report is starting - notify_observers(true); - - std::thread([this, bug_report_path]() { - SHELLEXECUTEINFOW sei{ sizeof(sei) }; - sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NO_CONSOLE }; - sei.lpFile = bug_report_path.c_str(); - sei.nShow = SW_HIDE; - if (ShellExecuteExW(&sei)) - { - WaitForSingleObject(sei.hProcess, INFINITE); - CloseHandle(sei.hProcess); - static const std::wstring bugreport_success = GET_RESOURCE_STRING(IDS_BUGREPORT_SUCCESS); - MessageBoxW(nullptr, bugreport_success.c_str(), L"PowerToys", MB_OK); - } - - m_isBugReportRunning.store(false); - // Notify observers that bug report has finished - notify_observers(false); - }).detach(); - } - else - { - notify_observers(false); - } -} - -bool BugReportManager::is_bug_report_running() const noexcept -{ - return m_isBugReportRunning.load(); -} - -// Legacy functions for backward compatibility -void launch_bug_report() noexcept -{ - BugReportManager::instance().launch_bug_report(); -} - -bool is_bug_report_running() noexcept -{ - return BugReportManager::instance().is_bug_report_running(); -} diff --git a/src/runner/bug_report.h b/src/runner/bug_report.h deleted file mode 100644 index 6edb1c6ba3..0000000000 --- a/src/runner/bug_report.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include -#include -#include - -// Observer pattern for bug report status changes -using BugReportCallback = std::function; - -class BugReportManager -{ -public: - static BugReportManager& instance(); - - // Register a callback to be notified when bug report status changes - void register_callback(const BugReportCallback& callback); - - // Remove all callbacks (useful for cleanup) - void clear_callbacks(); - - // Launch bug report and notify observers - void launch_bug_report() noexcept; - - // Check if bug report is currently running - bool is_bug_report_running() const noexcept; - -private: - BugReportManager() = default; - ~BugReportManager() = default; - BugReportManager(const BugReportManager&) = delete; - BugReportManager& operator=(const BugReportManager&) = delete; - - // Notify all registered callbacks - void notify_observers(bool isRunning); - - std::atomic_bool m_isBugReportRunning = false; - std::vector m_callbacks; - mutable std::mutex m_callbacksMutex; -}; - -// Legacy functions for backward compatibility -void launch_bug_report() noexcept; -bool is_bug_report_running() noexcept; \ No newline at end of file diff --git a/src/runner/centralized_hotkeys.cpp b/src/runner/centralized_hotkeys.cpp deleted file mode 100644 index d0ad870f52..0000000000 --- a/src/runner/centralized_hotkeys.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "pch.h" -#include "centralized_hotkeys.h" - -#include -#include -#include -#include - -namespace CentralizedHotkeys -{ - std::map> actions; - std::map ids; - HWND runnerWindow; - - std::wstring ToWstring(const Shortcut& shortcut) - { - std::wstring res = L""; - if (shortcut.modifiersMask & MOD_SHIFT) - { - res += L"shift+"; - } - - if (shortcut.modifiersMask & MOD_CONTROL) - { - res += L"ctrl+"; - } - - if (shortcut.modifiersMask & MOD_WIN) - { - res += L"win+"; - } - - if (shortcut.modifiersMask & MOD_ALT) - { - res += L"alt+"; - } - - res += PowerToysSettings::HotkeyObject::key_from_code(shortcut.vkCode); - - return res; - } - - bool AddHotkeyAction(Shortcut shortcut, Action action) - { - if (!actions[shortcut].empty()) - { - // It will only work if previous one is rewritten - Logger::warn(L"{} shortcut is already registered", ToWstring(shortcut)); - } - - actions[shortcut].push_back(action); - // Register hotkey if it is the first shortcut - if (actions[shortcut].size() == 1) - { - if (ids.find(shortcut) == ids.end()) - { - static int nextId = 0; - ids[shortcut] = nextId++; - } - - if (!RegisterHotKey(runnerWindow, ids[shortcut], shortcut.modifiersMask, shortcut.vkCode)) - { - Logger::warn(L"Failed to add {} shortcut. {}", ToWstring(shortcut), get_last_error_or_default(GetLastError())); - return false; - } - - Logger::trace(L"{} shortcut registered", ToWstring(shortcut)); - return true; - } - - return true; - } - - void UnregisterHotkeysForModule(std::wstring moduleName) - { - for (auto it = actions.begin(); it != actions.end(); it++) - { - auto val = std::find_if(it->second.begin(), it->second.end(), [moduleName](Action a) { return a.moduleName == moduleName; }); - if (val != it->second.end()) - { - it->second.erase(val); - - if (it->second.empty()) - { - if (!UnregisterHotKey(runnerWindow, ids[it->first])) - { - Logger::warn(L"Failed to unregister {} shortcut. {}", ToWstring(it->first), get_last_error_or_default(GetLastError())); - } - else - { - Logger::trace(L"{} shortcut unregistered", ToWstring(it->first)); - } - } - } - } - } - - void PopulateHotkey(Shortcut shortcut) - { - if (!actions.empty()) - { - try - { - actions[shortcut].begin()->action(shortcut.modifiersMask, shortcut.vkCode); - } - catch(std::exception& ex) - { - Logger::error("Failed to execute hotkey's action. {}", ex.what()); - } - catch(...) - { - Logger::error(L"Failed to execute hotkey's action"); - } - } - } - - void RegisterWindow(HWND hwnd) - { - runnerWindow = hwnd; - } -} diff --git a/src/runner/centralized_hotkeys.h b/src/runner/centralized_hotkeys.h deleted file mode 100644 index bb503d332d..0000000000 --- a/src/runner/centralized_hotkeys.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once -#include -#include - -namespace CentralizedHotkeys -{ - struct Action - { - std::wstring moduleName; - std::function action; - - Action(std::wstring moduleName = L"", std::function action = ([](WORD /*modifiersMask*/, WORD /*vkCode*/) {})) - { - this->moduleName = moduleName; - this->action = action; - } - }; - - struct Shortcut - { - WORD modifiersMask; - WORD vkCode; - int hotkeyID; - - Shortcut(WORD modifiersMask = 0, WORD vkCode = 0, const int hotkeyID = 0) - { - this->modifiersMask = modifiersMask; - this->vkCode = vkCode; - this->hotkeyID = hotkeyID; - } - - bool operator<(const Shortcut& key) const - { - return std::pair{ this->modifiersMask, this->vkCode } < std::pair{ key.modifiersMask, key.vkCode }; - } - }; - - std::wstring ToWstring(const Shortcut& shortcut); - - bool AddHotkeyAction(Shortcut shortcut, Action action); - - void UnregisterHotkeysForModule(std::wstring moduleName); - - void PopulateHotkey(Shortcut shortcut); - - void RegisterWindow(HWND hwnd); -} diff --git a/src/runner/centralized_kb_hook.cpp b/src/runner/centralized_kb_hook.cpp deleted file mode 100644 index 72b473bd08..0000000000 --- a/src/runner/centralized_kb_hook.cpp +++ /dev/null @@ -1,276 +0,0 @@ -#include "pch.h" -#include "centralized_kb_hook.h" -#include -#include -#include -#include - -namespace CentralizedKeyboardHook -{ - struct HotkeyDescriptor - { - Hotkey hotkey; - std::wstring moduleName; - std::function action; - - bool operator<(const HotkeyDescriptor& other) const - { - return hotkey < other.hotkey; - }; - }; - - std::multiset hotkeyDescriptors; - std::mutex mutex; - HHOOK hHook{}; - - // To store information about handling pressed keys. - struct PressedKeyDescriptor - { - DWORD virtualKey; // Virtual Key code of the key we're keeping track of. - std::wstring moduleName; - std::function action; - UINT_PTR idTimer; // Timer ID for calling SET_TIMER with. - UINT millisecondsToPress; // How much time the key must be pressed. - bool operator<(const PressedKeyDescriptor& other) const - { - // We'll use the virtual key as the real key, since looking for a hit with the key is done in the more time sensitive path (low level keyboard hook). - return virtualKey < other.virtualKey; - }; - }; - std::multiset pressedKeyDescriptors; - std::mutex pressedKeyMutex; - - // keep track of last pressed key, to detect repeated keys and if there are more keys pressed. - const DWORD VK_DISABLED = CommonSharedConstants::VK_DISABLED; - DWORD vkCodePressed = VK_DISABLED; - - // Save the runner window handle for registering timers. - HWND runnerWindow; - - struct DestroyOnExit - { - ~DestroyOnExit() - { - Stop(); - } - } destroyOnExitObj; - - // Handle the pressed key proc - void PressedKeyTimerProc( - HWND hwnd, - UINT /*message*/, - UINT_PTR idTimer, - DWORD /*dwTime*/) - { - std::multiset copy; - { - // Make a copy, to look for the action to call. - std::unique_lock lock{ pressedKeyMutex }; - copy = pressedKeyDescriptors; - } - for (const auto& it : copy) - { - if (it.idTimer == idTimer) - { - it.action(); - } - } - - KillTimer(hwnd, idTimer); - } - - LRESULT CALLBACK KeyboardHookProc(_In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam) - { - if (nCode < 0) - { - return CallNextHookEx(hHook, nCode, wParam, lParam); - } - - const auto& keyPressInfo = *reinterpret_cast(lParam); - - if (keyPressInfo.dwExtraInfo == PowertoyModuleIface::CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG) - { - // The new keystroke was generated from one of our actions. We should pass it along. - return CallNextHookEx(hHook, nCode, wParam, lParam); - } - - // Check if the keys are pressed. - if (!pressedKeyDescriptors.empty()) - { - bool wasKeyPressed = vkCodePressed != VK_DISABLED; - // Hold the lock for the shortest possible duration - if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)) - { - if (!wasKeyPressed) - { - // If no key was pressed before, let's start a timer to take into account this new key. - std::unique_lock lock{ pressedKeyMutex }; - PressedKeyDescriptor dummy{ .virtualKey = keyPressInfo.vkCode }; - auto [it, last] = pressedKeyDescriptors.equal_range(dummy); - for (; it != last; ++it) - { - SetTimer(runnerWindow, it->idTimer, it->millisecondsToPress, PressedKeyTimerProc); - } - } - else if (vkCodePressed != keyPressInfo.vkCode) - { - // If a different key was pressed, let's clear the timers we have started for the previous key. - std::unique_lock lock{ pressedKeyMutex }; - PressedKeyDescriptor dummy{ .virtualKey = vkCodePressed }; - auto [it, last] = pressedKeyDescriptors.equal_range(dummy); - for (; it != last; ++it) - { - KillTimer(runnerWindow, it->idTimer); - } - } - vkCodePressed = keyPressInfo.vkCode; - } - if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP) - { - std::unique_lock lock{ pressedKeyMutex }; - PressedKeyDescriptor dummy{ .virtualKey = keyPressInfo.vkCode }; - auto [it, last] = pressedKeyDescriptors.equal_range(dummy); - for (; it != last; ++it) - { - KillTimer(runnerWindow, it->idTimer); - } - vkCodePressed = 0x100; - } - } - - if ((wParam != WM_KEYDOWN) && (wParam != WM_SYSKEYDOWN)) - { - return CallNextHookEx(hHook, nCode, wParam, lParam); - } - - Hotkey hotkey{ - .win = (GetAsyncKeyState(VK_LWIN) & 0x8000) || (GetAsyncKeyState(VK_RWIN) & 0x8000), - .ctrl = static_cast(GetAsyncKeyState(VK_CONTROL) & 0x8000), - .shift = static_cast(GetAsyncKeyState(VK_SHIFT) & 0x8000), - .alt = static_cast(GetAsyncKeyState(VK_MENU) & 0x8000), - .key = static_cast(keyPressInfo.vkCode) - }; - - if (hotkey == Hotkey{}) - { - return CallNextHookEx(hHook, nCode, wParam, lParam); - } - - std::function action; - { - // Hold the lock for the shortest possible duration - std::unique_lock lock{ mutex }; - HotkeyDescriptor dummy{ .hotkey = hotkey }; - auto it = hotkeyDescriptors.find(dummy); - if (it != hotkeyDescriptors.end()) - { - action = it->action; - } - } - - if (action) - { - if (action()) - { - // After invoking the hotkey send a dummy key to prevent Start Menu from activating - INPUT dummyEvent[1] = {}; - dummyEvent[0].type = INPUT_KEYBOARD; - dummyEvent[0].ki.wVk = 0xFF; - dummyEvent[0].ki.dwFlags = KEYEVENTF_KEYUP; - SendInput(1, dummyEvent, sizeof(INPUT)); - - // Swallow the key press - return 1; - } - } - - return CallNextHookEx(hHook, nCode, wParam, lParam); - } - - void SetHotkeyAction(const std::wstring& moduleName, const Hotkey& hotkey, std::function&& action) noexcept - { - Logger::trace(L"Register hotkey action for {}", moduleName); - std::unique_lock lock{ mutex }; - hotkeyDescriptors.insert({ .hotkey = hotkey, .moduleName = moduleName, .action = std::move(action) }); - } - - void AddPressedKeyAction(const std::wstring& moduleName, const DWORD vk, const UINT milliseconds, std::function&& action) noexcept - { - // Calculate a unique TimerID. - auto hash = std::hash{}(moduleName); // Hash the module as the upper part of the timer ID. - const UINT upperId = hash & 0xFFFF; - const UINT lowerId = vk & 0xFFFF; // The key to press can be the lower ID. - const UINT timerId = upperId << 16 | lowerId; - std::unique_lock lock{ pressedKeyMutex }; - pressedKeyDescriptors.insert({ .virtualKey = vk, .moduleName = moduleName, .action = std::move(action), .idTimer = timerId, .millisecondsToPress = milliseconds }); - } - - void ClearModuleHotkeys(const std::wstring& moduleName) noexcept - { - Logger::trace(L"UnRegister hotkey action for {}", moduleName); - { - std::unique_lock lock{ mutex }; - auto it = hotkeyDescriptors.begin(); - while (it != hotkeyDescriptors.end()) - { - if (it->moduleName == moduleName) - { - it = hotkeyDescriptors.erase(it); - } - else - { - ++it; - } - } - } - { - std::unique_lock lock{ pressedKeyMutex }; - auto it = pressedKeyDescriptors.begin(); - while (it != pressedKeyDescriptors.end()) - { - if (it->moduleName == moduleName) - { - it = pressedKeyDescriptors.erase(it); - } - else - { - ++it; - } - } - } - } - - void Start() noexcept - { -#if defined(DISABLE_LOWLEVEL_HOOKS_WHEN_DEBUGGED) - const bool hook_disabled = IsDebuggerPresent(); -#else - const bool hook_disabled = false; -#endif - if (!hook_disabled) - { - if (!hHook) - { - hHook = SetWindowsHookExW(WH_KEYBOARD_LL, KeyboardHookProc, NULL, NULL); - if (!hHook) - { - DWORD errorCode = GetLastError(); - show_last_error_message(L"SetWindowsHookEx", errorCode, L"centralized_kb_hook"); - } - } - } - } - - void Stop() noexcept - { - if (hHook && UnhookWindowsHookEx(hHook)) - { - hHook = NULL; - } - } - - void RegisterWindow(HWND hwnd) noexcept - { - runnerWindow = hwnd; - } -} diff --git a/src/runner/centralized_kb_hook.h b/src/runner/centralized_kb_hook.h deleted file mode 100644 index 1ae36ebacb..0000000000 --- a/src/runner/centralized_kb_hook.h +++ /dev/null @@ -1,15 +0,0 @@ -#include "pch.h" - -#include "../modules/interface/powertoy_module_interface.h" - -namespace CentralizedKeyboardHook -{ - using Hotkey = PowertoyModuleIface::Hotkey; - - void Start() noexcept; - void Stop() noexcept; - void SetHotkeyAction(const std::wstring& moduleName, const Hotkey& hotkey, std::function&& action) noexcept; - void AddPressedKeyAction(const std::wstring& moduleName, const DWORD vk, const UINT milliseconds, std::function&& action) noexcept; - void ClearModuleHotkeys(const std::wstring& moduleName) noexcept; - void RegisterWindow(HWND hwnd) noexcept; -}; diff --git a/src/runner/general_settings.cpp b/src/runner/general_settings.cpp deleted file mode 100644 index 6225ed8f2a..0000000000 --- a/src/runner/general_settings.cpp +++ /dev/null @@ -1,588 +0,0 @@ -#include "pch.h" -#include "general_settings.h" -#include "auto_start_helper.h" -#include "tray_icon.h" -#include "quick_access_host.h" -#include "Generated files/resource.h" -#include "hotkey_conflict_detector.h" - -#include -#include "powertoy_module.h" -#include - -#include "trace.h" -#include "ai_detection.h" -#include -#include -#include - -namespace -{ - json::JsonValue create_empty_shortcut_array_value() - { - return json::JsonValue::Parse(L"[]"); - } - - void ensure_ignored_conflict_properties_shape(json::JsonObject& obj) - { - if (!json::has(obj, L"ignored_shortcuts", json::JsonValueType::Array)) - { - obj.SetNamedValue(L"ignored_shortcuts", create_empty_shortcut_array_value()); - } - } - - json::JsonObject create_default_ignored_conflict_properties() - { - json::JsonObject obj; - ensure_ignored_conflict_properties_shape(obj); - return obj; - } - - DashboardSortOrder parse_dashboard_sort_order(const json::JsonObject& obj, DashboardSortOrder fallback) - { - if (json::has(obj, L"dashboard_sort_order", json::JsonValueType::Number)) - { - const auto raw_value = static_cast(obj.GetNamedNumber(L"dashboard_sort_order", static_cast(static_cast(fallback)))); - return raw_value == static_cast(DashboardSortOrder::ByStatus) ? DashboardSortOrder::ByStatus : DashboardSortOrder::Alphabetical; - } - - if (json::has(obj, L"dashboard_sort_order", json::JsonValueType::String)) - { - const auto raw = obj.GetNamedString(L"dashboard_sort_order"); - if (raw == L"ByStatus") - { - return DashboardSortOrder::ByStatus; - } - - if (raw == L"Alphabetical") - { - return DashboardSortOrder::Alphabetical; - } - } - - return fallback; - } -} - -// TODO: would be nice to get rid of these globals, since they're basically cached json settings -static std::wstring settings_theme = L"system"; -static bool show_tray_icon = true; -static bool show_theme_adaptive_tray_icon = false; -static bool run_as_elevated = false; -static bool show_new_updates_toast_notification = true; -static bool download_updates_automatically = true; -static bool show_whats_new_after_updates = true; -static bool enable_experimentation = true; -static bool enable_warnings_elevated_apps = true; -static bool enable_quick_access = true; -static PowerToysSettings::HotkeyObject quick_access_shortcut; -static DashboardSortOrder dashboard_sort_order = DashboardSortOrder::Alphabetical; -static json::JsonObject ignored_conflict_properties = create_default_ignored_conflict_properties(); - -json::JsonObject GeneralSettings::to_json() -{ - json::JsonObject result; - - auto ignoredProps = ignoredConflictProperties; - ensure_ignored_conflict_properties_shape(ignoredProps); - - result.SetNamedValue(L"startup", json::value(isStartupEnabled)); - if (!startupDisabledReason.empty()) - { - result.SetNamedValue(L"startup_disabled_reason", json::value(startupDisabledReason)); - } - - json::JsonObject enabled; - for (const auto& [name, isEnabled] : isModulesEnabledMap) - { - enabled.SetNamedValue(name, json::value(isEnabled)); - } - result.SetNamedValue(L"enabled", std::move(enabled)); - - result.SetNamedValue(L"show_tray_icon", json::value(showSystemTrayIcon)); - result.SetNamedValue(L"show_theme_adaptive_tray_icon", json::value(showThemeAdaptiveTrayIcon)); - result.SetNamedValue(L"is_elevated", json::value(isElevated)); - result.SetNamedValue(L"run_elevated", json::value(isRunElevated)); - result.SetNamedValue(L"show_new_updates_toast_notification", json::value(showNewUpdatesToastNotification)); - result.SetNamedValue(L"download_updates_automatically", json::value(downloadUpdatesAutomatically)); - result.SetNamedValue(L"show_whats_new_after_updates", json::value(showWhatsNewAfterUpdates)); - result.SetNamedValue(L"enable_experimentation", json::value(enableExperimentation)); - result.SetNamedValue(L"dashboard_sort_order", json::value(static_cast(dashboardSortOrder))); - result.SetNamedValue(L"is_admin", json::value(isAdmin)); - result.SetNamedValue(L"enable_warnings_elevated_apps", json::value(enableWarningsElevatedApps)); - result.SetNamedValue(L"enable_quick_access", json::value(enableQuickAccess)); - result.SetNamedValue(L"quick_access_shortcut", quickAccessShortcut.get_json()); - result.SetNamedValue(L"theme", json::value(theme)); - result.SetNamedValue(L"system_theme", json::value(systemTheme)); - result.SetNamedValue(L"powertoys_version", json::value(powerToysVersion)); - result.SetNamedValue(L"ignored_conflict_properties", json::value(ignoredProps)); - - return result; -} - -json::JsonObject load_general_settings() -{ - auto loaded = PTSettingsHelper::load_general_settings(); - settings_theme = loaded.GetNamedString(L"theme", L"system"); - if (settings_theme != L"dark" && settings_theme != L"light") - { - settings_theme = L"system"; - } - show_tray_icon = loaded.GetNamedBoolean(L"show_tray_icon", true); - show_theme_adaptive_tray_icon = loaded.GetNamedBoolean(L"show_theme_adaptive_tray_icon", false); - run_as_elevated = loaded.GetNamedBoolean(L"run_elevated", false); - show_new_updates_toast_notification = loaded.GetNamedBoolean(L"show_new_updates_toast_notification", true); - download_updates_automatically = loaded.GetNamedBoolean(L"download_updates_automatically", true) && check_user_is_admin(); - show_whats_new_after_updates = loaded.GetNamedBoolean(L"show_whats_new_after_updates", true); - enable_experimentation = loaded.GetNamedBoolean(L"enable_experimentation", true); - enable_warnings_elevated_apps = loaded.GetNamedBoolean(L"enable_warnings_elevated_apps", true); - enable_quick_access = loaded.GetNamedBoolean(L"enable_quick_access", true); - if (json::has(loaded, L"quick_access_shortcut", json::JsonValueType::Object)) - { - quick_access_shortcut = PowerToysSettings::HotkeyObject::from_json(loaded.GetNamedObject(L"quick_access_shortcut")); - } - dashboard_sort_order = parse_dashboard_sort_order(loaded, dashboard_sort_order); - - if (json::has(loaded, L"ignored_conflict_properties", json::JsonValueType::Object)) - { - ignored_conflict_properties = loaded.GetNamedObject(L"ignored_conflict_properties"); - } - else - { - ignored_conflict_properties = create_default_ignored_conflict_properties(); - } - - ensure_ignored_conflict_properties_shape(ignored_conflict_properties); - - return loaded; -} - -GeneralSettings get_general_settings() -{ - const bool is_user_admin = check_user_is_admin(); - GeneralSettings settings - { - .showSystemTrayIcon = show_tray_icon, - .showThemeAdaptiveTrayIcon = show_theme_adaptive_tray_icon, - .isElevated = is_process_elevated(), - .isRunElevated = run_as_elevated, - .isAdmin = is_user_admin, - .enableWarningsElevatedApps = enable_warnings_elevated_apps, - .enableQuickAccess = enable_quick_access, - .quickAccessShortcut = quick_access_shortcut, - .showNewUpdatesToastNotification = show_new_updates_toast_notification, - .downloadUpdatesAutomatically = download_updates_automatically && is_user_admin, - .showWhatsNewAfterUpdates = show_whats_new_after_updates, - .enableExperimentation = enable_experimentation, - .dashboardSortOrder = dashboard_sort_order, - .theme = settings_theme, - .systemTheme = WindowsColors::is_dark_mode() ? L"dark" : L"light", - .powerToysVersion = get_product_version(), - .ignoredConflictProperties = ignored_conflict_properties - }; - - ensure_ignored_conflict_properties_shape(settings.ignoredConflictProperties); - - settings.isStartupEnabled = is_auto_start_task_active_for_this_user(); - - for (auto& [name, powertoy] : modules()) - { - settings.isModulesEnabledMap[name] = powertoy->is_enabled(); - } - - return settings; -} - -void apply_module_status_update(const json::JsonObject& module_config, bool save) -{ - Logger::info(L"apply_module_status_update: {}", std::wstring{ module_config.ToString() }); - - // Expected format: {"ModuleName": true/false} - only one module per update - auto iter = module_config.First(); - if (!iter.HasCurrent()) - { - Logger::warn(L"apply_module_status_update: Empty module config"); - return; - } - - const auto& element = iter.Current(); - const auto value = element.Value(); - if (value.ValueType() != json::JsonValueType::Boolean) - { - Logger::warn(L"apply_module_status_update: Invalid value type for module status"); - return; - } - - const std::wstring name{ element.Key().c_str() }; - if (modules().find(name) == modules().end()) - { - Logger::warn(L"apply_module_status_update: Module {} not found", name); - return; - } - - PowertoyModule& powertoy = modules().at(name); - const bool module_inst_enabled = powertoy->is_enabled(); - bool target_enabled = value.GetBoolean(); - - auto gpo_rule = powertoy->gpo_policy_enabled_configuration(); - if (gpo_rule == powertoys_gpo::gpo_rule_configured_enabled || gpo_rule == powertoys_gpo::gpo_rule_configured_disabled) - { - // Apply the GPO Rule. - target_enabled = gpo_rule == powertoys_gpo::gpo_rule_configured_enabled; - } - - if (module_inst_enabled == target_enabled) - { - Logger::info(L"apply_module_status_update: Module {} already in target state {}", name, target_enabled); - return; - } - - if (target_enabled) - { - Logger::info(L"apply_module_status_update: Enabling powertoy {}", name); - powertoy->enable(); - auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); - hkmng.EnableHotkeyByModule(name); - - // Trigger AI capability detection when ImageResizer is enabled - if (name == L"Image Resizer") - { - Logger::info(L"ImageResizer enabled, triggering AI capability detection"); - DetectAiCapabilitiesAsync(true); // Skip settings check since we know it's being enabled - } - } - else - { - Logger::info(L"apply_module_status_update: Disabling powertoy {}", name); - powertoy->disable(); - auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); - hkmng.DisableHotkeyByModule(name); - } - // Sync the hotkey state with the module state, so it can be removed for disabled modules. - powertoy.UpdateHotkeyEx(); - - if (save) - { - // Load existing settings and only update the specific module's enabled state - json::JsonObject current_settings = PTSettingsHelper::load_general_settings(); - - json::JsonObject enabled; - if (current_settings.HasKey(L"enabled")) - { - enabled = current_settings.GetNamedObject(L"enabled"); - } - - // Check if the saved state is different from the requested state - bool current_saved = enabled.HasKey(name) ? enabled.GetNamedBoolean(name, true) : true; - - if (current_saved != target_enabled) - { - // Update only this module's enabled state - enabled.SetNamedValue(name, json::value(target_enabled)); - current_settings.SetNamedValue(L"enabled", enabled); - - PTSettingsHelper::save_general_settings(current_settings); - - GeneralSettings settings_for_trace = get_general_settings(); - Trace::SettingsChanged(settings_for_trace); - } - } -} - -void apply_general_settings(const json::JsonObject& general_configs, bool save) -{ - std::wstring old_settings_json_string; - if (save) - { - old_settings_json_string = get_general_settings().to_json().Stringify().c_str(); - } - - Logger::info(L"apply_general_settings: {}", std::wstring{ general_configs.ToString() }); - run_as_elevated = general_configs.GetNamedBoolean(L"run_elevated", false); - - enable_warnings_elevated_apps = general_configs.GetNamedBoolean(L"enable_warnings_elevated_apps", true); - - bool new_enable_quick_access = general_configs.GetNamedBoolean(L"enable_quick_access", true); - Logger::info(L"apply_general_settings: enable_quick_access={}, new_enable_quick_access={}", enable_quick_access, new_enable_quick_access); - - PowerToysSettings::HotkeyObject new_quick_access_shortcut; - if (json::has(general_configs, L"quick_access_shortcut", json::JsonValueType::Object)) - { - new_quick_access_shortcut = PowerToysSettings::HotkeyObject::from_json(general_configs.GetNamedObject(L"quick_access_shortcut")); - } - - auto hotkey_equals = [](const PowerToysSettings::HotkeyObject& a, const PowerToysSettings::HotkeyObject& b) { - return a.get_code() == b.get_code() && - a.get_modifiers() == b.get_modifiers(); - }; - - if (enable_quick_access != new_enable_quick_access || !hotkey_equals(quick_access_shortcut, new_quick_access_shortcut)) - { - enable_quick_access = new_enable_quick_access; - quick_access_shortcut = new_quick_access_shortcut; - - if (enable_quick_access) - { - QuickAccessHost::start(); - } - else - { - QuickAccessHost::stop(); - } - update_quick_access_hotkey(enable_quick_access, quick_access_shortcut); - } - - show_new_updates_toast_notification = general_configs.GetNamedBoolean(L"show_new_updates_toast_notification", true); - - download_updates_automatically = general_configs.GetNamedBoolean(L"download_updates_automatically", true); - show_whats_new_after_updates = general_configs.GetNamedBoolean(L"show_whats_new_after_updates", true); - - enable_experimentation = general_configs.GetNamedBoolean(L"enable_experimentation", true); - dashboard_sort_order = parse_dashboard_sort_order(general_configs, dashboard_sort_order); - - // apply_general_settings is called by the runner's WinMain, so we can just force the run at startup gpo rule here. - auto gpo_run_as_startup = powertoys_gpo::getConfiguredRunAtStartupValue(); - - if (json::has(general_configs, L"startup", json::JsonValueType::Boolean)) - { - bool startup = general_configs.GetNamedBoolean(L"startup"); - - if (gpo_run_as_startup == powertoys_gpo::gpo_rule_configured_enabled) - { - startup = true; - } - else if (gpo_run_as_startup == powertoys_gpo::gpo_rule_configured_disabled) - { - startup = false; - } - - if (startup) - { - if (is_process_elevated()) - { - delete_auto_start_task_for_this_user(); - create_auto_start_task_for_this_user(run_as_elevated); - } - else - { - if (!is_auto_start_task_active_for_this_user()) - { - delete_auto_start_task_for_this_user(); - create_auto_start_task_for_this_user(false); - - run_as_elevated = false; - } - else if (!general_configs.GetNamedBoolean(L"run_elevated", false)) - { - delete_auto_start_task_for_this_user(); - create_auto_start_task_for_this_user(false); - } - } - } - else - { - delete_auto_start_task_for_this_user(); - } - } - else - { - delete_auto_start_task_for_this_user(); - if (gpo_run_as_startup == powertoys_gpo::gpo_rule_configured_enabled || gpo_run_as_startup == powertoys_gpo::gpo_rule_configured_not_configured) - { - create_auto_start_task_for_this_user(run_as_elevated); - } - } - - if (json::has(general_configs, L"enabled")) - { - for (const auto& enabled_element : general_configs.GetNamedObject(L"enabled")) - { - const auto value = enabled_element.Value(); - if (value.ValueType() != json::JsonValueType::Boolean) - { - continue; - } - const std::wstring name{ enabled_element.Key().c_str() }; - const bool found = modules().find(name) != modules().end(); - if (!found) - { - continue; - } - PowertoyModule& powertoy = modules().at(name); - const bool module_inst_enabled = powertoy->is_enabled(); - bool target_enabled = value.GetBoolean(); - - auto gpo_rule = powertoy->gpo_policy_enabled_configuration(); - if (gpo_rule == powertoys_gpo::gpo_rule_configured_enabled || gpo_rule == powertoys_gpo::gpo_rule_configured_disabled) - { - // Apply the GPO Rule. - target_enabled = gpo_rule == powertoys_gpo::gpo_rule_configured_enabled; - } - - if (module_inst_enabled == target_enabled) - { - continue; - } - if (target_enabled) - { - Logger::info(L"apply_general_settings: Enabling powertoy {}", name); - powertoy->enable(); - auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); - hkmng.EnableHotkeyByModule(name); - - // Trigger AI capability detection when ImageResizer is enabled - if (name == L"Image Resizer") - { - Logger::info(L"ImageResizer enabled, triggering AI capability detection"); - DetectAiCapabilitiesAsync(true); // Skip settings check since we know it's being enabled - } - } - else - { - Logger::info(L"apply_general_settings: Disabling powertoy {}", name); - powertoy->disable(); - auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); - hkmng.DisableHotkeyByModule(name); - } - // Sync the hotkey state with the module state, so it can be removed for disabled modules. - powertoy.UpdateHotkeyEx(); - } - } - - if (json::has(general_configs, L"theme", json::JsonValueType::String)) - { - settings_theme = general_configs.GetNamedString(L"theme"); - } - - if (json::has(general_configs, L"show_tray_icon", json::JsonValueType::Boolean)) - { - show_tray_icon = general_configs.GetNamedBoolean(L"show_tray_icon"); - set_tray_icon_visible(show_tray_icon); - } - - if (json::has(general_configs, L"show_theme_adaptive_tray_icon", json::JsonValueType::Boolean)) - { - bool new_theme_adaptive = general_configs.GetNamedBoolean(L"show_theme_adaptive_tray_icon"); - Logger::info(L"apply_general_settings: show_theme_adaptive_tray_icon current={}, new={}", - show_theme_adaptive_tray_icon, new_theme_adaptive); - if (show_theme_adaptive_tray_icon != new_theme_adaptive) - { - show_theme_adaptive_tray_icon = new_theme_adaptive; - set_tray_icon_theme_adaptive(show_theme_adaptive_tray_icon); - } - else - { - Logger::info(L"apply_general_settings: show_theme_adaptive_tray_icon unchanged, skipping update"); - } - } - else - { - Logger::warn(L"apply_general_settings: show_theme_adaptive_tray_icon not found in config"); - } - - if (json::has(general_configs, L"ignored_conflict_properties", json::JsonValueType::Object)) - { - ignored_conflict_properties = general_configs.GetNamedObject(L"ignored_conflict_properties"); - ensure_ignored_conflict_properties_shape(ignored_conflict_properties); - } - - if (save) - { - GeneralSettings save_settings = get_general_settings(); - std::wstring new_settings_json_string = save_settings.to_json().Stringify().c_str(); - if (old_settings_json_string != new_settings_json_string) - { - PTSettingsHelper::save_general_settings(save_settings.to_json()); - Trace::SettingsChanged(save_settings); - } - } -} - -void start_enabled_powertoys() -{ - std::unordered_set powertoys_to_disable; - std::unordered_map powertoys_gpo_configuration; - // Take into account default values supplied by modules themselves and gpo configurations - for (auto& [name, powertoy] : modules()) - { - auto gpo_rule = powertoy->gpo_policy_enabled_configuration(); - powertoys_gpo_configuration[name] = gpo_rule; - if (gpo_rule == powertoys_gpo::gpo_rule_configured_unavailable) - { - Logger::warn(L"start_enabled_powertoys: couldn't read the gpo rule for Powertoy {}", name); - } - if (gpo_rule == powertoys_gpo::gpo_rule_configured_wrong_value) - { - Logger::warn(L"start_enabled_powertoys: gpo rule for Powertoy {} is set to an unknown value", name); - } - - if (!powertoy->is_enabled_by_default()) - powertoys_to_disable.emplace(name); - } - - json::JsonObject general_settings; - try - { - general_settings = load_general_settings(); - if (general_settings.HasKey(L"enabled")) - { - json::JsonObject enabled = general_settings.GetNamedObject(L"enabled"); - for (const auto& disabled_element : enabled) - { - std::wstring disable_module_name{ static_cast(disabled_element.Key()) }; - - if (powertoys_gpo_configuration.find(disable_module_name) != powertoys_gpo_configuration.end() && (powertoys_gpo_configuration[disable_module_name] == powertoys_gpo::gpo_rule_configured_enabled || powertoys_gpo_configuration[disable_module_name] == powertoys_gpo::gpo_rule_configured_disabled)) - { - // If gpo forces the enabled setting, no need to check the setting for this PowerToy. It will be applied later on this function. - continue; - } - - // Disable explicitly disabled modules - if (!disabled_element.Value().GetBoolean()) - { - Logger::info(L"start_enabled_powertoys: Powertoy {} explicitly disabled", disable_module_name); - powertoys_to_disable.emplace(std::move(disable_module_name)); - } - // If module was scheduled for disable, but it's enabled in the settings - override default value - else if (auto it = powertoys_to_disable.find(disable_module_name); it != end(powertoys_to_disable)) - { - Logger::info(L"start_enabled_powertoys: Overriding default enabled value for {} powertoy", disable_module_name); - powertoys_to_disable.erase(it); - } - } - } - } - catch (...) - { - } - - for (auto& [name, powertoy] : modules()) - { - bool should_powertoy_be_enabled = true; - - auto gpo_rule = powertoys_gpo_configuration.find(name) != powertoys_gpo_configuration.end() ? powertoys_gpo_configuration[name] : powertoys_gpo::gpo_rule_configured_not_configured; - - if (gpo_rule == powertoys_gpo::gpo_rule_configured_enabled || gpo_rule == powertoys_gpo::gpo_rule_configured_disabled) - { - // Apply the GPO Rule. - should_powertoy_be_enabled = gpo_rule == powertoys_gpo::gpo_rule_configured_enabled; - Logger::info(L"start_enabled_powertoys: GPO sets the enabled state for {} powertoy as {}", name, should_powertoy_be_enabled); - } - else if (powertoys_to_disable.contains(name)) - { - // Apply the settings or default information provided by the PowerToy on first run. - should_powertoy_be_enabled = false; - } - - if (should_powertoy_be_enabled) - { - Logger::info(L"start_enabled_powertoys: Enabling powertoy {}", name); - powertoy->enable(); - auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); - hkmng.EnableHotkeyByModule(name); - powertoy.UpdateHotkeyEx(); - } - } -} - - diff --git a/src/runner/general_settings.h b/src/runner/general_settings.h deleted file mode 100644 index 487e3216da..0000000000 --- a/src/runner/general_settings.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include -#include - -enum class DashboardSortOrder -{ - Alphabetical = 0, - ByStatus = 1, -}; - -struct GeneralSettings -{ - bool isStartupEnabled; - bool showSystemTrayIcon; - bool showThemeAdaptiveTrayIcon; - std::wstring startupDisabledReason; - std::map isModulesEnabledMap; - bool isElevated; - bool isRunElevated; - bool isAdmin; - bool enableWarningsElevatedApps; - bool enableQuickAccess; - PowerToysSettings::HotkeyObject quickAccessShortcut; - bool showNewUpdatesToastNotification; - bool downloadUpdatesAutomatically; - bool showWhatsNewAfterUpdates; - bool enableExperimentation; - DashboardSortOrder dashboardSortOrder; - std::wstring theme; - std::wstring systemTheme; - std::wstring powerToysVersion; - json::JsonObject ignoredConflictProperties; - - json::JsonObject to_json(); -}; - -json::JsonObject load_general_settings(); -GeneralSettings get_general_settings(); -void apply_general_settings(const json::JsonObject& general_configs, bool save = true); -void apply_module_status_update(const json::JsonObject& module_config, bool save = true); -void start_enabled_powertoys(); \ No newline at end of file diff --git a/src/runner/hotkey_conflict_detector.cpp b/src/runner/hotkey_conflict_detector.cpp deleted file mode 100644 index 14c8a1ecd9..0000000000 --- a/src/runner/hotkey_conflict_detector.cpp +++ /dev/null @@ -1,471 +0,0 @@ -#include "pch.h" -#include "hotkey_conflict_detector.h" -#include -#include -#include -#include - -namespace HotkeyConflictDetector -{ - Hotkey ShortcutToHotkey(const CentralizedHotkeys::Shortcut& shortcut) - { - Hotkey hotkey; - - hotkey.win = (shortcut.modifiersMask & MOD_WIN) != 0; - hotkey.ctrl = (shortcut.modifiersMask & MOD_CONTROL) != 0; - hotkey.shift = (shortcut.modifiersMask & MOD_SHIFT) != 0; - hotkey.alt = (shortcut.modifiersMask & MOD_ALT) != 0; - - hotkey.key = shortcut.vkCode > 255 ? 0 : static_cast(shortcut.vkCode); - - return hotkey; - } - - HotkeyConflictManager* HotkeyConflictManager::instance = nullptr; - std::mutex HotkeyConflictManager::instanceMutex; - - HotkeyConflictManager& HotkeyConflictManager::GetInstance() - { - std::lock_guard lock(instanceMutex); - if (instance == nullptr) - { - instance = new HotkeyConflictManager(); - } - return *instance; - } - - HotkeyConflictType HotkeyConflictManager::HasConflict(Hotkey const& _hotkey, const wchar_t* _moduleName, const int _hotkeyID) - { - if (disabledHotkeys.find(_moduleName) != disabledHotkeys.end()) - { - return HotkeyConflictType::NoConflict; - } - - uint16_t handle = GetHotkeyHandle(_hotkey); - - if (handle == 0) - { - return HotkeyConflictType::NoConflict; - } - - // The order is important, first to check sys conflict and then inapp conflict - if (sysConflictHotkeyMap.find(handle) != sysConflictHotkeyMap.end()) - { - return HotkeyConflictType::SystemConflict; - } - - if (inAppConflictHotkeyMap.find(handle) != inAppConflictHotkeyMap.end()) - { - return HotkeyConflictType::InAppConflict; - } - - auto it = hotkeyMap.find(handle); - - if (it == hotkeyMap.end()) - { - return HasConflictWithSystemHotkey(_hotkey) ? - HotkeyConflictType::SystemConflict : - HotkeyConflictType::NoConflict; - } - - if (wcscmp(it->second.moduleName.c_str(), _moduleName) == 0 && it->second.hotkeyID == _hotkeyID) - { - // A shortcut matching its own assignment is not considered a conflict. - return HotkeyConflictType::NoConflict; - } - - return HotkeyConflictType::InAppConflict; - } - - HotkeyConflictType HotkeyConflictManager::HasConflict(Hotkey const& _hotkey) - { - uint16_t handle = GetHotkeyHandle(_hotkey); - - if (handle == 0) - { - return HotkeyConflictType::NoConflict; - } - - // The order is important, first to check sys conflict and then inapp conflict - if (sysConflictHotkeyMap.find(handle) != sysConflictHotkeyMap.end()) - { - return HotkeyConflictType::SystemConflict; - } - - if (inAppConflictHotkeyMap.find(handle) != inAppConflictHotkeyMap.end()) - { - return HotkeyConflictType::InAppConflict; - } - - auto it = hotkeyMap.find(handle); - - if (it == hotkeyMap.end()) - { - return HasConflictWithSystemHotkey(_hotkey) ? - HotkeyConflictType::SystemConflict : - HotkeyConflictType::NoConflict; - } - - return HotkeyConflictType::InAppConflict; - } - - // This function should only be called when a conflict has already been identified. - // It returns a list of all conflicting shortcuts. - std::vector HotkeyConflictManager::GetAllConflicts(Hotkey const& _hotkey) - { - std::vector conflicts; - uint16_t handle = GetHotkeyHandle(_hotkey); - - // Check in-app conflicts first - auto inAppIt = inAppConflictHotkeyMap.find(handle); - if (inAppIt != inAppConflictHotkeyMap.end()) - { - // Add all in-app conflicts - for (const auto& conflict : inAppIt->second) - { - conflicts.push_back(conflict); - } - - return conflicts; - } - - // Check system conflicts - auto sysIt = sysConflictHotkeyMap.find(handle); - if (sysIt != sysConflictHotkeyMap.end()) - { - HotkeyConflictInfo systemConflict; - systemConflict.hotkey = _hotkey; - systemConflict.moduleName = L"System"; - systemConflict.hotkeyID = 0; - - conflicts.push_back(systemConflict); - - return conflicts; - } - - // Check if there's a successfully registered hotkey that would conflict - auto registeredIt = hotkeyMap.find(handle); - if (registeredIt != hotkeyMap.end()) - { - conflicts.push_back(registeredIt->second); - - return conflicts; - } - - // If all the above conditions are ruled out, a system-level conflict is the only remaining explanation. - HotkeyConflictInfo systemConflict; - systemConflict.hotkey = _hotkey; - systemConflict.moduleName = L"System"; - systemConflict.hotkeyID = 0; - conflicts.push_back(systemConflict); - - return conflicts; - } - - bool HotkeyConflictManager::AddHotkey(Hotkey const& _hotkey, const wchar_t* _moduleName, const int _hotkeyID, bool isEnabled) - { - if (!isEnabled) - { - disabledHotkeys[_moduleName].push_back({ _hotkey, _moduleName, _hotkeyID }); - return true; - } - - uint16_t handle = GetHotkeyHandle(_hotkey); - - if (handle == 0) - { - return false; - } - - HotkeyConflictType conflictType = HasConflict(_hotkey, _moduleName, _hotkeyID); - if (conflictType != HotkeyConflictType::NoConflict) - { - if (conflictType == HotkeyConflictType::InAppConflict) - { - auto hotkeyFound = hotkeyMap.find(handle); - inAppConflictHotkeyMap[handle].insert({ _hotkey, _moduleName, _hotkeyID }); - - if (hotkeyFound != hotkeyMap.end()) - { - inAppConflictHotkeyMap[handle].insert(hotkeyFound->second); - hotkeyMap.erase(hotkeyFound); - } - } - else - { - sysConflictHotkeyMap[handle].insert({ _hotkey, _moduleName, _hotkeyID }); - } - return false; - } - - HotkeyConflictInfo hotkeyInfo; - hotkeyInfo.moduleName = _moduleName; - hotkeyInfo.hotkeyID = _hotkeyID; - hotkeyInfo.hotkey = _hotkey; - hotkeyMap[handle] = hotkeyInfo; - - return true; - } - - std::vector HotkeyConflictManager::RemoveHotkeyByModule(const std::wstring& moduleName) - { - std::vector removedHotkeys; - - if (disabledHotkeys.find(moduleName) != disabledHotkeys.end()) - { - disabledHotkeys.erase(moduleName); - } - - std::lock_guard lock(hotkeyMutex); - bool foundRecord = false; - - for (auto it = sysConflictHotkeyMap.begin(); it != sysConflictHotkeyMap.end();) - { - auto& conflictSet = it->second; - for (auto setIt = conflictSet.begin(); setIt != conflictSet.end();) - { - if (setIt->moduleName == moduleName) - { - removedHotkeys.push_back(*setIt); - setIt = conflictSet.erase(setIt); - foundRecord = true; - } - else - { - ++setIt; - } - } - if (conflictSet.empty()) - { - it = sysConflictHotkeyMap.erase(it); - } - else - { - ++it; - } - } - - for (auto it = inAppConflictHotkeyMap.begin(); it != inAppConflictHotkeyMap.end();) - { - auto& conflictSet = it->second; - uint16_t handle = it->first; - - for (auto setIt = conflictSet.begin(); setIt != conflictSet.end();) - { - if (setIt->moduleName == moduleName) - { - removedHotkeys.push_back(*setIt); - setIt = conflictSet.erase(setIt); - foundRecord = true; - } - else - { - ++setIt; - } - } - - if (conflictSet.empty()) - { - it = inAppConflictHotkeyMap.erase(it); - } - else if (conflictSet.size() == 1) - { - // Move the only remaining conflict to main map - const auto& onlyConflict = *conflictSet.begin(); - hotkeyMap[handle] = onlyConflict; - it = inAppConflictHotkeyMap.erase(it); - } - else - { - ++it; - } - } - - for (auto it = hotkeyMap.begin(); it != hotkeyMap.end();) - { - if (it->second.moduleName == moduleName) - { - uint16_t handle = it->first; - removedHotkeys.push_back(it->second); - it = hotkeyMap.erase(it); - foundRecord = true; - - auto inAppIt = inAppConflictHotkeyMap.find(handle); - if (inAppIt != inAppConflictHotkeyMap.end() && inAppIt->second.size() == 1) - { - // Move the only in-app conflict to main map - const auto& onlyConflict = *inAppIt->second.begin(); - hotkeyMap[handle] = onlyConflict; - inAppConflictHotkeyMap.erase(inAppIt); - } - } - else - { - ++it; - } - } - - return removedHotkeys; - } - - void HotkeyConflictManager::EnableHotkeyByModule(const std::wstring& moduleName) - { - if (disabledHotkeys.find(moduleName) == disabledHotkeys.end()) - { - return; // No disabled hotkeys for this module - } - - auto hotkeys = disabledHotkeys[moduleName]; - disabledHotkeys.erase(moduleName); - - for (const auto& hotkeyInfo : hotkeys) - { - // Re-add the hotkey as enabled - AddHotkey(hotkeyInfo.hotkey, moduleName.c_str(), hotkeyInfo.hotkeyID, true); - } - } - - void HotkeyConflictManager::DisableHotkeyByModule(const std::wstring& moduleName) - { - auto hotkeys = RemoveHotkeyByModule(moduleName); - disabledHotkeys[moduleName] = hotkeys; - } - - bool HotkeyConflictManager::HasConflictWithSystemHotkey(const Hotkey& hotkey) - { - // Convert PowerToys Hotkey format to Win32 RegisterHotKey format - UINT modifiers = 0; - if (hotkey.win) - { - modifiers |= MOD_WIN; - } - if (hotkey.ctrl) - { - modifiers |= MOD_CONTROL; - } - if (hotkey.alt) - { - modifiers |= MOD_ALT; - } - if (hotkey.shift) - { - modifiers |= MOD_SHIFT; - } - - // No modifiers or no key is not a valid hotkey - if (modifiers == 0 || hotkey.key == 0) - { - return false; - } - - // Use a unique ID for this test registration - const int hotkeyId = 0x0FFF; // Arbitrary ID for temporary registration - - // Try to register the hotkey with Windows, using nullptr instead of a window handle - if (!RegisterHotKey(nullptr, hotkeyId, modifiers, hotkey.key)) - { - // If registration fails with ERROR_HOTKEY_ALREADY_REGISTERED, it means the hotkey - // is already in use by the system or another application - if (GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED) - { - return true; - } - } - else - { - // If registration succeeds, unregister it immediately - UnregisterHotKey(nullptr, hotkeyId); - } - - return false; - } - - json::JsonObject HotkeyConflictManager::GetHotkeyConflictsAsJson() - { - std::lock_guard lock(hotkeyMutex); - - using namespace json; - JsonObject root; - - // Serialize hotkey to a unique string format for grouping - auto serializeHotkey = [](const Hotkey& hotkey) -> JsonObject { - JsonObject obj; - obj.Insert(L"win", value(hotkey.win)); - obj.Insert(L"ctrl", value(hotkey.ctrl)); - obj.Insert(L"shift", value(hotkey.shift)); - obj.Insert(L"alt", value(hotkey.alt)); - obj.Insert(L"key", value(static_cast(hotkey.key))); - return obj; - }; - - // New format: Group conflicts by hotkey - JsonArray inAppConflictsArray; - JsonArray sysConflictsArray; - - // Process in-app conflicts - only include hotkeys that are actually in conflict - for (const auto& [handle, conflicts] : inAppConflictHotkeyMap) - { - if (!conflicts.empty()) - { - JsonObject conflictGroup; - - // All entries have the same hotkey, so use the first one for the key - conflictGroup.Insert(L"hotkey", serializeHotkey(conflicts.begin()->hotkey)); - - // Create an array of module info without repeating the hotkey - JsonArray modules; - for (const auto& info : conflicts) - { - JsonObject moduleInfo; - moduleInfo.Insert(L"moduleName", value(info.moduleName)); - moduleInfo.Insert(L"hotkeyID", value(info.hotkeyID)); - modules.Append(moduleInfo); - } - - conflictGroup.Insert(L"modules", modules); - inAppConflictsArray.Append(conflictGroup); - } - } - - // Process system conflicts - only include hotkeys that are actually in conflict - for (const auto& [handle, conflicts] : sysConflictHotkeyMap) - { - if (!conflicts.empty()) - { - JsonObject conflictGroup; - - // All entries have the same hotkey, so use the first one for the key - conflictGroup.Insert(L"hotkey", serializeHotkey(conflicts.begin()->hotkey)); - - // Create an array of module info without repeating the hotkey - JsonArray modules; - for (const auto& info : conflicts) - { - JsonObject moduleInfo; - moduleInfo.Insert(L"moduleName", value(info.moduleName)); - moduleInfo.Insert(L"hotkeyID", value(info.hotkeyID)); - modules.Append(moduleInfo); - } - - conflictGroup.Insert(L"modules", modules); - sysConflictsArray.Append(conflictGroup); - } - } - - // Add the grouped conflicts to the root object - root.Insert(L"inAppConflicts", inAppConflictsArray); - root.Insert(L"sysConflicts", sysConflictsArray); - - return root; - } - - uint16_t HotkeyConflictManager::GetHotkeyHandle(const Hotkey& hotkey) - { - uint16_t handle = hotkey.key; - handle |= hotkey.win << 8; - handle |= hotkey.ctrl << 9; - handle |= hotkey.shift << 10; - handle |= hotkey.alt << 11; - return handle; - } -} \ No newline at end of file diff --git a/src/runner/hotkey_conflict_detector.h b/src/runner/hotkey_conflict_detector.h deleted file mode 100644 index c32954e3e4..0000000000 --- a/src/runner/hotkey_conflict_detector.h +++ /dev/null @@ -1,100 +0,0 @@ -#pragma once -#include "pch.h" -#include -#include -#include - -#include "../modules/interface/powertoy_module_interface.h" -#include "centralized_hotkeys.h" -#include "common/utils/json.h" - -namespace HotkeyConflictDetector -{ - using Hotkey = PowertoyModuleIface::Hotkey; - using HotkeyEx = PowertoyModuleIface::HotkeyEx; - using Shortcut = CentralizedHotkeys::Shortcut; - - struct HotkeyConflictInfo - { - Hotkey hotkey; - std::wstring moduleName; - int hotkeyID = 0; - - inline bool operator==(const HotkeyConflictInfo& other) const - { - return hotkey == other.hotkey && - moduleName == other.moduleName && - hotkeyID == other.hotkeyID; - } - }; - - Hotkey ShortcutToHotkey(const CentralizedHotkeys::Shortcut& shortcut); - - enum HotkeyConflictType - { - NoConflict = 0, - SystemConflict = 1, - InAppConflict = 2, - }; - - class HotkeyConflictManager - { - public: - static HotkeyConflictManager& GetInstance(); - - HotkeyConflictType HasConflict(const Hotkey& hotkey, const wchar_t* moduleName, const int hotkeyID); - HotkeyConflictType HotkeyConflictManager::HasConflict(Hotkey const& _hotkey); - std::vector HotkeyConflictManager::GetAllConflicts(Hotkey const& hotkey); - bool AddHotkey(const Hotkey& hotkey, const wchar_t* moduleName, const int hotkeyID, bool isEnabled); - std::vector RemoveHotkeyByModule(const std::wstring& moduleName); - - void EnableHotkeyByModule(const std::wstring& moduleName); - void DisableHotkeyByModule(const std::wstring& moduleName); - - json::JsonObject GetHotkeyConflictsAsJson(); - - private: - static std::mutex instanceMutex; - static HotkeyConflictManager* instance; - - std::mutex hotkeyMutex; - // Hotkey in hotkeyMap means the hotkey has been registered successfully - std::unordered_map hotkeyMap; - // Hotkey in sysConflictHotkeyMap means the hotkey has conflict with system defined hotkeys - std::unordered_map> sysConflictHotkeyMap; - // Hotkey in inAppConflictHotkeyMap means the hotkey has conflict with other modules - std::unordered_map> inAppConflictHotkeyMap; - - std::unordered_map> disabledHotkeys; - - uint16_t GetHotkeyHandle(const Hotkey&); - bool HasConflictWithSystemHotkey(const Hotkey&); - - HotkeyConflictManager() = default; - }; -}; - -namespace std -{ - template<> - struct hash - { - size_t operator()(const HotkeyConflictDetector::HotkeyConflictInfo& info) const - { - - size_t hotkeyHash = - (info.hotkey.win ? 1ULL : 0ULL) | - ((info.hotkey.ctrl ? 1ULL : 0ULL) << 1) | - ((info.hotkey.shift ? 1ULL : 0ULL) << 2) | - ((info.hotkey.alt ? 1ULL : 0ULL) << 3) | - (static_cast(info.hotkey.key) << 4); - - size_t moduleHash = std::hash{}(info.moduleName); - size_t idHash = std::hash{}(info.hotkeyID); - - return hotkeyHash ^ - ((moduleHash << 1) | (moduleHash >> (sizeof(size_t) * 8 - 1))) ^ // rotate left 1 bit - ((idHash << 2) | (idHash >> (sizeof(size_t) * 8 - 2))); // rotate left 2 bits - } - }; -} diff --git a/src/runner/main.cpp b/src/runner/main.cpp deleted file mode 100644 index 973cee4ba5..0000000000 --- a/src/runner/main.cpp +++ /dev/null @@ -1,643 +0,0 @@ -#include "pch.h" -#include -#include -#include -#include -#include "tray_icon.h" -#include "powertoy_module.h" -#include "trace.h" -#include "general_settings.h" -#include "restart_elevated.h" -#include "RestartManagement.h" -#include "Generated files/resource.h" -#include "settings_telemetry.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "UpdateUtils.h" -#include "ActionRunnerUtils.h" - -#include - -#include -#include -#include -#include "centralized_kb_hook.h" -#include "centralized_hotkeys.h" -#include "quick_access_host.h" -#include "ai_detection.h" -#include - -#if _DEBUG && _WIN64 -#include "unhandled_exception_handler.h" -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// disabling warning 4458 - declaration of 'identifier' hides class member -// to avoid warnings from GDI files - can't add winRT directory to external code -// in the Cpp.Build.props -#pragma warning(push) -#pragma warning(disable : 4458) -#include -#pragma warning(pop) - -namespace -{ - const wchar_t PT_URI_PROTOCOL_SCHEME[] = L"powertoys://"; - const wchar_t POWER_TOYS_MODULE_LOAD_FAIL[] = L"Failed to load "; // Module name will be appended on this message and it is not localized. -} - -void chdir_current_executable() -{ - // Change current directory to the path of the executable. - WCHAR executable_path[MAX_PATH]; - GetModuleFileName(NULL, executable_path, MAX_PATH); - PathRemoveFileSpec(executable_path); - if (!SetCurrentDirectory(executable_path)) - { - show_last_error_message(L"Change Directory to Executable Path", GetLastError(), L"PowerToys - runner"); - } -} - -// Detect AI capabilities by calling ImageResizer in detection mode. -// This runs in a background thread to avoid blocking the main startup. -// ImageResizer writes the result to a cache file that it reads on normal startup. -void DetectAiCapabilitiesAsync(bool skipSettingsCheck) -{ - std::thread([skipSettingsCheck]() { - try - { - // Check if ImageResizer module is enabled (skip if called from apply_general_settings) - if (!skipSettingsCheck) - { - auto settings = PTSettingsHelper::load_general_settings(); - if (json::has(settings, L"enabled", json::JsonValueType::Object)) - { - auto enabledModules = settings.GetNamedObject(L"enabled"); - if (json::has(enabledModules, L"Image Resizer", json::JsonValueType::Boolean)) - { - bool isEnabled = enabledModules.GetNamedBoolean(L"Image Resizer", false); - if (!isEnabled) - { - Logger::info(L"ImageResizer module is disabled, skipping AI detection"); - return; - } - } - } - } - - // Get ImageResizer.exe path (located in WinUI3Apps folder) - std::wstring imageResizerPath = get_module_folderpath(); - imageResizerPath += L"\\WinUI3Apps\\PowerToys.ImageResizer.exe"; - - if (!std::filesystem::exists(imageResizerPath)) - { - Logger::warn(L"ImageResizer.exe not found at {}, skipping AI detection", imageResizerPath); - return; - } - - Logger::info(L"Starting AI capability detection via ImageResizer"); - - // Call ImageResizer --detect-ai - SHELLEXECUTEINFO sei = { sizeof(sei) }; - sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI; - sei.lpFile = imageResizerPath.c_str(); - sei.lpParameters = L"--detect-ai"; - sei.nShow = SW_HIDE; - - if (ShellExecuteExW(&sei)) - { - // Wait for detection to complete (with timeout) - DWORD waitResult = WaitForSingleObject(sei.hProcess, 30000); // 30 second timeout - CloseHandle(sei.hProcess); - - if (waitResult == WAIT_OBJECT_0) - { - Logger::info(L"AI capability detection completed successfully"); - } - else if (waitResult == WAIT_TIMEOUT) - { - Logger::warn(L"AI capability detection timed out"); - } - else - { - Logger::warn(L"AI capability detection wait failed"); - } - } - else - { - Logger::warn(L"Failed to launch ImageResizer for AI detection, error: {}", GetLastError()); - } - } - catch (const std::exception& e) - { - Logger::error("Exception during AI capability detection: {}", e.what()); - } - catch (...) - { - Logger::error("Unknown exception during AI capability detection"); - } - }).detach(); -} - -inline wil::unique_mutex_nothrow create_msi_mutex() -{ - return createAppMutex(POWERTOYS_MSI_MUTEX_NAME); -} - -void open_menu_from_another_instance(std::optional settings_window) -{ - const HWND hwnd_main = FindWindowW(L"PToyTrayIconWindow", nullptr); - LPARAM msg = static_cast(ESettingsWindowNames::Dashboard); - if (settings_window.has_value() && settings_window.value() != "") - { - msg = static_cast(ESettingsWindowNames_from_string(settings_window.value())); - } - PostMessageW(hwnd_main, WM_COMMAND, ID_SETTINGS_MENU_COMMAND, msg); - SetForegroundWindow(hwnd_main); // Bring the settings window to the front -} - -int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow, bool openOobe, bool openScoobe, bool showRestartNotificationAfterUpdate) -{ - Logger::info("Runner is starting. Elevated={} openOobe={} openScoobe={} showRestartNotificationAfterUpdate={}", isProcessElevated, openOobe, openScoobe, showRestartNotificationAfterUpdate); - DPIAware::EnableDPIAwarenessForThisProcess(); - -#if _DEBUG && _WIN64 -//Global error handlers to diagnose errors. -//We prefer this not to show any longer until there's a bug to diagnose. -//init_global_error_handlers(); -#endif - Trace::RegisterProvider(); - - // Load settings from file before reading them - load_general_settings(); - auto const settings = get_general_settings(); - start_tray_icon(isProcessElevated, settings.showThemeAdaptiveTrayIcon); - - if (settings.enableQuickAccess) - { - QuickAccessHost::start(); - } - update_quick_access_hotkey(settings.enableQuickAccess, settings.quickAccessShortcut); - set_tray_icon_visible(settings.showSystemTrayIcon); - CentralizedKeyboardHook::Start(); - - int result = -1; - try - { - if (!openOobe && showRestartNotificationAfterUpdate) - { - std::thread{ - [] { - // Wait a bit, because Windows has a delay until it picks up toast notification registration in the registry - Sleep(10000); - Logger::info("Showing toast notification asking to restart PC"); - notifications::show_toast(GET_RESOURCE_STRING(IDS_PT_VERSION_CHANGE_ASK_FOR_COMPUTER_RESTART).c_str(), L"PowerToys"); - } - }.detach(); - } - - std::thread{ [] { - PeriodicUpdateWorker(); - } }.detach(); - - // Start AI capability detection in background (Windows 11+ only) - // AI Super Resolution is not supported on Windows 10 - // This calls ImageResizer --detect-ai which writes result to cache file - if (package::IsWin11OrGreater()) - { - DetectAiCapabilitiesAsync(); - } - else - { - Logger::info(L"AI capability detection skipped: Windows 10 does not support AI Super Resolution"); - } - - std::thread{ [] { - if (updating::uninstall_previous_msix_version_async().get()) - { - notifications::show_toast(GET_RESOURCE_STRING(IDS_OLDER_MSIX_UNINSTALLED).c_str(), L"PowerToys"); - } - } }.detach(); - - chdir_current_executable(); - - // We deprecated a utility called Video Conference Mute, which registered itself as a video input device. - // When running elevated, we try to clean up the device registration from previous installations. - // This is done here too because a user-scope installer won't be able to remove the driver registration due to lack of permissions. - if (isProcessElevated) - { - clean_video_conference(); - } - - // Load PowerToys DLLs - - std::vector knownModules = { - L"PowerToys.FancyZonesModuleInterface.dll", - L"PowerToys.powerpreview.dll", - L"WinUI3Apps/PowerToys.ImageResizerExt.dll", - L"PowerToys.KeyboardManager.dll", - L"PowerToys.Launcher.dll", - L"WinUI3Apps/PowerToys.PowerRenameExt.dll", - L"PowerToys.ShortcutGuideModuleInterface.dll", - L"PowerToys.ColorPicker.dll", - L"PowerToys.AwakeModuleInterface.dll", - L"PowerToys.FindMyMouse.dll", - L"PowerToys.MouseHighlighter.dll", - L"PowerToys.MouseJump.dll", - L"PowerToys.AlwaysOnTopModuleInterface.dll", - L"PowerToys.MousePointerCrosshairs.dll", - L"PowerToys.CursorWrap.dll", - L"PowerToys.PowerAccentModuleInterface.dll", - L"PowerToys.PowerOCRModuleInterface.dll", - L"PowerToys.AdvancedPasteModuleInterface.dll", - L"WinUI3Apps/PowerToys.FileLocksmithExt.dll", - L"WinUI3Apps/PowerToys.RegistryPreviewExt.dll", - L"WinUI3Apps/PowerToys.MeasureToolModuleInterface.dll", - L"WinUI3Apps/PowerToys.NewPlus.ShellExtension.dll", - L"WinUI3Apps/PowerToys.HostsModuleInterface.dll", - L"WinUI3Apps/PowerToys.Peek.dll", - L"WinUI3Apps/PowerToys.EnvironmentVariablesModuleInterface.dll", - L"PowerToys.MouseWithoutBordersModuleInterface.dll", - L"PowerToys.CropAndLockModuleInterface.dll", - L"PowerToys.CmdNotFoundModuleInterface.dll", - L"PowerToys.WorkspacesModuleInterface.dll", - L"PowerToys.CmdPalModuleInterface.dll", - L"PowerToys.ZoomItModuleInterface.dll", - L"PowerToys.LightSwitchModuleInterface.dll", - L"PowerToys.PowerDisplayModuleInterface.dll", - }; - - for (auto moduleSubdir : knownModules) - { - try - { - auto pt_module = load_powertoy(moduleSubdir); - modules().emplace(pt_module->get_key(), std::move(pt_module)); - } - catch (...) - { - std::wstring errorMessage = POWER_TOYS_MODULE_LOAD_FAIL; - errorMessage += moduleSubdir; - -#ifdef _DEBUG - // In debug mode, simply log the warning and continue execution. - // This contrasts with the past approach where developers had to build all modules - // without errors before debugging—slowing down quick clone-and-fix iterations. - Logger::warn(L"Debug mode: {}", errorMessage); -#else - // In release mode, show error dialog as before - MessageBoxW(NULL, - errorMessage.c_str(), - L"PowerToys", - MB_OK | MB_ICONERROR); -#endif - } - } - // Start initial powertoys - start_enabled_powertoys(); - std::wstring product_version = get_product_version(); - Trace::EventLaunch(product_version, isProcessElevated); - PTSettingsHelper::save_last_version_run(product_version); - - if (openSettings) - { - std::optional window; - if (!settingsWindow.empty()) - { - window = winrt::to_hstring(settingsWindow); - } - open_settings_window(window); - } - - if (openOobe) - { - PTSettingsHelper::save_oobe_opened_state(); - open_oobe_window(); - } - else if (openScoobe) - { - open_scoobe_window(); - } - - settings_telemetry::init(); - result = run_message_loop(); - } - catch (std::runtime_error& err) - { - std::string err_what = err.what(); - MessageBoxW(nullptr, std::wstring(err_what.begin(), err_what.end()).c_str(), GET_RESOURCE_STRING(IDS_ERROR).c_str(), MB_OK | MB_ICONERROR | MB_SETFOREGROUND); - result = -1; - } - Trace::UnregisterProvider(); - QuickAccessHost::stop(); - return result; -} - -// If the PT runner is launched as part of some action and manually by a user, e.g. being activated as a COM server -// for background toast notification handling, we should execute corresponding code flow instead of the main code flow. -enum class SpecialMode -{ - None, - Win32ToastNotificationCOMServer, - ToastNotificationHandler, - ReportSuccessfulUpdate -}; - -SpecialMode should_run_in_special_mode(const int n_cmd_args, LPWSTR* cmd_arg_list) -{ - for (size_t i = 1; i < n_cmd_args; ++i) - { - if (!wcscmp(notifications::TOAST_ACTIVATED_LAUNCH_ARG, cmd_arg_list[i])) - { - return SpecialMode::Win32ToastNotificationCOMServer; - } - else if (n_cmd_args == 2 && !wcsncmp(PT_URI_PROTOCOL_SCHEME, cmd_arg_list[i], wcslen(PT_URI_PROTOCOL_SCHEME))) - { - return SpecialMode::ToastNotificationHandler; - } - else if (n_cmd_args == 2 && !wcscmp(cmdArg::UPDATE_REPORT_SUCCESS, cmd_arg_list[i])) - { - return SpecialMode::ReportSuccessfulUpdate; - } - } - - return SpecialMode::None; -} - -int win32_toast_notification_COM_server_mode() -{ - notifications::run_desktop_app_activator_loop(); - return 0; -} - -enum class toast_notification_handler_result -{ - exit_success, - exit_error -}; - -toast_notification_handler_result toast_notification_handler(const std::wstring_view param) -{ - const std::wstring_view cant_drag_elevated_disable = L"cant_drag_elevated_disable/"; - const std::wstring_view couldnt_toggle_powerpreview_modules_disable = L"couldnt_toggle_powerpreview_modules_disable/"; - const std::wstring_view open_settings = L"open_settings/"; - const std::wstring_view open_overview = L"open_overview/"; - const std::wstring_view update_now = L"update_now/"; - - if (param == cant_drag_elevated_disable) - { - return notifications::disable_toast(notifications::ElevatedDontShowAgainRegistryPath) ? toast_notification_handler_result::exit_success : toast_notification_handler_result::exit_error; - } - else if (param.starts_with(update_now)) - { - std::wstring args{ cmdArg::UPDATE_NOW_LAUNCH_STAGE1 }; - LaunchPowerToysUpdate(args.c_str()); - return toast_notification_handler_result::exit_success; - } - else if (param == couldnt_toggle_powerpreview_modules_disable) - { - return notifications::disable_toast(notifications::PreviewModulesDontShowAgainRegistryPath) ? toast_notification_handler_result::exit_success : toast_notification_handler_result::exit_error; - } - else if (param == open_settings) - { - open_menu_from_another_instance(std::nullopt); - return toast_notification_handler_result::exit_success; - } - else if (param == open_overview) - { - open_menu_from_another_instance("Overview"); - return toast_notification_handler_result::exit_success; - } - else - { - return toast_notification_handler_result::exit_error; - } -} - -int WINAPI WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR lpCmdLine, int /*nCmdShow*/) -{ - Shared::Trace::ETWTrace trace{}; - trace.UpdateState(true); - - Gdiplus::GdiplusStartupInput gpStartupInput; - ULONG_PTR gpToken; - GdiplusStartup(&gpToken, &gpStartupInput, NULL); - - winrt::init_apartment(); - - const wchar_t* securityDescriptor = - L"O:BA" // Owner: Builtin (local) administrator - L"G:BA" // Group: Builtin (local) administrator - L"D:" - L"(A;;0x7;;;PS)" // Access allowed on COM_RIGHTS_EXECUTE, _LOCAL, & _REMOTE for Personal self - L"(A;;0x7;;;IU)" // Access allowed on COM_RIGHTS_EXECUTE for Interactive Users - L"(A;;0x3;;;SY)" // Access allowed on COM_RIGHTS_EXECUTE, & _LOCAL for Local system - L"(A;;0x7;;;BA)" // Access allowed on COM_RIGHTS_EXECUTE, _LOCAL, & _REMOTE for Builtin (local) administrator - L"(A;;0x3;;;S-1-15-3-1310292540-1029022339-4008023048-2190398717-53961996-4257829345-603366646)" // Access allowed on COM_RIGHTS_EXECUTE, & _LOCAL for Win32WebViewHost package capability - L"S:" - L"(ML;;NX;;;LW)"; // Integrity label on No execute up for Low mandatory level - initializeCOMSecurity(securityDescriptor); - - int n_cmd_args = 0; - LPWSTR* cmd_arg_list = CommandLineToArgvW(GetCommandLineW(), &n_cmd_args); - switch (should_run_in_special_mode(n_cmd_args, cmd_arg_list)) - { - case SpecialMode::Win32ToastNotificationCOMServer: - return win32_toast_notification_COM_server_mode(); - case SpecialMode::ToastNotificationHandler: - switch (toast_notification_handler(cmd_arg_list[1] + wcslen(PT_URI_PROTOCOL_SCHEME))) - { - case toast_notification_handler_result::exit_error: - return 1; - case toast_notification_handler_result::exit_success: - return 0; - } - [[fallthrough]]; - case SpecialMode::ReportSuccessfulUpdate: - { - notifications::remove_toasts_by_tag(notifications::UPDATING_PROCESS_TOAST_TAG); - notifications::remove_all_scheduled_toasts(); - notifications::show_toast(GET_RESOURCE_STRING(IDS_PT_UPDATE_MESSAGE_BOX_TEXT), - L"PowerToys", - notifications::toast_params{ notifications::UPDATING_PROCESS_TOAST_TAG }); - break; - } - - case SpecialMode::None: - // continue as usual - break; - } - - std::filesystem::path logFilePath(PTSettingsHelper::get_root_save_folder_location()); - logFilePath.append(LogSettings::runnerLogPath); - Logger::init(LogSettings::runnerLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location()); - - const std::string cmdLine{ lpCmdLine }; - Logger::info("Running powertoys with cmd args: {}", cmdLine); - - auto open_settings_it = cmdLine.find("--open-settings"); - const bool open_settings = open_settings_it != std::string::npos; - // Check if opening specific settings window - open_settings_it = cmdLine.find("--open-settings="); - std::string settings_window; - if (open_settings_it != std::string::npos) - { - std::string rest_of_cmd_line{ cmdLine, open_settings_it + std::string{ "--open-settings=" }.size() }; - std::istringstream iss(rest_of_cmd_line); - iss >> settings_window; - } - - // Check if another instance is already running. - wil::unique_mutex_nothrow msi_mutex = create_msi_mutex(); - if (!msi_mutex) - { - open_menu_from_another_instance(settings_window); - return 0; - } - - bool openOobe = false; - try - { - openOobe = !PTSettingsHelper::get_oobe_opened_state(); - } - catch (const std::exception& e) - { - Logger::error("Failed to get or save OOBE state with an exception: {}", e.what()); - } - - bool openScoobe = false; - bool showRestartNotificationAfterUpdate = false; - try - { - std::wstring last_version_run = PTSettingsHelper::get_last_version_run(); - const auto product_version = get_product_version(); - openScoobe = product_version != last_version_run; - showRestartNotificationAfterUpdate = openScoobe; - Logger::info(L"Scoobe: product_version={} last_version_run={}", product_version, last_version_run); - } - catch (const std::exception& e) - { - Logger::error("Failed to get last version with an exception: {}", e.what()); - } - - int result = 0; - try - { - // Singletons initialization order needs to be preserved, first events and - // then modules to guarantee the reverse destruction order. - modules(); - - std::thread{ [] { - auto state = UpdateState::read(); - if (state.state == UpdateState::upToDate) - { - updating::cleanup_updates(); - } - } }.detach(); - - auto general_settings = load_general_settings(); - - // Apply the general settings but don't save it as the modules() variable has not been loaded yet - apply_general_settings(general_settings, false); - const bool elevated = is_process_elevated(); - const bool with_dont_elevate_arg = cmdLine.find("--dont-elevate") != std::string::npos; - const bool run_elevated_setting = general_settings.GetNamedBoolean(L"run_elevated", false); - const bool with_restartedElevated_arg = cmdLine.find("--restartedElevated") != std::string::npos; - - // Update scoobe behavior based on setting and gpo - bool scoobeSettingDisabled = general_settings.GetNamedBoolean(L"show_whats_new_after_updates", true) == false; - bool scoobeDisabledByGpo = powertoys_gpo::getDisableShowWhatsNewAfterUpdatesValue() == powertoys_gpo::gpo_rule_configured_enabled; - if (openScoobe && (scoobeSettingDisabled || scoobeDisabledByGpo)) - { - // Scoobe should show after an update, but is disabled by policy or setting - Logger::info(L"Scoobe: Showing scoobe after updates is disabled by setting or by GPO."); - openScoobe = false; - } - - bool dataDiagnosticsDisabledByGpo = powertoys_gpo::getAllowDataDiagnosticsValue() == powertoys_gpo::gpo_rule_configured_disabled; - if (dataDiagnosticsDisabledByGpo) - { - Logger::info(L"Data diagnostics: Data diagnostics is disabled by GPO."); - PTSettingsHelper::save_data_diagnostics(false); - } - - if (elevated && with_dont_elevate_arg && !run_elevated_setting) - { - Logger::info("Scheduling restart as non elevated"); - schedule_restart_as_non_elevated(); - result = 0; - } - else if (elevated || !run_elevated_setting || with_dont_elevate_arg || (!elevated && with_restartedElevated_arg)) - { - // The condition (!elevated && with_restartedElevated_arg) solves issue #19307. Restart elevated loop detected, running non-elevated - if (!elevated && with_restartedElevated_arg) - { - Logger::info("Restart as elevated failed. Running non-elevated."); - } - - result = runner(elevated, open_settings, settings_window, openOobe, openScoobe, showRestartNotificationAfterUpdate); - - if (result == 0) - { - // Save settings on closing, if closed 'normal' - PTSettingsHelper::save_general_settings(get_general_settings().to_json()); - } - } - else - { - Logger::info("Scheduling restart as elevated"); - schedule_restart_as_elevated(open_settings); - result = 0; - } - } - catch (std::runtime_error& err) - { - std::string err_what = err.what(); - MessageBoxW(nullptr, std::wstring(err_what.begin(), err_what.end()).c_str(), GET_RESOURCE_STRING(IDS_ERROR).c_str(), MB_OK | MB_ICONERROR); - result = -1; - } - - trace.Flush(); - trace.UpdateState(false); - - // We need to release the mutexes to be able to restart the application - if (msi_mutex) - { - msi_mutex.reset(nullptr); - } - - if (is_restart_scheduled()) - { - modules().clear(); - if (!restart_if_scheduled()) - { - // If it's not possible to restart non-elevated due to some condition in the user's configuration, user should start PowerToys manually. - Logger::warn("Scheduled restart failed. Couldn't restart non-elevated. PowerToys exits here because retrying it would just mean failing in a loop."); - } - } - stop_tray_icon(); - - return result; -} diff --git a/src/runner/pch.cpp b/src/runner/pch.cpp deleted file mode 100644 index 1d9f38c57d..0000000000 --- a/src/runner/pch.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "pch.h" diff --git a/src/runner/pch.h b/src/runner/pch.h deleted file mode 100644 index 537bef12d6..0000000000 --- a/src/runner/pch.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include diff --git a/src/runner/powertoy_module.cpp b/src/runner/powertoy_module.cpp deleted file mode 100644 index eb1f7c4fd7..0000000000 --- a/src/runner/powertoy_module.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "pch.h" -#include "powertoy_module.h" -#include "centralized_kb_hook.h" -#include "centralized_hotkeys.h" -#include -#include - -std::map& modules() -{ - static std::map modules; - return modules; -} - -PowertoyModule load_powertoy(const std::wstring_view filename) -{ - auto handle = winrt::check_pointer(LoadLibraryW(filename.data())); - auto create = reinterpret_cast(GetProcAddress(handle, "powertoy_create")); - if (!create) - { - FreeLibrary(handle); - winrt::throw_last_error(); - } - auto pt_module = create(); - if (!pt_module) - { - FreeLibrary(handle); - winrt::throw_hresult(winrt::hresult(E_POINTER)); - } - return PowertoyModule(pt_module, handle); -} - -json::JsonObject PowertoyModule::json_config() const -{ - int size = 0; - pt_module->get_config(nullptr, &size); - std::wstring result; - result.resize(static_cast(size) - 1); - pt_module->get_config(result.data(), &size); - return json::JsonObject::Parse(result); -} - -PowertoyModule::PowertoyModule(PowertoyModuleIface* pt_module, HMODULE handle) : - handle(handle), pt_module(pt_module), hkmng(HotkeyConflictDetector::HotkeyConflictManager::GetInstance()) -{ - if (!pt_module) - { - throw std::runtime_error("Module not initialized"); - } - - remove_hotkey_records(); - update_hotkeys(); - UpdateHotkeyEx(); -} - -void PowertoyModule::update_hotkeys() -{ - CentralizedKeyboardHook::ClearModuleHotkeys(pt_module->get_key()); - - size_t hotkeyCount = pt_module->get_hotkeys(nullptr, 0); - std::vector hotkeys(hotkeyCount); - pt_module->get_hotkeys(hotkeys.data(), hotkeyCount); - - auto modulePtr = pt_module.get(); - - for (size_t i = 0; i < hotkeyCount; i++) - { - if (hotkeys[i].isShown) - { - hkmng.AddHotkey(hotkeys[i], pt_module->get_key(), static_cast(i), pt_module->is_enabled()); - - CentralizedKeyboardHook::SetHotkeyAction(pt_module->get_key(), hotkeys[i], [modulePtr, i] { - Logger::trace(L"{} hotkey is invoked from Centralized keyboard hook", modulePtr->get_key()); - return modulePtr->on_hotkey(i); - }); - } - } -} - -void PowertoyModule::UpdateHotkeyEx() -{ - CentralizedHotkeys::UnregisterHotkeysForModule(pt_module->get_key()); - - auto container = pt_module->GetHotkeyEx(); - if (container.has_value() && pt_module->is_enabled()) - { - hkmng.RemoveHotkeyByModule(pt_module->get_key()); - - auto hotkey = container.value(); - auto modulePtr = pt_module.get(); - auto action = [modulePtr](WORD /*modifiersMask*/, WORD /*vkCode*/) { - Logger::trace(L"{} hotkey Ex is invoked from Centralized keyboard hook", modulePtr->get_key()); - modulePtr->OnHotkeyEx(); - }; - - HotkeyConflictDetector::Hotkey _hotkey = HotkeyConflictDetector::ShortcutToHotkey({ hotkey.modifiersMask, hotkey.vkCode }); - hkmng.AddHotkey(_hotkey, pt_module->get_key(), 0, pt_module->is_enabled()); // This is the only one activation hotkey, so we use "0" as the name. - - CentralizedHotkeys::AddHotkeyAction({ hotkey.modifiersMask, hotkey.vkCode }, { pt_module->get_key(), action }); - } - - // HACK: - // Just for enabling the shortcut guide legacy behavior of pressing the Windows Key. - // This is not the sort of behavior we'd like to have generalized on other modules. - // But this was a way to bring back the long windows key behavior that the community wanted back while maintaining the separate process. - if (pt_module->keep_track_of_pressed_win_key()) - { - auto modulePtr = pt_module.get(); - auto action = [modulePtr] { - modulePtr->OnHotkeyEx(); - return false; - }; - CentralizedKeyboardHook::AddPressedKeyAction(pt_module->get_key(), VK_LWIN, pt_module->milliseconds_win_key_must_be_pressed(), action); - CentralizedKeyboardHook::AddPressedKeyAction(pt_module->get_key(), VK_RWIN, pt_module->milliseconds_win_key_must_be_pressed(), action); - } -} diff --git a/src/runner/powertoy_module.h b/src/runner/powertoy_module.h deleted file mode 100644 index 81e020820c..0000000000 --- a/src/runner/powertoy_module.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include "hotkey_conflict_detector.h" - -#include - -struct PowertoyModuleDeleter -{ - void operator()(PowertoyModuleIface* pt_module) const - { - if (pt_module) - { - pt_module->destroy(); - } - } -}; - -struct PowertoyModuleDLLDeleter -{ - using pointer = HMODULE; - void operator()(HMODULE handle) const - { - FreeLibrary(handle); - } -}; - -class PowertoyModule -{ -public: - PowertoyModule(PowertoyModuleIface* pt_module, HMODULE handle); - - inline PowertoyModuleIface* operator->() - { - return pt_module.get(); - } - - json::JsonObject json_config() const; - - void update_hotkeys(); - - void UpdateHotkeyEx(); - - inline void remove_hotkey_records() - { - hkmng.RemoveHotkeyByModule(pt_module->get_key()); - } - -private: - HotkeyConflictDetector::HotkeyConflictManager& hkmng; - std::unique_ptr handle; - std::unique_ptr pt_module; - - -}; - -PowertoyModule load_powertoy(const std::wstring_view filename); -std::map& modules(); diff --git a/src/runner/quick_access_host.cpp b/src/runner/quick_access_host.cpp deleted file mode 100644 index b546ee244e..0000000000 --- a/src/runner/quick_access_host.cpp +++ /dev/null @@ -1,296 +0,0 @@ -#include "pch.h" -#include "quick_access_host.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -extern void receive_json_send_to_main_thread(const std::wstring& msg); - -namespace -{ - wil::unique_handle quick_access_process; - wil::unique_handle quick_access_job; - wil::unique_handle show_event; - wil::unique_handle exit_event; - std::wstring show_event_name; - std::wstring exit_event_name; - std::wstring runner_pipe_name; - std::wstring app_pipe_name; - std::unique_ptr quick_access_ipc; - std::mutex quick_access_mutex; - - bool is_process_active_locked() - { - if (!quick_access_process) - { - return false; - } - - DWORD exit_code = 0; - if (!GetExitCodeProcess(quick_access_process.get(), &exit_code)) - { - Logger::warn(L"QuickAccessHost: failed to read Quick Access process exit code. error={}.", GetLastError()); - return false; - } - - return exit_code == STILL_ACTIVE; - } - - void reset_state_locked() - { - if (quick_access_ipc) - { - quick_access_ipc->end(); - quick_access_ipc.reset(); - } - - quick_access_process.reset(); - quick_access_job.reset(); - show_event.reset(); - exit_event.reset(); - show_event_name.clear(); - exit_event_name.clear(); - runner_pipe_name.clear(); - app_pipe_name.clear(); - } - - std::wstring build_event_name(const wchar_t* suffix) - { - std::wstring name = L"Local\\PowerToysQuickAccess_"; - name += std::to_wstring(GetCurrentProcessId()); - if (suffix) - { - name += suffix; - } - return name; - } - - std::wstring build_command_line(const std::wstring& exe_path) - { - std::wstring command_line = L"\""; - command_line += exe_path; - command_line += L"\" --show-event=\""; - command_line += show_event_name; - command_line += L"\" --exit-event=\""; - command_line += exit_event_name; - command_line += L"\""; - if (!runner_pipe_name.empty()) - { - command_line.append(L" --runner-pipe=\""); - command_line += runner_pipe_name; - command_line += L"\""; - } - if (!app_pipe_name.empty()) - { - command_line.append(L" --app-pipe=\""); - command_line += app_pipe_name; - command_line += L"\""; - } - return command_line; - } -} - -namespace QuickAccessHost -{ - bool is_running() - { - std::scoped_lock lock(quick_access_mutex); - return is_process_active_locked(); - } - - void start() - { - Logger::info(L"QuickAccessHost::start() called"); - std::scoped_lock lock(quick_access_mutex); - if (is_process_active_locked()) - { - Logger::info(L"QuickAccessHost::start: process already active"); - return; - } - - reset_state_locked(); - - show_event_name = build_event_name(L"_Show"); - exit_event_name = build_event_name(L"_Exit"); - - show_event.reset(CreateEventW(nullptr, FALSE, FALSE, show_event_name.c_str())); - if (!show_event) - { - Logger::error(L"QuickAccessHost: failed to create show event. error={}.", GetLastError()); - reset_state_locked(); - return; - } - - exit_event.reset(CreateEventW(nullptr, FALSE, FALSE, exit_event_name.c_str())); - if (!exit_event) - { - Logger::error(L"QuickAccessHost: failed to create exit event. error={}.", GetLastError()); - reset_state_locked(); - return; - } - - runner_pipe_name = L"\\\\.\\pipe\\powertoys_quick_access_runner_"; - app_pipe_name = L"\\\\.\\pipe\\powertoys_quick_access_ui_"; - UUID temp_uuid; - wchar_t* uuid_chars = nullptr; - if (UuidCreate(&temp_uuid) == RPC_S_UUID_NO_ADDRESS) - { - Logger::warn(L"QuickAccessHost: failed to create UUID for pipe names. error={}.", GetLastError()); - } - else if (UuidToString(&temp_uuid, reinterpret_cast(&uuid_chars)) != RPC_S_OK) - { - Logger::warn(L"QuickAccessHost: failed to convert UUID to string. error={}.", GetLastError()); - } - - if (uuid_chars != nullptr) - { - runner_pipe_name += std::wstring(uuid_chars); - app_pipe_name += std::wstring(uuid_chars); - RpcStringFree(reinterpret_cast(&uuid_chars)); - uuid_chars = nullptr; - } - else - { - const std::wstring fallback_suffix = std::to_wstring(GetTickCount64()); - runner_pipe_name += fallback_suffix; - app_pipe_name += fallback_suffix; - } - - HANDLE token_handle = nullptr; - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token_handle)) - { - Logger::error(L"QuickAccessHost: failed to open process token. error={}.", GetLastError()); - reset_state_locked(); - return; - } - - wil::unique_handle token(token_handle); - quick_access_ipc.reset(new (std::nothrow) TwoWayPipeMessageIPC(runner_pipe_name, app_pipe_name, receive_json_send_to_main_thread)); - if (!quick_access_ipc) - { - Logger::error(L"QuickAccessHost: failed to allocate IPC instance."); - reset_state_locked(); - return; - } - - try - { - quick_access_ipc->start(token.get()); - } - catch (...) - { - Logger::error(L"QuickAccessHost: failed to start IPC server for Quick Access."); - reset_state_locked(); - return; - } - - const std::wstring exe_path = get_module_folderpath() + L"\\WinUI3Apps\\PowerToys.QuickAccess.exe"; - if (GetFileAttributesW(exe_path.c_str()) == INVALID_FILE_ATTRIBUTES) - { - Logger::warn(L"QuickAccessHost: missing Quick Access executable at {}", exe_path); - reset_state_locked(); - return; - } - - const std::wstring command_line = build_command_line(exe_path); - std::vector command_line_buffer(command_line.begin(), command_line.end()); - command_line_buffer.push_back(L'\0'); - STARTUPINFOW startup_info{}; - startup_info.cb = sizeof(startup_info); - PROCESS_INFORMATION process_info{}; - - BOOL created = CreateProcessW(exe_path.c_str(), command_line_buffer.data(), nullptr, nullptr, FALSE, CREATE_SUSPENDED, nullptr, nullptr, &startup_info, &process_info); - if (!created) - { - Logger::error(L"QuickAccessHost: failed to launch Quick Access host. error={}.", GetLastError()); - reset_state_locked(); - return; - } - - quick_access_process.reset(process_info.hProcess); - - // Assign to job object to ensure the process is killed if the runner exits unexpectedly (e.g. debugging stop) - quick_access_job.reset(CreateJobObjectW(nullptr, nullptr)); - if (quick_access_job) - { - JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; - jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; - if (!SetInformationJobObject(quick_access_job.get(), JobObjectExtendedLimitInformation, &jeli, sizeof(jeli))) - { - Logger::warn(L"QuickAccessHost: failed to set job object information. error={}", GetLastError()); - } - else - { - if (!AssignProcessToJobObject(quick_access_job.get(), quick_access_process.get())) - { - Logger::warn(L"QuickAccessHost: failed to assign process to job object. error={}", GetLastError()); - } - } - } - else - { - Logger::warn(L"QuickAccessHost: failed to create job object. error={}", GetLastError()); - } - - ResumeThread(process_info.hThread); - CloseHandle(process_info.hThread); - } - - void show() - { - start(); - std::scoped_lock lock(quick_access_mutex); - - if (show_event) - { - if (!SetEvent(show_event.get())) - { - Logger::warn(L"QuickAccessHost: failed to signal show event. error={}.", GetLastError()); - } - } - } - - void stop() - { - Logger::info(L"QuickAccessHost::stop() called"); - std::unique_lock lock(quick_access_mutex); - if (exit_event) - { - SetEvent(exit_event.get()); - } - - if (quick_access_process) - { - const DWORD wait_result = WaitForSingleObject(quick_access_process.get(), 2000); - Logger::info(L"QuickAccessHost::stop: WaitForSingleObject result={}", wait_result); - if (wait_result == WAIT_TIMEOUT) - { - Logger::warn(L"QuickAccessHost: Quick Access process did not exit in time, terminating."); - if (!TerminateProcess(quick_access_process.get(), 0)) - { - Logger::error(L"QuickAccessHost: failed to terminate Quick Access process. error={}.", GetLastError()); - } - else - { - Logger::info(L"QuickAccessHost: TerminateProcess succeeded."); - WaitForSingleObject(quick_access_process.get(), 5000); - } - } - else if (wait_result == WAIT_FAILED) - { - Logger::error(L"QuickAccessHost: failed while waiting for Quick Access process. error={}.", GetLastError()); - } - } - - reset_state_locked(); - } -} diff --git a/src/runner/quick_access_host.h b/src/runner/quick_access_host.h deleted file mode 100644 index 22a65a9c26..0000000000 --- a/src/runner/quick_access_host.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include -#include - -namespace QuickAccessHost -{ - void start(); - void show(); - void stop(); - bool is_running(); -} diff --git a/src/runner/resource.base.h b/src/runner/resource.base.h deleted file mode 100644 index 7037f4342d..0000000000 --- a/src/runner/resource.base.h +++ /dev/null @@ -1,23 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by runner.rc - -////////////////////////////// -// Non-localizable - -#define FILE_DESCRIPTION "PowerToys.Runner" -#define INTERNAL_NAME "PowerToys" -#define ORIGINAL_FILENAME "PowerToys.exe" - -// Non-localizable -////////////////////////////// - -#define APPICON 101 -#define ID_TRAY_MENU 102 - -#define ID_CLOSE_MENU_COMMAND 40001 -#define ID_SETTINGS_MENU_COMMAND 40002 -#define ID_ABOUT_MENU_COMMAND 40003 -#define ID_REPORT_BUG_COMMAND 40004 -#define ID_DOCUMENTATION_MENU_COMMAND 40005 -#define ID_QUICK_ACCESS_MENU_COMMAND 40006 diff --git a/src/runner/restart_elevated.cpp b/src/runner/restart_elevated.cpp deleted file mode 100644 index c14b63d479..0000000000 --- a/src/runner/restart_elevated.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "pch.h" -#include "restart_elevated.h" - -#include - -enum State -{ - None, - RestartAsElevated, - RestartAsElevatedOpenSettings, - RestartAsNonElevated, - RestartAsNonElevatedOpenSettings -}; -static State state = None; - -void schedule_restart_as_elevated(bool openSettings) -{ - state = openSettings ? RestartAsElevatedOpenSettings : RestartAsElevated; -} - -void schedule_restart_as_non_elevated() -{ - state = RestartAsNonElevated; -} - -void schedule_restart_as_non_elevated(bool openSettings) -{ - state = openSettings ? RestartAsNonElevatedOpenSettings : RestartAsNonElevated; -} - -bool is_restart_scheduled() -{ - return state != None; -} - -bool restart_if_scheduled() -{ - // Make sure we have enough room, even for the long (\\?\) paths - constexpr DWORD exe_path_size = 0xFFFF; - auto exe_path = std::make_unique(exe_path_size); - GetModuleFileNameW(nullptr, exe_path.get(), exe_path_size); - switch (state) - { - case RestartAsElevated: - return run_elevated(exe_path.get(), L"--restartedElevated"); - case RestartAsElevatedOpenSettings: - return run_elevated(exe_path.get(), L"--restartedElevated --open-settings"); - case RestartAsNonElevatedOpenSettings: - return run_non_elevated(exe_path.get(), L"--open-settings", NULL); - case RestartAsNonElevated: - return run_non_elevated(exe_path.get(), L"", NULL); - default: - return false; - } -} - -bool restart_same_elevation() -{ - constexpr DWORD exe_path_size = 0xFFFF; - auto exe_path = std::make_unique(exe_path_size); - GetModuleFileNameW(nullptr, exe_path.get(), exe_path_size); - return run_same_elevation(exe_path.get(), L"", nullptr); -} diff --git a/src/runner/restart_elevated.h b/src/runner/restart_elevated.h deleted file mode 100644 index 9ffb545c91..0000000000 --- a/src/runner/restart_elevated.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once -void schedule_restart_as_elevated(bool openSettings); -void schedule_restart_as_non_elevated(); -void schedule_restart_as_non_elevated(bool openSettings); -bool is_restart_scheduled(); -bool restart_if_scheduled(); -bool restart_same_elevation(); diff --git a/src/runner/runner.base.rc b/src/runner/runner.base.rc deleted file mode 100644 index 9c6560cc97cb0b1ba80bc1b80984e9f6cb902c97..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3118 zcmbuBYflqF6o$`d6aPcAe33+HLB5z6linpjyYvDvF=?=rN`$s)3+kU&pLd2~cgspz z$Od+H=FEA|dC#qX|7_WnO>Ah_c54?lvVwiIpKkBMrmPmWW8dwQy|!2OST?dbcNR$A zvKq3Mbo5{89nOo$P3?wf3UZN~OYpAIQnWiX%voKzvqYEB%NFw-Sk>Cr!p>wBapTU$ z{Qt^LX`g`OSKb!gKd_n&tY;lGePMNMb@cSn6jqX|u-ino<$Ne`swW0BMmA<0rM|rO zAeDbNoCcHwY^Z}NO(%FSJAd$X&RYyFoF7X&VtolW@7TS*mx}BylHQXO>=6ft_)_Lw zMQfKQ@oeC@ItHtZKedcUPg&IkdFi4uajd3MyP))V#87i%v?4Li?T)Z? zWHW4-gIj=)TOyJmcbs4HM;ukKp~+hnvT4+x&rp@@oRYJnOzf)UZ=3w6ugQUG(PwC~ zQa$eC^(k69=<=K@^BU;ZX@k8ZPO}n)hyB6IiSEScYJ=5>r{2oBDm{IgcRye@KrXu) zP*WzWrw=yrR%wu+#Fz0{XT+e&yu@o?W@vTu&)j}%CM5YTe4qP z!eWoCT)uGlX)MJ{D0&ZISvhs)DqR_V#_oID%OLdVq%n5uR>R5H!0;%+`z}mZILk`z zp}P;pA%D`XjxJmBduRonsxfgKVaJks(A*k>s@XBZ$_Z>vIhB^s-SV|1r)jMv+lQeK z{O!|?O0LS(uL{^HUg{1{op`~FE7%)k#Hqiv?K*QG89#UYEKOu8NN#g$$lY@{)kGrL&SAto_#_f@+&+9_zsZvpR1f|9NH0TI$<_fu(oEM?8o;Y{G{ zdWAV@)2#0B7Tc6A?_~SV zDL&30n0-#i$yRL-ZK~J>@k;-$P(7))_|BrQUHWc`r$9e?X-5jWp6*5o7s=`$+f$d_ diff --git a/src/runner/runner.vcxproj b/src/runner/runner.vcxproj deleted file mode 100644 index 88b74e3faa..0000000000 --- a/src/runner/runner.vcxproj +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - - 81010002 - - - - PackageReference - - native,Version=v0.0 - - Windows - $(WindowsTargetPlatformVersion) - - - 15.0 - {9412D5C6-2CF2-4FC2-A601-B55508EA9B27} - powertoys - runner - - - - - - - - - - - - Application - - None - true - true - - - - - - - - PowerToys - - - - ..\common\inc;..\common\os-detection;..\common\Telemetry;..;..\modules;%(AdditionalIncludeDirectories) - - - AsInvoker - $(OutDir)$(TargetName)$(TargetExt) - Shcore.lib;gdiplus.lib;Msi.lib;WindowsApp.lib;taskschd.lib;Rstrtmgr.lib;Shlwapi.lib;dwmapi.lib;%(AdditionalDependencies) - - - false - - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - Document - $(OutDir)\svgs - - - - - {7319089e-46d6-4400-bc65-e39bdf1416ee} - - - {caba8dfb-823b-4bf2-93ac-3f31984150d9} - - - {d9b8fc84-322a-4f9f-bbb9-20915c47ddfd} - - - {1d5be09d-78c0-4fd7-af00-ae7c1af7c525} - - - {8f021b46-362b-485c-bfba-ccf83e820cbd} - - - {98537082-0fdb-40de-abd8-0dc5a4269bab} - - - {17da04df-e393-4397-9cf0-84dabe11032e} - - - - - - - - - - - true - true - true - true - $(OutDir)\svgs - $(OutDir)\svgs - $(OutDir)\svgs - $(OutDir)\svgs - - - true - true - true - true - $(OutDir)\svgs - $(OutDir)\svgs - $(OutDir)\svgs - $(OutDir)\svgs - - - - - - - - - - - - NotUsing - - - - \ No newline at end of file diff --git a/src/runner/runner.vcxproj.filters b/src/runner/runner.vcxproj.filters deleted file mode 100644 index 4d1e82ff0d..0000000000 --- a/src/runner/runner.vcxproj.filters +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - - - {bc27e9c1-8afa-4d62-8179-789f4651c0b6} - - - {74d0b535-16ee-46cc-9adf-dc4668bbcfda} - - - {18a4e642-9246-4494-b916-8505aed19914} - - - - - - - - - - - - - - - - - - - Resource Files - - - - - - \ No newline at end of file diff --git a/src/runner/settings_telemetry.cpp b/src/runner/settings_telemetry.cpp deleted file mode 100644 index 7bab24d448..0000000000 --- a/src/runner/settings_telemetry.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#pragma once -#include "pch.h" -#include "settings_telemetry.h" -#include -#include -#include -#include -#include -#include -#include "powertoy_module.h" - -using JsonObject = winrt::Windows::Data::Json::JsonObject; -using JsonValue = winrt::Windows::Data::Json::JsonValue; - -std::wstring get_info_file_path() -{ - std::filesystem::path settingsFilePath(PTSettingsHelper::get_root_save_folder_location()); - settingsFilePath = settingsFilePath.append(settings_telemetry::send_info_file); - return settingsFilePath.wstring(); -} - -std::optional get_last_send_time() -{ - auto settings = json::from_file(get_info_file_path()); - if (!settings.has_value() || !settings.value().HasKey(settings_telemetry::last_send_option)) - { - return std::nullopt; - } - - auto stringTime = (std::wstring)settings.value().GetNamedString(settings_telemetry::last_send_option); - return timeutil::from_string(stringTime); -} - -void update_last_send_time(time_t time) -{ - auto settings = JsonObject(); - settings.SetNamedValue(settings_telemetry::last_send_option, JsonValue::CreateStringValue(timeutil::to_string(time))); - json::to_file(get_info_file_path(), settings); -} - -void send() -{ - for (auto& [name, powertoy] : modules()) - { - if (powertoy->is_enabled()) - { - try - { - powertoy->send_settings_telemetry(); - } - catch (...) - { - Logger::error(L"Failed to send telemetry for {} module", name); - } - } - } -} - -void run_interval() -{ - auto time = get_last_send_time(); - long long wait_time = 24 * 3600; - long long left_to_wait = 0; - if (time.has_value()) - { - left_to_wait = max(0, wait_time - timeutil::diff::in_seconds(timeutil::now(), time.value())); - } - - Sleep(static_cast(left_to_wait * 1000)); - send(); - update_last_send_time(timeutil::now()); - - while (true) - { - Sleep(static_cast(wait_time * 1000)); - send(); - update_last_send_time(timeutil::now()); - } -} - -void settings_telemetry::init() -{ - std::thread([]() { - try - { - run_interval(); - } - catch (...) - { - Logger::error("Failed to send settings telemetry"); - } - }).detach(); -} diff --git a/src/runner/settings_telemetry.h b/src/runner/settings_telemetry.h deleted file mode 100644 index c72972914a..0000000000 --- a/src/runner/settings_telemetry.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once -namespace settings_telemetry -{ - static std::wstring send_info_file = L"settings-telemetry.json"; - static std::wstring last_send_option = L"last_send_time"; - void init(); -} \ No newline at end of file diff --git a/src/runner/settings_window.cpp b/src/runner/settings_window.cpp deleted file mode 100644 index 022ad9d76c..0000000000 --- a/src/runner/settings_window.cpp +++ /dev/null @@ -1,960 +0,0 @@ -#include "pch.h" -#include -#include -#include -#include - -#include "powertoy_module.h" -#include -#include -#include "tray_icon.h" -#include "general_settings.h" -#include "restart_elevated.h" -#include "UpdateUtils.h" -#include "centralized_kb_hook.h" -#include "Generated files/resource.h" -#include "hotkey_conflict_detector.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "settings_window.h" -#include "bug_report.h" - -#define BUFSIZE 1024 - -TwoWayPipeMessageIPC* current_settings_ipc = NULL; -std::mutex ipc_mutex; -std::atomic_bool g_isLaunchInProgress = false; -std::atomic_bool isUpdateCheckThreadRunning = false; -HANDLE g_terminateSettingsEvent = CreateEventW(nullptr, false, false, CommonSharedConstants::TERMINATE_SETTINGS_SHARED_EVENT); - -json::JsonObject get_power_toys_settings() -{ - json::JsonObject result; - for (const auto& [name, powertoy] : modules()) - { - try - { - result.SetNamedValue(name, powertoy.json_config()); - } - catch (...) - { - Logger::error(L"get_power_toys_settings(): got malformed json for {} module", name); - } - } - return result; -} - -json::JsonObject get_all_settings() -{ - json::JsonObject result; - - result.SetNamedValue(L"general", get_general_settings().to_json()); - result.SetNamedValue(L"powertoys", get_power_toys_settings()); - return result; -} - -std::optional dispatch_json_action_to_module(const json::JsonObject& powertoys_configs) -{ - std::optional result; - for (const auto& powertoy_element : powertoys_configs) - { - const std::wstring name{ powertoy_element.Key().c_str() }; - // Currently, there is only one custom action in the general settings screen, - // so it has to be the "restart as (non-)elevated" button. - if (name == L"general") - { - try - { - const auto value = powertoy_element.Value().GetObjectW(); - const auto action = value.GetNamedString(L"action_name"); - if (action == L"restart_elevation") - { - if (is_process_elevated()) - { - schedule_restart_as_non_elevated(); - PostQuitMessage(0); - } - else - { - schedule_restart_as_elevated(true); - PostQuitMessage(0); - } - } - else if (action == L"restart_maintain_elevation") - { - // this was added to restart and maintain elevation, which is needed after settings are change from outside the normal process. - // since a normal PostQuitMessage(0) would usually cause this process to save its in memory settings to disk, we need to - // send a PostQuitMessage(1) and check for that on exit, and skip the settings-flush. - auto loaded = PTSettingsHelper::load_general_settings(); - - if (is_process_elevated()) - { - schedule_restart_as_elevated(true); - PostQuitMessage(1); - } - else - { - schedule_restart_as_non_elevated(true); - PostQuitMessage(1); - } - } - else if (action == L"check_for_updates") - { - bool expected_isUpdateCheckThreadRunning = false; - if (isUpdateCheckThreadRunning.compare_exchange_strong(expected_isUpdateCheckThreadRunning, true)) - { - std::thread([]() { - CheckForUpdatesCallback(); - isUpdateCheckThreadRunning.store(false); - }).detach(); - } - } - else if (action == L"request_update_state_date") - { - json::JsonObject json; - - auto update_state = UpdateState::read(); - if (update_state.githubUpdateLastCheckedDate) - { - const time_t date = *update_state.githubUpdateLastCheckedDate; - json.SetNamedValue(L"updateStateDate", json::value(std::to_wstring(date))); - } - - result.emplace(json.Stringify()); - } - } - catch (...) - { - } - } - else if (modules().find(name) != modules().end()) - { - const auto element = powertoy_element.Value().Stringify(); - modules().at(name)->call_custom_action(element.c_str()); - } - } - - return result; -} - -void send_json_config_to_module(const std::wstring& module_key, const std::wstring& settings, bool hotkeyUpdated) -{ - auto moduleIt = modules().find(module_key); - if (moduleIt != modules().end()) - { - moduleIt->second->set_config(settings.c_str()); - - if (hotkeyUpdated) - { - moduleIt->second.remove_hotkey_records(); - moduleIt->second.update_hotkeys(); - moduleIt->second.UpdateHotkeyEx(); - } - } -} - -void dispatch_json_config_to_modules(const json::JsonObject& powertoys_configs) -{ - for (const auto& powertoy_element : powertoys_configs) - { - const auto element = powertoy_element.Value().Stringify(); - - /* As PowerToys Run hotkeys are not registered by the runner, hotkey updates are - * triggered only when hotkey properties change to avoid incorrect conflict detection; - * otherwise, the existing logic remains. - */ - auto settings = powertoy_element.Value().GetObjectW(); - bool hotkeyUpdated = true; - if (settings.HasKey(L"properties")) - { - const auto properties = settings.GetNamedObject(L"properties"); - - // Currently, only PowerToys Run settings use the 'hotkey_changed' property. - if (properties.HasKey(L"hotkey_changed")) - { - json::get(properties, L"hotkey_changed", hotkeyUpdated, true); - } - } - - send_json_config_to_module(powertoy_element.Key().c_str(), element.c_str(), hotkeyUpdated); - } -}; - -void dispatch_received_json(const std::wstring& json_to_parse) -{ - json::JsonObject j; - const bool ok = json::JsonObject::TryParse(json_to_parse, j); - if (!ok) - { - Logger::error(L"dispatch_received_json: got malformed json: {}", json_to_parse); - return; - } - - Logger::info(L"dispatch_received_json: {}", json_to_parse); - - for (const auto& base_element : j) - { - const auto name = base_element.Key(); - const auto value = base_element.Value(); - - if (name == L"general") - { - apply_general_settings(value.GetObjectW()); - // const std::wstring settings_string{ get_all_settings().Stringify().c_str() }; - // { - // std::unique_lock lock{ ipc_mutex }; - // if (current_settings_ipc) - // current_settings_ipc->send(settings_string); - // } - } - else if (name == L"module_status") - { - // Handle single module enable/disable update - // Expected format: {"module_status": {"ModuleName": true/false}} - apply_module_status_update(value.GetObjectW()); - } - else if (name == L"powertoys") - { - dispatch_json_config_to_modules(value.GetObjectW()); - const std::wstring settings_string{ get_all_settings().Stringify().c_str() }; - { - std::unique_lock lock{ ipc_mutex }; - if (current_settings_ipc) - current_settings_ipc->send(settings_string); - } - } - else if (name == L"refresh") - { - const std::wstring settings_string{ get_all_settings().Stringify().c_str() }; - { - std::unique_lock lock{ ipc_mutex }; - if (current_settings_ipc) - current_settings_ipc->send(settings_string); - } - } - else if (name == L"action") - { - auto result = dispatch_json_action_to_module(value.GetObjectW()); - if (result.has_value()) - { - { - std::unique_lock lock{ ipc_mutex }; - if (current_settings_ipc) - current_settings_ipc->send(result.value()); - } - } - } - else if (name == L"bugreport") - { - launch_bug_report(); - } - else if (name == L"bug_report_status") - { - json::JsonObject result; - result.SetNamedValue(L"bug_report_running", winrt::Windows::Data::Json::JsonValue::CreateBooleanValue(is_bug_report_running())); - std::unique_lock lock{ ipc_mutex }; - if (current_settings_ipc) - current_settings_ipc->send(result.Stringify().c_str()); - } - else if (name == L"killrunner") - { - const auto pt_main_window = FindWindowW(pt_tray_icon_window_class, nullptr); - if (pt_main_window != nullptr) - { - SendMessageW(pt_main_window, WM_CLOSE, 0, 0); - } - } - else if (name == L"language") - { - constexpr const wchar_t* language_filename = L"\\language.json"; - const std::wstring save_file_location = PTSettingsHelper::get_root_save_folder_location() + language_filename; - json::to_file(save_file_location, j); - } - else if (name == L"check_hotkey_conflict") - { - try - { - PowertoyModuleIface::Hotkey hotkey; - hotkey.win = value.GetObjectW().GetNamedBoolean(L"win", false); - hotkey.ctrl = value.GetObjectW().GetNamedBoolean(L"ctrl", false); - hotkey.shift = value.GetObjectW().GetNamedBoolean(L"shift", false); - hotkey.alt = value.GetObjectW().GetNamedBoolean(L"alt", false); - hotkey.key = static_cast(value.GetObjectW().GetNamedNumber(L"key", 0)); - - std::wstring requestId = value.GetObjectW().GetNamedString(L"request_id", L"").c_str(); - - auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); - bool hasConflict = hkmng.HasConflict(hotkey); - - json::JsonObject response; - response.SetNamedValue(L"response_type", json::JsonValue::CreateStringValue(L"hotkey_conflict_result")); - response.SetNamedValue(L"request_id", json::JsonValue::CreateStringValue(requestId)); - response.SetNamedValue(L"has_conflict", json::JsonValue::CreateBooleanValue(hasConflict)); - - if (hasConflict) - { - auto conflicts = hkmng.GetAllConflicts(hotkey); - if (!conflicts.empty()) - { - // Include all conflicts in the response - json::JsonArray allConflicts; - for (const auto& conflict : conflicts) - { - json::JsonObject conflictObj; - conflictObj.SetNamedValue(L"module", json::JsonValue::CreateStringValue(conflict.moduleName)); - conflictObj.SetNamedValue(L"hotkeyID", json::JsonValue::CreateNumberValue(conflict.hotkeyID)); - allConflicts.Append(conflictObj); - } - response.SetNamedValue(L"all_conflicts", allConflicts); - } - } - - std::unique_lock lock{ ipc_mutex }; - if (current_settings_ipc) - { - current_settings_ipc->send(response.Stringify().c_str()); - } - } - catch (...) - { - Logger::error(L"Failed to process hotkey conflict check request"); - } - } - else if (name == L"get_all_hotkey_conflicts") - { - try - { - auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); - auto conflictsJson = hkmng.GetHotkeyConflictsAsJson(); - - // Add response type identifier - conflictsJson.SetNamedValue(L"response_type", json::JsonValue::CreateStringValue(L"all_hotkey_conflicts")); - - std::unique_lock lock{ ipc_mutex }; - if (current_settings_ipc) - { - current_settings_ipc->send(conflictsJson.Stringify().c_str()); - } - } - catch (...) - { - Logger::error(L"Failed to process get all hotkey conflicts request"); - } - } - } - return; -} - -void dispatch_received_json_callback(PVOID data) -{ - std::wstring* msg = static_cast(data); - dispatch_received_json(*msg); - delete msg; -} - -void receive_json_send_to_main_thread(const std::wstring& msg) -{ - std::wstring* copy = new std::wstring(msg); - dispatch_run_on_main_ui_thread(dispatch_received_json_callback, copy); -} - -// Try to run the Settings process with non-elevated privileges. -BOOL run_settings_non_elevated(LPCWSTR executable_path, LPWSTR executable_args, PROCESS_INFORMATION* process_info) -{ - HWND hwnd = GetShellWindow(); - if (!hwnd) - { - return false; - } - - DWORD pid; - GetWindowThreadProcessId(hwnd, &pid); - - winrt::handle process{ OpenProcess(PROCESS_CREATE_PROCESS, FALSE, pid) }; - if (!process) - { - return false; - } - - SIZE_T size = 0; - InitializeProcThreadAttributeList(nullptr, 1, 0, &size); - auto pproc_buffer = std::unique_ptr{ new (std::nothrow) char[size] }; - auto pptal = reinterpret_cast(pproc_buffer.get()); - if (!pptal) - { - return false; - } - - if (!InitializeProcThreadAttributeList(pptal, 1, 0, &size)) - { - return false; - } - - if (!UpdateProcThreadAttribute(pptal, - 0, - PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, - &process, - sizeof(process), - nullptr, - nullptr)) - { - return false; - } - - STARTUPINFOEX siex = { 0 }; - siex.lpAttributeList = pptal; - siex.StartupInfo.cb = sizeof(siex); - - BOOL process_created = CreateProcessW(executable_path, - executable_args, - nullptr, - nullptr, - FALSE, - EXTENDED_STARTUPINFO_PRESENT, - nullptr, - nullptr, - &siex.StartupInfo, - process_info); - g_isLaunchInProgress = false; - return process_created; -} - -DWORD g_settings_process_id = 0; - -void run_settings_window(bool show_oobe_window, bool show_scoobe_window, std::optional settings_window) -{ - g_isLaunchInProgress = true; - - PROCESS_INFORMATION process_info = { 0 }; - HANDLE hToken = nullptr; - - // Arguments for calling the settings executable: - // "C:\powertoys_path\PowerToysSettings.exe" powertoys_pipe settings_pipe powertoys_pid settings_theme - // powertoys_pipe: PowerToys pipe server. - // settings_pipe : Settings pipe server. - // powertoys_pid : PowerToys process pid. - // settings_theme: pass "dark" to start the settings window in dark mode - - // Arg 1: executable path. - std::wstring executable_path = get_module_folderpath(); - - executable_path.append(L"\\WinUI3Apps\\PowerToys.Settings.exe"); - - // Args 2,3: pipe server. Generate unique names for the pipes, if getting a UUID is possible. - std::wstring powertoys_pipe_name(L"\\\\.\\pipe\\powertoys_runner_"); - std::wstring settings_pipe_name(L"\\\\.\\pipe\\powertoys_settings_"); - UUID temp_uuid; - wchar_t* uuid_chars = nullptr; - if (UuidCreate(&temp_uuid) == RPC_S_UUID_NO_ADDRESS) - { - auto val = get_last_error_message(GetLastError()); - Logger::warn(L"UuidCreate cannot create guid. {}", val.has_value() ? val.value() : L""); - } - else if (UuidToString(&temp_uuid, reinterpret_cast(&uuid_chars)) != RPC_S_OK) - { - auto val = get_last_error_message(GetLastError()); - Logger::warn(L"UuidToString cannot convert to string. {}", val.has_value() ? val.value() : L""); - } - - if (uuid_chars != nullptr) - { - powertoys_pipe_name += std::wstring(uuid_chars); - settings_pipe_name += std::wstring(uuid_chars); - RpcStringFree(reinterpret_cast(&uuid_chars)); - uuid_chars = nullptr; - } - - // Arg 4: process pid. - DWORD powertoys_pid = GetCurrentProcessId(); - - GeneralSettings save_settings = get_general_settings(); - - // Arg 5: settings theme. - const std::wstring settings_theme_setting{ save_settings.theme }; - std::wstring settings_theme = L"system"; - if (settings_theme_setting == L"dark" || (settings_theme_setting == L"system" && WindowsColors::is_dark_mode())) - { - settings_theme = L"dark"; - } - - // Arg 6: elevated status - bool isElevated{ save_settings.isElevated }; - std::wstring settings_elevatedStatus = isElevated ? L"true" : L"false"; - - // Arg 7: is user an admin - bool isAdmin{ save_settings.isAdmin }; - std::wstring settings_isUserAnAdmin = isAdmin ? L"true" : L"false"; - - // Arg 8: should oobe window be shown - std::wstring settings_showOobe = show_oobe_window ? L"true" : L"false"; - - // Arg 9: should scoobe window be shown - std::wstring settings_showScoobe = show_scoobe_window ? L"true" : L"false"; - - // Arg 10: contains if there's a settings window argument. If true, will add one extra argument with the value to the call. - std::wstring settings_containsSettingsWindow = settings_window.has_value() ? L"true" : L"false"; - - // Args 11, .... : Optional arguments depending on the options presented before. All by the same value. - - // create general settings file to initialize the settings file with installation configurations like : - // 1. Run on start up. - PTSettingsHelper::save_general_settings(save_settings.to_json()); - - std::wstring executable_args = fmt::format(L"\"{}\" {} {} {} {} {} {} {} {} {}", - executable_path, - powertoys_pipe_name, - settings_pipe_name, - std::to_wstring(powertoys_pid), - settings_theme, - settings_elevatedStatus, - settings_isUserAnAdmin, - settings_showOobe, - settings_showScoobe, - settings_containsSettingsWindow); - - if (settings_window.has_value()) - { - executable_args.append(L" "); - executable_args.append(settings_window.value()); - } - - BOOL process_created = false; - - // Commented out to fix #22659 - // Running settings non-elevated and modules elevated when PowerToys is running elevated results - // in settings making changes in one file (non-elevated user dir) and modules are reading settings - // from different (elevated user) dir - //if (is_process_elevated()) - //{ - - // auto res = RunNonElevatedFailsafe(executable_path, executable_args, get_module_folderpath()); - // process_created = res.has_value(); - // if (process_created) - // { - // process_info.dwProcessId = res->processID; - // process_info.hProcess = res->processHandle.release(); - // g_isLaunchInProgress = false; - // } - //} - - if (FALSE == process_created) - { - // The runner is not elevated or we failed to create the process using the - // attribute list from Windows Explorer (this happens when PowerToys is executed - // as Administrator from a non-Administrator user or an error occur trying). - // In the second case the Settings process will run elevated. - STARTUPINFO startup_info = { sizeof(startup_info) }; - if (!CreateProcessW(executable_path.c_str(), - executable_args.data(), - nullptr, - nullptr, - FALSE, - 0, - nullptr, - nullptr, - &startup_info, - &process_info)) - { - goto LExit; - } - else - { - g_isLaunchInProgress = false; - } - } - - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) - { - goto LExit; - } - - { - std::unique_lock lock{ ipc_mutex }; - current_settings_ipc = new TwoWayPipeMessageIPC(powertoys_pipe_name, settings_pipe_name, receive_json_send_to_main_thread); - current_settings_ipc->start(hToken); - - // Register callback for bug report status changes - BugReportManager::instance().register_callback([](bool isRunning) { - json::JsonObject result; - result.SetNamedValue(L"bug_report_running", winrt::Windows::Data::Json::JsonValue::CreateBooleanValue(isRunning)); - - std::unique_lock lock{ ipc_mutex }; - if (current_settings_ipc) - current_settings_ipc->send(result.Stringify().c_str()); - }); - } - - g_settings_process_id = process_info.dwProcessId; - - if (process_info.hProcess) - { - WaitForSingleObject(process_info.hProcess, INFINITE); - if (WaitForSingleObject(process_info.hProcess, INFINITE) != WAIT_OBJECT_0) - { - show_last_error_message(L"Couldn't wait on the Settings Window to close.", GetLastError(), L"PowerToys - runner"); - } - } - else - { - auto val = get_last_error_message(GetLastError()); - Logger::error(L"Process handle is empty. {}", val.has_value() ? val.value() : L""); - } - -LExit: - - if (process_info.hProcess) - { - CloseHandle(process_info.hProcess); - } - - if (process_info.hThread) - { - CloseHandle(process_info.hThread); - } - { - std::unique_lock lock{ ipc_mutex }; - if (current_settings_ipc) - { - current_settings_ipc->end(); - delete current_settings_ipc; - current_settings_ipc = nullptr; - } - } - - if (hToken) - { - CloseHandle(hToken); - } - - g_settings_process_id = 0; -} - -#define MAX_TITLE_LENGTH 100 -void bring_settings_to_front() -{ - auto callback = [](HWND hwnd, LPARAM /*data*/) -> BOOL { - DWORD processId; - if (GetWindowThreadProcessId(hwnd, &processId) && processId == g_settings_process_id) - { - std::wstring windowTitle = L"PowerToys Settings"; - - WCHAR title[MAX_TITLE_LENGTH]; - int len = GetWindowTextW(hwnd, title, MAX_TITLE_LENGTH); - if (len <= 0) - { - return TRUE; - } - if (wcsncmp(title, windowTitle.c_str(), len) == 0) - { - auto lStyles = GetWindowLong(hwnd, GWL_STYLE); - - if (lStyles & WS_MAXIMIZE) - { - ShowWindow(hwnd, SW_MAXIMIZE); - } - else - { - ShowWindow(hwnd, SW_RESTORE); - } - - SetForegroundWindow(hwnd); - return FALSE; - } - } - - return TRUE; - }; - - EnumWindows(callback, 0); -} - -void open_settings_window(std::optional settings_window) -{ - if (g_settings_process_id != 0) - { - // nl instead of showing the window, send message to it (flyout might need to be hidden, main setting window activated) - // bring_settings_to_front(); - if (current_settings_ipc) - { - if (settings_window.has_value()) - { - std::wstring msg = L"{\"ShowYourself\":\"" + settings_window.value() + L"\"}"; - current_settings_ipc->send(msg); - } - else - { - current_settings_ipc->send(L"{\"ShowYourself\":\"Dashboard\"}"); - } - } - } - else - { - if (!g_isLaunchInProgress) - { - std::thread([settings_window]() { - run_settings_window(false, false, settings_window); - }).detach(); - } - } -} - -void close_settings_window() -{ - if (g_settings_process_id != 0) - { - SetEvent(g_terminateSettingsEvent); - wil::unique_handle proc{ OpenProcess(PROCESS_ALL_ACCESS, false, g_settings_process_id) }; - if (proc) - { - WaitForSingleObject(proc.get(), 1500); - TerminateProcess(proc.get(), 0); - } - } -} - -void open_oobe_window() -{ - std::thread([]() { - run_settings_window(true, false, std::nullopt); - }).detach(); -} - -void open_scoobe_window() -{ - std::thread([]() { - run_settings_window(false, true, std::nullopt); - }).detach(); -} - -std::string ESettingsWindowNames_to_string(ESettingsWindowNames value) -{ - switch (value) - { - case ESettingsWindowNames::Dashboard: - return "Dashboard"; - case ESettingsWindowNames::Overview: - return "Overview"; - case ESettingsWindowNames::AlwaysOnTop: - return "AlwaysOnTop"; - case ESettingsWindowNames::Awake: - return "Awake"; - case ESettingsWindowNames::ColorPicker: - return "ColorPicker"; - case ESettingsWindowNames::CmdNotFound: - return "CmdNotFound"; - case ESettingsWindowNames::LightSwitch: - return "LightSwitch"; - case ESettingsWindowNames::FancyZones: - return "FancyZones"; - case ESettingsWindowNames::FileLocksmith: - return "FileLocksmith"; - case ESettingsWindowNames::Run: - return "Run"; - case ESettingsWindowNames::ImageResizer: - return "ImageResizer"; - case ESettingsWindowNames::KBM: - return "KBM"; - case ESettingsWindowNames::MouseUtils: - return "MouseUtils"; - case ESettingsWindowNames::MouseWithoutBorders: - return "MouseWithoutBorders"; - case ESettingsWindowNames::Peek: - return "Peek"; - case ESettingsWindowNames::PowerAccent: - return "PowerAccent"; - case ESettingsWindowNames::PowerLauncher: - return "PowerLauncher"; - case ESettingsWindowNames::PowerPreview: - return "PowerPreview"; - case ESettingsWindowNames::PowerRename: - return "PowerRename"; - case ESettingsWindowNames::FileExplorer: - return "FileExplorer"; - case ESettingsWindowNames::ShortcutGuide: - return "ShortcutGuide"; - case ESettingsWindowNames::Hosts: - return "Hosts"; - case ESettingsWindowNames::MeasureTool: - return "MeasureTool"; - case ESettingsWindowNames::PowerOCR: - return "PowerOcr"; - case ESettingsWindowNames::Workspaces: - return "Workspaces"; - case ESettingsWindowNames::RegistryPreview: - return "RegistryPreview"; - case ESettingsWindowNames::CropAndLock: - return "CropAndLock"; - case ESettingsWindowNames::EnvironmentVariables: - return "EnvironmentVariables"; - case ESettingsWindowNames::AdvancedPaste: - return "AdvancedPaste"; - case ESettingsWindowNames::NewPlus: - return "NewPlus"; - case ESettingsWindowNames::CmdPal: - return "CmdPal"; - case ESettingsWindowNames::ZoomIt: - return "ZoomIt"; - case ESettingsWindowNames::PowerDisplay: - return "PowerDisplay"; - default: - { - Logger::error(L"Can't convert ESettingsWindowNames value={} to string", static_cast(value)); - assert(false); - } - } - return ""; -} - -ESettingsWindowNames ESettingsWindowNames_from_string(std::string value) -{ - if (value == "Dashboard") - { - return ESettingsWindowNames::Dashboard; - } - else if (value == "Overview") - { - return ESettingsWindowNames::Overview; - } - else if (value == "AlwaysOnTop") - { - return ESettingsWindowNames::AlwaysOnTop; - } - else if (value == "Awake") - { - return ESettingsWindowNames::Awake; - } - else if (value == "ColorPicker") - { - return ESettingsWindowNames::ColorPicker; - } - else if (value == "CmdNotFound") - { - return ESettingsWindowNames::CmdNotFound; - } - else if (value == "LightSwitch") - { - return ESettingsWindowNames::LightSwitch; - } - else if (value == "FancyZones") - { - return ESettingsWindowNames::FancyZones; - } - else if (value == "FileLocksmith") - { - return ESettingsWindowNames::FileLocksmith; - } - else if (value == "Run") - { - return ESettingsWindowNames::Run; - } - else if (value == "ImageResizer") - { - return ESettingsWindowNames::ImageResizer; - } - else if (value == "KBM") - { - return ESettingsWindowNames::KBM; - } - else if (value == "MouseUtils") - { - return ESettingsWindowNames::MouseUtils; - } - else if (value == "MouseWithoutBorders") - { - return ESettingsWindowNames::MouseWithoutBorders; - } - else if (value == "Peek") - { - return ESettingsWindowNames::Peek; - } - else if (value == "PowerAccent") - { - return ESettingsWindowNames::PowerAccent; - } - else if (value == "PowerLauncher") - { - return ESettingsWindowNames::PowerLauncher; - } - else if (value == "PowerPreview") - { - return ESettingsWindowNames::PowerPreview; - } - else if (value == "PowerRename") - { - return ESettingsWindowNames::PowerRename; - } - else if (value == "FileExplorer") - { - return ESettingsWindowNames::FileExplorer; - } - else if (value == "ShortcutGuide") - { - return ESettingsWindowNames::ShortcutGuide; - } - else if (value == "Hosts") - { - return ESettingsWindowNames::Hosts; - } - else if (value == "MeasureTool") - { - return ESettingsWindowNames::MeasureTool; - } - else if (value == "PowerOcr") - { - return ESettingsWindowNames::PowerOCR; - } - else if (value == "Workspaces") - { - return ESettingsWindowNames::Workspaces; - } - else if (value == "RegistryPreview") - { - return ESettingsWindowNames::RegistryPreview; - } - else if (value == "CropAndLock") - { - return ESettingsWindowNames::CropAndLock; - } - else if (value == "EnvironmentVariables") - { - return ESettingsWindowNames::EnvironmentVariables; - } - else if (value == "AdvancedPaste") - { - return ESettingsWindowNames::AdvancedPaste; - } - else if (value == "NewPlus") - { - return ESettingsWindowNames::NewPlus; - } - else if (value == "CmdPal") - { - return ESettingsWindowNames::CmdPal; - } - else if (value == "ZoomIt") - { - return ESettingsWindowNames::ZoomIt; - } - else if (value == "PowerDisplay") - { - return ESettingsWindowNames::PowerDisplay; - } - else - { - Logger::error(L"Can't convert string value={} to ESettingsWindowNames", winrt::to_hstring(value)); - assert(false); - } - - return ESettingsWindowNames::Dashboard; -} diff --git a/src/runner/settings_window.h b/src/runner/settings_window.h deleted file mode 100644 index 4da4d70a7a..0000000000 --- a/src/runner/settings_window.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once -#include -#include - -enum class ESettingsWindowNames -{ - Dashboard = 0, - Overview, - AlwaysOnTop, - Awake, - ColorPicker, - CmdNotFound, - LightSwitch, - FancyZones, - FileLocksmith, - Run, - ImageResizer, - KBM, - MouseUtils, - MouseWithoutBorders, - Peek, - PowerAccent, - PowerLauncher, - PowerPreview, - PowerRename, - FileExplorer, - ShortcutGuide, - Hosts, - MeasureTool, - PowerOCR, - Workspaces, - RegistryPreview, - CropAndLock, - EnvironmentVariables, - AdvancedPaste, - NewPlus, - CmdPal, - ZoomIt, - PowerDisplay, -}; - -std::string ESettingsWindowNames_to_string(ESettingsWindowNames value); -ESettingsWindowNames ESettingsWindowNames_from_string(std::string value); - -void open_settings_window(std::optional settings_window); -void close_settings_window(); - -void open_oobe_window(); -void open_scoobe_window(); diff --git a/src/runner/svgs/PowerToysDark.ico b/src/runner/svgs/PowerToysDark.ico deleted file mode 100644 index 313a3d01ec2c67f29a7b952ac0805d36fb1f7ef4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37916 zcmeHQ33$xc7QZ85G$>xFSZeaxk?>l?(;{esYGW+1w8UCVLz1V#OIid?hLE(Cs!pgV zt>*iR(h7=1k!JFFrFkfydX|JHYAcdvDGgcQ`DJqD=07vZWMdNl<2$+M-h1x3=bU@) z^4|ty3Z`TL1#@7bjToCx^nd||eCI)o?v@@npZ>evi zJwKsgX2ah{C9y7Dw1*UfvKuTvHT{!*E91i3ZcIo{3s@I->_*Q$A+LUylNNn4XMT?V z0#elg&Ud#z;d*wc?tkjISB`ZFW8d|j9HUE9U+7Snb4HmuNHF z`3K5r-4c67sJ8TO;2vlDweI4Gg1@QeEpZ*0JwX>1VK-py)w7wOsrnQyZt(o!p4zPu z`)$X2WSXO&-vvV5Pt}gn3E`P=x3DTuB3A3G*Fh-ZR;`)UkyTTQ7)?S?$l^Fj=pTo)< zNjnAwq%TSwc&V%Nm(7m0*)sQsvA#t&UGqHhrh9E_b>K|l)PSeXM-IG|(>0?{w6m_a zZ;p$0tZvWd2BTUp{HxdfsP&gL{eRk6(9~%i(=yh8HKxe1gwQYVdi>sBcaQA-HSY51 zYdsvVxvsio-*DQk7q%9@cI9-VZSi|A&xq=|%k!UI(EF`?|8?hpqqkX(U!Gf0}zzvh;l2-X=k>o1v_ZAGqa5<&_WwAXL@LC`n$S) zJ$B^zMcuu#)hpbyU(mNo%^dapg~M;BwAS9-v(78P?uc*r%(nwwXWB5A?xpxJ^bQTZ&l#+P>=Ta@5Cpz)eoEy^j&b&FDDCQH@vyBcR`@H;?#(f z5gS$BOy}j2xM$7cSDDXFxBhoie6xrB>AvvGICZeo{nM^t9-rs-{$aFR@PCv`KFiHm z8<(hD6`Y+iGP_`O(D(n!(yu(6r+9vqqQizZnr_$M&p5whqU-*~`ZXSfUlk~q9nuuI zE}hz;N#yUoMR73^@h4u^<`lT(FF3J#>F$w*8M^$)t5cHKj$NUQU32w@dR+&n&aPRT z)b|~q34ZEQ!VTr2A?ss%O?<&A@aEPZPR8_&PVDP3TNB;1DE)&z;b|jot;^}SCE;M+ zfv2^H$Az}OeJ#ba*=%uHy(BV2fzmGRjL~Cl!c1AyS4q zoQJ)lZLn1e`>8CX`uiLA&DXSV`M+7PNz3&4Fxx+3~7w z{LABC)}M0x8~a0^|Hi9PeOdoHlWAC|%ft7K&1a)4XajkpOtcHMpdEBF2Q|I^o9o9~ z%Vqn^u20q7|EzVK&FLkNzdZip8AXnN-rRX6Qu+K-)}MS1%I6>B zVBx+IQ%m9x{PO;9>`!_BH$C^{{m(d7c!|9Km5muo)*pHQD;Odd9B2@T_%(^_5BOJ0l_+0 zml5B7*IHD`0fq1 z!^VmL@d4iY@ck>+b=cCGPzKopWjs(MfqRBpRjMIX@>Flg+we5O&@RN{^qwMBsa1s} zR5h)1f6Z<5ndq;Mrj@jpj|)#zSurSi%EwhQ+(lRvoC&89K4!lY(Sl5NBOGdF2%VY} zmIwGDt1LomJ)2~ZZqU&bpxj#Zmg==oVgO<$Q_%l9(I>17p%b?QF#?@AxDvtZZV)Zj zah^w=LMPD%H$frHRjxn$Zmj^_xSkq8Nm+lv8MR10&i=<)f1erbAozT^86LDn9f!6= zn3JdFOp>%Z{*NJ9eC|k7C!wFW%i)_X@I6}&AM7#(vi_#WK=yxGztl$jVD2HdO<_wR zSi73xK|9oOc#;THvQRdHGfC3w#J@z;BgxA8KN7b;==5>+KjswnAC5S4i@?iysuC(e z^KzaF)eN$DInv=`r9fB5|I+<8LXZnmx+j}E-*P^&Ib`v2q_wer%KDe}vF!g+4_I>j zCC85(Kl1un8UynBU%GzC`&VgPV2+pqdHpQ)5zaUw$njI^8##UqzOc6Qv-JKU-klUd zdM{9Xm-i)Nl-7%FeI@l;u~ML`v;PWW9vLa?|Hxcl+;M&NzxezP&&aIx`Q0_rjbG=x z388@J+L=Nfo}IAK6{tif!IfE z)y4NWq_$Xn-tgX#A!sloQlYVuF+EZn!%L%hvoZvX35&tL6IhxNhPN+pzm z=4UQmj5fTiD(5dQr>0YD+4r$XyJW|R>az=h7htuSWKBb z!kUUf$bwA3Q-sK4U-GUYge-ig%zXmAXA#yEKu^fz{(ji<4^rPrC5ZbLfDMGa3^ZT~ zAul^nTw?fBk^X4I#~RPt0eBwC%RmD@A>?If!=WPi(2qagE%#LLm| zqw+s=s18`_AMA+$?t^wj19={G;6c7J{^8@RfdB$NhN3@F1{g{Rx-#P{%QyH;^ryJ~ z$o?tcKL<F<&o3q#dCc>g zK4XGO72PXF`$6`M$i_Jgogua0 z9EN+`uMuKhtqP(oWB`z+62h0cRYbH+CFFV`4|5t;5z!VhxQ);YvZ@Mbi@4*y66N9d zmhcWFusz`jArBhgQ}TL#UMNoL&OM tb>+nmRa*>v{Hi;D&>^2km6^k6!?cE@GjpSr*1@(E)f92&5WKwY{{cnD{?7ma diff --git a/src/runner/svgs/PowerToysWhite.ico b/src/runner/svgs/PowerToysWhite.ico deleted file mode 100644 index 9e55ac8794145e3b5b5872b6ae7f71e4b144c2ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37822 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 ?VJPSV#OqUiqkY5bCqxZ#V;BUIp0M zz}`>&&Y@q~BL`im z-#L6biOa3PJeSD0GhM#(TWyf?K~8Nxd9|r_4C=GtZ-}vj^8lP#u$=e{z|2O~Uu0v>k=ly*<&+*;m1DngAQFwKyzO$;Ed_8b5 zz>WyEC&-EH=;-(#Ezl;kO|?~$>m+a$(EQL{KFm>Ib1VQaXanrE^XJbe%*@RGqXpW8 zwn1-f6Qi!_yz=qpn1y@5eu{I-lKcrnc1~T$r`v@)k%oL`z@0!jbir2-xk7y zI}sH>(wB?;(OtO#=)D9uKP2!QfEU2wXh3dE(htqaiAl@?rli?4hXmkvYk@{^!mdh1^_h zASd{2IsS9(cZM8vm;+#3=tS{3Q*!U29E@G%!@k*y@#a_gHD4e2$9Qwe zP=9mk_#u5`eC6!)OH$W#?4RuF&%=9mT=VzkA^GBZ^x^UP?>J+K?Z2a9+3A1$ZQmpI z)8QJ+2Q}%di{t%$|M~o{Awc>|(5<*mM}G^U@=x6}4j3m~gO5oC6+=|8pD92ZefZ~J zj|iYM5`*d|qMq5Q_77@Y4>#7E>Tlu1cvEfeRR0C|Sw#HRir|m4g$v zP4!VxeJWk#p!!nSG3Hb`c%P5YIC#zfvuf-c>-K!k8RpM=E^ZgULz(ya;Aa3EIR4(B zRbyXAx99WmA+UV|Y~KO(eY}74I@X8nC+Hp%3wwC5@#F8|n)DBV?Vt2vlyU$6AH9y- z!@de${V`V%e-GENSAh4Dl0FFZ8~v--@qK*l{G2^5{vNJjuLJuowtc@dPU(+c$L*1} za^!2^)gSZq@b~_#8r$l5pO5#bywAmF4LB40(Ly~#;C9(Q;dkBi$9quxJ*eRwHH#K4 zBFxRr|D^)=LL1aJ@m$WUKYLHy`TN2>@P0gOcO~Bor;o-BwhN~r`xkou8`!NOz6@;E z@UAy(2Znc=!F%1H4eIl8TpaK7u^pKDUAPy=U4a~6OXu2DK@Jpu2sU4M?-XTL|Q`|~?(lvoCMKG;vOjhBr50{bqu?IQa#yzdBX&tNNsxIu`EB4fM2 zmW%Aoy!zvHjraNZeMR`$P{X}o$K~3Zkv*KWIbypgk^^jb5Fa!)+m5u^!uwRfUJJ2u zZ$l)yJs)hLJ;gNPa|rMA`=j_DcsC9ihXwC~fp_6Rybr`)AvqvE25gC7mj!z#`92S@ zbwX?svTgI~kJou#{qdQI_xa@eS&&^0+lxv2CfE%*woR~Wf*lTGrpOo_PCN+tju{k} z!~1-^&Ubr0yf1@e!^AScy22zE^LeiV2&3fJZac0pug1zQ`$cYr+*Y^xAs193tS z>jXB{ZqMhe^SsXoJ0P|JQlAg@HEdf0J0%n7njf}IL-?1L>0?2_HZpcR3$h;oUmt8vV825)Mu?YisASv2zy=CA#UaiE zVpSkEg7^7&o$vO19vc(L0dpth1}ANG9D5>Z|DxEwAm=y43V_WEVjUpAH@3+^j(gtu z7q9cY&&RpCsrtj;u;zfB@n0!$FK>I;SKj^k{~aDbUgvqAkL^^v^8Tkk<8{8r=l5iX zqS{ShjF5$GeEM3gj-tb_yqP^x=Q-5A6+_unnN+b9X7p;Q~GmK1bm5 z3_jO!xq#@L&pGQiVO7|EPAZQQ_F|m(no{_kc#lrCFJOKb^*Q)FkK4!bs{g4ugZHeA z*UtY``&bt&e@{F*IFkcLfHyoB_+7AvgLA}z;|b(7-tS=f@Na|LC;dP?95R@n!2bgK zBDfDYZ!kxJt_M$^Ca>{+huc2M8SCVJg+kp4xl6f(JQ-XLez|jC6 z3B3Om@?MbKkv$ST?X!6;SbjKzfFFd~KJ5GP8HnUuz_|mR!GI4k8J#&GzXNbU$a4=m zZ&2ljaRP8z_u=j>@2fYShkU;dXMYbdxbQwD@X3=gw3j6e1>a`%1Qy(jO! zlikm#drmwyJNKKNyh+?X+Fv$N--pocIoK2$4TSlkRQ89L2lu!gjhYdm-%Kz&;ifZ$bJKID0MJGG5F7 zo&E{!a@#|5#J|%P+zb97+#c1=&bxQ{z55#~mmc;tSU%pp%J1FJ+(Ou5`C#1R_IURu zzjyxvdt}@mjC0%`)G){Voz$zbP&JZO-|4Q#x?#fE!fFM{QRIRdUh9yZc`iuMLv z+bQr(Id)Ung8-)(-UrX#gNSk4quMC(nhov2It}k@m%?08$YX^#qQJWZ&L!AE-yKBz z0c3v!8z`2Kx(~o>G_(giN^<>&yg}}lkkev<72kS2U9whG!t+&AEf;FAY;{hBlw5CJe4&cDS znht!ennYwrLu)$T&%zkP?ZLVM?LmR(!J7Pg3YHD-gE5BNgLMzL_pjDq*TL;k?I`Ru zt~1XGX}{svTA?3wuA$x5HEw&j-Ty>Q5TDQ*CjB2N&=#y$Kx}w)ua9%?N&T3G0ou9zYvxw$Sd_VLX zJZHi+IFmsUk7BX?Fvu4J?>L8Y;F=!k0|Gw~z8~gFJV(Mc@TowNJl@Pc6CpnWoQI$s zxu;LgV=$ND`(bW`vkCqTb0U - -TRACELOGGING_DEFINE_PROVIDER( - g_hProvider, - "Microsoft.PowerToys", - // {38e8889b-9731-53f5-e901-e8a7c1753074} - (0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74), - TraceLoggingOptionProjectTelemetry()); - -void Trace::EventLaunch(const std::wstring& versionNumber, bool isProcessElevated) -{ - TraceLoggingWriteWrapper( - g_hProvider, - "Runner_Launch", - TraceLoggingWideString(versionNumber.c_str(), "Version"), - TraceLoggingBoolean(isProcessElevated, "Elevated"), - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); -} - -void Trace::SettingsChanged(const GeneralSettings& settings) -{ - std::wstring enabledModules; - for (const auto& [name, isEnabled] : settings.isModulesEnabledMap) - { - if (isEnabled) - { - if (!enabledModules.empty()) - { - enabledModules += L", "; - } - - enabledModules += name; - } - } - - TraceLoggingWriteWrapper( - g_hProvider, - "GeneralSettingsChanged", - TraceLoggingBoolean(settings.isStartupEnabled, "RunAtStartup"), - TraceLoggingBoolean(settings.enableWarningsElevatedApps, "EnableWarningsElevatedApps"), - TraceLoggingWideString(settings.startupDisabledReason.c_str(), "StartupDisabledReason"), - TraceLoggingWideString(enabledModules.c_str(), "ModulesEnabled"), - TraceLoggingBoolean(settings.isRunElevated, "AlwaysRunElevated"), - TraceLoggingBoolean(settings.downloadUpdatesAutomatically, "DownloadUpdatesAutomatically"), - TraceLoggingBoolean(settings.enableExperimentation, "EnableExperimentation"), - TraceLoggingWideString(settings.theme.c_str(), "Theme"), - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); -} - -void Trace::UpdateCheckCompleted(bool success, bool updateAvailable, const std::wstring& fromVersion, const std::wstring& toVersion) -{ - TraceLoggingWriteWrapper( - g_hProvider, - "UpdateCheck_Completed", - TraceLoggingBoolean(success, "Success"), - TraceLoggingBoolean(updateAvailable, "UpdateAvailable"), - TraceLoggingWideString(fromVersion.c_str(), "FromVersion"), - TraceLoggingWideString(toVersion.c_str(), "ToVersion"), - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); -} - -void Trace::UpdateDownloadCompleted(bool success, const std::wstring& version) -{ - TraceLoggingWriteWrapper( - g_hProvider, - "UpdateDownload_Completed", - TraceLoggingBoolean(success, "Success"), - TraceLoggingWideString(version.c_str(), "Version"), - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); -} - -void Trace::TrayIconLeftClick(bool quickAccessEnabled) -{ - TraceLoggingWriteWrapper( - g_hProvider, - "TrayIcon_LeftClick", - TraceLoggingBoolean(quickAccessEnabled, "QuickAccessEnabled"), - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); -} - -void Trace::TrayIconDoubleClick(bool quickAccessEnabled) -{ - TraceLoggingWriteWrapper( - g_hProvider, - "TrayIcon_DoubleClick", - TraceLoggingBoolean(quickAccessEnabled, "QuickAccessEnabled"), - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); -} - -void Trace::TrayIconRightClick(bool quickAccessEnabled) -{ - TraceLoggingWriteWrapper( - g_hProvider, - "TrayIcon_RightClick", - TraceLoggingBoolean(quickAccessEnabled, "QuickAccessEnabled"), - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); -} diff --git a/src/runner/trace.h b/src/runner/trace.h deleted file mode 100644 index fb22ce3301..0000000000 --- a/src/runner/trace.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include - -struct GeneralSettings; - -class Trace : public telemetry::TraceBase -{ -public: - static void EventLaunch(const std::wstring& versionNumber, bool isProcessElevated); - static void SettingsChanged(const GeneralSettings& settings); - - // Auto-update telemetry - static void UpdateCheckCompleted(bool success, bool updateAvailable, const std::wstring& fromVersion, const std::wstring& toVersion); - static void UpdateDownloadCompleted(bool success, const std::wstring& version); - - // Tray icon interaction telemetry - static void TrayIconLeftClick(bool quickAccessEnabled); - static void TrayIconDoubleClick(bool quickAccessEnabled); - static void TrayIconRightClick(bool quickAccessEnabled); -}; diff --git a/src/runner/tray_icon.cpp b/src/runner/tray_icon.cpp deleted file mode 100644 index 307129d63b..0000000000 --- a/src/runner/tray_icon.cpp +++ /dev/null @@ -1,513 +0,0 @@ -#include "pch.h" -#include "Generated files/resource.h" -#include "settings_window.h" -#include "tray_icon.h" -#include "general_settings.h" -#include "centralized_hotkeys.h" -#include "centralized_kb_hook.h" -#include "quick_access_host.h" -#include "hotkey_conflict_detector.h" -#include "trace.h" -#include - -#include -#include -#include -#include -#include -#include -#include "bug_report.h" - -namespace -{ - HWND tray_icon_hwnd = NULL; - - enum - { - wm_icon_notify = WM_APP, - wm_run_on_main_ui_thread, - }; - - // Contains the Windows Message for taskbar creation. - UINT wm_taskbar_restart = 0; - - NOTIFYICONDATAW tray_icon_data; - bool tray_icon_created = false; - - bool about_box_shown = false; - - HMENU h_menu = nullptr; - HMENU h_sub_menu = nullptr; - bool double_click_timer_running = false; - bool double_clicked = false; - POINT tray_icon_click_point; - std::optional last_quick_access_state; // Track the last known Quick Access state - - static ThemeListener theme_listener; - static bool theme_adaptive_enabled = false; -} - -// Struct to fill with callback and the data. The window_proc is responsible for cleaning it. -struct run_on_main_ui_thread_msg -{ - main_loop_callback_function _callback; - PVOID data; -}; - -bool dispatch_run_on_main_ui_thread(main_loop_callback_function _callback, PVOID data) -{ - if (tray_icon_hwnd == NULL) - { - return false; - } - struct run_on_main_ui_thread_msg* wnd_msg = new struct run_on_main_ui_thread_msg(); - wnd_msg->_callback = _callback; - wnd_msg->data = data; - - PostMessage(tray_icon_hwnd, wm_run_on_main_ui_thread, 0, reinterpret_cast(wnd_msg)); - - return true; -} - -void change_menu_item_text(const UINT item_id, wchar_t* new_text) -{ - MENUITEMINFOW menuitem = { .cbSize = sizeof(MENUITEMINFOW), .fMask = MIIM_TYPE | MIIM_DATA }; - GetMenuItemInfoW(h_menu, item_id, false, &menuitem); - menuitem.dwTypeData = new_text; - SetMenuItemInfoW(h_menu, item_id, false, &menuitem); -} - -void open_quick_access_flyout_window() -{ - QuickAccessHost::show(); -} - -void handle_tray_command(HWND window, const WPARAM command_id, LPARAM lparam) -{ - switch (command_id) - { - case ID_SETTINGS_MENU_COMMAND: - { - std::wstring settings_window{ winrt::to_hstring(ESettingsWindowNames_to_string(static_cast(lparam))) }; - open_settings_window(settings_window); - } - break; - case ID_CLOSE_MENU_COMMAND: - if (h_menu) - { - DestroyMenu(h_menu); - } - DestroyWindow(window); - break; - case ID_ABOUT_MENU_COMMAND: - if (!about_box_shown) - { - about_box_shown = true; - std::wstring about_msg = L"PowerToys\nVersion " + get_product_version() + L"\n\xa9 2019 Microsoft Corporation"; - MessageBoxW(nullptr, about_msg.c_str(), L"About PowerToys", MB_OK); - about_box_shown = false; - } - break; - case ID_REPORT_BUG_COMMAND: - { - launch_bug_report(); - break; - } - - case ID_DOCUMENTATION_MENU_COMMAND: - { - RunNonElevatedEx(L"https://aka.ms/PowerToysOverview", L"", L""); - break; - } - case ID_QUICK_ACCESS_MENU_COMMAND: - { - open_quick_access_flyout_window(); - break; - } - } -} - -void click_timer_elapsed() -{ - double_click_timer_running = false; - if (!double_clicked) - { - // Log telemetry for single click (confirmed it's not a double click) - Trace::TrayIconLeftClick(get_general_settings().enableQuickAccess); - - if (get_general_settings().enableQuickAccess) - { - open_quick_access_flyout_window(); - } - else - { - open_settings_window(std::nullopt); - } - } -} - -LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) -{ - switch (message) - { - case WM_HOTKEY: - { - // We use the tray icon WndProc to avoid creating a dedicated window just for this message. - const auto modifiersMask = LOWORD(lparam); - const auto vkCode = HIWORD(lparam); - Logger::trace(L"On {} hotkey", CentralizedHotkeys::ToWstring({ modifiersMask, vkCode })); - CentralizedHotkeys::PopulateHotkey({ modifiersMask, vkCode }); - break; - } - case WM_CREATE: - if (wm_taskbar_restart == 0) - { - tray_icon_hwnd = window; - wm_taskbar_restart = RegisterWindowMessageW(L"TaskbarCreated"); - } - break; - case WM_DESTROY: - if (tray_icon_created) - { - Shell_NotifyIcon(NIM_DELETE, &tray_icon_data); - tray_icon_created = false; - } - close_settings_window(); - PostQuitMessage(0); - break; - case WM_CLOSE: - DestroyWindow(window); - break; - case WM_COMMAND: - handle_tray_command(window, wparam, lparam); - break; - // Shell_NotifyIcon can fail when we invoke it during the time explorer.exe isn't present/ready to handle it. - // We'll also never receive wm_taskbar_restart message if the first call to Shell_NotifyIcon failed, so we use - // WM_WINDOWPOSCHANGING which is always received on explorer startup sequence. - case WM_WINDOWPOSCHANGING: - { - if (!tray_icon_created) - { - tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE; - } - break; - } - default: - if (message == wm_icon_notify) - { - switch (lparam) - { - case WM_RBUTTONUP: - case WM_CONTEXTMENU: - { - bool quick_access_enabled = get_general_settings().enableQuickAccess; - - // Log telemetry - Trace::TrayIconRightClick(quick_access_enabled); - - // Reload menu if Quick Access state has changed or is first time - if (h_menu && (!last_quick_access_state.has_value() || quick_access_enabled != last_quick_access_state.value())) - { - DestroyMenu(h_menu); - h_menu = nullptr; - h_sub_menu = nullptr; - } - - last_quick_access_state = quick_access_enabled; - - if (!h_menu) - { - h_menu = LoadMenu(reinterpret_cast(&__ImageBase), MAKEINTRESOURCE(ID_TRAY_MENU)); - } - if (h_menu) - { - static std::wstring settings_menuitem_label = GET_RESOURCE_STRING(IDS_SETTINGS_MENU_TEXT); - static std::wstring settings_menuitem_label_leftclick = GET_RESOURCE_STRING(IDS_SETTINGS_MENU_TEXT_LEFTCLICK); - static std::wstring close_menuitem_label = GET_RESOURCE_STRING(IDS_CLOSE_MENU_TEXT); - static std::wstring submit_bug_menuitem_label = GET_RESOURCE_STRING(IDS_SUBMIT_BUG_TEXT); - static std::wstring documentation_menuitem_label = GET_RESOURCE_STRING(IDS_DOCUMENTATION_MENU_TEXT); - static std::wstring quick_access_menuitem_label = GET_RESOURCE_STRING(IDS_QUICK_ACCESS_MENU_TEXT); - - // Update Settings menu text based on Quick Access state - if (quick_access_enabled) - { - change_menu_item_text(ID_SETTINGS_MENU_COMMAND, settings_menuitem_label.data()); - } - else - { - change_menu_item_text(ID_SETTINGS_MENU_COMMAND, settings_menuitem_label_leftclick.data()); - } - - change_menu_item_text(ID_CLOSE_MENU_COMMAND, close_menuitem_label.data()); - change_menu_item_text(ID_REPORT_BUG_COMMAND, submit_bug_menuitem_label.data()); - bool bug_report_disabled = is_bug_report_running(); - EnableMenuItem(h_sub_menu, ID_REPORT_BUG_COMMAND, MF_BYCOMMAND | (bug_report_disabled ? MF_GRAYED : MF_ENABLED)); - change_menu_item_text(ID_DOCUMENTATION_MENU_COMMAND, documentation_menuitem_label.data()); - change_menu_item_text(ID_QUICK_ACCESS_MENU_COMMAND, quick_access_menuitem_label.data()); - - // Hide or show Quick Access menu item based on setting - if (!h_sub_menu) - { - h_sub_menu = GetSubMenu(h_menu, 0); - } - if (!quick_access_enabled) - { - // Remove Quick Access menu item when disabled - DeleteMenu(h_sub_menu, ID_QUICK_ACCESS_MENU_COMMAND, MF_BYCOMMAND); - } - } - if (!h_sub_menu) - { - h_sub_menu = GetSubMenu(h_menu, 0); - } - POINT mouse_pointer; - GetCursorPos(&mouse_pointer); - SetForegroundWindow(window); // Needed for the context menu to disappear. - TrackPopupMenu(h_sub_menu, TPM_CENTERALIGN | TPM_BOTTOMALIGN, mouse_pointer.x, mouse_pointer.y, 0, window, nullptr); - break; - } - case WM_LBUTTONUP: - { - // ignore event if this is the second click of a double click - if (!double_click_timer_running) - { - // start timer for detecting single or double click - double_click_timer_running = true; - double_clicked = false; - - UINT doubleClickTime = GetDoubleClickTime(); - std::thread([doubleClickTime]() { - std::this_thread::sleep_for(std::chrono::milliseconds(doubleClickTime)); - click_timer_elapsed(); - }).detach(); - } - break; - } - case WM_LBUTTONDBLCLK: - { - // Log telemetry - Trace::TrayIconDoubleClick(get_general_settings().enableQuickAccess); - - double_clicked = true; - open_settings_window(std::nullopt); - break; - } - break; - } - } - else if (message == wm_run_on_main_ui_thread) - { - if (lparam != NULL) - { - struct run_on_main_ui_thread_msg* msg = reinterpret_cast(lparam); - msg->_callback(msg->data); - delete msg; - lparam = NULL; - } - break; - } - else if (message == wm_taskbar_restart) - { - tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE; - break; - } - } - return DefWindowProc(window, message, wparam, lparam); -} - -static HICON get_icon(Theme theme) -{ - std::wstring icon_path = get_module_folderpath(); - icon_path += theme == Theme::Dark ? L"\\svgs\\PowerToysWhite.ico" : L"\\svgs\\PowerToysDark.ico"; - Logger::trace(L"get_icon: Loading icon from path: {}", icon_path); - - HICON icon = static_cast(LoadImage(NULL, - icon_path.c_str(), - IMAGE_ICON, - 0, - 0, - LR_LOADFROMFILE | LR_DEFAULTSIZE | LR_SHARED)); - if (!icon) - { - Logger::warn(L"get_icon: Failed to load icon from {}, error: {}", icon_path, GetLastError()); - } - return icon; -} - - -static void handle_theme_change() -{ - if (theme_adaptive_enabled) - { - tray_icon_data.hIcon = get_icon(ThemeHelpers::GetSystemTheme()); - Shell_NotifyIcon(NIM_MODIFY, &tray_icon_data); - } -} - -void update_bug_report_menu_status(bool isRunning) -{ - if (h_sub_menu != nullptr) - { - EnableMenuItem(h_sub_menu, ID_REPORT_BUG_COMMAND, MF_BYCOMMAND | (isRunning ? MF_GRAYED : MF_ENABLED)); - } -} - -void start_tray_icon(bool isProcessElevated, bool theme_adaptive) -{ - theme_adaptive_enabled = theme_adaptive; - auto h_instance = reinterpret_cast(&__ImageBase); - HICON const icon = theme_adaptive ? get_icon(ThemeHelpers::GetSystemTheme()) : LoadIcon(h_instance, MAKEINTRESOURCE(APPICON)); - if (icon) - { - UINT id_tray_icon = 1; - - WNDCLASS wc = {}; - wc.hCursor = LoadCursor(nullptr, IDC_ARROW); - wc.hInstance = h_instance; - wc.lpszClassName = pt_tray_icon_window_class; - wc.style = CS_HREDRAW | CS_VREDRAW; - wc.lpfnWndProc = tray_icon_window_proc; - wc.hIcon = icon; - RegisterClass(&wc); - auto hwnd = CreateWindowW(wc.lpszClassName, - pt_tray_icon_window_class, - WS_OVERLAPPEDWINDOW | WS_POPUP, - CW_USEDEFAULT, - CW_USEDEFAULT, - CW_USEDEFAULT, - CW_USEDEFAULT, - nullptr, - nullptr, - wc.hInstance, - nullptr); - WINRT_VERIFY(hwnd); - CentralizedHotkeys::RegisterWindow(hwnd); - CentralizedKeyboardHook::RegisterWindow(hwnd); - memset(&tray_icon_data, 0, sizeof(tray_icon_data)); - tray_icon_data.cbSize = sizeof(tray_icon_data); - tray_icon_data.hIcon = icon; - tray_icon_data.hWnd = hwnd; - tray_icon_data.uID = id_tray_icon; - tray_icon_data.uCallbackMessage = wm_icon_notify; - - std::wstringstream pt_version_tooltip_stream; - if (isProcessElevated) - { - pt_version_tooltip_stream << GET_RESOURCE_STRING(IDS_TRAY_ICON_ADMIN_TOOLTIP) << L": "; - } - - pt_version_tooltip_stream << L"PowerToys " << get_product_version() << '\0'; - std::wstring pt_version_tooltip = pt_version_tooltip_stream.str(); - wcscpy_s(tray_icon_data.szTip, sizeof(tray_icon_data.szTip) / sizeof(WCHAR), pt_version_tooltip.c_str()); - tray_icon_data.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE; - ChangeWindowMessageFilterEx(hwnd, WM_COMMAND, MSGFLT_ALLOW, nullptr); - - tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE; - theme_listener.AddSystemThemeChangedHandler(&handle_theme_change); - - // Register callback to update bug report menu item status - BugReportManager::instance().register_callback([](bool isRunning) { - dispatch_run_on_main_ui_thread([](PVOID data) { - bool* running = static_cast(data); - update_bug_report_menu_status(*running); - delete running; - }, - new bool(isRunning)); - }); - } -} - -void set_tray_icon_visible(bool shouldIconBeVisible) -{ - tray_icon_data.uFlags |= NIF_STATE; - tray_icon_data.dwStateMask = NIS_HIDDEN; - tray_icon_data.dwState = shouldIconBeVisible ? 0 : NIS_HIDDEN; - Shell_NotifyIcon(NIM_MODIFY, &tray_icon_data); -} - -void set_tray_icon_theme_adaptive(bool theme_adaptive) -{ - Logger::info(L"set_tray_icon_theme_adaptive: Called with theme_adaptive={}, current theme_adaptive_enabled={}", - theme_adaptive, theme_adaptive_enabled); - - auto h_instance = reinterpret_cast(&__ImageBase); - HICON icon = nullptr; - - if (theme_adaptive) - { - icon = get_icon(ThemeHelpers::GetSystemTheme()); - if (!icon) - { - Logger::warn(L"set_tray_icon_theme_adaptive: Failed to load theme adaptive icon, falling back to default"); - } - } - - // If not requesting adaptive icon, or if adaptive icon failed to load, use default icon - if (!icon) - { - icon = LoadIcon(h_instance, MAKEINTRESOURCE(APPICON)); - if (theme_adaptive && icon) - { - // We requested adaptive but had to fall back, so update the flag - theme_adaptive = false; - Logger::info(L"set_tray_icon_theme_adaptive: Using default icon as fallback"); - } - } - - theme_adaptive_enabled = theme_adaptive; - - if (icon) - { - tray_icon_data.hIcon = icon; - BOOL result = Shell_NotifyIcon(NIM_MODIFY, &tray_icon_data); - Logger::info(L"set_tray_icon_theme_adaptive: Icon updated, theme_adaptive_enabled={}, Shell_NotifyIcon result={}", - theme_adaptive_enabled, result); - } - else - { - Logger::error(L"set_tray_icon_theme_adaptive: Failed to load any icon"); - } -} - -void stop_tray_icon() -{ - if (tray_icon_created) - { - // Clear bug report callbacks - BugReportManager::instance().clear_callbacks(); - SendMessage(tray_icon_hwnd, WM_CLOSE, 0, 0); - } -} -void update_quick_access_hotkey(bool enabled, PowerToysSettings::HotkeyObject hotkey) -{ - static PowerToysSettings::HotkeyObject current_hotkey; - static bool is_registered = false; - auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); - - if (is_registered) - { - CentralizedKeyboardHook::ClearModuleHotkeys(L"QuickAccess"); - hkmng.RemoveHotkeyByModule(L"GeneralSettings"); - is_registered = false; - } - - if (enabled && hotkey.get_code() != 0) - { - HotkeyConflictDetector::Hotkey hk = { - hotkey.win_pressed(), - hotkey.ctrl_pressed(), - hotkey.shift_pressed(), - hotkey.alt_pressed(), - static_cast(hotkey.get_code()) - }; - - hkmng.AddHotkey(hk, L"GeneralSettings", 0, true); - CentralizedKeyboardHook::SetHotkeyAction(L"QuickAccess", hk, []() { - open_quick_access_flyout_window(); - return true; - }); - - current_hotkey = hotkey; - is_registered = true; - } -} diff --git a/src/runner/tray_icon.h b/src/runner/tray_icon.h deleted file mode 100644 index 5ef4c3a75b..0000000000 --- a/src/runner/tray_icon.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include -#include -#include - -// Start the Tray Icon -void start_tray_icon(bool isProcessElevated, bool theme_adaptive); -// Change the Tray Icon visibility -void set_tray_icon_visible(bool shouldIconBeVisible); -// Enable or disable theme adaptive tray icon at runtime -void set_tray_icon_theme_adaptive(bool theme_adaptive); -// Stop the Tray Icon -void stop_tray_icon(); -// Open the Settings Window -void open_settings_window(std::optional settings_window); -// Update Quick Access Hotkey -void update_quick_access_hotkey(bool enabled, PowerToysSettings::HotkeyObject hotkey); -// Callback type to be called by the tray icon loop -typedef void (*main_loop_callback_function)(PVOID); -// Calls a callback in _callback -bool dispatch_run_on_main_ui_thread(main_loop_callback_function _callback, PVOID data); - -// Must be the same as: settings-ui/Settings.UI/Views/ShellPage.xaml.cs -> ExitPTItem_Tapped() -> const string ptTrayIconWindowClass -const inline wchar_t* pt_tray_icon_window_class = L"PToyTrayIconWindow"; \ No newline at end of file diff --git a/src/runner/unhandled_exception_handler.cpp b/src/runner/unhandled_exception_handler.cpp deleted file mode 100644 index 1d01349dd3..0000000000 --- a/src/runner/unhandled_exception_handler.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include "pch.h" -#if _DEBUG && _WIN64 -#include "unhandled_exception_handler.h" -#include -#pragma comment(lib, "DbgHelp.lib") -#include -#include -#include - -static IMAGEHLP_SYMBOL64* p_symbol = static_cast(malloc(sizeof(IMAGEHLP_SYMBOL64) + MAX_PATH * sizeof(WCHAR))); -static IMAGEHLP_LINE64 line; -static bool processing_exception = false; -static WCHAR module_path[MAX_PATH]; -static LPTOP_LEVEL_EXCEPTION_FILTER default_top_level_exception_handler = NULL; - -static const WCHAR* exception_description(const DWORD& code) -{ - switch (code) - { - case EXCEPTION_ACCESS_VIOLATION: - return L"EXCEPTION_ACCESS_VIOLATION"; - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - return L"EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; - case EXCEPTION_BREAKPOINT: - return L"EXCEPTION_BREAKPOINT"; - case EXCEPTION_DATATYPE_MISALIGNMENT: - return L"EXCEPTION_DATATYPE_MISALIGNMENT"; - case EXCEPTION_FLT_DENORMAL_OPERAND: - return L"EXCEPTION_FLT_DENORMAL_OPERAND"; - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - return L"EXCEPTION_FLT_DIVIDE_BY_ZERO"; - case EXCEPTION_FLT_INEXACT_RESULT: - return L"EXCEPTION_FLT_INEXACT_RESULT"; - case EXCEPTION_FLT_INVALID_OPERATION: - return L"EXCEPTION_FLT_INVALID_OPERATION"; - case EXCEPTION_FLT_OVERFLOW: - return L"EXCEPTION_FLT_OVERFLOW"; - case EXCEPTION_FLT_STACK_CHECK: - return L"EXCEPTION_FLT_STACK_CHECK"; - case EXCEPTION_FLT_UNDERFLOW: - return L"EXCEPTION_FLT_UNDERFLOW"; - case EXCEPTION_ILLEGAL_INSTRUCTION: - return L"EXCEPTION_ILLEGAL_INSTRUCTION"; - case EXCEPTION_IN_PAGE_ERROR: - return L"EXCEPTION_IN_PAGE_ERROR"; - case EXCEPTION_INT_DIVIDE_BY_ZERO: - return L"EXCEPTION_INT_DIVIDE_BY_ZERO"; - case EXCEPTION_INT_OVERFLOW: - return L"EXCEPTION_INT_OVERFLOW"; - case EXCEPTION_INVALID_DISPOSITION: - return L"EXCEPTION_INVALID_DISPOSITION"; - case EXCEPTION_NONCONTINUABLE_EXCEPTION: - return L"EXCEPTION_NONCONTINUABLE_EXCEPTION"; - case EXCEPTION_PRIV_INSTRUCTION: - return L"EXCEPTION_PRIV_INSTRUCTION"; - case EXCEPTION_SINGLE_STEP: - return L"EXCEPTION_SINGLE_STEP"; - case EXCEPTION_STACK_OVERFLOW: - return L"EXCEPTION_STACK_OVERFLOW"; - default: - return L"UNKNOWN EXCEPTION"; - } -} - -void init_symbols() -{ - SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); - line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - auto process = GetCurrentProcess(); - SymInitialize(process, NULL, TRUE); -} - -void log_stack_trace(std::wstring& generalErrorDescription) -{ - memset(p_symbol, '\0', sizeof(*p_symbol) + MAX_PATH); - memset(&module_path[0], '\0', sizeof(module_path)); - line.LineNumber = 0; - - CONTEXT context; - RtlCaptureContext(&context); - auto process = GetCurrentProcess(); - auto thread = GetCurrentThread(); - STACKFRAME64 stack; - memset(&stack, 0, sizeof(STACKFRAME64)); - -#ifdef _M_ARM64 - stack.AddrPC.Offset = context.Pc; - stack.AddrStack.Offset = context.Sp; - stack.AddrFrame.Offset = context.Fp; -#else - stack.AddrPC.Offset = context.Rip; - stack.AddrStack.Offset = context.Rsp; - stack.AddrFrame.Offset = context.Rbp; -#endif - stack.AddrPC.Mode = AddrModeFlat; - stack.AddrStack.Mode = AddrModeFlat; - stack.AddrFrame.Mode = AddrModeFlat; - - std::wstringstream ss; - ss << generalErrorDescription << std::endl; - for (ULONG frame = 0;; frame++) - { - auto result = StackWalk64( -#ifdef _M_ARM64 - IMAGE_FILE_MACHINE_ARM64, -#else - IMAGE_FILE_MACHINE_AMD64, -#endif - process, - thread, - &stack, - &context, - NULL, - SymFunctionTableAccess64, - SymGetModuleBase64, - NULL); - - p_symbol->MaxNameLength = MAX_PATH; - p_symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); - - DWORD64 dw64Displacement; - SymGetSymFromAddr64(process, stack.AddrPC.Offset, &dw64Displacement, p_symbol); - DWORD dwDisplacement; - SymGetLineFromAddr64(process, stack.AddrPC.Offset, &dwDisplacement, &line); - - auto module_base = SymGetModuleBase64(process, stack.AddrPC.Offset); - if (module_base) - { - GetModuleFileName(reinterpret_cast(module_base), module_path, MAX_PATH); - } - ss << module_path << "!" - << p_symbol->Name - << "(" << line.FileName << ":" << line.LineNumber << ")\n"; - if (!result) - { - break; - } - } - auto errorString = ss.str(); - MessageBoxW(NULL, errorString.c_str(), L"Unhandled Error", MB_OK | MB_ICONERROR); -} - -LONG WINAPI unhandled_exception_handler(PEXCEPTION_POINTERS info) -{ - if (!processing_exception) - { - processing_exception = true; - try - { - init_symbols(); - std::wstring ex_description = L"Exception code not available"; - if (info != NULL && info->ExceptionRecord != NULL && info->ExceptionRecord->ExceptionCode != NULL) - { - ex_description = exception_description(info->ExceptionRecord->ExceptionCode); - } - log_stack_trace(ex_description); - } - catch (...) - { - } - if (default_top_level_exception_handler != NULL && info != NULL) - { - default_top_level_exception_handler(info); - } - processing_exception = false; - } - return EXCEPTION_CONTINUE_SEARCH; -} - -extern "C" void AbortHandler(int /*signal_number*/) -{ - init_symbols(); - std::wstring ex_description = L"SIGABRT was raised."; - log_stack_trace(ex_description); -} - -void init_global_error_handlers() -{ - default_top_level_exception_handler = SetUnhandledExceptionFilter(unhandled_exception_handler); - signal(SIGABRT, &AbortHandler); -} -#endif diff --git a/src/runner/unhandled_exception_handler.h b/src/runner/unhandled_exception_handler.h deleted file mode 100644 index 2aaf07b099..0000000000 --- a/src/runner/unhandled_exception_handler.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -#if _DEBUG && _WIN64 -void init_global_error_handlers(); -#endif