diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index cd9e2ffa6c..5aea64e0e9 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -569,6 +569,7 @@ errc errorlevel ERRORMESSAGE ERRORTITLE +ESettings esize estdir etcore @@ -994,6 +995,7 @@ IRepository IResult ISavable isbi +iss ISearch IService isetting diff --git a/src/runner/main.cpp b/src/runner/main.cpp index 070028c123..dac5749708 100644 --- a/src/runner/main.cpp +++ b/src/runner/main.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "tray_icon.h" #include "powertoy_module.h" #include "trace.h" @@ -69,10 +70,15 @@ inline wil::unique_mutex_nothrow create_msi_mutex() return createAppMutex(POWERTOYS_MSI_MUTEX_NAME); } -void open_menu_from_another_instance() +void open_menu_from_another_instance(std::optional settings_window) { const HWND hwnd_main = FindWindowW(L"PToyTrayIconWindow", nullptr); - PostMessageW(hwnd_main, WM_COMMAND, ID_SETTINGS_MENU_COMMAND, 0); + LPARAM msg = static_cast(ESettingsWindowNames::Overview); + if (settings_window.has_value()) + { + msg = static_cast(ESettingsWindowNames_from_string(settings_window.value())); + } + PostMessageW(hwnd_main, WM_COMMAND, ID_SETTINGS_MENU_COMMAND, msg); } void debug_verify_launcher_assets() @@ -99,7 +105,7 @@ void debug_verify_launcher_assets() } } -int runner(bool isProcessElevated, bool openSettings, bool openOobe) +int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow, bool openOobe) { Logger::info("Runner is starting. Elevated={}", isProcessElevated); DPIAware::EnableDPIAwarenessForThisProcess(); @@ -176,7 +182,12 @@ int runner(bool isProcessElevated, bool openSettings, bool openOobe) if (openSettings) { - open_settings_window(); + std::optional window; + if (!settingsWindow.empty()) + { + window = winrt::to_hstring(settingsWindow); + } + open_settings_window(window); } if (openOobe) @@ -263,7 +274,7 @@ toast_notification_handler_result toast_notification_handler(const std::wstring_ } else if (param == open_settings) { - open_menu_from_another_instance(); + open_menu_from_another_instance(std::nullopt); return toast_notification_handler_result::exit_success; } else @@ -325,11 +336,24 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine logFilePath.append(LogSettings::runnerLogPath); Logger::init(LogSettings::runnerLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location()); + const std::string cmdLine{ lpCmdLine }; + 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(); + open_menu_from_another_instance(settings_window); return 0; } @@ -355,7 +379,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine modules(); auto general_settings = load_general_settings(); - const bool openSettings = std::string(lpCmdLine).find("--open-settings") != std::string::npos; // Apply the general settings but don't save it as the modules() variable has not been loaded yet apply_general_settings(general_settings, false); @@ -363,13 +386,13 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine const bool elevated = is_process_elevated(); if ((elevated || general_settings.GetNamedBoolean(L"run_elevated", false) == false || - std::string(lpCmdLine).find("--dont-elevate") != std::string::npos)) + cmdLine.find("--dont-elevate") != std::string::npos)) { - result = runner(elevated, openSettings, openOobe); + result = runner(elevated, open_settings, settings_window, openOobe); } else { - schedule_restart_as_elevated(openSettings); + schedule_restart_as_elevated(open_settings); result = 0; } } diff --git a/src/runner/settings_window.cpp b/src/runner/settings_window.cpp index 839de4167b..9d91bbb020 100644 --- a/src/runner/settings_window.cpp +++ b/src/runner/settings_window.cpp @@ -23,6 +23,7 @@ #include #include #include +#include "settings_window.h" #define BUFSIZE 1024 @@ -259,7 +260,7 @@ BOOL run_settings_non_elevated(LPCWSTR executable_path, LPWSTR executable_args, DWORD g_settings_process_id = 0; -void run_settings_window(bool showOobeWindow) +void run_settings_window(bool show_oobe_window, std::optional settings_window) { g_isLaunchInProgress = true; @@ -324,7 +325,7 @@ void run_settings_window(bool showOobeWindow) std::wstring settings_isUserAnAdmin = isAdmin ? L"true" : L"false"; // Arg 8: should oobe window be shown - std::wstring settings_showOobe = showOobeWindow ? L"true" : L"false"; + std::wstring settings_showOobe = show_oobe_window ? L"true" : L"false"; // create general settings file to initialize the settings file with installation configurations like : // 1. Run on start up. @@ -347,6 +348,12 @@ void run_settings_window(bool showOobeWindow) executable_args.append(L" "); executable_args.append(settings_showOobe); + if (settings_window.has_value()) + { + executable_args.append(L" "); + executable_args.append(settings_window.value()); + } + BOOL process_created = false; if (is_process_elevated()) @@ -462,7 +469,7 @@ void bring_settings_to_front() EnumWindows(callback, 0); } -void open_settings_window() +void open_settings_window(std::optional settings_window) { if (g_settings_process_id != 0) { @@ -472,8 +479,8 @@ void open_settings_window() { if (!g_isLaunchInProgress) { - std::thread([]() { - run_settings_window(false); + std::thread([settings_window]() { + run_settings_window(false, settings_window); }).detach(); } } @@ -494,6 +501,96 @@ void close_settings_window() void open_oobe_window() { std::thread([]() { - run_settings_window(true); + run_settings_window(true, std::nullopt); }).detach(); } + +std::string ESettingsWindowNames_to_string(ESettingsWindowNames value) +{ + switch (value) + { + case ESettingsWindowNames::Overview: + return "Overview"; + case ESettingsWindowNames::Awake: + return "Awake"; + case ESettingsWindowNames::ColorPicker: + return "ColorPicker"; + case ESettingsWindowNames::FancyZones: + return "FancyZones"; + case ESettingsWindowNames::Run: + return "Run"; + case ESettingsWindowNames::ImageResizer: + return "ImageResizer"; + case ESettingsWindowNames::KBM: + return "KBM"; + case ESettingsWindowNames::PowerRename: + return "PowerRename"; + case ESettingsWindowNames::FileExplorer: + return "FileExplorer"; + case ESettingsWindowNames::ShortcutGuide: + return "ShortcutGuide"; + case ESettingsWindowNames::VideoConference: + return "VideoConference"; + 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 == "Overview") + { + return ESettingsWindowNames::Overview; + } + else if (value == "Awake") + { + return ESettingsWindowNames::Awake; + } + else if (value == "ColorPicker") + { + return ESettingsWindowNames::ColorPicker; + } + else if (value == "FancyZones") + { + return ESettingsWindowNames::FancyZones; + } + else if (value == "Run") + { + return ESettingsWindowNames::Run; + } + else if (value == "ImageResizer") + { + return ESettingsWindowNames::ImageResizer; + } + else if (value == "KBM") + { + return ESettingsWindowNames::KBM; + } + else if (value == "PowerRename") + { + return ESettingsWindowNames::PowerRename; + } + else if (value == "FileExplorer") + { + return ESettingsWindowNames::FileExplorer; + } + else if (value == "ShortcutGuide") + { + return ESettingsWindowNames::ShortcutGuide; + } + else if (value == "VideoConference") + { + return ESettingsWindowNames::VideoConference; + } + else + { + Logger::error(L"Can't convert string value={} to ESettingsWindowNames", winrt::to_hstring(value)); + assert(false); + } + + return ESettingsWindowNames::Overview; +} diff --git a/src/runner/settings_window.h b/src/runner/settings_window.h index c4eb56bb7c..44614b0a01 100644 --- a/src/runner/settings_window.h +++ b/src/runner/settings_window.h @@ -1,5 +1,26 @@ #pragma once -void open_settings_window(); +#include +#include + +enum class ESettingsWindowNames +{ + Overview = 0, + Awake, + ColorPicker, + FancyZones, + Run, + ImageResizer, + KBM, + PowerRename, + FileExplorer, + ShortcutGuide, + VideoConference +}; + +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(); \ No newline at end of file diff --git a/src/runner/tray_icon.cpp b/src/runner/tray_icon.cpp index 1c059eff7c..96f1630c65 100644 --- a/src/runner/tray_icon.cpp +++ b/src/runner/tray_icon.cpp @@ -62,12 +62,15 @@ void change_menu_item_text(const UINT item_id, wchar_t* new_text) SetMenuItemInfoW(h_menu, item_id, false, &menuitem); } -void handle_tray_command(HWND window, const WPARAM command_id) +void handle_tray_command(HWND window, const WPARAM command_id, LPARAM lparam) { switch (command_id) { case ID_SETTINGS_MENU_COMMAND: - open_settings_window(); + { + std::wstring settings_window{ winrt::to_hstring(ESettingsWindowNames_to_string(static_cast(lparam))) }; + open_settings_window(settings_window); + } break; case ID_EXIT_MENU_COMMAND: if (h_menu) @@ -147,7 +150,7 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam DestroyWindow(window); break; case WM_COMMAND: - handle_tray_command(window, wparam); + 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 @@ -167,7 +170,7 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam { case WM_LBUTTONUP: { - open_settings_window(); + open_settings_window(std::nullopt); break; } case WM_RBUTTONUP: diff --git a/src/runner/tray_icon.h b/src/runner/tray_icon.h index f97cc6ea95..e65fa9720f 100644 --- a/src/runner/tray_icon.h +++ b/src/runner/tray_icon.h @@ -1,10 +1,13 @@ #pragma once +#include +#include + // Start the Tray Icon void start_tray_icon(); // Stop the Tray Icon void stop_tray_icon(); // Open the Settings Window -void open_settings_window(); +void open_settings_window(std::optional settings_window); // Callback type to be called by the tray icon loop typedef void (*main_loop_callback_function)(PVOID); // Calls a callback in _callback diff --git a/src/settings-ui/PowerToys.Settings/App.xaml.cs b/src/settings-ui/PowerToys.Settings/App.xaml.cs index cc6b3553a8..fdcb9b63c9 100644 --- a/src/settings-ui/PowerToys.Settings/App.xaml.cs +++ b/src/settings-ui/PowerToys.Settings/App.xaml.cs @@ -18,6 +18,8 @@ namespace PowerToys.Settings public bool ShowOobe { get; set; } + public Type StartupPage { get; set; } = typeof(Microsoft.PowerToys.Settings.UI.Views.GeneralPage); + public void OpenSettingsWindow(Type type) { if (settingsWindow == null) @@ -47,6 +49,7 @@ namespace PowerToys.Settings { settingsWindow = new MainWindow(); settingsWindow.Show(); + settingsWindow.NavigateToSection(StartupPage); } else { diff --git a/src/settings-ui/PowerToys.Settings/Program.cs b/src/settings-ui/PowerToys.Settings/Program.cs index 5c5424c9f2..90d49b7f37 100644 --- a/src/settings-ui/PowerToys.Settings/Program.cs +++ b/src/settings-ui/PowerToys.Settings/Program.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics; using System.Windows; using interop; using ManagedCommon; @@ -20,11 +21,12 @@ namespace PowerToys.Settings ElevatedStatus, IsUserAdmin, ShowOobeWindow, + SettingsWindow, } // Quantity of arguments - private const int RequiredArgumentsQty = 6; - private const int RequiredAndOptionalArgumentsQty = 7; + private const int RequiredArgumentsQty = 7; + private const int RequiredAndOptionalArgumentsQty = 8; // Create an instance of the IPC wrapper. private static TwoWayPipeMessageIPCManaged ipcmanager; @@ -52,11 +54,26 @@ namespace PowerToys.Settings IsElevated = args[(int)Arguments.ElevatedStatus] == "true"; IsUserAnAdmin = args[(int)Arguments.IsUserAdmin] == "true"; + app.ShowOobe = args[(int)Arguments.ShowOobeWindow] == "true"; if (args.Length == RequiredAndOptionalArgumentsQty) { - // open oobe window - app.ShowOobe = args[(int)Arguments.ShowOobeWindow] == "true"; + // open specific window + switch (args[(int)Arguments.SettingsWindow]) + { + case "Overview": app.StartupPage = typeof(Microsoft.PowerToys.Settings.UI.Views.GeneralPage); break; + case "Awake": app.StartupPage = typeof(Microsoft.PowerToys.Settings.UI.Views.AwakePage); break; + case "ColorPicker": app.StartupPage = typeof(Microsoft.PowerToys.Settings.UI.Views.ColorPickerPage); break; + case "FancyZones": app.StartupPage = typeof(Microsoft.PowerToys.Settings.UI.Views.FancyZonesPage); break; + case "Run": app.StartupPage = typeof(Microsoft.PowerToys.Settings.UI.Views.PowerLauncherPage); break; + case "ImageResizer": app.StartupPage = typeof(Microsoft.PowerToys.Settings.UI.Views.ImageResizerPage); break; + case "KBM": app.StartupPage = typeof(Microsoft.PowerToys.Settings.UI.Views.KeyboardManagerPage); break; + case "PowerRename": app.StartupPage = typeof(Microsoft.PowerToys.Settings.UI.Views.PowerRenamePage); break; + case "FileExplorer": app.StartupPage = typeof(Microsoft.PowerToys.Settings.UI.Views.PowerPreviewPage); break; + case "ShortcutGuide": app.StartupPage = typeof(Microsoft.PowerToys.Settings.UI.Views.ShortcutGuidePage); break; + case "VideoConference": app.StartupPage = typeof(Microsoft.PowerToys.Settings.UI.Views.VideoConferencePage); break; + default: Debug.Assert(false, "Unexpected SettingsWindow argument value"); break; + } } RunnerHelper.WaitForPowerToysRunner(PowerToysPID, () =>