mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 09:46:54 +02:00
Settings Flyout improvement (#43840)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This pull request introduces the new Quick Access feature to PowerToys by integrating its host process management into the runner and system tray. The changes add the Quick Access host implementation, update project and build files to include it, and modify the runner and tray icon logic to launch and interact with the Quick Access UI. <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] Closes: #43694 <!-- - [ ] Closes: #yyy (add separate lines for additional resolved issues) --> - [x] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [x] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed, or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <img width="290" height="420" alt="image" src="https://github.com/user-attachments/assets/7390a706-171c-479f-a4a2-999b18cfc65f" /> <img width="290" height="420" alt="image" src="https://github.com/user-attachments/assets/99e99bc9-b1a3-46c6-b648-81e3048dec1b" /> <img width="490" height="350" alt="image" src="https://github.com/user-attachments/assets/2cce4ad6-a54e-4587-87b7-fdc7fba1f54f" /> <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed --------- Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com> Signed-off-by: Shuai Yuan <shuai.yuan.zju@gmail.com> Co-authored-by: Niels Laute <niels.laute@live.nl>
This commit is contained in:
7
.github/actions/spell-check/expect.txt
vendored
7
.github/actions/spell-check/expect.txt
vendored
@@ -365,6 +365,7 @@ DEFAULTICON
|
|||||||
defaultlib
|
defaultlib
|
||||||
DEFAULTONLY
|
DEFAULTONLY
|
||||||
DEFAULTTONEAREST
|
DEFAULTTONEAREST
|
||||||
|
Defaulttonearest
|
||||||
DEFAULTTONULL
|
DEFAULTTONULL
|
||||||
DEFAULTTOPRIMARY
|
DEFAULTTOPRIMARY
|
||||||
DEFERERASE
|
DEFERERASE
|
||||||
@@ -868,6 +869,7 @@ lastcodeanalysissucceeded
|
|||||||
LASTEXITCODE
|
LASTEXITCODE
|
||||||
LAYOUTRTL
|
LAYOUTRTL
|
||||||
lbl
|
lbl
|
||||||
|
Lbuttondown
|
||||||
LCh
|
LCh
|
||||||
lcid
|
lcid
|
||||||
LCIDTo
|
LCIDTo
|
||||||
@@ -990,6 +992,7 @@ maxversiontested
|
|||||||
mber
|
mber
|
||||||
MBM
|
MBM
|
||||||
MBR
|
MBR
|
||||||
|
Mbuttondown
|
||||||
MDICHILD
|
MDICHILD
|
||||||
MDL
|
MDL
|
||||||
mdtext
|
mdtext
|
||||||
@@ -1448,6 +1451,7 @@ RAWINPUTHEADER
|
|||||||
RAWMODE
|
RAWMODE
|
||||||
RAWPATH
|
RAWPATH
|
||||||
rbhid
|
rbhid
|
||||||
|
Rbuttondown
|
||||||
rclsid
|
rclsid
|
||||||
RCZOOMIT
|
RCZOOMIT
|
||||||
remotedesktop
|
remotedesktop
|
||||||
@@ -1753,6 +1757,7 @@ svgz
|
|||||||
SVSI
|
SVSI
|
||||||
SWFO
|
SWFO
|
||||||
SWP
|
SWP
|
||||||
|
Swp
|
||||||
SWPNOSIZE
|
SWPNOSIZE
|
||||||
SWPNOZORDER
|
SWPNOZORDER
|
||||||
SWRESTORE
|
SWRESTORE
|
||||||
@@ -1772,6 +1777,7 @@ syskeydown
|
|||||||
SYSKEYUP
|
SYSKEYUP
|
||||||
SYSLIB
|
SYSLIB
|
||||||
SYSMENU
|
SYSMENU
|
||||||
|
Sysmenu
|
||||||
systemai
|
systemai
|
||||||
SYSTEMAPPS
|
SYSTEMAPPS
|
||||||
SYSTEMMODAL
|
SYSTEMMODAL
|
||||||
@@ -2097,6 +2103,7 @@ Wwanpp
|
|||||||
xap
|
xap
|
||||||
XAxis
|
XAxis
|
||||||
XButton
|
XButton
|
||||||
|
Xbuttondown
|
||||||
xclip
|
xclip
|
||||||
xcopy
|
xcopy
|
||||||
XDeployment
|
XDeployment
|
||||||
|
|||||||
@@ -1005,6 +1005,14 @@
|
|||||||
<Project Path="src/modules/ZoomIt/ZoomItSettingsInterop/ZoomItSettingsInterop.vcxproj" Id="ca7d8106-30b9-4aec-9d05-b69b31b8c461" />
|
<Project Path="src/modules/ZoomIt/ZoomItSettingsInterop/ZoomItSettingsInterop.vcxproj" Id="ca7d8106-30b9-4aec-9d05-b69b31b8c461" />
|
||||||
</Folder>
|
</Folder>
|
||||||
<Folder Name="/settings-ui/">
|
<Folder Name="/settings-ui/">
|
||||||
|
<Project Path="src/settings-ui/QuickAccess.UI/PowerToys.QuickAccess.csproj">
|
||||||
|
<Platform Solution="*|ARM64" Project="ARM64" />
|
||||||
|
<Platform Solution="*|x64" Project="x64" />
|
||||||
|
</Project>
|
||||||
|
<Project Path="src/settings-ui/Settings.UI.Controls/Settings.UI.Controls.csproj">
|
||||||
|
<Platform Solution="*|ARM64" Project="ARM64" />
|
||||||
|
<Platform Solution="*|x64" Project="x64" />
|
||||||
|
</Project>
|
||||||
<Project Path="src/settings-ui/Settings.UI.Library/Settings.UI.Library.csproj">
|
<Project Path="src/settings-ui/Settings.UI.Library/Settings.UI.Library.csproj">
|
||||||
<Platform Solution="*|ARM64" Project="ARM64" />
|
<Platform Solution="*|ARM64" Project="ARM64" />
|
||||||
<Platform Solution="*|x64" Project="x64" />
|
<Platform Solution="*|x64" Project="x64" />
|
||||||
|
|||||||
@@ -36,5 +36,6 @@ namespace ManagedCommon
|
|||||||
PowerOCR,
|
PowerOCR,
|
||||||
Workspaces,
|
Workspaces,
|
||||||
ZoomIt,
|
ZoomIt,
|
||||||
|
GeneralSettings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,6 +119,16 @@ namespace PowerToysSettings
|
|||||||
class HotkeyObject
|
class HotkeyObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
HotkeyObject() :
|
||||||
|
m_json(json::JsonObject())
|
||||||
|
{
|
||||||
|
m_json.SetNamedValue(L"win", json::value(false));
|
||||||
|
m_json.SetNamedValue(L"ctrl", json::value(false));
|
||||||
|
m_json.SetNamedValue(L"alt", json::value(false));
|
||||||
|
m_json.SetNamedValue(L"shift", json::value(false));
|
||||||
|
m_json.SetNamedValue(L"code", json::value(0));
|
||||||
|
m_json.SetNamedValue(L"key", json::value(L""));
|
||||||
|
}
|
||||||
static HotkeyObject from_json(json::JsonObject json)
|
static HotkeyObject from_json(json::JsonObject json)
|
||||||
{
|
{
|
||||||
return HotkeyObject(std::move(json));
|
return HotkeyObject(std::move(json));
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "general_settings.h"
|
#include "general_settings.h"
|
||||||
#include "auto_start_helper.h"
|
#include "auto_start_helper.h"
|
||||||
#include "tray_icon.h"
|
#include "tray_icon.h"
|
||||||
|
#include "quick_access_host.h"
|
||||||
#include "Generated files/resource.h"
|
#include "Generated files/resource.h"
|
||||||
#include "hotkey_conflict_detector.h"
|
#include "hotkey_conflict_detector.h"
|
||||||
|
|
||||||
@@ -72,6 +73,8 @@ static bool download_updates_automatically = true;
|
|||||||
static bool show_whats_new_after_updates = true;
|
static bool show_whats_new_after_updates = true;
|
||||||
static bool enable_experimentation = true;
|
static bool enable_experimentation = true;
|
||||||
static bool enable_warnings_elevated_apps = 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 DashboardSortOrder dashboard_sort_order = DashboardSortOrder::Alphabetical;
|
||||||
static json::JsonObject ignored_conflict_properties = create_default_ignored_conflict_properties();
|
static json::JsonObject ignored_conflict_properties = create_default_ignored_conflict_properties();
|
||||||
|
|
||||||
@@ -105,6 +108,8 @@ json::JsonObject GeneralSettings::to_json()
|
|||||||
result.SetNamedValue(L"dashboard_sort_order", json::value(static_cast<int>(dashboardSortOrder)));
|
result.SetNamedValue(L"dashboard_sort_order", json::value(static_cast<int>(dashboardSortOrder)));
|
||||||
result.SetNamedValue(L"is_admin", json::value(isAdmin));
|
result.SetNamedValue(L"is_admin", json::value(isAdmin));
|
||||||
result.SetNamedValue(L"enable_warnings_elevated_apps", json::value(enableWarningsElevatedApps));
|
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"theme", json::value(theme));
|
||||||
result.SetNamedValue(L"system_theme", json::value(systemTheme));
|
result.SetNamedValue(L"system_theme", json::value(systemTheme));
|
||||||
result.SetNamedValue(L"powertoys_version", json::value(powerToysVersion));
|
result.SetNamedValue(L"powertoys_version", json::value(powerToysVersion));
|
||||||
@@ -127,6 +132,11 @@ json::JsonObject load_general_settings()
|
|||||||
show_whats_new_after_updates = loaded.GetNamedBoolean(L"show_whats_new_after_updates", true);
|
show_whats_new_after_updates = loaded.GetNamedBoolean(L"show_whats_new_after_updates", true);
|
||||||
enable_experimentation = loaded.GetNamedBoolean(L"enable_experimentation", true);
|
enable_experimentation = loaded.GetNamedBoolean(L"enable_experimentation", true);
|
||||||
enable_warnings_elevated_apps = loaded.GetNamedBoolean(L"enable_warnings_elevated_apps", 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);
|
dashboard_sort_order = parse_dashboard_sort_order(loaded, dashboard_sort_order);
|
||||||
|
|
||||||
if (json::has(loaded, L"ignored_conflict_properties", json::JsonValueType::Object))
|
if (json::has(loaded, L"ignored_conflict_properties", json::JsonValueType::Object))
|
||||||
@@ -153,6 +163,8 @@ GeneralSettings get_general_settings()
|
|||||||
.isRunElevated = run_as_elevated,
|
.isRunElevated = run_as_elevated,
|
||||||
.isAdmin = is_user_admin,
|
.isAdmin = is_user_admin,
|
||||||
.enableWarningsElevatedApps = enable_warnings_elevated_apps,
|
.enableWarningsElevatedApps = enable_warnings_elevated_apps,
|
||||||
|
.enableQuickAccess = enable_quick_access,
|
||||||
|
.quickAccessShortcut = quick_access_shortcut,
|
||||||
.showNewUpdatesToastNotification = show_new_updates_toast_notification,
|
.showNewUpdatesToastNotification = show_new_updates_toast_notification,
|
||||||
.downloadUpdatesAutomatically = download_updates_automatically && is_user_admin,
|
.downloadUpdatesAutomatically = download_updates_automatically && is_user_admin,
|
||||||
.showWhatsNewAfterUpdates = show_whats_new_after_updates,
|
.showWhatsNewAfterUpdates = show_whats_new_after_updates,
|
||||||
@@ -178,11 +190,47 @@ GeneralSettings get_general_settings()
|
|||||||
|
|
||||||
void apply_general_settings(const json::JsonObject& general_configs, bool save)
|
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() });
|
Logger::info(L"apply_general_settings: {}", std::wstring{ general_configs.ToString() });
|
||||||
run_as_elevated = general_configs.GetNamedBoolean(L"run_elevated", false);
|
run_as_elevated = general_configs.GetNamedBoolean(L"run_elevated", false);
|
||||||
|
|
||||||
enable_warnings_elevated_apps = general_configs.GetNamedBoolean(L"enable_warnings_elevated_apps", true);
|
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);
|
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);
|
download_updates_automatically = general_configs.GetNamedBoolean(L"download_updates_automatically", true);
|
||||||
@@ -321,8 +369,12 @@ void apply_general_settings(const json::JsonObject& general_configs, bool save)
|
|||||||
if (save)
|
if (save)
|
||||||
{
|
{
|
||||||
GeneralSettings save_settings = get_general_settings();
|
GeneralSettings save_settings = get_general_settings();
|
||||||
PTSettingsHelper::save_general_settings(save_settings.to_json());
|
std::wstring new_settings_json_string = save_settings.to_json().Stringify().c_str();
|
||||||
Trace::SettingsChanged(save_settings);
|
if (old_settings_json_string != new_settings_json_string)
|
||||||
|
{
|
||||||
|
PTSettingsHelper::save_general_settings(save_settings.to_json());
|
||||||
|
Trace::SettingsChanged(save_settings);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,3 +464,5 @@ void start_enabled_powertoys()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <common/utils/json.h>
|
#include <common/utils/json.h>
|
||||||
|
#include <common/SettingsAPI/settings_objects.h>
|
||||||
|
|
||||||
enum class DashboardSortOrder
|
enum class DashboardSortOrder
|
||||||
{
|
{
|
||||||
@@ -18,6 +19,8 @@ struct GeneralSettings
|
|||||||
bool isRunElevated;
|
bool isRunElevated;
|
||||||
bool isAdmin;
|
bool isAdmin;
|
||||||
bool enableWarningsElevatedApps;
|
bool enableWarningsElevatedApps;
|
||||||
|
bool enableQuickAccess;
|
||||||
|
PowerToysSettings::HotkeyObject quickAccessShortcut;
|
||||||
bool showNewUpdatesToastNotification;
|
bool showNewUpdatesToastNotification;
|
||||||
bool downloadUpdatesAutomatically;
|
bool downloadUpdatesAutomatically;
|
||||||
bool showWhatsNewAfterUpdates;
|
bool showWhatsNewAfterUpdates;
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
#include "centralized_kb_hook.h"
|
#include "centralized_kb_hook.h"
|
||||||
#include "centralized_hotkeys.h"
|
#include "centralized_hotkeys.h"
|
||||||
|
#include "quick_access_host.h"
|
||||||
#include "ai_detection.h"
|
#include "ai_detection.h"
|
||||||
#include <common/utils/package.h>
|
#include <common/utils/package.h>
|
||||||
|
|
||||||
@@ -189,6 +190,11 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow
|
|||||||
#endif
|
#endif
|
||||||
Trace::RegisterProvider();
|
Trace::RegisterProvider();
|
||||||
start_tray_icon(isProcessElevated);
|
start_tray_icon(isProcessElevated);
|
||||||
|
if (get_general_settings().enableQuickAccess)
|
||||||
|
{
|
||||||
|
QuickAccessHost::start();
|
||||||
|
}
|
||||||
|
update_quick_access_hotkey(get_general_settings().enableQuickAccess, get_general_settings().quickAccessShortcut);
|
||||||
set_tray_icon_visible(get_general_settings().showSystemTrayIcon);
|
set_tray_icon_visible(get_general_settings().showSystemTrayIcon);
|
||||||
CentralizedKeyboardHook::Start();
|
CentralizedKeyboardHook::Start();
|
||||||
|
|
||||||
@@ -316,7 +322,7 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow
|
|||||||
{
|
{
|
||||||
window = winrt::to_hstring(settingsWindow);
|
window = winrt::to_hstring(settingsWindow);
|
||||||
}
|
}
|
||||||
open_settings_window(window, false);
|
open_settings_window(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (openOobe)
|
if (openOobe)
|
||||||
@@ -339,6 +345,7 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow
|
|||||||
result = -1;
|
result = -1;
|
||||||
}
|
}
|
||||||
Trace::UnregisterProvider();
|
Trace::UnregisterProvider();
|
||||||
|
QuickAccessHost::stop();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
269
src/runner/quick_access_host.cpp
Normal file
269
src/runner/quick_access_host.cpp
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "quick_access_host.h"
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <rpc.h>
|
||||||
|
#include <new>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <common/logger/logger.h>
|
||||||
|
#include <common/utils/process_path.h>
|
||||||
|
#include <common/interop/two_way_pipe_message_ipc.h>
|
||||||
|
#include <wil/resource.h>
|
||||||
|
|
||||||
|
extern void receive_json_send_to_main_thread(const std::wstring& msg);
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
wil::unique_handle quick_access_process;
|
||||||
|
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<TwoWayPipeMessageIPC> 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();
|
||||||
|
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<RPC_WSTR*>(&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<RPC_WSTR*>(&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<wchar_t> 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, 0, 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);
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/runner/quick_access_host.h
Normal file
12
src/runner/quick_access_host.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
namespace QuickAccessHost
|
||||||
|
{
|
||||||
|
void start();
|
||||||
|
void show();
|
||||||
|
void stop();
|
||||||
|
bool is_running();
|
||||||
|
}
|
||||||
@@ -70,6 +70,7 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="powertoy_module.cpp" />
|
<ClCompile Include="powertoy_module.cpp" />
|
||||||
<ClCompile Include="main.cpp" />
|
<ClCompile Include="main.cpp" />
|
||||||
|
<ClCompile Include="quick_access_host.cpp" />
|
||||||
<ClCompile Include="restart_elevated.cpp" />
|
<ClCompile Include="restart_elevated.cpp" />
|
||||||
<ClCompile Include="centralized_kb_hook.cpp" />
|
<ClCompile Include="centralized_kb_hook.cpp" />
|
||||||
<ClCompile Include="settings_telemetry.cpp" />
|
<ClCompile Include="settings_telemetry.cpp" />
|
||||||
@@ -85,6 +86,7 @@
|
|||||||
<ClInclude Include="auto_start_helper.h" />
|
<ClInclude Include="auto_start_helper.h" />
|
||||||
<ClInclude Include="bug_report.h" />
|
<ClInclude Include="bug_report.h" />
|
||||||
<ClInclude Include="centralized_hotkeys.h" />
|
<ClInclude Include="centralized_hotkeys.h" />
|
||||||
|
<ClInclude Include="quick_access_host.h" />
|
||||||
<ClInclude Include="general_settings.h" />
|
<ClInclude Include="general_settings.h" />
|
||||||
<ClInclude Include="hotkey_conflict_detector.h" />
|
<ClInclude Include="hotkey_conflict_detector.h" />
|
||||||
<ClInclude Include="pch.h" />
|
<ClInclude Include="pch.h" />
|
||||||
|
|||||||
@@ -48,6 +48,9 @@
|
|||||||
<ClCompile Include="hotkey_conflict_detector.cpp">
|
<ClCompile Include="hotkey_conflict_detector.cpp">
|
||||||
<Filter>Utils</Filter>
|
<Filter>Utils</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="quick_access_host.cpp">
|
||||||
|
<Filter>Utils</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="pch.h" />
|
<ClInclude Include="pch.h" />
|
||||||
@@ -102,6 +105,9 @@
|
|||||||
<ClInclude Include="hotkey_conflict_detector.h">
|
<ClInclude Include="hotkey_conflict_detector.h">
|
||||||
<Filter>Utils</Filter>
|
<Filter>Utils</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="quick_access_host.h">
|
||||||
|
<Filter>Utils</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="Utils">
|
<Filter Include="Utils">
|
||||||
|
|||||||
@@ -198,6 +198,8 @@ void dispatch_received_json(const std::wstring& json_to_parse)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger::info(L"dispatch_received_json: {}", json_to_parse);
|
||||||
|
|
||||||
for (const auto& base_element : j)
|
for (const auto& base_element : j)
|
||||||
{
|
{
|
||||||
const auto name = base_element.Key();
|
const auto name = base_element.Key();
|
||||||
@@ -206,12 +208,12 @@ void dispatch_received_json(const std::wstring& json_to_parse)
|
|||||||
if (name == L"general")
|
if (name == L"general")
|
||||||
{
|
{
|
||||||
apply_general_settings(value.GetObjectW());
|
apply_general_settings(value.GetObjectW());
|
||||||
const std::wstring settings_string{ get_all_settings().Stringify().c_str() };
|
// const std::wstring settings_string{ get_all_settings().Stringify().c_str() };
|
||||||
{
|
// {
|
||||||
std::unique_lock lock{ ipc_mutex };
|
// std::unique_lock lock{ ipc_mutex };
|
||||||
if (current_settings_ipc)
|
// if (current_settings_ipc)
|
||||||
current_settings_ipc->send(settings_string);
|
// current_settings_ipc->send(settings_string);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
else if (name == L"powertoys")
|
else if (name == L"powertoys")
|
||||||
{
|
{
|
||||||
@@ -421,7 +423,7 @@ BOOL run_settings_non_elevated(LPCWSTR executable_path, LPWSTR executable_args,
|
|||||||
|
|
||||||
DWORD g_settings_process_id = 0;
|
DWORD g_settings_process_id = 0;
|
||||||
|
|
||||||
void run_settings_window(bool show_oobe_window, bool show_scoobe_window, std::optional<std::wstring> settings_window, bool show_flyout = false, const std::optional<POINT>& flyout_position = std::nullopt)
|
void run_settings_window(bool show_oobe_window, bool show_scoobe_window, std::optional<std::wstring> settings_window)
|
||||||
{
|
{
|
||||||
g_isLaunchInProgress = true;
|
g_isLaunchInProgress = true;
|
||||||
|
|
||||||
@@ -491,22 +493,16 @@ void run_settings_window(bool show_oobe_window, bool show_scoobe_window, std::op
|
|||||||
// Arg 9: should scoobe window be shown
|
// Arg 9: should scoobe window be shown
|
||||||
std::wstring settings_showScoobe = show_scoobe_window ? L"true" : L"false";
|
std::wstring settings_showScoobe = show_scoobe_window ? L"true" : L"false";
|
||||||
|
|
||||||
// Arg 10: should flyout be shown
|
// 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_showFlyout = show_flyout ? L"true" : L"false";
|
|
||||||
|
|
||||||
// Arg 11: 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";
|
std::wstring settings_containsSettingsWindow = settings_window.has_value() ? L"true" : L"false";
|
||||||
|
|
||||||
// Arg 12: contains if there's flyout coordinates. If true, will add two extra arguments to the call containing the x and y coordinates.
|
// Args 11, .... : Optional arguments depending on the options presented before. All by the same value.
|
||||||
std::wstring settings_containsFlyoutPosition = flyout_position.has_value() ? L"true" : L"false";
|
|
||||||
|
|
||||||
// Args 13, .... : 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 :
|
// create general settings file to initialize the settings file with installation configurations like :
|
||||||
// 1. Run on start up.
|
// 1. Run on start up.
|
||||||
PTSettingsHelper::save_general_settings(save_settings.to_json());
|
PTSettingsHelper::save_general_settings(save_settings.to_json());
|
||||||
|
|
||||||
std::wstring executable_args = fmt::format(L"\"{}\" {} {} {} {} {} {} {} {} {} {} {}",
|
std::wstring executable_args = fmt::format(L"\"{}\" {} {} {} {} {} {} {} {} {}",
|
||||||
executable_path,
|
executable_path,
|
||||||
powertoys_pipe_name,
|
powertoys_pipe_name,
|
||||||
settings_pipe_name,
|
settings_pipe_name,
|
||||||
@@ -516,9 +512,7 @@ void run_settings_window(bool show_oobe_window, bool show_scoobe_window, std::op
|
|||||||
settings_isUserAnAdmin,
|
settings_isUserAnAdmin,
|
||||||
settings_showOobe,
|
settings_showOobe,
|
||||||
settings_showScoobe,
|
settings_showScoobe,
|
||||||
settings_showFlyout,
|
settings_containsSettingsWindow);
|
||||||
settings_containsSettingsWindow,
|
|
||||||
settings_containsFlyoutPosition);
|
|
||||||
|
|
||||||
if (settings_window.has_value())
|
if (settings_window.has_value())
|
||||||
{
|
{
|
||||||
@@ -526,14 +520,6 @@ void run_settings_window(bool show_oobe_window, bool show_scoobe_window, std::op
|
|||||||
executable_args.append(settings_window.value());
|
executable_args.append(settings_window.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flyout_position)
|
|
||||||
{
|
|
||||||
executable_args.append(L" ");
|
|
||||||
executable_args.append(std::to_wstring(flyout_position.value().x));
|
|
||||||
executable_args.append(L" ");
|
|
||||||
executable_args.append(std::to_wstring(flyout_position.value().y));
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL process_created = false;
|
BOOL process_created = false;
|
||||||
|
|
||||||
// Commented out to fix #22659
|
// Commented out to fix #22659
|
||||||
@@ -684,39 +670,22 @@ void bring_settings_to_front()
|
|||||||
EnumWindows(callback, 0);
|
EnumWindows(callback, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void open_settings_window(std::optional<std::wstring> settings_window, bool show_flyout = false, const std::optional<POINT>& flyout_position)
|
void open_settings_window(std::optional<std::wstring> settings_window)
|
||||||
{
|
{
|
||||||
if (g_settings_process_id != 0)
|
if (g_settings_process_id != 0)
|
||||||
{
|
{
|
||||||
if (show_flyout)
|
// 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 (current_settings_ipc)
|
if (settings_window.has_value())
|
||||||
{
|
{
|
||||||
if (!flyout_position.has_value())
|
std::wstring msg = L"{\"ShowYourself\":\"" + settings_window.value() + L"\"}";
|
||||||
{
|
current_settings_ipc->send(msg);
|
||||||
current_settings_ipc->send(L"{\"ShowYourself\":\"flyout\"}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
current_settings_ipc->send(fmt::format(L"{{\"ShowYourself\":\"flyout\", \"x_position\":{}, \"y_position\":{} }}", std::to_wstring(flyout_position.value().x), std::to_wstring(flyout_position.value().y)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
|
||||||
{
|
|
||||||
// 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())
|
current_settings_ipc->send(L"{\"ShowYourself\":\"Dashboard\"}");
|
||||||
{
|
|
||||||
std::wstring msg = L"{\"ShowYourself\":\"" + settings_window.value() + L"\"}";
|
|
||||||
current_settings_ipc->send(msg);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
current_settings_ipc->send(L"{\"ShowYourself\":\"Dashboard\"}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -724,8 +693,8 @@ void open_settings_window(std::optional<std::wstring> settings_window, bool show
|
|||||||
{
|
{
|
||||||
if (!g_isLaunchInProgress)
|
if (!g_isLaunchInProgress)
|
||||||
{
|
{
|
||||||
std::thread([settings_window, show_flyout, flyout_position]() {
|
std::thread([settings_window]() {
|
||||||
run_settings_window(false, false, settings_window, show_flyout, flyout_position);
|
run_settings_window(false, false, settings_window);
|
||||||
}).detach();
|
}).detach();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,9 +41,8 @@ enum class ESettingsWindowNames
|
|||||||
std::string ESettingsWindowNames_to_string(ESettingsWindowNames value);
|
std::string ESettingsWindowNames_to_string(ESettingsWindowNames value);
|
||||||
ESettingsWindowNames ESettingsWindowNames_from_string(std::string value);
|
ESettingsWindowNames ESettingsWindowNames_from_string(std::string value);
|
||||||
|
|
||||||
void open_settings_window(std::optional<std::wstring> settings_window, bool show_flyout, const std::optional<POINT>& flyout_position);
|
void open_settings_window(std::optional<std::wstring> settings_window);
|
||||||
void close_settings_window();
|
void close_settings_window();
|
||||||
|
|
||||||
void open_oobe_window();
|
void open_oobe_window();
|
||||||
void open_scoobe_window();
|
void open_scoobe_window();
|
||||||
void open_flyout();
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
#include "general_settings.h"
|
#include "general_settings.h"
|
||||||
#include "centralized_hotkeys.h"
|
#include "centralized_hotkeys.h"
|
||||||
#include "centralized_kb_hook.h"
|
#include "centralized_kb_hook.h"
|
||||||
|
#include "quick_access_host.h"
|
||||||
|
#include "hotkey_conflict_detector.h"
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
#include <common/utils/resources.h>
|
#include <common/utils/resources.h>
|
||||||
@@ -69,9 +71,9 @@ void change_menu_item_text(const UINT item_id, wchar_t* new_text)
|
|||||||
SetMenuItemInfoW(h_menu, item_id, false, &menuitem);
|
SetMenuItemInfoW(h_menu, item_id, false, &menuitem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void open_quick_access_flyout_window(const POINT flyout_position)
|
void open_quick_access_flyout_window()
|
||||||
{
|
{
|
||||||
open_settings_window(std::nullopt, true, flyout_position);
|
QuickAccessHost::show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_tray_command(HWND window, const WPARAM command_id, LPARAM lparam)
|
void handle_tray_command(HWND window, const WPARAM command_id, LPARAM lparam)
|
||||||
@@ -81,7 +83,7 @@ void handle_tray_command(HWND window, const WPARAM command_id, LPARAM lparam)
|
|||||||
case ID_SETTINGS_MENU_COMMAND:
|
case ID_SETTINGS_MENU_COMMAND:
|
||||||
{
|
{
|
||||||
std::wstring settings_window{ winrt::to_hstring(ESettingsWindowNames_to_string(static_cast<ESettingsWindowNames>(lparam))) };
|
std::wstring settings_window{ winrt::to_hstring(ESettingsWindowNames_to_string(static_cast<ESettingsWindowNames>(lparam))) };
|
||||||
open_settings_window(settings_window, false);
|
open_settings_window(settings_window);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ID_CLOSE_MENU_COMMAND:
|
case ID_CLOSE_MENU_COMMAND:
|
||||||
@@ -113,9 +115,7 @@ void handle_tray_command(HWND window, const WPARAM command_id, LPARAM lparam)
|
|||||||
}
|
}
|
||||||
case ID_QUICK_ACCESS_MENU_COMMAND:
|
case ID_QUICK_ACCESS_MENU_COMMAND:
|
||||||
{
|
{
|
||||||
POINT mouse_pointer;
|
open_quick_access_flyout_window();
|
||||||
GetCursorPos(&mouse_pointer);
|
|
||||||
open_quick_access_flyout_window(mouse_pointer);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -126,7 +126,14 @@ void click_timer_elapsed()
|
|||||||
double_click_timer_running = false;
|
double_click_timer_running = false;
|
||||||
if (!double_clicked)
|
if (!double_clicked)
|
||||||
{
|
{
|
||||||
open_quick_access_flyout_window(tray_icon_click_point);
|
if (get_general_settings().enableQuickAccess)
|
||||||
|
{
|
||||||
|
open_quick_access_flyout_window();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
open_settings_window(std::nullopt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,9 +225,6 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam
|
|||||||
// ignore event if this is the second click of a double click
|
// ignore event if this is the second click of a double click
|
||||||
if (!double_click_timer_running)
|
if (!double_click_timer_running)
|
||||||
{
|
{
|
||||||
// save the cursor position for sending where to show the popup.
|
|
||||||
GetCursorPos(&tray_icon_click_point);
|
|
||||||
|
|
||||||
// start timer for detecting single or double click
|
// start timer for detecting single or double click
|
||||||
double_click_timer_running = true;
|
double_click_timer_running = true;
|
||||||
double_clicked = false;
|
double_clicked = false;
|
||||||
@@ -236,7 +240,7 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam
|
|||||||
case WM_LBUTTONDBLCLK:
|
case WM_LBUTTONDBLCLK:
|
||||||
{
|
{
|
||||||
double_clicked = true;
|
double_clicked = true;
|
||||||
open_settings_window(std::nullopt, false);
|
open_settings_window(std::nullopt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -349,4 +353,37 @@ void stop_tray_icon()
|
|||||||
BugReportManager::instance().clear_callbacks();
|
BugReportManager::instance().clear_callbacks();
|
||||||
SendMessage(tray_icon_hwnd, WM_CLOSE, 0, 0);
|
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<unsigned char>(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <common/SettingsAPI/settings_objects.h>
|
||||||
|
|
||||||
// Start the Tray Icon
|
// Start the Tray Icon
|
||||||
void start_tray_icon(bool isProcessElevated);
|
void start_tray_icon(bool isProcessElevated);
|
||||||
@@ -9,7 +10,9 @@ void set_tray_icon_visible(bool shouldIconBeVisible);
|
|||||||
// Stop the Tray Icon
|
// Stop the Tray Icon
|
||||||
void stop_tray_icon();
|
void stop_tray_icon();
|
||||||
// Open the Settings Window
|
// Open the Settings Window
|
||||||
void open_settings_window(std::optional<std::wstring> settings_window, bool show_flyout, const std::optional<POINT>& flyout_position = std::nullopt);
|
void open_settings_window(std::optional<std::wstring> 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
|
// Callback type to be called by the tray icon loop
|
||||||
typedef void (*main_loop_callback_function)(PVOID);
|
typedef void (*main_loop_callback_function)(PVOID);
|
||||||
// Calls a callback in _callback
|
// Calls a callback in _callback
|
||||||
|
|||||||
49
src/settings-ui/QuickAccess.UI/Helpers/ModuleGpoHelper.cs
Normal file
49
src/settings-ui/QuickAccess.UI/Helpers/ModuleGpoHelper.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using global::PowerToys.GPOWrapper;
|
||||||
|
using ManagedCommon;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.QuickAccess.Helpers;
|
||||||
|
|
||||||
|
internal static class ModuleGpoHelper
|
||||||
|
{
|
||||||
|
public static GpoRuleConfigured GetModuleGpoConfiguration(ModuleType moduleType)
|
||||||
|
{
|
||||||
|
return moduleType switch
|
||||||
|
{
|
||||||
|
ModuleType.AdvancedPaste => GPOWrapper.GetConfiguredAdvancedPasteEnabledValue(),
|
||||||
|
ModuleType.AlwaysOnTop => GPOWrapper.GetConfiguredAlwaysOnTopEnabledValue(),
|
||||||
|
ModuleType.Awake => GPOWrapper.GetConfiguredAwakeEnabledValue(),
|
||||||
|
ModuleType.CmdPal => GPOWrapper.GetConfiguredCmdPalEnabledValue(),
|
||||||
|
ModuleType.ColorPicker => GPOWrapper.GetConfiguredColorPickerEnabledValue(),
|
||||||
|
ModuleType.CropAndLock => GPOWrapper.GetConfiguredCropAndLockEnabledValue(),
|
||||||
|
ModuleType.CursorWrap => GPOWrapper.GetConfiguredCursorWrapEnabledValue(),
|
||||||
|
ModuleType.EnvironmentVariables => GPOWrapper.GetConfiguredEnvironmentVariablesEnabledValue(),
|
||||||
|
ModuleType.FancyZones => GPOWrapper.GetConfiguredFancyZonesEnabledValue(),
|
||||||
|
ModuleType.FileLocksmith => GPOWrapper.GetConfiguredFileLocksmithEnabledValue(),
|
||||||
|
ModuleType.FindMyMouse => GPOWrapper.GetConfiguredFindMyMouseEnabledValue(),
|
||||||
|
ModuleType.Hosts => GPOWrapper.GetConfiguredHostsFileEditorEnabledValue(),
|
||||||
|
ModuleType.ImageResizer => GPOWrapper.GetConfiguredImageResizerEnabledValue(),
|
||||||
|
ModuleType.KeyboardManager => GPOWrapper.GetConfiguredKeyboardManagerEnabledValue(),
|
||||||
|
ModuleType.MouseHighlighter => GPOWrapper.GetConfiguredMouseHighlighterEnabledValue(),
|
||||||
|
ModuleType.MouseJump => GPOWrapper.GetConfiguredMouseJumpEnabledValue(),
|
||||||
|
ModuleType.MousePointerCrosshairs => GPOWrapper.GetConfiguredMousePointerCrosshairsEnabledValue(),
|
||||||
|
ModuleType.MouseWithoutBorders => GPOWrapper.GetConfiguredMouseWithoutBordersEnabledValue(),
|
||||||
|
ModuleType.NewPlus => GPOWrapper.GetConfiguredNewPlusEnabledValue(),
|
||||||
|
ModuleType.Peek => GPOWrapper.GetConfiguredPeekEnabledValue(),
|
||||||
|
ModuleType.PowerRename => GPOWrapper.GetConfiguredPowerRenameEnabledValue(),
|
||||||
|
ModuleType.PowerLauncher => GPOWrapper.GetConfiguredPowerLauncherEnabledValue(),
|
||||||
|
ModuleType.PowerAccent => GPOWrapper.GetConfiguredQuickAccentEnabledValue(),
|
||||||
|
ModuleType.Workspaces => GPOWrapper.GetConfiguredWorkspacesEnabledValue(),
|
||||||
|
ModuleType.RegistryPreview => GPOWrapper.GetConfiguredRegistryPreviewEnabledValue(),
|
||||||
|
ModuleType.MeasureTool => GPOWrapper.GetConfiguredScreenRulerEnabledValue(),
|
||||||
|
ModuleType.ShortcutGuide => GPOWrapper.GetConfiguredShortcutGuideEnabledValue(),
|
||||||
|
ModuleType.PowerOCR => GPOWrapper.GetConfiguredTextExtractorEnabledValue(),
|
||||||
|
ModuleType.ZoomIt => GPOWrapper.GetConfiguredZoomItEnabledValue(),
|
||||||
|
_ => GpoRuleConfigured.Unavailable,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using Microsoft.Windows.ApplicationModel.Resources;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.QuickAccess.Helpers;
|
||||||
|
|
||||||
|
internal static class ResourceLoaderInstance
|
||||||
|
{
|
||||||
|
internal static ResourceLoader ResourceLoader { get; } = new("PowerToys.QuickAccess.pri");
|
||||||
|
}
|
||||||
89
src/settings-ui/QuickAccess.UI/PowerToys.QuickAccess.csproj
Normal file
89
src/settings-ui/QuickAccess.UI/PowerToys.QuickAccess.csproj
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<Import Project="..\..\Common.Dotnet.CsWinRT.props" />
|
||||||
|
<Import Project="..\..\Common.SelfContained.props" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<TargetFramework>net9.0-windows10.0.26100.0</TargetFramework>
|
||||||
|
<RootNamespace>Microsoft.PowerToys.QuickAccess</RootNamespace>
|
||||||
|
<AssemblyName>PowerToys.QuickAccess</AssemblyName>
|
||||||
|
<UseWinUI>true</UseWinUI>
|
||||||
|
<WindowsPackageType>None</WindowsPackageType>
|
||||||
|
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
|
||||||
|
<EnablePreviewMsixTooling>true</EnablePreviewMsixTooling>
|
||||||
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
|
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||||
|
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||||
|
<OutputPath>..\..\..\$(Platform)\$(Configuration)\WinUI3Apps</OutputPath>
|
||||||
|
<EnableDefaultPageItems>false</EnableDefaultPageItems>
|
||||||
|
<EnableDefaultApplicationDefinition>false</EnableDefaultApplicationDefinition>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ProjectPriFileName>PowerToys.QuickAccess.pri</ProjectPriFileName>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<CsWinRTIncludes>PowerToys.GPOWrapper</CsWinRTIncludes>
|
||||||
|
<CsWinRTGeneratedFilesDir>$(OutDir)</CsWinRTGeneratedFilesDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ApplicationDefinition Include="QuickAccessXaml\App.xaml" />
|
||||||
|
<Page Include="QuickAccessXaml\MainWindow.xaml" />
|
||||||
|
<Page Include="QuickAccessXaml\Flyout\ShellPage.xaml" />
|
||||||
|
<Page Include="QuickAccessXaml\Flyout\LaunchPage.xaml" />
|
||||||
|
<Page Include="QuickAccessXaml\Flyout\AppsListPage.xaml" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Page Include="..\Settings.UI\SettingsXAML\Styles\Button.xaml">
|
||||||
|
<Link>Resources\Styles\Button.xaml</Link>
|
||||||
|
</Page>
|
||||||
|
<Page Include="..\Settings.UI\SettingsXAML\Styles\TextBlock.xaml">
|
||||||
|
<Link>Resources\Styles\TextBlock.xaml</Link>
|
||||||
|
</Page>
|
||||||
|
<Page Include="..\Settings.UI\SettingsXAML\Themes\Colors.xaml">
|
||||||
|
<Link>Resources\Themes\Colors.xaml</Link>
|
||||||
|
</Page>
|
||||||
|
<Page Include="..\Settings.UI\SettingsXAML\Themes\Generic.xaml">
|
||||||
|
<Link>Resources\Themes\Generic.xaml</Link>
|
||||||
|
</Page>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PRIResource Include="..\Settings.UI\Strings\en-us\Resources.resw">
|
||||||
|
<Link>Strings\en-us\Resources.resw</Link>
|
||||||
|
</PRIResource>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="..\Settings.UI\Assets\Settings\Icons\**\*">
|
||||||
|
<Link>Assets\Settings\Icons\%(RecursiveDir)%(Filename)%(Extension)</Link>
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="CommunityToolkit.WinUI.Animations" />
|
||||||
|
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" />
|
||||||
|
<PackageReference Include="CommunityToolkit.WinUI.Controls.SettingsControls" />
|
||||||
|
<PackageReference Include="CommunityToolkit.WinUI.Controls.Segmented" />
|
||||||
|
<PackageReference Include="CommunityToolkit.WinUI.Converters" />
|
||||||
|
<PackageReference Include="CommunityToolkit.WinUI.Extensions" />
|
||||||
|
<PackageReference Include="Microsoft.WindowsAppSDK" />
|
||||||
|
<PackageReference Include="WinUIEx" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\common\GPOWrapper\GPOWrapper.vcxproj" />
|
||||||
|
<ProjectReference Include="..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||||
|
<ProjectReference Include="..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
|
||||||
|
<ProjectReference Include="..\..\common\interop\PowerToys.Interop.vcxproj" />
|
||||||
|
<ProjectReference Include="..\..\common\Common.UI\Common.UI.csproj" />
|
||||||
|
<ProjectReference Include="..\Settings.UI.Library\Settings.UI.Library.csproj" />
|
||||||
|
<ProjectReference Include="..\Settings.UI.Controls\Settings.UI.Controls.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Manifest Include="$(ApplicationManifest)" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
62
src/settings-ui/QuickAccess.UI/QuickAccessLaunchContext.cs
Normal file
62
src/settings-ui/QuickAccess.UI/QuickAccessLaunchContext.cs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.QuickAccess;
|
||||||
|
|
||||||
|
public sealed record QuickAccessLaunchContext(string? ShowEventName, string? ExitEventName, string? RunnerPipeName, string? AppPipeName)
|
||||||
|
{
|
||||||
|
public static QuickAccessLaunchContext Parse(string[] args)
|
||||||
|
{
|
||||||
|
string? showEvent = null;
|
||||||
|
string? exitEvent = null;
|
||||||
|
string? runnerPipe = null;
|
||||||
|
string? appPipe = null;
|
||||||
|
|
||||||
|
foreach (var arg in args)
|
||||||
|
{
|
||||||
|
if (TryReadValue(arg, "--show-event", out var value))
|
||||||
|
{
|
||||||
|
showEvent = value;
|
||||||
|
}
|
||||||
|
else if (TryReadValue(arg, "--exit-event", out value))
|
||||||
|
{
|
||||||
|
exitEvent = value;
|
||||||
|
}
|
||||||
|
else if (TryReadValue(arg, "--runner-pipe", out value))
|
||||||
|
{
|
||||||
|
runnerPipe = value;
|
||||||
|
}
|
||||||
|
else if (TryReadValue(arg, "--app-pipe", out value))
|
||||||
|
{
|
||||||
|
appPipe = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new QuickAccessLaunchContext(showEvent, exitEvent, runnerPipe, appPipe);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryReadValue(string candidate, string key, [NotNullWhen(true)] out string? value)
|
||||||
|
{
|
||||||
|
if (candidate.StartsWith(key, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
if (candidate.Length == key.Length)
|
||||||
|
{
|
||||||
|
value = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidate[key.Length] == '=')
|
||||||
|
{
|
||||||
|
value = candidate[(key.Length + 1)..].Trim('"');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
60
src/settings-ui/QuickAccess.UI/QuickAccessXAML/App.xaml
Normal file
60
src/settings-ui/QuickAccess.UI/QuickAccessXAML/App.xaml
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<Application
|
||||||
|
x:Class="Microsoft.PowerToys.QuickAccess.App"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:tkconverters="using:CommunityToolkit.WinUI.Converters">
|
||||||
|
<Application.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||||
|
<ResourceDictionary Source="/Resources/Styles/Button.xaml" />
|
||||||
|
<ResourceDictionary Source="/Resources/Styles/TextBlock.xaml" />
|
||||||
|
<ResourceDictionary Source="/Resources/Themes/Colors.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
|
||||||
|
<ResourceDictionary.ThemeDictionaries>
|
||||||
|
<ResourceDictionary x:Key="Default">
|
||||||
|
<SolidColorBrush
|
||||||
|
x:Key="LayerOnAcrylicFillColorDefaultBrush"
|
||||||
|
Opacity="0.7"
|
||||||
|
Color="#FFFFFFFF" />
|
||||||
|
<SolidColorBrush x:Key="CardStrokeColorDefaultBrush" Color="#0F000000" />
|
||||||
|
<SolidColorBrush x:Key="CardBackgroundFillColorDefaultBrush" Color="#B3FFFFFF" />
|
||||||
|
</ResourceDictionary>
|
||||||
|
<ResourceDictionary x:Key="Light">
|
||||||
|
<SolidColorBrush
|
||||||
|
x:Key="LayerOnAcrylicFillColorDefaultBrush"
|
||||||
|
Opacity="0.7"
|
||||||
|
Color="#FFFFFFFF" />
|
||||||
|
<SolidColorBrush x:Key="CardStrokeColorDefaultBrush" Color="#0F000000" />
|
||||||
|
<SolidColorBrush x:Key="CardBackgroundFillColorDefaultBrush" Color="#B3FFFFFF" />
|
||||||
|
</ResourceDictionary>
|
||||||
|
<ResourceDictionary x:Key="Dark">
|
||||||
|
<SolidColorBrush
|
||||||
|
x:Key="LayerOnAcrylicFillColorDefaultBrush"
|
||||||
|
Opacity="0.6"
|
||||||
|
Color="#FF000000" />
|
||||||
|
<SolidColorBrush x:Key="CardStrokeColorDefaultBrush" Color="#0FFFFFFF" />
|
||||||
|
<SolidColorBrush x:Key="CardBackgroundFillColorDefaultBrush" Color="#0DFFFFFF" />
|
||||||
|
</ResourceDictionary>
|
||||||
|
<ResourceDictionary x:Key="HighContrast">
|
||||||
|
<SolidColorBrush x:Key="LayerOnAcrylicFillColorDefaultBrush" Color="{ThemeResource SystemColorWindowColor}" />
|
||||||
|
<SolidColorBrush x:Key="CardStrokeColorDefaultBrush" Color="{ThemeResource SystemColorWindowTextColor}" />
|
||||||
|
<SolidColorBrush x:Key="CardBackgroundFillColorDefaultBrush" Color="{ThemeResource SystemColorWindowColor}" />
|
||||||
|
</ResourceDictionary>
|
||||||
|
</ResourceDictionary.ThemeDictionaries>
|
||||||
|
|
||||||
|
<tkconverters:BoolToVisibilityConverter
|
||||||
|
x:Key="ReverseBoolToVisibilityConverter"
|
||||||
|
FalseValue="Visible"
|
||||||
|
TrueValue="Collapsed" />
|
||||||
|
<tkconverters:BoolToVisibilityConverter
|
||||||
|
x:Key="BoolToVisibilityConverter"
|
||||||
|
FalseValue="Collapsed"
|
||||||
|
TrueValue="Visible" />
|
||||||
|
<tkconverters:BoolNegationConverter x:Key="BoolNegationConverter" />
|
||||||
|
<tkconverters:StringVisibilityConverter x:Key="StringVisibilityConverter" />
|
||||||
|
</ResourceDictionary>
|
||||||
|
</Application.Resources>
|
||||||
|
</Application>
|
||||||
36
src/settings-ui/QuickAccess.UI/QuickAccessXAML/App.xaml.cs
Normal file
36
src/settings-ui/QuickAccess.UI/QuickAccessXAML/App.xaml.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.QuickAccess;
|
||||||
|
|
||||||
|
public partial class App : Application
|
||||||
|
{
|
||||||
|
private static MainWindow? _window;
|
||||||
|
|
||||||
|
public App()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnLaunched(LaunchActivatedEventArgs args)
|
||||||
|
{
|
||||||
|
var launchContext = QuickAccessLaunchContext.Parse(Environment.GetCommandLineArgs());
|
||||||
|
_window = new MainWindow(launchContext);
|
||||||
|
_window.Closed += OnWindowClosed;
|
||||||
|
_window.Activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnWindowClosed(object sender, WindowEventArgs args)
|
||||||
|
{
|
||||||
|
if (sender is MainWindow window)
|
||||||
|
{
|
||||||
|
window.Closed -= OnWindowClosed;
|
||||||
|
}
|
||||||
|
|
||||||
|
_window = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
<Page
|
||||||
|
x:Class="Microsoft.PowerToys.QuickAccess.Flyout.AppsListPage"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||||
|
xmlns:converters="using:Microsoft.PowerToys.Settings.UI.Controls.Converters"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="using:Microsoft.PowerToys.QuickAccess.Flyout"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:viewModels="using:Microsoft.PowerToys.QuickAccess.ViewModels"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<Page.Resources>
|
||||||
|
<converters:EnumToBooleanConverter x:Key="EnumToBooleanConverter" />
|
||||||
|
</Page.Resources>
|
||||||
|
<Grid Background="{ThemeResource LayerOnAcrylicFillColorDefaultBrush}">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid Padding="24,32,24,0">
|
||||||
|
<TextBlock
|
||||||
|
x:Uid="AllAppsTxt"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource BodyStrongTextBlockStyle}" />
|
||||||
|
<StackPanel
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Orientation="Horizontal"
|
||||||
|
Spacing="8">
|
||||||
|
<Button
|
||||||
|
x:Uid="Dashboard_SortBy"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||||
|
Style="{StaticResource SubtleButtonStyle}">
|
||||||
|
<ToolTipService.ToolTip>
|
||||||
|
<TextBlock x:Uid="Dashboard_SortBy_ToolTip" />
|
||||||
|
</ToolTipService.ToolTip>
|
||||||
|
<Button.Content>
|
||||||
|
<FontIcon FontSize="14" Glyph="" />
|
||||||
|
</Button.Content>
|
||||||
|
<Button.Flyout>
|
||||||
|
<MenuFlyout Placement="BottomEdgeAlignedRight">
|
||||||
|
<ToggleMenuFlyoutItem
|
||||||
|
x:Uid="Dashboard_SortAlphabetical"
|
||||||
|
Click="SortAlphabetical_Click"
|
||||||
|
IsChecked="{x:Bind ViewModel.DashboardSortOrder, Mode=OneWay, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=Alphabetical}" />
|
||||||
|
<ToggleMenuFlyoutItem
|
||||||
|
x:Uid="Dashboard_SortByStatus"
|
||||||
|
Click="SortByStatus_Click"
|
||||||
|
IsChecked="{x:Bind ViewModel.DashboardSortOrder, Mode=OneWay, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=ByStatus}" />
|
||||||
|
</MenuFlyout>
|
||||||
|
</Button.Flyout>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
x:Uid="BackBtn"
|
||||||
|
Padding="8,4,8,4"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Click="BackButton_Click">
|
||||||
|
<Button.Content>
|
||||||
|
<StackPanel
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Orientation="Horizontal"
|
||||||
|
Spacing="12">
|
||||||
|
<FontIcon
|
||||||
|
Margin="0,2,0,0"
|
||||||
|
FontSize="12"
|
||||||
|
Glyph="" />
|
||||||
|
<TextBlock x:Uid="BackLabel" Style="{StaticResource CaptionTextBlockStyle}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Button.Content>
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
<Grid Grid.Row="1">
|
||||||
|
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||||
|
<controls:ModuleList
|
||||||
|
Margin="8,12,12,12"
|
||||||
|
DividerThickness="0,0,0,0"
|
||||||
|
IsItemClickable="False"
|
||||||
|
ItemsSource="{x:Bind ViewModel.FlyoutMenuItems, Mode=OneWay}" />
|
||||||
|
</ScrollViewer>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Page>
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Microsoft.PowerToys.QuickAccess.ViewModels;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using Microsoft.UI.Xaml.Media.Animation;
|
||||||
|
using Microsoft.UI.Xaml.Navigation;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.QuickAccess.Flyout;
|
||||||
|
|
||||||
|
public sealed partial class AppsListPage : Page
|
||||||
|
{
|
||||||
|
private FlyoutNavigationContext? _context;
|
||||||
|
|
||||||
|
public AppsListPage()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AllAppsViewModel ViewModel { get; private set; } = default!;
|
||||||
|
|
||||||
|
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnNavigatedTo(e);
|
||||||
|
|
||||||
|
if (e.Parameter is FlyoutNavigationContext context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
ViewModel = context.AllAppsViewModel;
|
||||||
|
DataContext = ViewModel;
|
||||||
|
ViewModel.RefreshSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BackButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (_context == null || Frame == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Frame.Navigate(typeof(LaunchPage), _context, new SlideNavigationTransitionInfo { Effect = SlideNavigationTransitionEffect.FromLeft });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SortAlphabetical_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
ViewModel.DashboardSortOrder = DashboardSortOrder.Alphabetical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SortByStatus_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
ViewModel.DashboardSortOrder = DashboardSortOrder.ByStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using Microsoft.PowerToys.QuickAccess.Services;
|
||||||
|
using Microsoft.PowerToys.QuickAccess.ViewModels;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.QuickAccess.Flyout;
|
||||||
|
|
||||||
|
internal sealed record FlyoutNavigationContext(
|
||||||
|
LauncherViewModel LauncherViewModel,
|
||||||
|
AllAppsViewModel AllAppsViewModel,
|
||||||
|
IQuickAccessCoordinator Coordinator);
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<Page
|
<Page
|
||||||
x:Class="Microsoft.PowerToys.Settings.UI.Flyout.LaunchPage"
|
x:Class="Microsoft.PowerToys.QuickAccess.Flyout.LaunchPage"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:animatedVisuals="using:Microsoft.UI.Xaml.Controls.AnimatedVisuals"
|
xmlns:animatedVisuals="using:Microsoft.UI.Xaml.Controls.AnimatedVisuals"
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||||
xmlns:tkconverters="using:CommunityToolkit.WinUI.Converters"
|
xmlns:tkconverters="using:CommunityToolkit.WinUI.Converters"
|
||||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||||
xmlns:viewModels="using:Microsoft.PowerToys.Settings.UI.ViewModels"
|
xmlns:viewModels="using:Microsoft.PowerToys.QuickAccess.ViewModels"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<Page.Resources>
|
<Page.Resources>
|
||||||
<Style
|
<Style
|
||||||
@@ -52,7 +52,6 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Orientation="Horizontal"
|
Orientation="Horizontal"
|
||||||
Spacing="12">
|
Spacing="12">
|
||||||
|
|
||||||
<TextBlock x:Uid="MoreLabel" Style="{StaticResource CaptionTextBlockStyle}" />
|
<TextBlock x:Uid="MoreLabel" Style="{StaticResource CaptionTextBlockStyle}" />
|
||||||
<FontIcon
|
<FontIcon
|
||||||
Margin="0,2,0,0"
|
Margin="0,2,0,0"
|
||||||
@@ -64,45 +63,12 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid Grid.Row="1">
|
<Grid Grid.Row="1">
|
||||||
<ScrollViewer>
|
<ScrollViewer>
|
||||||
<ItemsControl
|
<controls:QuickAccessList
|
||||||
Margin="12,26,12,24"
|
Margin="12,26,12,24"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
ItemsSource="{x:Bind ViewModel.FlyoutMenuItems}"
|
ItemsSource="{x:Bind ViewModel.FlyoutMenuItems}"
|
||||||
TabNavigation="Local">
|
TabNavigation="Local" />
|
||||||
<ItemsControl.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<tkcontrols:WrapPanel HorizontalAlignment="Stretch" VerticalSpacing="12" />
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</ItemsControl.ItemsPanel>
|
|
||||||
<ItemsControl.ItemTemplate>
|
|
||||||
<DataTemplate x:DataType="viewModels:FlyoutMenuItem">
|
|
||||||
<controls:FlyoutMenuButton
|
|
||||||
AutomationProperties.Name="{x:Bind Label}"
|
|
||||||
Click="ModuleButton_Click"
|
|
||||||
Tag="{x:Bind Tag}"
|
|
||||||
Visibility="{x:Bind Visible, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BoolToVisibilityConverter}}">
|
|
||||||
<controls:FlyoutMenuButton.Content>
|
|
||||||
<TextBlock
|
|
||||||
Style="{StaticResource CaptionTextBlockStyle}"
|
|
||||||
Text="{x:Bind Label}"
|
|
||||||
TextAlignment="Center"
|
|
||||||
TextWrapping="Wrap" />
|
|
||||||
</controls:FlyoutMenuButton.Content>
|
|
||||||
<controls:FlyoutMenuButton.Icon>
|
|
||||||
<Image>
|
|
||||||
<Image.Source>
|
|
||||||
<BitmapImage UriSource="{x:Bind Icon, Mode=OneWay}" />
|
|
||||||
</Image.Source>
|
|
||||||
</Image>
|
|
||||||
</controls:FlyoutMenuButton.Icon>
|
|
||||||
<ToolTipService.ToolTip>
|
|
||||||
<ToolTip Content="{x:Bind ToolTip}" Visibility="{x:Bind ToolTip, Converter={StaticResource StringVisibilityConverter}}" />
|
|
||||||
</ToolTipService.ToolTip>
|
|
||||||
</controls:FlyoutMenuButton>
|
|
||||||
</DataTemplate>
|
|
||||||
</ItemsControl.ItemTemplate>
|
|
||||||
</ItemsControl>
|
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -150,7 +116,7 @@
|
|||||||
<ToolTipService.ToolTip>
|
<ToolTipService.ToolTip>
|
||||||
<TextBlock x:Uid="SettingsTooltip" />
|
<TextBlock x:Uid="SettingsTooltip" />
|
||||||
</ToolTipService.ToolTip>
|
</ToolTipService.ToolTip>
|
||||||
<AnimatedIcon x:Name="SearchAnimatedIcon">
|
<AnimatedIcon x:Name="SettingsAnimatedIcon">
|
||||||
<AnimatedIcon.Source>
|
<AnimatedIcon.Source>
|
||||||
<animatedVisuals:AnimatedSettingsVisualSource />
|
<animatedVisuals:AnimatedSettingsVisualSource />
|
||||||
</AnimatedIcon.Source>
|
</AnimatedIcon.Source>
|
||||||
@@ -159,14 +125,6 @@
|
|||||||
</AnimatedIcon.FallbackIconSource>
|
</AnimatedIcon.FallbackIconSource>
|
||||||
</AnimatedIcon>
|
</AnimatedIcon>
|
||||||
</Button>
|
</Button>
|
||||||
<!--<AppBarSeparator />
|
|
||||||
<Button
|
|
||||||
x:Name="QuitBtn"
|
|
||||||
Style="{StaticResource FlyoutButtonStyle}"
|
|
||||||
ToolTipService.ToolTip="Quit"
|
|
||||||
Click="QuitButton_Click">
|
|
||||||
<FontIcon FontSize="16" Glyph="" />
|
|
||||||
</Button>-->
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using ManagedCommon;
|
||||||
|
using Microsoft.PowerToys.QuickAccess.Services;
|
||||||
|
using Microsoft.PowerToys.QuickAccess.ViewModels;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Controls;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using Microsoft.UI.Xaml.Input;
|
||||||
|
using Microsoft.UI.Xaml.Media.Animation;
|
||||||
|
using Microsoft.UI.Xaml.Navigation;
|
||||||
|
using PowerToys.Interop;
|
||||||
|
using Windows.System;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.QuickAccess.Flyout;
|
||||||
|
|
||||||
|
public sealed partial class LaunchPage : Page
|
||||||
|
{
|
||||||
|
private AllAppsViewModel? _allAppsViewModel;
|
||||||
|
private IQuickAccessCoordinator? _coordinator;
|
||||||
|
|
||||||
|
public LaunchPage()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public LauncherViewModel ViewModel { get; private set; } = default!;
|
||||||
|
|
||||||
|
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnNavigatedTo(e);
|
||||||
|
|
||||||
|
if (e.Parameter is FlyoutNavigationContext context)
|
||||||
|
{
|
||||||
|
ViewModel = context.LauncherViewModel;
|
||||||
|
_allAppsViewModel = context.AllAppsViewModel;
|
||||||
|
_coordinator = context.Coordinator;
|
||||||
|
DataContext = ViewModel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SettingsBtn_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
_coordinator?.OpenSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void DocsBtn_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (_coordinator == null || !await _coordinator.ShowDocumentationAsync())
|
||||||
|
{
|
||||||
|
await Launcher.LaunchUriAsync(new Uri("https://aka.ms/PowerToysOverview"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AllAppButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (Frame == null || _allAppsViewModel == null || ViewModel == null || _coordinator == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var context = new FlyoutNavigationContext(ViewModel, _allAppsViewModel, _coordinator);
|
||||||
|
Frame.Navigate(typeof(AppsListPage), context, new SlideNavigationTransitionInfo { Effect = SlideNavigationTransitionEffect.FromRight });
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReportBugBtn_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
_coordinator?.ReportBug();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateInfoBar_Tapped(object sender, TappedRoutedEventArgs e)
|
||||||
|
{
|
||||||
|
_coordinator?.OpenGeneralSettingsForUpdates();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<Page
|
<Page
|
||||||
x:Class="Microsoft.PowerToys.Settings.UI.Flyout.ShellPage"
|
x:Class="Microsoft.PowerToys.QuickAccess.Flyout.ShellPage"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using Microsoft.PowerToys.QuickAccess.Services;
|
||||||
|
using Microsoft.PowerToys.QuickAccess.ViewModels;
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using Microsoft.UI.Xaml.Media.Animation;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.QuickAccess.Flyout;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hosts the flyout navigation frame.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class ShellPage : Page
|
||||||
|
{
|
||||||
|
private LauncherViewModel? _launcherViewModel;
|
||||||
|
private AllAppsViewModel? _allAppsViewModel;
|
||||||
|
private IQuickAccessCoordinator? _coordinator;
|
||||||
|
|
||||||
|
public ShellPage()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Initialize(IQuickAccessCoordinator coordinator, LauncherViewModel launcherViewModel, AllAppsViewModel allAppsViewModel)
|
||||||
|
{
|
||||||
|
_coordinator = coordinator;
|
||||||
|
_launcherViewModel = launcherViewModel;
|
||||||
|
_allAppsViewModel = allAppsViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Page_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (_launcherViewModel == null || _allAppsViewModel == null || _coordinator == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ContentFrame.Content is LaunchPage)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var context = new FlyoutNavigationContext(_launcherViewModel, _allAppsViewModel, _coordinator);
|
||||||
|
ContentFrame.Navigate(typeof(LaunchPage), context, new SuppressNavigationTransitionInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void NavigateToLaunch()
|
||||||
|
{
|
||||||
|
if (_launcherViewModel == null || _allAppsViewModel == null || _coordinator == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var context = new FlyoutNavigationContext(_launcherViewModel, _allAppsViewModel, _coordinator);
|
||||||
|
ContentFrame.Navigate(typeof(LaunchPage), context, new SlideNavigationTransitionInfo { Effect = SlideNavigationTransitionEffect.FromLeft });
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void RefreshIfAppsList()
|
||||||
|
{
|
||||||
|
if (ContentFrame.Content is AppsListPage appsListPage)
|
||||||
|
{
|
||||||
|
appsListPage.ViewModel?.RefreshSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,16 @@
|
|||||||
<winuiex:WindowEx
|
<winuiEx:WindowEx
|
||||||
x:Class="Microsoft.PowerToys.Settings.UI.FlyoutWindow"
|
x:Class="Microsoft.PowerToys.QuickAccess.MainWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:flyout="using:Microsoft.PowerToys.Settings.UI.Flyout"
|
xmlns:flyout="using:Microsoft.PowerToys.QuickAccess.Flyout"
|
||||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:winuiex="using:WinUIEx"
|
xmlns:winuiEx="using:WinUIEx"
|
||||||
Title="PowerToys Settings"
|
Title="PowerToys Quick Access (Preview)"
|
||||||
|
Width="400"
|
||||||
|
Height="516"
|
||||||
|
MinWidth="400"
|
||||||
|
MinHeight="516"
|
||||||
IsAlwaysOnTop="True"
|
IsAlwaysOnTop="True"
|
||||||
IsMaximizable="False"
|
IsMaximizable="False"
|
||||||
IsMinimizable="False"
|
IsMinimizable="False"
|
||||||
@@ -15,8 +18,8 @@
|
|||||||
IsShownInSwitchers="False"
|
IsShownInSwitchers="False"
|
||||||
IsTitleBarVisible="False"
|
IsTitleBarVisible="False"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<winuiex:WindowEx.Backdrop>
|
<winuiEx:WindowEx.Backdrop>
|
||||||
<winuiex:AcrylicSystemBackdrop
|
<winuiEx:AcrylicSystemBackdrop
|
||||||
DarkFallbackColor="#1c1c1c"
|
DarkFallbackColor="#1c1c1c"
|
||||||
DarkLuminosityOpacity="0.96"
|
DarkLuminosityOpacity="0.96"
|
||||||
DarkTintColor="#202020"
|
DarkTintColor="#202020"
|
||||||
@@ -25,8 +28,9 @@
|
|||||||
LightLuminosityOpacity="0.90"
|
LightLuminosityOpacity="0.90"
|
||||||
LightTintColor="#F3F3F3"
|
LightTintColor="#F3F3F3"
|
||||||
LightTintOpacity="0" />
|
LightTintOpacity="0" />
|
||||||
</winuiex:WindowEx.Backdrop>
|
</winuiEx:WindowEx.Backdrop>
|
||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<flyout:ShellPage x:Name="FlyoutShellPage" />
|
<flyout:ShellPage x:Name="ShellHost" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</winuiex:WindowEx>
|
</winuiEx:WindowEx>
|
||||||
@@ -0,0 +1,732 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using ManagedCommon;
|
||||||
|
using Microsoft.PowerToys.QuickAccess.Services;
|
||||||
|
using Microsoft.PowerToys.QuickAccess.ViewModels;
|
||||||
|
using Microsoft.UI.Dispatching;
|
||||||
|
using Microsoft.UI.Windowing;
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
using Windows.Graphics;
|
||||||
|
using WinRT.Interop;
|
||||||
|
using WinUIEx;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.QuickAccess;
|
||||||
|
|
||||||
|
public sealed partial class MainWindow : WindowEx, IDisposable
|
||||||
|
{
|
||||||
|
private readonly QuickAccessLaunchContext _launchContext;
|
||||||
|
private readonly DispatcherQueue _dispatcherQueue;
|
||||||
|
private readonly IntPtr _hwnd;
|
||||||
|
private readonly AppWindow? _appWindow;
|
||||||
|
private readonly LauncherViewModel _launcherViewModel;
|
||||||
|
private readonly AllAppsViewModel _allAppsViewModel;
|
||||||
|
private readonly QuickAccessCoordinator _coordinator;
|
||||||
|
private bool _disposed;
|
||||||
|
private EventWaitHandle? _showEvent;
|
||||||
|
private EventWaitHandle? _exitEvent;
|
||||||
|
private ManualResetEventSlim? _listenerShutdownEvent;
|
||||||
|
private Thread? _showListenerThread;
|
||||||
|
private Thread? _exitListenerThread;
|
||||||
|
private bool _isWindowCloaked;
|
||||||
|
private bool _initialActivationHandled;
|
||||||
|
private bool _isPrimed;
|
||||||
|
|
||||||
|
// Prevent auto-hide until the window actually gained focus once.
|
||||||
|
private bool _hasSeenInteractiveActivation;
|
||||||
|
private bool _isVisible;
|
||||||
|
private IntPtr _mouseHook;
|
||||||
|
private LowLevelMouseProc? _mouseHookDelegate;
|
||||||
|
private CancellationTokenSource? _trimCts;
|
||||||
|
|
||||||
|
private const int DefaultWidth = 320;
|
||||||
|
private const int DefaultHeight = 480;
|
||||||
|
private const int DwmWaCloak = 13;
|
||||||
|
private const int GwlStyle = -16;
|
||||||
|
private const int GwlExStyle = -20;
|
||||||
|
private const int SwHide = 0;
|
||||||
|
private const int SwShow = 5;
|
||||||
|
private const int SwShowNoActivate = 8;
|
||||||
|
private const uint SwpShowWindow = 0x0040;
|
||||||
|
private const uint SwpNoZorder = 0x0004;
|
||||||
|
private const uint SwpNoSize = 0x0001;
|
||||||
|
private const uint SwpNoMove = 0x0002;
|
||||||
|
private const uint SwpNoActivate = 0x0010;
|
||||||
|
private const uint SwpFrameChanged = 0x0020;
|
||||||
|
private const long WsSysmenu = 0x00080000L;
|
||||||
|
private const long WsMinimizeBox = 0x00020000L;
|
||||||
|
private const long WsMaximizeBox = 0x00010000L;
|
||||||
|
private const long WsExToolWindow = 0x00000080L;
|
||||||
|
private const uint MonitorDefaulttonearest = 0x00000002;
|
||||||
|
private static readonly IntPtr HwndTopmost = new(-1);
|
||||||
|
private static readonly IntPtr HwndBottom = new(1);
|
||||||
|
|
||||||
|
public MainWindow(QuickAccessLaunchContext launchContext)
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
_launchContext = launchContext;
|
||||||
|
_dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||||
|
_hwnd = WindowNative.GetWindowHandle(this);
|
||||||
|
_appWindow = InitializeAppWindow(_hwnd);
|
||||||
|
Title = "PowerToys Quick Access (Preview)";
|
||||||
|
|
||||||
|
_coordinator = new QuickAccessCoordinator(this, _launchContext);
|
||||||
|
_launcherViewModel = new LauncherViewModel(_coordinator);
|
||||||
|
_allAppsViewModel = new AllAppsViewModel(_coordinator);
|
||||||
|
ShellHost.Initialize(_coordinator, _launcherViewModel, _allAppsViewModel);
|
||||||
|
|
||||||
|
CustomizeWindowChrome();
|
||||||
|
HideFromTaskbar();
|
||||||
|
HideWindow();
|
||||||
|
InitializeEventListeners();
|
||||||
|
Closed += OnClosed;
|
||||||
|
Activated += OnActivated;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AppWindow? InitializeAppWindow(IntPtr hwnd)
|
||||||
|
{
|
||||||
|
var windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hwnd);
|
||||||
|
return AppWindow.GetFromWindowId(windowId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HideWindow()
|
||||||
|
{
|
||||||
|
if (_hwnd != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
var cloaked = CloakWindow();
|
||||||
|
|
||||||
|
if (!ShowWindowNative(_hwnd, SwHide) && _appWindow != null)
|
||||||
|
{
|
||||||
|
_appWindow.Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cloaked)
|
||||||
|
{
|
||||||
|
ShowWindowNative(_hwnd, SwShowNoActivate);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetWindowPosNative(_hwnd, HwndBottom, 0, 0, 0, 0, SwpNoMove | SwpNoSize | SwpNoActivate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (_appWindow != null)
|
||||||
|
{
|
||||||
|
_appWindow.Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
_isVisible = false;
|
||||||
|
RemoveGlobalMouseHook();
|
||||||
|
|
||||||
|
ScheduleMemoryTrim();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void RequestHide()
|
||||||
|
{
|
||||||
|
if (_dispatcherQueue.HasThreadAccess)
|
||||||
|
{
|
||||||
|
HideWindow();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_dispatcherQueue.TryEnqueue(HideWindow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ScheduleMemoryTrim()
|
||||||
|
{
|
||||||
|
CancelMemoryTrim();
|
||||||
|
_trimCts = new CancellationTokenSource();
|
||||||
|
var token = _trimCts.Token;
|
||||||
|
|
||||||
|
// Delay the trim to avoid aggressive GC during quick toggles
|
||||||
|
Task.Delay(2000, token).ContinueWith(
|
||||||
|
_ =>
|
||||||
|
{
|
||||||
|
if (token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TrimMemory();
|
||||||
|
},
|
||||||
|
token,
|
||||||
|
TaskContinuationOptions.None,
|
||||||
|
TaskScheduler.Default);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CancelMemoryTrim()
|
||||||
|
{
|
||||||
|
_trimCts?.Cancel();
|
||||||
|
_trimCts?.Dispose();
|
||||||
|
_trimCts = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TrimMemory()
|
||||||
|
{
|
||||||
|
GC.Collect();
|
||||||
|
GC.WaitForPendingFinalizers();
|
||||||
|
GC.Collect();
|
||||||
|
SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeEventListeners()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(_launchContext.ShowEventName))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_showEvent = EventWaitHandle.OpenExisting(_launchContext.ShowEventName!);
|
||||||
|
EnsureListenerInfrastructure();
|
||||||
|
StartShowListenerThread();
|
||||||
|
}
|
||||||
|
catch (WaitHandleCannotBeOpenedException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(_launchContext.ExitEventName))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_exitEvent = EventWaitHandle.OpenExisting(_launchContext.ExitEventName!);
|
||||||
|
EnsureListenerInfrastructure();
|
||||||
|
StartExitListenerThread();
|
||||||
|
}
|
||||||
|
catch (WaitHandleCannotBeOpenedException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowWindow()
|
||||||
|
{
|
||||||
|
CancelMemoryTrim();
|
||||||
|
|
||||||
|
if (_hwnd != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
UncloakWindow();
|
||||||
|
|
||||||
|
ShowWindowNative(_hwnd, SwShow);
|
||||||
|
|
||||||
|
var flags = SwpNoSize | SwpShowWindow;
|
||||||
|
var targetX = 0;
|
||||||
|
var targetY = 0;
|
||||||
|
|
||||||
|
var windowSize = _appWindow?.Size;
|
||||||
|
var windowWidth = windowSize?.Width ?? DefaultWidth;
|
||||||
|
var windowHeight = windowSize?.Height ?? DefaultHeight;
|
||||||
|
|
||||||
|
GetCursorPos(out var cursorPosition);
|
||||||
|
var monitorHandle = MonitorFromPointNative(cursorPosition, MonitorDefaulttonearest);
|
||||||
|
if (monitorHandle != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
var monitorInfo = new MonitorInfo { CbSize = Marshal.SizeOf<MonitorInfo>() };
|
||||||
|
if (GetMonitorInfoNative(monitorHandle, ref monitorInfo))
|
||||||
|
{
|
||||||
|
targetX = monitorInfo.RcWork.Right - windowWidth;
|
||||||
|
targetY = monitorInfo.RcWork.Bottom - windowHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetWindowPosNative(_hwnd, HwndTopmost, targetX, targetY, 0, 0, flags);
|
||||||
|
WindowHelpers.BringToForeground(_hwnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
_hasSeenInteractiveActivation = true;
|
||||||
|
_initialActivationHandled = true;
|
||||||
|
Activate();
|
||||||
|
_isVisible = true;
|
||||||
|
EnsureGlobalMouseHook();
|
||||||
|
ShellHost.RefreshIfAppsList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnActivated(object sender, WindowActivatedEventArgs args)
|
||||||
|
{
|
||||||
|
if (args.WindowActivationState == WindowActivationState.Deactivated)
|
||||||
|
{
|
||||||
|
if (!_hasSeenInteractiveActivation)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HideWindow();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_hasSeenInteractiveActivation = true;
|
||||||
|
|
||||||
|
if (_initialActivationHandled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_initialActivationHandled = true;
|
||||||
|
PrimeWindow();
|
||||||
|
HideWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnClosed(object sender, WindowEventArgs e)
|
||||||
|
{
|
||||||
|
Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrimeWindow()
|
||||||
|
{
|
||||||
|
if (_isPrimed || _hwnd == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isPrimed = true;
|
||||||
|
|
||||||
|
if (_appWindow != null)
|
||||||
|
{
|
||||||
|
var currentPosition = _appWindow.Position;
|
||||||
|
_appWindow.MoveAndResize(new RectInt32(currentPosition.X, currentPosition.Y, DefaultWidth, DefaultHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warm up the window while cloaked so the first summon does not pay XAML initialization cost.
|
||||||
|
var cloaked = CloakWindow();
|
||||||
|
if (cloaked)
|
||||||
|
{
|
||||||
|
ShowWindowNative(_hwnd, SwShowNoActivate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HideFromTaskbar()
|
||||||
|
{
|
||||||
|
if (_appWindow == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_appWindow.IsShownInSwitchers = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CloakWindow()
|
||||||
|
{
|
||||||
|
if (_hwnd == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_isWindowCloaked)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cloak = 1;
|
||||||
|
var result = DwmSetWindowAttribute(_hwnd, DwmWaCloak, ref cloak, sizeof(int));
|
||||||
|
if (result == 0)
|
||||||
|
{
|
||||||
|
_isWindowCloaked = true;
|
||||||
|
SetWindowPosNative(_hwnd, HwndBottom, 0, 0, 0, 0, SwpNoMove | SwpNoSize | SwpNoActivate);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UncloakWindow()
|
||||||
|
{
|
||||||
|
if (_hwnd == IntPtr.Zero || !_isWindowCloaked)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cloak = 0;
|
||||||
|
var result = DwmSetWindowAttribute(_hwnd, DwmWaCloak, ref cloak, sizeof(int));
|
||||||
|
if (result == 0)
|
||||||
|
{
|
||||||
|
_isWindowCloaked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
StopEventListeners();
|
||||||
|
|
||||||
|
_showEvent?.Dispose();
|
||||||
|
_showEvent = null;
|
||||||
|
|
||||||
|
_exitEvent?.Dispose();
|
||||||
|
_exitEvent = null;
|
||||||
|
|
||||||
|
if (_hwnd != IntPtr.Zero && IsWindow(_hwnd))
|
||||||
|
{
|
||||||
|
UncloakWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveGlobalMouseHook();
|
||||||
|
|
||||||
|
_coordinator.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
private static extern bool IsWindow(IntPtr hWnd);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", EntryPoint = "ShowWindow", SetLastError = true)]
|
||||||
|
private static extern bool ShowWindowNative(IntPtr hWnd, int nCmdShow);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr", SetLastError = true)]
|
||||||
|
private static extern nint GetWindowLongPtrNative(IntPtr hWnd, int nIndex);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", SetLastError = true)]
|
||||||
|
private static extern nint SetWindowLongPtrNative(IntPtr hWnd, int nIndex, nint dwNewLong);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", EntryPoint = "SetWindowPos", SetLastError = true)]
|
||||||
|
private static extern bool SetWindowPosNative(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", EntryPoint = "SetForegroundWindow", SetLastError = true)]
|
||||||
|
private static extern bool SetForegroundWindowNative(IntPtr hWnd);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", EntryPoint = "GetForegroundWindow", SetLastError = true)]
|
||||||
|
private static extern IntPtr GetForegroundWindowNative();
|
||||||
|
|
||||||
|
[DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId", SetLastError = true)]
|
||||||
|
private static extern uint GetWindowThreadProcessIdNative(IntPtr hWnd, IntPtr lpdwProcessId);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", EntryPoint = "AttachThreadInput", SetLastError = true)]
|
||||||
|
private static extern bool AttachThreadInputNative(uint idAttach, uint idAttachTo, bool fAttach);
|
||||||
|
|
||||||
|
[DllImport("dwmapi.dll", EntryPoint = "DwmSetWindowAttribute", SetLastError = true)]
|
||||||
|
private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", EntryPoint = "MonitorFromPoint", SetLastError = true)]
|
||||||
|
private static extern IntPtr MonitorFromPointNative(NativePoint pt, uint dwFlags);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", EntryPoint = "GetMonitorInfoW", SetLastError = true)]
|
||||||
|
private static extern bool GetMonitorInfoNative(IntPtr hMonitor, ref MonitorInfo lpmi);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", EntryPoint = "SetWindowsHookExW", SetLastError = true)]
|
||||||
|
private static extern IntPtr SetWindowsHookExNative(int idHook, LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", EntryPoint = "UnhookWindowsHookEx", SetLastError = true)]
|
||||||
|
private static extern bool UnhookWindowsHookExNative(IntPtr hhk);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", EntryPoint = "CallNextHookEx", SetLastError = true)]
|
||||||
|
private static extern IntPtr CallNextHookExNative(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", EntryPoint = "GetModuleHandleW", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
|
private static extern IntPtr GetModuleHandleNative([MarshalAs(UnmanagedType.LPWStr)] string? lpModuleName);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", EntryPoint = "GetWindowRect", SetLastError = true)]
|
||||||
|
private static extern bool GetWindowRectNative(IntPtr hWnd, out Rect rect);
|
||||||
|
|
||||||
|
private void EnsureGlobalMouseHook()
|
||||||
|
{
|
||||||
|
if (_mouseHook != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_mouseHookDelegate ??= LowLevelMouseHookCallback;
|
||||||
|
var moduleHandle = GetModuleHandleNative(null);
|
||||||
|
_mouseHook = SetWindowsHookExNative(WhMouseLl, _mouseHookDelegate, moduleHandle, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveGlobalMouseHook()
|
||||||
|
{
|
||||||
|
if (_mouseHook == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnhookWindowsHookExNative(_mouseHook);
|
||||||
|
_mouseHook = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IntPtr LowLevelMouseHookCallback(int nCode, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
if (nCode >= 0 && _isVisible && lParam != IntPtr.Zero && IsMouseButtonDownMessage(wParam))
|
||||||
|
{
|
||||||
|
var data = Marshal.PtrToStructure<LowLevelMouseInput>(lParam);
|
||||||
|
if (!IsPointInsideWindow(data.Point))
|
||||||
|
{
|
||||||
|
_dispatcherQueue.TryEnqueue(() =>
|
||||||
|
{
|
||||||
|
if (_isVisible)
|
||||||
|
{
|
||||||
|
HideWindow();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CallNextHookExNative(_mouseHook, nCode, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsMouseButtonDownMessage(IntPtr wParam)
|
||||||
|
{
|
||||||
|
var message = wParam.ToInt32();
|
||||||
|
return message == WmLbuttondown || message == WmRbuttondown || message == WmMbuttondown || message == WmXbuttondown;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsPointInsideWindow(NativePoint point)
|
||||||
|
{
|
||||||
|
if (_hwnd == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GetWindowRectNative(_hwnd, out var rect))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return point.X >= rect.Left && point.X <= rect.Right && point.Y >= rect.Top && point.Y <= rect.Bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnsureListenerInfrastructure()
|
||||||
|
{
|
||||||
|
_listenerShutdownEvent ??= new ManualResetEventSlim(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartShowListenerThread()
|
||||||
|
{
|
||||||
|
if (_showEvent == null || _listenerShutdownEvent == null || _showListenerThread != null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_showListenerThread = new Thread(ListenForShowEvents)
|
||||||
|
{
|
||||||
|
IsBackground = true,
|
||||||
|
Name = "QuickAccess-ShowEventListener",
|
||||||
|
};
|
||||||
|
_showListenerThread.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartExitListenerThread()
|
||||||
|
{
|
||||||
|
if (_exitEvent == null || _listenerShutdownEvent == null || _exitListenerThread != null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_exitListenerThread = new Thread(ListenForExitEvents)
|
||||||
|
{
|
||||||
|
IsBackground = true,
|
||||||
|
Name = "QuickAccess-ExitEventListener",
|
||||||
|
};
|
||||||
|
_exitListenerThread.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ListenForShowEvents()
|
||||||
|
{
|
||||||
|
if (_showEvent == null || _listenerShutdownEvent == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var handles = new WaitHandle[] { _showEvent, _listenerShutdownEvent.WaitHandle };
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var index = WaitHandle.WaitAny(handles);
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
_dispatcherQueue.TryEnqueue(ShowWindow);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (ThreadInterruptedException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ListenForExitEvents()
|
||||||
|
{
|
||||||
|
if (_exitEvent == null || _listenerShutdownEvent == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var handles = new WaitHandle[] { _exitEvent, _listenerShutdownEvent.WaitHandle };
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var index = WaitHandle.WaitAny(handles);
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
_dispatcherQueue.TryEnqueue(Close);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == 1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (ThreadInterruptedException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StopEventListeners()
|
||||||
|
{
|
||||||
|
if (_listenerShutdownEvent == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_listenerShutdownEvent.Set();
|
||||||
|
|
||||||
|
JoinListenerThread(ref _showListenerThread);
|
||||||
|
JoinListenerThread(ref _exitListenerThread);
|
||||||
|
|
||||||
|
_listenerShutdownEvent.Dispose();
|
||||||
|
_listenerShutdownEvent = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void JoinListenerThread(ref Thread? thread)
|
||||||
|
{
|
||||||
|
if (thread == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!thread.Join(TimeSpan.FromMilliseconds(250)))
|
||||||
|
{
|
||||||
|
thread.Interrupt();
|
||||||
|
thread.Join(TimeSpan.FromMilliseconds(250));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ThreadInterruptedException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (ThreadStateException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
thread = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CustomizeWindowChrome()
|
||||||
|
{
|
||||||
|
if (_hwnd == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var windowAttributesChanged = false;
|
||||||
|
|
||||||
|
var stylePtr = GetWindowLongPtrNative(_hwnd, GwlStyle);
|
||||||
|
var styleError = Marshal.GetLastWin32Error();
|
||||||
|
if (!(stylePtr == nint.Zero && styleError != 0))
|
||||||
|
{
|
||||||
|
var styleValue = (long)stylePtr;
|
||||||
|
var newStyleValue = styleValue & ~(WsSysmenu | WsMinimizeBox | WsMaximizeBox);
|
||||||
|
|
||||||
|
if (newStyleValue != styleValue)
|
||||||
|
{
|
||||||
|
SetWindowLongPtrNative(_hwnd, GwlStyle, (nint)newStyleValue);
|
||||||
|
windowAttributesChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var exStylePtr = GetWindowLongPtrNative(_hwnd, GwlExStyle);
|
||||||
|
var exStyleError = Marshal.GetLastWin32Error();
|
||||||
|
if (!(exStylePtr == nint.Zero && exStyleError != 0))
|
||||||
|
{
|
||||||
|
var exStyleValue = (long)exStylePtr;
|
||||||
|
var newExStyleValue = exStyleValue | WsExToolWindow;
|
||||||
|
if (newExStyleValue != exStyleValue)
|
||||||
|
{
|
||||||
|
SetWindowLongPtrNative(_hwnd, GwlExStyle, (nint)newExStyleValue);
|
||||||
|
windowAttributesChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (windowAttributesChanged)
|
||||||
|
{
|
||||||
|
// Apply the new chrome immediately so caption buttons disappear right away and the tool-window flag takes effect.
|
||||||
|
SetWindowPosNative(_hwnd, IntPtr.Zero, 0, 0, 0, 0, SwpNoMove | SwpNoSize | SwpNoZorder | SwpNoActivate | SwpFrameChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const int WhMouseLl = 14;
|
||||||
|
private const int WmLbuttondown = 0x0201;
|
||||||
|
private const int WmRbuttondown = 0x0204;
|
||||||
|
private const int WmMbuttondown = 0x0207;
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern bool GetCursorPos(out NativePoint lpPoint);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
private static extern bool SetProcessWorkingSetSize(IntPtr hProcess, int dwMinimumWorkingSetSize, int dwMaximumWorkingSetSize);
|
||||||
|
|
||||||
|
private const int WmXbuttondown = 0x020B;
|
||||||
|
|
||||||
|
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
|
private struct Rect
|
||||||
|
{
|
||||||
|
public int Left;
|
||||||
|
public int Top;
|
||||||
|
public int Right;
|
||||||
|
public int Bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
private struct LowLevelMouseInput
|
||||||
|
{
|
||||||
|
public NativePoint Point;
|
||||||
|
public int MouseData;
|
||||||
|
public int Flags;
|
||||||
|
public int Time;
|
||||||
|
public IntPtr DwExtraInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct NativePoint
|
||||||
|
{
|
||||||
|
public int X;
|
||||||
|
public int Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
private struct MonitorInfo
|
||||||
|
{
|
||||||
|
public int CbSize;
|
||||||
|
public Rect RcMonitor;
|
||||||
|
public Rect RcWork;
|
||||||
|
public uint DwFlags;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using ManagedCommon;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.QuickAccess.Services;
|
||||||
|
|
||||||
|
public interface IQuickAccessCoordinator
|
||||||
|
{
|
||||||
|
bool IsRunnerElevated { get; }
|
||||||
|
|
||||||
|
void HideFlyout();
|
||||||
|
|
||||||
|
void OpenSettings();
|
||||||
|
|
||||||
|
void OpenGeneralSettingsForUpdates();
|
||||||
|
|
||||||
|
Task<bool> ShowDocumentationAsync();
|
||||||
|
|
||||||
|
void NotifyUserSettingsInteraction();
|
||||||
|
|
||||||
|
bool UpdateModuleEnabled(ModuleType moduleType, bool isEnabled);
|
||||||
|
|
||||||
|
void ReportBug();
|
||||||
|
|
||||||
|
void OnModuleLaunched(ModuleType moduleType);
|
||||||
|
}
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Common.UI;
|
||||||
|
using ManagedCommon;
|
||||||
|
using Microsoft.PowerToys.QuickAccess.Helpers;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||||
|
using PowerToys.Interop;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.QuickAccess.Services;
|
||||||
|
|
||||||
|
internal sealed class QuickAccessCoordinator : IQuickAccessCoordinator, IDisposable
|
||||||
|
{
|
||||||
|
private readonly MainWindow _window;
|
||||||
|
private readonly QuickAccessLaunchContext _launchContext;
|
||||||
|
private readonly SettingsUtils _settingsUtils = SettingsUtils.Default;
|
||||||
|
private readonly object _generalSettingsLock = new();
|
||||||
|
private readonly object _ipcLock = new();
|
||||||
|
private TwoWayPipeMessageIPCManaged? _ipcManager;
|
||||||
|
private bool _ipcUnavailableLogged;
|
||||||
|
|
||||||
|
public QuickAccessCoordinator(MainWindow window, QuickAccessLaunchContext launchContext)
|
||||||
|
{
|
||||||
|
_window = window;
|
||||||
|
_launchContext = launchContext;
|
||||||
|
InitializeIpc();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsRunnerElevated => false; // TODO: wire up real elevation state.
|
||||||
|
|
||||||
|
public void HideFlyout()
|
||||||
|
{
|
||||||
|
_window.RequestHide();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OpenSettings()
|
||||||
|
{
|
||||||
|
Common.UI.SettingsDeepLink.OpenSettings(Common.UI.SettingsDeepLink.SettingsWindow.Dashboard);
|
||||||
|
_window.RequestHide();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OpenGeneralSettingsForUpdates()
|
||||||
|
{
|
||||||
|
Common.UI.SettingsDeepLink.OpenSettings(Common.UI.SettingsDeepLink.SettingsWindow.Overview);
|
||||||
|
_window.RequestHide();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<bool> ShowDocumentationAsync()
|
||||||
|
{
|
||||||
|
Logger.LogInfo("QuickAccessCoordinator.ShowDocumentationAsync is not yet connected.");
|
||||||
|
return Task.FromResult(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NotifyUserSettingsInteraction()
|
||||||
|
{
|
||||||
|
Logger.LogDebug("QuickAccessCoordinator.NotifyUserSettingsInteraction invoked.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool UpdateModuleEnabled(ModuleType moduleType, bool isEnabled)
|
||||||
|
{
|
||||||
|
GeneralSettings? updatedSettings = null;
|
||||||
|
lock (_generalSettingsLock)
|
||||||
|
{
|
||||||
|
var repository = SettingsRepository<GeneralSettings>.GetInstance(_settingsUtils);
|
||||||
|
var generalSettings = repository.SettingsConfig;
|
||||||
|
var current = ModuleHelper.GetIsModuleEnabled(generalSettings, moduleType);
|
||||||
|
if (current == isEnabled)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleHelper.SetIsModuleEnabled(generalSettings, moduleType, isEnabled);
|
||||||
|
_settingsUtils.SaveSettings(generalSettings.ToJsonString());
|
||||||
|
Logger.LogInfo($"QuickAccess updated module '{moduleType}' enabled state to {isEnabled}.");
|
||||||
|
updatedSettings = generalSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updatedSettings != null)
|
||||||
|
{
|
||||||
|
SendGeneralSettingsUpdate(updatedSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReportBug()
|
||||||
|
{
|
||||||
|
if (!TrySendIpcMessage("{\"bugreport\": 0 }", "bug report request"))
|
||||||
|
{
|
||||||
|
Logger.LogWarning("QuickAccessCoordinator: failed to dispatch bug report request; IPC unavailable.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnModuleLaunched(ModuleType moduleType)
|
||||||
|
{
|
||||||
|
Logger.LogInfo($"QuickAccessLauncher invoked module {moduleType}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
DisposeIpc();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeIpc()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_launchContext.RunnerPipeName) || string.IsNullOrEmpty(_launchContext.AppPipeName))
|
||||||
|
{
|
||||||
|
Logger.LogWarning("QuickAccessCoordinator: IPC pipe names not provided. Runner will not receive updates.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_ipcManager = new TwoWayPipeMessageIPCManaged(_launchContext.AppPipeName, _launchContext.RunnerPipeName, OnIpcMessageReceived);
|
||||||
|
_ipcManager.Start();
|
||||||
|
_ipcUnavailableLogged = false;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError("QuickAccessCoordinator: failed to start IPC channel to runner.", ex);
|
||||||
|
DisposeIpc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnIpcMessageReceived(string message)
|
||||||
|
{
|
||||||
|
Logger.LogDebug($"QuickAccessCoordinator received IPC payload: {message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SendGeneralSettingsUpdate(GeneralSettings updatedSettings)
|
||||||
|
{
|
||||||
|
string payload;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
payload = new OutGoingGeneralSettings(updatedSettings).ToString();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError("QuickAccessCoordinator: failed to serialize general settings payload.", ex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TrySendIpcMessage(payload, "general settings update");
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TrySendIpcMessage(string payload, string operationDescription)
|
||||||
|
{
|
||||||
|
lock (_ipcLock)
|
||||||
|
{
|
||||||
|
if (_ipcManager == null)
|
||||||
|
{
|
||||||
|
if (!_ipcUnavailableLogged)
|
||||||
|
{
|
||||||
|
_ipcUnavailableLogged = true;
|
||||||
|
Logger.LogWarning($"QuickAccessCoordinator: unable to send {operationDescription} because IPC is not available.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_ipcManager.Send(payload);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError($"QuickAccessCoordinator: failed to send {operationDescription}.", ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DisposeIpc()
|
||||||
|
{
|
||||||
|
lock (_ipcLock)
|
||||||
|
{
|
||||||
|
if (_ipcManager == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_ipcManager.End();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogWarning($"QuickAccessCoordinator: exception while shutting down IPC. {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
_ipcManager.Dispose();
|
||||||
|
_ipcManager = null;
|
||||||
|
_ipcUnavailableLogged = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System.Threading;
|
||||||
|
using ManagedCommon;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Controls;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
|
using PowerToys.Interop;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.QuickAccess.Services
|
||||||
|
{
|
||||||
|
public class QuickAccessLauncher : Microsoft.PowerToys.Settings.UI.Controls.QuickAccessLauncher
|
||||||
|
{
|
||||||
|
private readonly IQuickAccessCoordinator? _coordinator;
|
||||||
|
|
||||||
|
public QuickAccessLauncher(IQuickAccessCoordinator? coordinator)
|
||||||
|
: base(coordinator?.IsRunnerElevated ?? false)
|
||||||
|
{
|
||||||
|
_coordinator = coordinator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Launch(ModuleType moduleType)
|
||||||
|
{
|
||||||
|
bool moduleRun = base.Launch(moduleType);
|
||||||
|
|
||||||
|
if (moduleRun)
|
||||||
|
{
|
||||||
|
_coordinator?.OnModuleLaunched(moduleType);
|
||||||
|
}
|
||||||
|
|
||||||
|
_coordinator?.HideFlyout();
|
||||||
|
|
||||||
|
return moduleRun;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
172
src/settings-ui/QuickAccess.UI/ViewModels/AllAppsViewModel.cs
Normal file
172
src/settings-ui/QuickAccess.UI/ViewModels/AllAppsViewModel.cs
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using global::PowerToys.GPOWrapper;
|
||||||
|
using ManagedCommon;
|
||||||
|
using Microsoft.PowerToys.QuickAccess.Helpers;
|
||||||
|
using Microsoft.PowerToys.QuickAccess.Services;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library.ViewModels.Commands;
|
||||||
|
using Microsoft.UI.Dispatching;
|
||||||
|
using Microsoft.Windows.ApplicationModel.Resources;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.QuickAccess.ViewModels;
|
||||||
|
|
||||||
|
public sealed class AllAppsViewModel : Observable
|
||||||
|
{
|
||||||
|
private readonly IQuickAccessCoordinator _coordinator;
|
||||||
|
private readonly ISettingsRepository<GeneralSettings> _settingsRepository;
|
||||||
|
private readonly SettingsUtils _settingsUtils;
|
||||||
|
private readonly ResourceLoader _resourceLoader;
|
||||||
|
private readonly DispatcherQueue _dispatcherQueue;
|
||||||
|
private GeneralSettings _generalSettings;
|
||||||
|
|
||||||
|
public ObservableCollection<FlyoutMenuItem> FlyoutMenuItems { get; }
|
||||||
|
|
||||||
|
public DashboardSortOrder DashboardSortOrder
|
||||||
|
{
|
||||||
|
get => _generalSettings.DashboardSortOrder;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_generalSettings.DashboardSortOrder != value)
|
||||||
|
{
|
||||||
|
_generalSettings.DashboardSortOrder = value;
|
||||||
|
_settingsUtils.SaveSettings(_generalSettings.ToJsonString(), _generalSettings.GetModuleName());
|
||||||
|
OnPropertyChanged();
|
||||||
|
RefreshFlyoutMenuItems();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AllAppsViewModel(IQuickAccessCoordinator coordinator)
|
||||||
|
{
|
||||||
|
_coordinator = coordinator;
|
||||||
|
_dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||||
|
_settingsUtils = SettingsUtils.Default;
|
||||||
|
_settingsRepository = SettingsRepository<GeneralSettings>.GetInstance(_settingsUtils);
|
||||||
|
_generalSettings = _settingsRepository.SettingsConfig;
|
||||||
|
_generalSettings.AddEnabledModuleChangeNotification(ModuleEnabledChangedOnSettingsPage);
|
||||||
|
_settingsRepository.SettingsChanged += OnSettingsChanged;
|
||||||
|
|
||||||
|
_resourceLoader = Helpers.ResourceLoaderInstance.ResourceLoader;
|
||||||
|
FlyoutMenuItems = new ObservableCollection<FlyoutMenuItem>();
|
||||||
|
|
||||||
|
RefreshFlyoutMenuItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSettingsChanged(GeneralSettings newSettings)
|
||||||
|
{
|
||||||
|
_dispatcherQueue.TryEnqueue(() =>
|
||||||
|
{
|
||||||
|
_generalSettings = newSettings;
|
||||||
|
_generalSettings.AddEnabledModuleChangeNotification(ModuleEnabledChangedOnSettingsPage);
|
||||||
|
OnPropertyChanged(nameof(DashboardSortOrder));
|
||||||
|
RefreshFlyoutMenuItems();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RefreshSettings()
|
||||||
|
{
|
||||||
|
if (_settingsRepository.ReloadSettings())
|
||||||
|
{
|
||||||
|
OnSettingsChanged(_settingsRepository.SettingsConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshFlyoutMenuItems()
|
||||||
|
{
|
||||||
|
var desiredItems = new List<FlyoutMenuItem>();
|
||||||
|
|
||||||
|
foreach (ModuleType moduleType in Enum.GetValues<ModuleType>())
|
||||||
|
{
|
||||||
|
if (moduleType == ModuleType.GeneralSettings)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var gpo = Helpers.ModuleGpoHelper.GetModuleGpoConfiguration(moduleType);
|
||||||
|
var isLocked = gpo is GpoRuleConfigured.Enabled or GpoRuleConfigured.Disabled;
|
||||||
|
var isEnabled = gpo == GpoRuleConfigured.Enabled || (!isLocked && Microsoft.PowerToys.Settings.UI.Library.Helpers.ModuleHelper.GetIsModuleEnabled(_generalSettings, moduleType));
|
||||||
|
|
||||||
|
var existingItem = FlyoutMenuItems.FirstOrDefault(x => x.Tag == moduleType);
|
||||||
|
|
||||||
|
if (existingItem != null)
|
||||||
|
{
|
||||||
|
existingItem.Label = _resourceLoader.GetString(Microsoft.PowerToys.Settings.UI.Library.Helpers.ModuleHelper.GetModuleLabelResourceName(moduleType));
|
||||||
|
existingItem.IsLocked = isLocked;
|
||||||
|
existingItem.Icon = Microsoft.PowerToys.Settings.UI.Library.Helpers.ModuleHelper.GetModuleTypeFluentIconName(moduleType);
|
||||||
|
|
||||||
|
if (existingItem.IsEnabled != isEnabled)
|
||||||
|
{
|
||||||
|
var callback = existingItem.EnabledChangedCallback;
|
||||||
|
existingItem.EnabledChangedCallback = null;
|
||||||
|
existingItem.IsEnabled = isEnabled;
|
||||||
|
existingItem.EnabledChangedCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
desiredItems.Add(existingItem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
desiredItems.Add(new FlyoutMenuItem
|
||||||
|
{
|
||||||
|
Label = _resourceLoader.GetString(Microsoft.PowerToys.Settings.UI.Library.Helpers.ModuleHelper.GetModuleLabelResourceName(moduleType)),
|
||||||
|
IsEnabled = isEnabled,
|
||||||
|
IsLocked = isLocked,
|
||||||
|
Tag = moduleType,
|
||||||
|
Icon = Microsoft.PowerToys.Settings.UI.Library.Helpers.ModuleHelper.GetModuleTypeFluentIconName(moduleType),
|
||||||
|
EnabledChangedCallback = EnabledChangedOnUI,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var sortedItems = DashboardSortOrder switch
|
||||||
|
{
|
||||||
|
DashboardSortOrder.ByStatus => desiredItems.OrderByDescending(x => x.IsEnabled).ThenBy(x => x.Label).ToList(),
|
||||||
|
_ => desiredItems.OrderBy(x => x.Label).ToList(),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = FlyoutMenuItems.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (!sortedItems.Contains(FlyoutMenuItems[i]))
|
||||||
|
{
|
||||||
|
FlyoutMenuItems.RemoveAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < sortedItems.Count; i++)
|
||||||
|
{
|
||||||
|
var item = sortedItems[i];
|
||||||
|
var oldIndex = FlyoutMenuItems.IndexOf(item);
|
||||||
|
|
||||||
|
if (oldIndex < 0)
|
||||||
|
{
|
||||||
|
FlyoutMenuItems.Insert(i, item);
|
||||||
|
}
|
||||||
|
else if (oldIndex != i)
|
||||||
|
{
|
||||||
|
FlyoutMenuItems.Move(oldIndex, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnabledChangedOnUI(FlyoutMenuItem item)
|
||||||
|
{
|
||||||
|
if (_coordinator.UpdateModuleEnabled(item.Tag, item.IsEnabled))
|
||||||
|
{
|
||||||
|
_coordinator.NotifyUserSettingsInteraction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ModuleEnabledChangedOnSettingsPage()
|
||||||
|
{
|
||||||
|
RefreshFlyoutMenuItems();
|
||||||
|
}
|
||||||
|
}
|
||||||
52
src/settings-ui/QuickAccess.UI/ViewModels/FlyoutMenuItem.cs
Normal file
52
src/settings-ui/QuickAccess.UI/ViewModels/FlyoutMenuItem.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using ManagedCommon;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Controls;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.QuickAccess.ViewModels;
|
||||||
|
|
||||||
|
public sealed class FlyoutMenuItem : ModuleListItem
|
||||||
|
{
|
||||||
|
private bool _visible;
|
||||||
|
|
||||||
|
public string ToolTip { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public new ModuleType Tag
|
||||||
|
{
|
||||||
|
get => (ModuleType)(base.Tag ?? ModuleType.PowerLauncher);
|
||||||
|
set => base.Tag = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsEnabled
|
||||||
|
{
|
||||||
|
get => base.IsEnabled;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (base.IsEnabled != value)
|
||||||
|
{
|
||||||
|
base.IsEnabled = value;
|
||||||
|
EnabledChangedCallback?.Invoke(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action<FlyoutMenuItem>? EnabledChangedCallback { get; set; }
|
||||||
|
|
||||||
|
public bool Visible
|
||||||
|
{
|
||||||
|
get => _visible;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_visible != value)
|
||||||
|
{
|
||||||
|
_visible = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using global::PowerToys.GPOWrapper;
|
||||||
|
using ManagedCommon;
|
||||||
|
using Microsoft.PowerToys.QuickAccess.Services;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Controls;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||||
|
using Microsoft.UI.Dispatching;
|
||||||
|
using Microsoft.Windows.ApplicationModel.Resources;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.QuickAccess.ViewModels;
|
||||||
|
|
||||||
|
public sealed class LauncherViewModel : Observable
|
||||||
|
{
|
||||||
|
private readonly IQuickAccessCoordinator _coordinator;
|
||||||
|
private readonly ISettingsRepository<GeneralSettings> _settingsRepository;
|
||||||
|
private readonly ResourceLoader _resourceLoader;
|
||||||
|
private readonly DispatcherQueue _dispatcherQueue;
|
||||||
|
private readonly QuickAccessViewModel _quickAccessViewModel;
|
||||||
|
|
||||||
|
public ObservableCollection<QuickAccessItem> FlyoutMenuItems => _quickAccessViewModel.Items;
|
||||||
|
|
||||||
|
public bool IsUpdateAvailable { get; private set; }
|
||||||
|
|
||||||
|
public LauncherViewModel(IQuickAccessCoordinator coordinator)
|
||||||
|
{
|
||||||
|
_coordinator = coordinator;
|
||||||
|
_dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||||
|
var settingsUtils = SettingsUtils.Default;
|
||||||
|
_settingsRepository = SettingsRepository<GeneralSettings>.GetInstance(settingsUtils);
|
||||||
|
|
||||||
|
_resourceLoader = Helpers.ResourceLoaderInstance.ResourceLoader;
|
||||||
|
|
||||||
|
_quickAccessViewModel = new QuickAccessViewModel(
|
||||||
|
_settingsRepository,
|
||||||
|
new Microsoft.PowerToys.QuickAccess.Services.QuickAccessLauncher(_coordinator),
|
||||||
|
moduleType => Helpers.ModuleGpoHelper.GetModuleGpoConfiguration(moduleType) == GpoRuleConfigured.Disabled,
|
||||||
|
_resourceLoader);
|
||||||
|
var updatingSettings = UpdatingSettings.LoadSettings() ?? new UpdatingSettings();
|
||||||
|
IsUpdateAvailable = updatingSettings.State is UpdatingSettings.UpdatingState.ReadyToInstall or UpdatingSettings.UpdatingState.ReadyToDownload;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/settings-ui/QuickAccess.UI/app.manifest
Normal file
16
src/settings-ui/QuickAccess.UI/app.manifest
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<assemblyIdentity version="1.0.0.0" name="PowerToys.QuickAccess.app" />
|
||||||
|
|
||||||
|
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<windowsSettings>
|
||||||
|
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
|
||||||
|
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||||
|
</windowsSettings>
|
||||||
|
</application>
|
||||||
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
|
<application>
|
||||||
|
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||||
|
</application>
|
||||||
|
</compatibility>
|
||||||
|
</assembly>
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
// Copyright (c) Microsoft Corporation
|
// Copyright (c) Microsoft Corporation
|
||||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.UI.Xaml.Data;
|
using Microsoft.UI.Xaml.Data;
|
||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI.Converters
|
namespace Microsoft.PowerToys.Settings.UI.Controls.Converters
|
||||||
{
|
{
|
||||||
public partial class EnumToBooleanConverter : IValueConverter
|
public partial class EnumToBooleanConverter : IValueConverter
|
||||||
{
|
{
|
||||||
@@ -20,7 +20,7 @@ namespace Microsoft.PowerToys.Settings.UI.Converters
|
|||||||
var enumString = value.ToString();
|
var enumString = value.ToString();
|
||||||
var parameterString = parameter.ToString();
|
var parameterString = parameter.ToString();
|
||||||
|
|
||||||
return enumString.Equals(parameterString, StringComparison.OrdinalIgnoreCase);
|
return enumString!.Equals(parameterString, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Microsoft.UI.Xaml.Data;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Controls.Converters
|
||||||
|
{
|
||||||
|
public partial class ModuleListSortOptionToBooleanConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
if (value is ModuleListSortOption sortOption && parameter is string paramString)
|
||||||
|
{
|
||||||
|
if (Enum.TryParse(typeof(ModuleListSortOption), paramString, out object? result) && result != null)
|
||||||
|
{
|
||||||
|
return sortOption == (ModuleListSortOption)result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
if (value is bool isChecked && isChecked && parameter is string paramString)
|
||||||
|
{
|
||||||
|
if (Enum.TryParse(typeof(ModuleListSortOption), paramString, out object? result) && result != null)
|
||||||
|
{
|
||||||
|
return (ModuleListSortOption)result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ModuleListSortOption.Alphabetical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
107
src/settings-ui/Settings.UI.Controls/ModuleList/ModuleList.xaml
Normal file
107
src/settings-ui/Settings.UI.Controls/ModuleList/ModuleList.xaml
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="Microsoft.PowerToys.Settings.UI.Controls.ModuleList"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||||
|
xmlns:converters="using:Microsoft.PowerToys.Settings.UI.Controls.Converters"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:tk="using:CommunityToolkit.WinUI"
|
||||||
|
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||||
|
xmlns:tkconverters="using:CommunityToolkit.WinUI.Converters"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<UserControl.Resources>
|
||||||
|
<converters:ModuleListSortOptionToBooleanConverter x:Key="ModuleListSortOptionToBooleanConverter" />
|
||||||
|
<x:Double x:Key="SettingsCardWrapThreshold">0</x:Double>
|
||||||
|
<tkconverters:BoolToVisibilityConverter
|
||||||
|
x:Key="BoolToVisibilityConverter"
|
||||||
|
FalseValue="Collapsed"
|
||||||
|
TrueValue="Visible" />
|
||||||
|
<tkconverters:BoolToVisibilityConverter
|
||||||
|
x:Key="ReverseBoolToVisibilityConverter"
|
||||||
|
FalseValue="Visible"
|
||||||
|
TrueValue="Collapsed" />
|
||||||
|
<tkconverters:BoolNegationConverter x:Key="BoolNegationConverter" />
|
||||||
|
|
||||||
|
<Style x:Key="NewInfoBadgeStyle" TargetType="InfoBadge">
|
||||||
|
<Setter Property="Padding" Value="5,1,5,2" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="InfoBadge">
|
||||||
|
<Border
|
||||||
|
x:Name="RootGrid"
|
||||||
|
Padding="{TemplateBinding Padding}"
|
||||||
|
Background="{TemplateBinding Background}"
|
||||||
|
CornerRadius="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.InfoBadgeCornerRadius}">
|
||||||
|
<TextBlock
|
||||||
|
x:Uid="NewInfoBadge"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
FontSize="10" />
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</UserControl.Resources>
|
||||||
|
<ItemsRepeater x:Name="DashboardView" ItemsSource="{x:Bind ItemsSource, Mode=OneWay}">
|
||||||
|
<ItemsRepeater.Layout>
|
||||||
|
<StackLayout Orientation="Vertical" Spacing="0" />
|
||||||
|
</ItemsRepeater.Layout>
|
||||||
|
<ItemsRepeater.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="controls:ModuleListItem">
|
||||||
|
<tkcontrols:SettingsCard
|
||||||
|
MinWidth="0"
|
||||||
|
MinHeight="0"
|
||||||
|
Padding="12,4,12,4"
|
||||||
|
tk:FrameworkElementExtensions.AncestorType="controls:ModuleList"
|
||||||
|
Background="Transparent"
|
||||||
|
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
|
||||||
|
BorderThickness="{Binding (tk:FrameworkElementExtensions.Ancestor).DividerThickness, RelativeSource={RelativeSource Self}}"
|
||||||
|
Click="OnSettingsCardClick"
|
||||||
|
CornerRadius="0"
|
||||||
|
IsClickEnabled="{Binding (tk:FrameworkElementExtensions.Ancestor).IsItemClickable, RelativeSource={RelativeSource Self}}"
|
||||||
|
Tag="{x:Bind}">
|
||||||
|
<tkcontrols:SettingsCard.Header>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock Text="{x:Bind Label, Mode=OneWay}" />
|
||||||
|
<!-- InfoBadge -->
|
||||||
|
<InfoBadge
|
||||||
|
x:Name="NewInfoBadge"
|
||||||
|
Margin="4,0,0,0"
|
||||||
|
Style="{StaticResource NewInfoBadgeStyle}"
|
||||||
|
Visibility="{x:Bind IsNew, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||||
|
<FontIcon
|
||||||
|
Width="20"
|
||||||
|
Margin="4,0,0,0"
|
||||||
|
FontSize="16"
|
||||||
|
Glyph=""
|
||||||
|
Visibility="{x:Bind IsLocked, Converter={StaticResource ReverseBoolToVisibilityConverter}, ConverterParameter=True}">
|
||||||
|
<ToolTipService.ToolTip>
|
||||||
|
<TextBlock x:Uid="GPOWarning" TextWrapping="WrapWholeWords" />
|
||||||
|
</ToolTipService.ToolTip>
|
||||||
|
</FontIcon>
|
||||||
|
</StackPanel>
|
||||||
|
</tkcontrols:SettingsCard.Header>
|
||||||
|
|
||||||
|
<tkcontrols:SettingsCard.HeaderIcon>
|
||||||
|
<ImageIcon>
|
||||||
|
<ImageIcon.Source>
|
||||||
|
<BitmapImage UriSource="{x:Bind Icon, Mode=OneWay}" />
|
||||||
|
</ImageIcon.Source>
|
||||||
|
</ImageIcon>
|
||||||
|
</tkcontrols:SettingsCard.HeaderIcon>
|
||||||
|
|
||||||
|
<ToggleSwitch
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
AutomationProperties.Name="{x:Bind Label, Mode=OneWay}"
|
||||||
|
IsEnabled="{x:Bind IsLocked, Converter={StaticResource BoolNegationConverter}, ConverterParameter=True, Mode=OneWay}"
|
||||||
|
IsOn="{x:Bind IsEnabled, Mode=TwoWay}"
|
||||||
|
OffContent=""
|
||||||
|
OnContent="" />
|
||||||
|
</tkcontrols:SettingsCard>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsRepeater.ItemTemplate>
|
||||||
|
</ItemsRepeater>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Controls
|
||||||
|
{
|
||||||
|
public sealed partial class ModuleList : UserControl
|
||||||
|
{
|
||||||
|
public ModuleList()
|
||||||
|
{
|
||||||
|
this.InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Thickness DividerThickness
|
||||||
|
{
|
||||||
|
get => (Thickness)GetValue(DividerThicknessProperty);
|
||||||
|
set => SetValue(DividerThicknessProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly DependencyProperty DividerThicknessProperty = DependencyProperty.Register(nameof(DividerThickness), typeof(Thickness), typeof(ModuleList), new PropertyMetadata(new Thickness(0, 1, 0, 0)));
|
||||||
|
|
||||||
|
public bool IsItemClickable
|
||||||
|
{
|
||||||
|
get => (bool)GetValue(IsItemClickableProperty);
|
||||||
|
set => SetValue(IsItemClickableProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly DependencyProperty IsItemClickableProperty = DependencyProperty.Register(nameof(IsItemClickable), typeof(bool), typeof(ModuleList), new PropertyMetadata(true));
|
||||||
|
|
||||||
|
public object ItemsSource
|
||||||
|
{
|
||||||
|
get => (object)GetValue(ItemsSourceProperty);
|
||||||
|
set => SetValue(ItemsSourceProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(nameof(ItemsSource), typeof(object), typeof(ModuleList), new PropertyMetadata(null));
|
||||||
|
|
||||||
|
public ModuleListSortOption SortOption
|
||||||
|
{
|
||||||
|
get => (ModuleListSortOption)GetValue(SortOptionProperty);
|
||||||
|
set => SetValue(SortOptionProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly DependencyProperty SortOptionProperty = DependencyProperty.Register(nameof(SortOption), typeof(ModuleListSortOption), typeof(ModuleList), new PropertyMetadata(ModuleListSortOption.Alphabetical));
|
||||||
|
|
||||||
|
private void OnSettingsCardClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is FrameworkElement element && element.Tag is ModuleListItem item)
|
||||||
|
{
|
||||||
|
item.ClickCommand?.Execute(item.Tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Controls
|
||||||
|
{
|
||||||
|
public class ModuleListItem : INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
private bool _isEnabled;
|
||||||
|
private string _label = string.Empty;
|
||||||
|
private string _icon = string.Empty;
|
||||||
|
private bool _isNew;
|
||||||
|
private bool _isLocked;
|
||||||
|
private object? _tag;
|
||||||
|
private ICommand? _clickCommand;
|
||||||
|
|
||||||
|
public virtual string Label
|
||||||
|
{
|
||||||
|
get => _label;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_label != value)
|
||||||
|
{
|
||||||
|
_label = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual string Icon
|
||||||
|
{
|
||||||
|
get => _icon;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_icon != value)
|
||||||
|
{
|
||||||
|
_icon = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool IsNew
|
||||||
|
{
|
||||||
|
get => _isNew;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_isNew != value)
|
||||||
|
{
|
||||||
|
_isNew = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool IsLocked
|
||||||
|
{
|
||||||
|
get => _isLocked;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_isLocked != value)
|
||||||
|
{
|
||||||
|
_isLocked = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool IsEnabled
|
||||||
|
{
|
||||||
|
get => _isEnabled;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_isEnabled != value)
|
||||||
|
{
|
||||||
|
_isEnabled = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual object? Tag
|
||||||
|
{
|
||||||
|
get => _tag;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_tag != value)
|
||||||
|
{
|
||||||
|
_tag = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual ICommand? ClickCommand
|
||||||
|
{
|
||||||
|
get => _clickCommand;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_clickCommand != value)
|
||||||
|
{
|
||||||
|
_clickCommand = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public event PropertyChangedEventHandler? PropertyChanged;
|
||||||
|
|
||||||
|
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Controls
|
||||||
|
{
|
||||||
|
public enum ModuleListSortOption
|
||||||
|
{
|
||||||
|
Alphabetical,
|
||||||
|
ByStatus,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,11 +21,11 @@
|
|||||||
BorderThickness="{x:Bind BorderThickness, Mode=OneWay}"
|
BorderThickness="{x:Bind BorderThickness, Mode=OneWay}"
|
||||||
CornerRadius="{x:Bind CornerRadius, Mode=OneWay}">
|
CornerRadius="{x:Bind CornerRadius, Mode=OneWay}">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" MinHeight="44" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid x:Name="TitleGrid">
|
<Grid x:Name="TitleGrid" MinHeight="44">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
@@ -11,9 +11,9 @@ namespace Microsoft.PowerToys.Settings.UI.Controls
|
|||||||
{
|
{
|
||||||
public static readonly DependencyProperty TitleContentProperty = DependencyProperty.Register(nameof(TitleContent), typeof(object), typeof(Card), new PropertyMetadata(defaultValue: null, OnVisualPropertyChanged));
|
public static readonly DependencyProperty TitleContentProperty = DependencyProperty.Register(nameof(TitleContent), typeof(object), typeof(Card), new PropertyMetadata(defaultValue: null, OnVisualPropertyChanged));
|
||||||
|
|
||||||
public object TitleContent
|
public object? TitleContent
|
||||||
{
|
{
|
||||||
get => (object)GetValue(TitleContentProperty);
|
get => (object?)GetValue(TitleContentProperty);
|
||||||
set => SetValue(TitleContentProperty, value);
|
set => SetValue(TitleContentProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ namespace Microsoft.PowerToys.Settings.UI.Controls
|
|||||||
set => SetValue(ContentProperty, value);
|
set => SetValue(ContentProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly DependencyProperty DividerVisibilityProperty = DependencyProperty.Register(nameof(DividerVisibility), typeof(Visibility), typeof(Card), new PropertyMetadata(defaultValue: null));
|
public static readonly DependencyProperty DividerVisibilityProperty = DependencyProperty.Register(nameof(DividerVisibility), typeof(Visibility), typeof(Card), new PropertyMetadata(defaultValue: Visibility.Visible));
|
||||||
|
|
||||||
public Visibility DividerVisibility
|
public Visibility DividerVisibility
|
||||||
{
|
{
|
||||||
@@ -66,7 +66,6 @@ namespace Microsoft.PowerToys.Settings.UI.Controls
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
VisualStateManager.GoToState(this, "TitleGridVisible", true);
|
VisualStateManager.GoToState(this, "TitleGridVisible", true);
|
||||||
DividerVisibility = Visibility.Visible;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) Microsoft Corporation
|
// Copyright (c) Microsoft Corporation
|
||||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using ManagedCommon;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Controls
|
||||||
|
{
|
||||||
|
public interface IQuickAccessLauncher
|
||||||
|
{
|
||||||
|
bool Launch(ModuleType moduleType);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System.Windows.Input;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Controls
|
||||||
|
{
|
||||||
|
public sealed class QuickAccessItem : Observable
|
||||||
|
{
|
||||||
|
private string _title = string.Empty;
|
||||||
|
|
||||||
|
public string Title
|
||||||
|
{
|
||||||
|
get => _title;
|
||||||
|
set => Set(ref _title, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _description = string.Empty;
|
||||||
|
|
||||||
|
public string Description
|
||||||
|
{
|
||||||
|
get => _description;
|
||||||
|
set => Set(ref _description, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _icon = string.Empty;
|
||||||
|
|
||||||
|
public string Icon
|
||||||
|
{
|
||||||
|
get => _icon;
|
||||||
|
set => Set(ref _icon, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICommand? _command;
|
||||||
|
|
||||||
|
public ICommand? Command
|
||||||
|
{
|
||||||
|
get => _command;
|
||||||
|
set => Set(ref _command, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private object? _commandParameter;
|
||||||
|
|
||||||
|
public object? CommandParameter
|
||||||
|
{
|
||||||
|
get => _commandParameter;
|
||||||
|
set => Set(ref _commandParameter, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _visible = true;
|
||||||
|
|
||||||
|
public bool Visible
|
||||||
|
{
|
||||||
|
get => _visible;
|
||||||
|
set => Set(ref _visible, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private object? _tag;
|
||||||
|
|
||||||
|
public object? Tag
|
||||||
|
{
|
||||||
|
get => _tag;
|
||||||
|
set => Set(ref _tag, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System.Threading;
|
||||||
|
using ManagedCommon;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
|
using PowerToys.Interop;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Controls
|
||||||
|
{
|
||||||
|
public class QuickAccessLauncher : IQuickAccessLauncher
|
||||||
|
{
|
||||||
|
private readonly bool _isElevated;
|
||||||
|
|
||||||
|
public QuickAccessLauncher(bool isElevated)
|
||||||
|
{
|
||||||
|
_isElevated = isElevated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool Launch(ModuleType moduleType)
|
||||||
|
{
|
||||||
|
switch (moduleType)
|
||||||
|
{
|
||||||
|
case ModuleType.ColorPicker:
|
||||||
|
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowColorPickerSharedEvent()))
|
||||||
|
{
|
||||||
|
eventHandle.Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case ModuleType.EnvironmentVariables:
|
||||||
|
{
|
||||||
|
bool launchAdmin = SettingsRepository<EnvironmentVariablesSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.LaunchAdministrator;
|
||||||
|
string eventName = !_isElevated && launchAdmin
|
||||||
|
? Constants.ShowEnvironmentVariablesAdminSharedEvent()
|
||||||
|
: Constants.ShowEnvironmentVariablesSharedEvent();
|
||||||
|
|
||||||
|
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName))
|
||||||
|
{
|
||||||
|
eventHandle.Set();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case ModuleType.FancyZones:
|
||||||
|
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.FZEToggleEvent()))
|
||||||
|
{
|
||||||
|
eventHandle.Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case ModuleType.Hosts:
|
||||||
|
{
|
||||||
|
bool launchAdmin = SettingsRepository<HostsSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.LaunchAdministrator;
|
||||||
|
string eventName = !_isElevated && launchAdmin
|
||||||
|
? Constants.ShowHostsAdminSharedEvent()
|
||||||
|
: Constants.ShowHostsSharedEvent();
|
||||||
|
|
||||||
|
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName))
|
||||||
|
{
|
||||||
|
eventHandle.Set();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case ModuleType.PowerLauncher:
|
||||||
|
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.PowerLauncherSharedEvent()))
|
||||||
|
{
|
||||||
|
eventHandle.Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case ModuleType.PowerOCR:
|
||||||
|
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowPowerOCRSharedEvent()))
|
||||||
|
{
|
||||||
|
eventHandle.Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case ModuleType.RegistryPreview:
|
||||||
|
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.RegistryPreviewTriggerEvent()))
|
||||||
|
{
|
||||||
|
eventHandle.Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case ModuleType.MeasureTool:
|
||||||
|
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.MeasureToolTriggerEvent()))
|
||||||
|
{
|
||||||
|
eventHandle.Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case ModuleType.ShortcutGuide:
|
||||||
|
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShortcutGuideTriggerEvent()))
|
||||||
|
{
|
||||||
|
eventHandle.Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case ModuleType.CmdPal:
|
||||||
|
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowCmdPalEvent()))
|
||||||
|
{
|
||||||
|
eventHandle.Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case ModuleType.Workspaces:
|
||||||
|
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.WorkspacesLaunchEditorEvent()))
|
||||||
|
{
|
||||||
|
eventHandle.Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="Microsoft.PowerToys.Settings.UI.Controls.QuickAccessList"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||||
|
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||||
|
xmlns:tkconverters="using:CommunityToolkit.WinUI.Converters">
|
||||||
|
|
||||||
|
<UserControl.Resources>
|
||||||
|
<tkconverters:BoolToVisibilityConverter
|
||||||
|
x:Key="BoolToVisibilityConverter"
|
||||||
|
FalseValue="Collapsed"
|
||||||
|
TrueValue="Visible" />
|
||||||
|
<tkconverters:StringVisibilityConverter x:Key="StringVisibilityConverter" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
|
||||||
|
<ItemsControl ItemsSource="{x:Bind ItemsSource, Mode=OneWay}">
|
||||||
|
<ItemsControl.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<tkcontrols:WrapPanel HorizontalAlignment="Stretch" VerticalSpacing="12" />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ItemsControl.ItemsPanel>
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="local:QuickAccessItem">
|
||||||
|
<local:FlyoutMenuButton
|
||||||
|
AutomationProperties.Name="{x:Bind Title}"
|
||||||
|
Command="{x:Bind Command}"
|
||||||
|
CommandParameter="{x:Bind CommandParameter}"
|
||||||
|
Visibility="{x:Bind Visible, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||||
|
<local:FlyoutMenuButton.Content>
|
||||||
|
<TextBlock
|
||||||
|
Style="{StaticResource CaptionTextBlockStyle}"
|
||||||
|
Text="{x:Bind Title}"
|
||||||
|
TextAlignment="Center"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</local:FlyoutMenuButton.Content>
|
||||||
|
<local:FlyoutMenuButton.Icon>
|
||||||
|
<Image>
|
||||||
|
<Image.Source>
|
||||||
|
<BitmapImage UriSource="{x:Bind Icon}" />
|
||||||
|
</Image.Source>
|
||||||
|
</Image>
|
||||||
|
</local:FlyoutMenuButton.Icon>
|
||||||
|
<ToolTipService.ToolTip>
|
||||||
|
<ToolTip Content="{x:Bind Description}" Visibility="{x:Bind Description, Converter={StaticResource StringVisibilityConverter}}" />
|
||||||
|
</ToolTipService.ToolTip>
|
||||||
|
</local:FlyoutMenuButton>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Controls
|
||||||
|
{
|
||||||
|
public sealed partial class QuickAccessList : UserControl
|
||||||
|
{
|
||||||
|
public QuickAccessList()
|
||||||
|
{
|
||||||
|
this.InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ItemsSource
|
||||||
|
{
|
||||||
|
get => (object)GetValue(ItemsSourceProperty);
|
||||||
|
set => SetValue(ItemsSourceProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(nameof(ItemsSource), typeof(object), typeof(QuickAccessList), new PropertyMetadata(null));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,44 +1,64 @@
|
|||||||
// Copyright (c) Microsoft Corporation
|
// Copyright (c) Microsoft Corporation
|
||||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
using global::PowerToys.GPOWrapper;
|
|
||||||
using ManagedCommon;
|
using ManagedCommon;
|
||||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
|
||||||
using Microsoft.PowerToys.Settings.UI.Library;
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library.ViewModels.Commands;
|
||||||
|
using Microsoft.UI.Dispatching;
|
||||||
using Microsoft.Windows.ApplicationModel.Resources;
|
using Microsoft.Windows.ApplicationModel.Resources;
|
||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
namespace Microsoft.PowerToys.Settings.UI.Controls
|
||||||
{
|
{
|
||||||
public partial class LauncherViewModel : Observable
|
public partial class QuickAccessViewModel : Observable
|
||||||
{
|
{
|
||||||
public bool IsUpdateAvailable { get; set; }
|
private readonly ISettingsRepository<GeneralSettings> _settingsRepository;
|
||||||
|
private readonly IQuickAccessLauncher _launcher;
|
||||||
|
private readonly Func<ModuleType, bool> _isModuleGpoDisabled;
|
||||||
|
private readonly ResourceLoader _resourceLoader;
|
||||||
|
private readonly DispatcherQueue _dispatcherQueue;
|
||||||
|
private GeneralSettings _generalSettings;
|
||||||
|
|
||||||
public ObservableCollection<FlyoutMenuItem> FlyoutMenuItems { get; set; }
|
public ObservableCollection<QuickAccessItem> Items { get; } = new();
|
||||||
|
|
||||||
private GeneralSettings generalSettingsConfig;
|
public QuickAccessViewModel(
|
||||||
private UpdatingSettings updatingSettingsConfig;
|
ISettingsRepository<GeneralSettings> settingsRepository,
|
||||||
private ISettingsRepository<GeneralSettings> _settingsRepository;
|
IQuickAccessLauncher launcher,
|
||||||
private ResourceLoader resourceLoader;
|
Func<ModuleType, bool> isModuleGpoDisabled,
|
||||||
|
ResourceLoader resourceLoader)
|
||||||
private Func<string, int> SendIPCMessage { get; }
|
|
||||||
|
|
||||||
public LauncherViewModel(ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc)
|
|
||||||
{
|
{
|
||||||
_settingsRepository = settingsRepository;
|
_settingsRepository = settingsRepository;
|
||||||
generalSettingsConfig = settingsRepository.SettingsConfig;
|
_launcher = launcher;
|
||||||
generalSettingsConfig.AddEnabledModuleChangeNotification(ModuleEnabledChanged);
|
_isModuleGpoDisabled = isModuleGpoDisabled;
|
||||||
|
_resourceLoader = resourceLoader;
|
||||||
|
_dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||||
|
|
||||||
// set the callback functions value to handle outgoing IPC message.
|
_generalSettings = _settingsRepository.SettingsConfig;
|
||||||
SendIPCMessage = ipcMSGCallBackFunc;
|
_generalSettings.AddEnabledModuleChangeNotification(ModuleEnabledChanged);
|
||||||
resourceLoader = ResourceLoaderInstance.ResourceLoader;
|
_settingsRepository.SettingsChanged += OnSettingsChanged;
|
||||||
FlyoutMenuItems = new ObservableCollection<FlyoutMenuItem>();
|
|
||||||
|
|
||||||
|
InitializeItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSettingsChanged(GeneralSettings newSettings)
|
||||||
|
{
|
||||||
|
if (_dispatcherQueue != null)
|
||||||
|
{
|
||||||
|
_dispatcherQueue.TryEnqueue(() =>
|
||||||
|
{
|
||||||
|
_generalSettings = newSettings;
|
||||||
|
_generalSettings.AddEnabledModuleChangeNotification(ModuleEnabledChanged);
|
||||||
|
RefreshItemsVisibility();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeItems()
|
||||||
|
{
|
||||||
AddFlyoutMenuItem(ModuleType.ColorPicker);
|
AddFlyoutMenuItem(ModuleType.ColorPicker);
|
||||||
AddFlyoutMenuItem(ModuleType.CmdPal);
|
AddFlyoutMenuItem(ModuleType.CmdPal);
|
||||||
AddFlyoutMenuItem(ModuleType.EnvironmentVariables);
|
AddFlyoutMenuItem(ModuleType.EnvironmentVariables);
|
||||||
@@ -50,40 +70,50 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
AddFlyoutMenuItem(ModuleType.MeasureTool);
|
AddFlyoutMenuItem(ModuleType.MeasureTool);
|
||||||
AddFlyoutMenuItem(ModuleType.ShortcutGuide);
|
AddFlyoutMenuItem(ModuleType.ShortcutGuide);
|
||||||
AddFlyoutMenuItem(ModuleType.Workspaces);
|
AddFlyoutMenuItem(ModuleType.Workspaces);
|
||||||
|
|
||||||
updatingSettingsConfig = UpdatingSettings.LoadSettings();
|
|
||||||
if (updatingSettingsConfig == null)
|
|
||||||
{
|
|
||||||
updatingSettingsConfig = new UpdatingSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updatingSettingsConfig.State == UpdatingSettings.UpdatingState.ReadyToInstall || updatingSettingsConfig.State == UpdatingSettings.UpdatingState.ReadyToDownload)
|
|
||||||
{
|
|
||||||
IsUpdateAvailable = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
IsUpdateAvailable = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddFlyoutMenuItem(ModuleType moduleType)
|
private void AddFlyoutMenuItem(ModuleType moduleType)
|
||||||
{
|
{
|
||||||
if (ModuleHelper.GetModuleGpoConfiguration(moduleType) == GpoRuleConfigured.Disabled)
|
if (_isModuleGpoDisabled(moduleType))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FlyoutMenuItems.Add(new FlyoutMenuItem()
|
Items.Add(new QuickAccessItem
|
||||||
{
|
{
|
||||||
Label = resourceLoader.GetString(ModuleHelper.GetModuleLabelResourceName(moduleType)),
|
Title = _resourceLoader.GetString(Microsoft.PowerToys.Settings.UI.Library.Helpers.ModuleHelper.GetModuleLabelResourceName(moduleType)),
|
||||||
Tag = moduleType,
|
Tag = moduleType,
|
||||||
Visible = ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, moduleType),
|
Visible = Microsoft.PowerToys.Settings.UI.Library.Helpers.ModuleHelper.GetIsModuleEnabled(_generalSettings, moduleType),
|
||||||
ToolTip = GetModuleToolTip(moduleType),
|
Description = GetModuleToolTip(moduleType),
|
||||||
Icon = ModuleHelper.GetModuleTypeFluentIconName(moduleType),
|
Icon = Microsoft.PowerToys.Settings.UI.Library.Helpers.ModuleHelper.GetModuleTypeFluentIconName(moduleType),
|
||||||
|
Command = new RelayCommand(() => _launcher.Launch(moduleType)),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ModuleEnabledChanged()
|
||||||
|
{
|
||||||
|
if (_dispatcherQueue != null)
|
||||||
|
{
|
||||||
|
_dispatcherQueue.TryEnqueue(() =>
|
||||||
|
{
|
||||||
|
_generalSettings = _settingsRepository.SettingsConfig;
|
||||||
|
_generalSettings.AddEnabledModuleChangeNotification(ModuleEnabledChanged);
|
||||||
|
RefreshItemsVisibility();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshItemsVisibility()
|
||||||
|
{
|
||||||
|
foreach (var item in Items)
|
||||||
|
{
|
||||||
|
if (item.Tag is ModuleType moduleType)
|
||||||
|
{
|
||||||
|
item.Visible = Microsoft.PowerToys.Settings.UI.Library.Helpers.ModuleHelper.GetIsModuleEnabled(_generalSettings, moduleType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private string GetModuleToolTip(ModuleType moduleType)
|
private string GetModuleToolTip(ModuleType moduleType)
|
||||||
{
|
{
|
||||||
return moduleType switch
|
return moduleType switch
|
||||||
@@ -99,16 +129,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ModuleEnabledChanged()
|
|
||||||
{
|
|
||||||
generalSettingsConfig = _settingsRepository.SettingsConfig;
|
|
||||||
generalSettingsConfig.AddEnabledModuleChangeNotification(ModuleEnabledChanged);
|
|
||||||
foreach (FlyoutMenuItem item in FlyoutMenuItems)
|
|
||||||
{
|
|
||||||
item.Visible = ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, item.Tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetShortcutGuideToolTip()
|
private string GetShortcutGuideToolTip()
|
||||||
{
|
{
|
||||||
var shortcutGuideSettings = SettingsRepository<ShortcutGuideSettings>.GetInstance(SettingsUtils.Default).SettingsConfig;
|
var shortcutGuideSettings = SettingsRepository<ShortcutGuideSettings>.GetInstance(SettingsUtils.Default).SettingsConfig;
|
||||||
@@ -116,15 +136,5 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
? "Win"
|
? "Win"
|
||||||
: shortcutGuideSettings.Properties.OpenShortcutGuide.ToString();
|
: shortcutGuideSettings.Properties.OpenShortcutGuide.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void StartBugReport()
|
|
||||||
{
|
|
||||||
SendIPCMessage("{\"bugreport\": 0 }");
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void KillRunner()
|
|
||||||
{
|
|
||||||
SendIPCMessage("{\"killrunner\": 0 }");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<Import Project="..\..\Common.Dotnet.CsWinRT.props" />
|
||||||
|
<Import Project="..\..\Common.SelfContained.props" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<TargetFramework>net9.0-windows10.0.26100.0</TargetFramework>
|
||||||
|
<RootNamespace>Microsoft.PowerToys.Settings.UI.Controls</RootNamespace>
|
||||||
|
<AssemblyName>PowerToys.Settings.UI.Controls</AssemblyName>
|
||||||
|
<UseWinUI>true</UseWinUI>
|
||||||
|
<EnablePreviewMsixTooling>true</EnablePreviewMsixTooling>
|
||||||
|
<GenerateLibraryLayout>true</GenerateLibraryLayout>
|
||||||
|
<ProjectPriFileName>PowerToys.Settings.UI.Controls.pri</ProjectPriFileName>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<Platforms>x64;ARM64</Platforms>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="CommunityToolkit.WinUI.Controls.SettingsControls" />
|
||||||
|
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" />
|
||||||
|
<PackageReference Include="CommunityToolkit.WinUI.Extensions" />
|
||||||
|
<PackageReference Include="CommunityToolkit.WinUI.Converters" />
|
||||||
|
<PackageReference Include="Microsoft.WindowsAppSDK" />
|
||||||
|
<PackageReference Include="WinUIEx" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||||
|
<ProjectReference Include="..\Settings.UI.Library\Settings.UI.Library.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="Dashboard_SortBy_ToolTip.Text" xml:space="preserve">
|
||||||
|
<value>Sort utilities</value>
|
||||||
|
</data>
|
||||||
|
<data name="Dashboard_SortAlphabetical.Text" xml:space="preserve">
|
||||||
|
<value>Alphabetically</value>
|
||||||
|
</data>
|
||||||
|
<data name="Dashboard_SortByStatus.Text" xml:space="preserve">
|
||||||
|
<value>By status</value>
|
||||||
|
</data>
|
||||||
|
<data name="Dashboard_SortBy.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||||
|
<value>Sort utilities</value>
|
||||||
|
</data>
|
||||||
|
<data name="NewInfoBadge.Text" xml:space="preserve">
|
||||||
|
<value>NEW</value>
|
||||||
|
</data>
|
||||||
|
<data name="GPOWarning.Text" xml:space="preserve">
|
||||||
|
<value>This setting is managed by your organization</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
@@ -1,14 +1,9 @@
|
|||||||
<!-- Copyright (c) Microsoft Corporation and Contributors. -->
|
|
||||||
<!-- Licensed under the MIT License. -->
|
|
||||||
|
|
||||||
<ResourceDictionary
|
<ResourceDictionary
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls">
|
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls">
|
||||||
|
|
||||||
<Style BasedOn="{StaticResource DefaultFlyoutMenuButtonStyle}" TargetType="controls:FlyoutMenuButton" />
|
<Style TargetType="controls:FlyoutMenuButton">
|
||||||
|
|
||||||
<Style x:Key="DefaultFlyoutMenuButtonStyle" TargetType="controls:FlyoutMenuButton">
|
|
||||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||||
<Setter Property="VerticalAlignment" Value="Stretch" />
|
<Setter Property="VerticalAlignment" Value="Stretch" />
|
||||||
<Setter Property="Width" Value="116" />
|
<Setter Property="Width" Value="116" />
|
||||||
@@ -7,6 +7,7 @@ using System.Text.Json;
|
|||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
using ManagedCommon;
|
using ManagedCommon;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||||
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
||||||
using Settings.UI.Library.Attributes;
|
using Settings.UI.Library.Attributes;
|
||||||
@@ -19,7 +20,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
ByStatus,
|
ByStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GeneralSettings : ISettingsConfig
|
public class GeneralSettings : ISettingsConfig, IHotkeyConfig
|
||||||
{
|
{
|
||||||
// Gets or sets a value indicating whether run powertoys on start-up.
|
// Gets or sets a value indicating whether run powertoys on start-up.
|
||||||
[JsonPropertyName("startup")]
|
[JsonPropertyName("startup")]
|
||||||
@@ -48,6 +49,14 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
[JsonPropertyName("enable_warnings_elevated_apps")]
|
[JsonPropertyName("enable_warnings_elevated_apps")]
|
||||||
public bool EnableWarningsElevatedApps { get; set; }
|
public bool EnableWarningsElevatedApps { get; set; }
|
||||||
|
|
||||||
|
// Gets or sets a value indicating whether Quick Access is enabled.
|
||||||
|
[JsonPropertyName("enable_quick_access")]
|
||||||
|
public bool EnableQuickAccess { get; set; }
|
||||||
|
|
||||||
|
// Gets or sets Quick Access shortcut.
|
||||||
|
[JsonPropertyName("quick_access_shortcut")]
|
||||||
|
public HotkeySettings QuickAccessShortcut { get; set; }
|
||||||
|
|
||||||
// Gets or sets theme Name.
|
// Gets or sets theme Name.
|
||||||
[JsonPropertyName("theme")]
|
[JsonPropertyName("theme")]
|
||||||
public string Theme { get; set; }
|
public string Theme { get; set; }
|
||||||
@@ -94,6 +103,8 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
ShowSysTrayIcon = true;
|
ShowSysTrayIcon = true;
|
||||||
IsAdmin = false;
|
IsAdmin = false;
|
||||||
EnableWarningsElevatedApps = true;
|
EnableWarningsElevatedApps = true;
|
||||||
|
EnableQuickAccess = true;
|
||||||
|
QuickAccessShortcut = new HotkeySettings();
|
||||||
IsElevated = false;
|
IsElevated = false;
|
||||||
ShowNewUpdatesToastNotification = true;
|
ShowNewUpdatesToastNotification = true;
|
||||||
AutoDownloadUpdates = false;
|
AutoDownloadUpdates = false;
|
||||||
@@ -116,6 +127,22 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
IgnoredConflictProperties = new ShortcutConflictProperties();
|
IgnoredConflictProperties = new ShortcutConflictProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HotkeyAccessor[] GetAllHotkeyAccessors()
|
||||||
|
{
|
||||||
|
return new HotkeyAccessor[]
|
||||||
|
{
|
||||||
|
new HotkeyAccessor(
|
||||||
|
() => QuickAccessShortcut,
|
||||||
|
(hotkey) => { QuickAccessShortcut = hotkey; },
|
||||||
|
"GeneralPage_QuickAccessShortcut"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModuleType GetModuleType()
|
||||||
|
{
|
||||||
|
return ModuleType.GeneralSettings;
|
||||||
|
}
|
||||||
|
|
||||||
// converts the current to a json string.
|
// converts the current to a json string.
|
||||||
public string ToJsonString()
|
public string ToJsonString()
|
||||||
{
|
{
|
||||||
|
|||||||
121
src/settings-ui/Settings.UI.Library/Helpers/ModuleHelper.cs
Normal file
121
src/settings-ui/Settings.UI.Library/Helpers/ModuleHelper.cs
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using ManagedCommon;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Library.Helpers
|
||||||
|
{
|
||||||
|
public static class ModuleHelper
|
||||||
|
{
|
||||||
|
public static string GetModuleLabelResourceName(ModuleType moduleType)
|
||||||
|
{
|
||||||
|
return moduleType switch
|
||||||
|
{
|
||||||
|
ModuleType.Workspaces => "Workspaces/ModuleTitle",
|
||||||
|
ModuleType.PowerAccent => "QuickAccent/ModuleTitle",
|
||||||
|
ModuleType.PowerOCR => "TextExtractor/ModuleTitle",
|
||||||
|
ModuleType.FindMyMouse => "MouseUtils_FindMyMouse/Header",
|
||||||
|
ModuleType.MouseHighlighter => "MouseUtils_MouseHighlighter/Header",
|
||||||
|
ModuleType.MouseJump => "MouseUtils_MouseJump/Header",
|
||||||
|
ModuleType.MousePointerCrosshairs => "MouseUtils_MousePointerCrosshairs/Header",
|
||||||
|
ModuleType.CursorWrap => "MouseUtils_CursorWrap/Header",
|
||||||
|
ModuleType.GeneralSettings => "QuickAccessTitle/Title",
|
||||||
|
_ => $"{moduleType}/ModuleTitle",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetModuleTypeFluentIconName(ModuleType moduleType)
|
||||||
|
{
|
||||||
|
return moduleType switch
|
||||||
|
{
|
||||||
|
ModuleType.AdvancedPaste => "ms-appx:///Assets/Settings/Icons/AdvancedPaste.png",
|
||||||
|
ModuleType.Workspaces => "ms-appx:///Assets/Settings/Icons/Workspaces.png",
|
||||||
|
ModuleType.PowerOCR => "ms-appx:///Assets/Settings/Icons/TextExtractor.png",
|
||||||
|
ModuleType.PowerAccent => "ms-appx:///Assets/Settings/Icons/QuickAccent.png",
|
||||||
|
ModuleType.MousePointerCrosshairs => "ms-appx:///Assets/Settings/Icons/MouseCrosshairs.png",
|
||||||
|
ModuleType.MeasureTool => "ms-appx:///Assets/Settings/Icons/ScreenRuler.png",
|
||||||
|
ModuleType.PowerLauncher => "ms-appx:///Assets/Settings/Icons/PowerToysRun.png",
|
||||||
|
ModuleType.GeneralSettings => "ms-appx:///Assets/Settings/Icons/PowerToys.png",
|
||||||
|
_ => $"ms-appx:///Assets/Settings/Icons/{moduleType}.png",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool GetIsModuleEnabled(GeneralSettings generalSettingsConfig, ModuleType moduleType)
|
||||||
|
{
|
||||||
|
return moduleType switch
|
||||||
|
{
|
||||||
|
ModuleType.AdvancedPaste => generalSettingsConfig.Enabled.AdvancedPaste,
|
||||||
|
ModuleType.AlwaysOnTop => generalSettingsConfig.Enabled.AlwaysOnTop,
|
||||||
|
ModuleType.Awake => generalSettingsConfig.Enabled.Awake,
|
||||||
|
ModuleType.CmdPal => generalSettingsConfig.Enabled.CmdPal,
|
||||||
|
ModuleType.ColorPicker => generalSettingsConfig.Enabled.ColorPicker,
|
||||||
|
ModuleType.CropAndLock => generalSettingsConfig.Enabled.CropAndLock,
|
||||||
|
ModuleType.CursorWrap => generalSettingsConfig.Enabled.CursorWrap,
|
||||||
|
ModuleType.EnvironmentVariables => generalSettingsConfig.Enabled.EnvironmentVariables,
|
||||||
|
ModuleType.FancyZones => generalSettingsConfig.Enabled.FancyZones,
|
||||||
|
ModuleType.FileLocksmith => generalSettingsConfig.Enabled.FileLocksmith,
|
||||||
|
ModuleType.FindMyMouse => generalSettingsConfig.Enabled.FindMyMouse,
|
||||||
|
ModuleType.Hosts => generalSettingsConfig.Enabled.Hosts,
|
||||||
|
ModuleType.ImageResizer => generalSettingsConfig.Enabled.ImageResizer,
|
||||||
|
ModuleType.KeyboardManager => generalSettingsConfig.Enabled.KeyboardManager,
|
||||||
|
ModuleType.LightSwitch => generalSettingsConfig.Enabled.LightSwitch,
|
||||||
|
ModuleType.MouseHighlighter => generalSettingsConfig.Enabled.MouseHighlighter,
|
||||||
|
ModuleType.MouseJump => generalSettingsConfig.Enabled.MouseJump,
|
||||||
|
ModuleType.MousePointerCrosshairs => generalSettingsConfig.Enabled.MousePointerCrosshairs,
|
||||||
|
ModuleType.MouseWithoutBorders => generalSettingsConfig.Enabled.MouseWithoutBorders,
|
||||||
|
ModuleType.NewPlus => generalSettingsConfig.Enabled.NewPlus,
|
||||||
|
ModuleType.Peek => generalSettingsConfig.Enabled.Peek,
|
||||||
|
ModuleType.PowerRename => generalSettingsConfig.Enabled.PowerRename,
|
||||||
|
ModuleType.PowerLauncher => generalSettingsConfig.Enabled.PowerLauncher,
|
||||||
|
ModuleType.PowerAccent => generalSettingsConfig.Enabled.PowerAccent,
|
||||||
|
ModuleType.RegistryPreview => generalSettingsConfig.Enabled.RegistryPreview,
|
||||||
|
ModuleType.MeasureTool => generalSettingsConfig.Enabled.MeasureTool,
|
||||||
|
ModuleType.ShortcutGuide => generalSettingsConfig.Enabled.ShortcutGuide,
|
||||||
|
ModuleType.PowerOCR => generalSettingsConfig.Enabled.PowerOcr,
|
||||||
|
ModuleType.Workspaces => generalSettingsConfig.Enabled.Workspaces,
|
||||||
|
ModuleType.ZoomIt => generalSettingsConfig.Enabled.ZoomIt,
|
||||||
|
ModuleType.GeneralSettings => generalSettingsConfig.EnableQuickAccess,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetIsModuleEnabled(GeneralSettings generalSettingsConfig, ModuleType moduleType, bool isEnabled)
|
||||||
|
{
|
||||||
|
switch (moduleType)
|
||||||
|
{
|
||||||
|
case ModuleType.AdvancedPaste: generalSettingsConfig.Enabled.AdvancedPaste = isEnabled; break;
|
||||||
|
case ModuleType.AlwaysOnTop: generalSettingsConfig.Enabled.AlwaysOnTop = isEnabled; break;
|
||||||
|
case ModuleType.Awake: generalSettingsConfig.Enabled.Awake = isEnabled; break;
|
||||||
|
case ModuleType.CmdPal: generalSettingsConfig.Enabled.CmdPal = isEnabled; break;
|
||||||
|
case ModuleType.ColorPicker: generalSettingsConfig.Enabled.ColorPicker = isEnabled; break;
|
||||||
|
case ModuleType.CropAndLock: generalSettingsConfig.Enabled.CropAndLock = isEnabled; break;
|
||||||
|
case ModuleType.CursorWrap: generalSettingsConfig.Enabled.CursorWrap = isEnabled; break;
|
||||||
|
case ModuleType.EnvironmentVariables: generalSettingsConfig.Enabled.EnvironmentVariables = isEnabled; break;
|
||||||
|
case ModuleType.FancyZones: generalSettingsConfig.Enabled.FancyZones = isEnabled; break;
|
||||||
|
case ModuleType.FileLocksmith: generalSettingsConfig.Enabled.FileLocksmith = isEnabled; break;
|
||||||
|
case ModuleType.FindMyMouse: generalSettingsConfig.Enabled.FindMyMouse = isEnabled; break;
|
||||||
|
case ModuleType.Hosts: generalSettingsConfig.Enabled.Hosts = isEnabled; break;
|
||||||
|
case ModuleType.ImageResizer: generalSettingsConfig.Enabled.ImageResizer = isEnabled; break;
|
||||||
|
case ModuleType.KeyboardManager: generalSettingsConfig.Enabled.KeyboardManager = isEnabled; break;
|
||||||
|
case ModuleType.LightSwitch: generalSettingsConfig.Enabled.LightSwitch = isEnabled; break;
|
||||||
|
case ModuleType.MouseHighlighter: generalSettingsConfig.Enabled.MouseHighlighter = isEnabled; break;
|
||||||
|
case ModuleType.MouseJump: generalSettingsConfig.Enabled.MouseJump = isEnabled; break;
|
||||||
|
case ModuleType.MousePointerCrosshairs: generalSettingsConfig.Enabled.MousePointerCrosshairs = isEnabled; break;
|
||||||
|
case ModuleType.MouseWithoutBorders: generalSettingsConfig.Enabled.MouseWithoutBorders = isEnabled; break;
|
||||||
|
case ModuleType.NewPlus: generalSettingsConfig.Enabled.NewPlus = isEnabled; break;
|
||||||
|
case ModuleType.Peek: generalSettingsConfig.Enabled.Peek = isEnabled; break;
|
||||||
|
case ModuleType.PowerRename: generalSettingsConfig.Enabled.PowerRename = isEnabled; break;
|
||||||
|
case ModuleType.PowerLauncher: generalSettingsConfig.Enabled.PowerLauncher = isEnabled; break;
|
||||||
|
case ModuleType.PowerAccent: generalSettingsConfig.Enabled.PowerAccent = isEnabled; break;
|
||||||
|
case ModuleType.RegistryPreview: generalSettingsConfig.Enabled.RegistryPreview = isEnabled; break;
|
||||||
|
case ModuleType.MeasureTool: generalSettingsConfig.Enabled.MeasureTool = isEnabled; break;
|
||||||
|
case ModuleType.ShortcutGuide: generalSettingsConfig.Enabled.ShortcutGuide = isEnabled; break;
|
||||||
|
case ModuleType.PowerOCR: generalSettingsConfig.Enabled.PowerOcr = isEnabled; break;
|
||||||
|
case ModuleType.Workspaces: generalSettingsConfig.Enabled.Workspaces = isEnabled; break;
|
||||||
|
case ModuleType.ZoomIt: generalSettingsConfig.Enabled.ZoomIt = isEnabled; break;
|
||||||
|
case ModuleType.GeneralSettings: generalSettingsConfig.EnableQuickAccess = isEnabled; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI.Library.Interfaces
|
namespace Microsoft.PowerToys.Settings.UI.Library.Interfaces
|
||||||
{
|
{
|
||||||
public interface ISettingsRepository<T>
|
public interface ISettingsRepository<T>
|
||||||
@@ -9,5 +11,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library.Interfaces
|
|||||||
T SettingsConfig { get; set; }
|
T SettingsConfig { get; set; }
|
||||||
|
|
||||||
bool ReloadSettings();
|
bool ReloadSettings();
|
||||||
|
|
||||||
|
event Action<T> SettingsChanged;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,11 @@ namespace Microsoft.PowerToys.Settings.UI.Services
|
|||||||
if (settingsInstance != null)
|
if (settingsInstance != null)
|
||||||
{
|
{
|
||||||
var moduleName = settingsInstance.GetModuleName();
|
var moduleName = settingsInstance.GetModuleName();
|
||||||
|
if (string.IsNullOrEmpty(moduleName) && type == typeof(GeneralSettings))
|
||||||
|
{
|
||||||
|
moduleName = "GeneralSettings";
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(moduleName))
|
if (!string.IsNullOrEmpty(moduleName))
|
||||||
{
|
{
|
||||||
settingsTypes[moduleName] = type;
|
settingsTypes[moduleName] = type;
|
||||||
@@ -104,7 +109,13 @@ namespace Microsoft.PowerToys.Settings.UI.Services
|
|||||||
var genericMethod = getSettingsMethod?.MakeGenericMethod(settingsType);
|
var genericMethod = getSettingsMethod?.MakeGenericMethod(settingsType);
|
||||||
|
|
||||||
// Call GetSettingsOrDefault<T>(moduleKey) to get fresh settings from file
|
// Call GetSettingsOrDefault<T>(moduleKey) to get fresh settings from file
|
||||||
var freshSettings = genericMethod?.Invoke(_settingsUtils, new object[] { moduleKey, "settings.json" });
|
string actualModuleKey = moduleKey;
|
||||||
|
if (moduleKey == "GeneralSettings")
|
||||||
|
{
|
||||||
|
actualModuleKey = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
var freshSettings = genericMethod?.Invoke(_settingsUtils, new object[] { actualModuleKey, "settings.json" });
|
||||||
|
|
||||||
return freshSettings as IHotkeyConfig;
|
return freshSettings as IHotkeyConfig;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,15 +3,16 @@
|
|||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using ManagedCommon;
|
||||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||||
{
|
{
|
||||||
// This Singleton class is a wrapper around the settings configurations that are accessed by viewmodels.
|
// This Singleton class is a wrapper around the settings configurations that are accessed by viewmodels.
|
||||||
// This class can have only one instance and therefore the settings configurations are common to all.
|
// This class can have only one instance and therefore the settings configurations are common to all.
|
||||||
public class SettingsRepository<T> : ISettingsRepository<T>
|
public sealed class SettingsRepository<T> : ISettingsRepository<T>, IDisposable
|
||||||
where T : class, ISettingsConfig, new()
|
where T : class, ISettingsConfig, new()
|
||||||
{
|
{
|
||||||
private static readonly Lock _SettingsRepoLock = new Lock();
|
private static readonly Lock _SettingsRepoLock = new Lock();
|
||||||
@@ -22,6 +23,10 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
|
|
||||||
private T settingsConfig;
|
private T settingsConfig;
|
||||||
|
|
||||||
|
private FileSystemWatcher _watcher;
|
||||||
|
|
||||||
|
public event Action<T> SettingsChanged;
|
||||||
|
|
||||||
// Suppressing the warning as this is a singleton class and this method is
|
// Suppressing the warning as this is a singleton class and this method is
|
||||||
// necessarily static
|
// necessarily static
|
||||||
#pragma warning disable CA1000 // Do not declare static members on generic types
|
#pragma warning disable CA1000 // Do not declare static members on generic types
|
||||||
@@ -35,6 +40,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
{
|
{
|
||||||
settingsRepository = new SettingsRepository<T>();
|
settingsRepository = new SettingsRepository<T>();
|
||||||
_settingsUtils = settingsUtils ?? throw new ArgumentNullException(nameof(settingsUtils));
|
_settingsUtils = settingsUtils ?? throw new ArgumentNullException(nameof(settingsUtils));
|
||||||
|
settingsRepository.InitializeWatcher();
|
||||||
}
|
}
|
||||||
|
|
||||||
return settingsRepository;
|
return settingsRepository;
|
||||||
@@ -46,12 +52,51 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InitializeWatcher()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var settingsItem = new T();
|
||||||
|
var filePath = _settingsUtils.GetSettingsFilePath(settingsItem.GetModuleName());
|
||||||
|
var directory = Path.GetDirectoryName(filePath);
|
||||||
|
var fileName = Path.GetFileName(filePath);
|
||||||
|
|
||||||
|
if (!Directory.Exists(directory))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
_watcher = new FileSystemWatcher(directory, fileName);
|
||||||
|
_watcher.NotifyFilter = NotifyFilters.LastWrite;
|
||||||
|
_watcher.Changed += Watcher_Changed;
|
||||||
|
_watcher.EnableRaisingEvents = true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError($"Failed to initialize settings watcher for {typeof(T).Name}", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Watcher_Changed(object sender, FileSystemEventArgs e)
|
||||||
|
{
|
||||||
|
// Wait a bit for the file write to complete and retry if needed
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
Thread.Sleep(100);
|
||||||
|
if (ReloadSettings())
|
||||||
|
{
|
||||||
|
SettingsChanged?.Invoke(SettingsConfig);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool ReloadSettings()
|
public bool ReloadSettings()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
T settingsItem = new T();
|
T settingsItem = new T();
|
||||||
settingsConfig = _settingsUtils.GetSettingsOrDefault<T>(settingsItem.GetModuleName());
|
settingsConfig = _settingsUtils.GetSettings<T>(settingsItem.GetModuleName());
|
||||||
|
|
||||||
SettingsConfig = settingsConfig;
|
SettingsConfig = settingsConfig;
|
||||||
|
|
||||||
@@ -85,5 +130,26 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void StopWatching()
|
||||||
|
{
|
||||||
|
if (_watcher != null)
|
||||||
|
{
|
||||||
|
_watcher.EnableRaisingEvents = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartWatching()
|
||||||
|
{
|
||||||
|
if (_watcher != null)
|
||||||
|
{
|
||||||
|
_watcher.EnableRaisingEvents = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_watcher?.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
|
|
||||||
// Main Settings Classes
|
// Main Settings Classes
|
||||||
[JsonSerializable(typeof(GeneralSettings))]
|
[JsonSerializable(typeof(GeneralSettings))]
|
||||||
|
[JsonSerializable(typeof(OutGoingGeneralSettings))]
|
||||||
[JsonSerializable(typeof(AdvancedPasteSettings))]
|
[JsonSerializable(typeof(AdvancedPasteSettings))]
|
||||||
[JsonSerializable(typeof(AlwaysOnTopSettings))]
|
[JsonSerializable(typeof(AlwaysOnTopSettings))]
|
||||||
[JsonSerializable(typeof(AwakeSettings))]
|
[JsonSerializable(typeof(AwakeSettings))]
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ namespace Microsoft.PowerToys.Settings.UI.UnitTests.BackwardsCompatibility
|
|||||||
private readonly SettingsUtils _settingsUtils;
|
private readonly SettingsUtils _settingsUtils;
|
||||||
private T _settingsConfig;
|
private T _settingsConfig;
|
||||||
|
|
||||||
|
// Implements ISettingsRepository<T>.SettingsChanged
|
||||||
|
#pragma warning disable CS0067
|
||||||
|
public event System.Action<T> SettingsChanged;
|
||||||
|
#pragma warning restore CS0067
|
||||||
|
|
||||||
public MockSettingsRepository(SettingsUtils settingsUtils)
|
public MockSettingsRepository(SettingsUtils settingsUtils)
|
||||||
{
|
{
|
||||||
_settingsUtils = settingsUtils;
|
_settingsUtils = settingsUtils;
|
||||||
|
|||||||
@@ -28,6 +28,28 @@ namespace ViewModelTests
|
|||||||
mockGeneralSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<GeneralSettings>();
|
mockGeneralSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<GeneralSettings>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private sealed class TestGeneralViewModel : GeneralViewModel
|
||||||
|
{
|
||||||
|
public TestGeneralViewModel(
|
||||||
|
Microsoft.PowerToys.Settings.UI.Library.Interfaces.ISettingsRepository<GeneralSettings> settingsRepository,
|
||||||
|
string runAsAdminText,
|
||||||
|
string runAsUserText,
|
||||||
|
bool isElevated,
|
||||||
|
bool isAdmin,
|
||||||
|
Func<string, int> ipcMSGCallBackFunc,
|
||||||
|
Func<string, int> ipcMSGRestartAsAdminMSGCallBackFunc,
|
||||||
|
Func<string, int> ipcMSGCheckForUpdatesCallBackFunc,
|
||||||
|
string configFileSubfolder = "")
|
||||||
|
: base(settingsRepository, runAsAdminText, runAsUserText, isElevated, isAdmin, ipcMSGCallBackFunc, ipcMSGRestartAsAdminMSGCallBackFunc, ipcMSGCheckForUpdatesCallBackFunc, configFileSubfolder)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Microsoft.UI.Dispatching.DispatcherQueue GetDispatcherQueue()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
[DataRow("v0.18.2")]
|
[DataRow("v0.18.2")]
|
||||||
[DataRow("v0.19.2")]
|
[DataRow("v0.19.2")]
|
||||||
@@ -49,7 +71,7 @@ namespace ViewModelTests
|
|||||||
Func<string, int> sendMockIPCConfigMSG = msg => 0;
|
Func<string, int> sendMockIPCConfigMSG = msg => 0;
|
||||||
Func<string, int> sendRestartAdminIPCMessage = msg => 0;
|
Func<string, int> sendRestartAdminIPCMessage = msg => 0;
|
||||||
Func<string, int> sendCheckForUpdatesIPCMessage = msg => 0;
|
Func<string, int> sendCheckForUpdatesIPCMessage = msg => 0;
|
||||||
var viewModel = new GeneralViewModel(
|
var viewModel = new TestGeneralViewModel(
|
||||||
settingsRepository: generalSettingsRepository,
|
settingsRepository: generalSettingsRepository,
|
||||||
runAsAdminText: "GeneralSettings_RunningAsAdminText",
|
runAsAdminText: "GeneralSettings_RunningAsAdminText",
|
||||||
runAsUserText: "GeneralSettings_RunningAsUserText",
|
runAsUserText: "GeneralSettings_RunningAsUserText",
|
||||||
@@ -78,7 +100,7 @@ namespace ViewModelTests
|
|||||||
Func<string, int> sendMockIPCConfigMSG = msg => { return 0; };
|
Func<string, int> sendMockIPCConfigMSG = msg => { return 0; };
|
||||||
Func<string, int> sendRestartAdminIPCMessage = msg => { return 0; };
|
Func<string, int> sendRestartAdminIPCMessage = msg => { return 0; };
|
||||||
Func<string, int> sendCheckForUpdatesIPCMessage = msg => { return 0; };
|
Func<string, int> sendCheckForUpdatesIPCMessage = msg => { return 0; };
|
||||||
GeneralViewModel viewModel = new GeneralViewModel(
|
GeneralViewModel viewModel = new TestGeneralViewModel(
|
||||||
settingsRepository: SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object),
|
settingsRepository: SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object),
|
||||||
"GeneralSettings_RunningAsAdminText",
|
"GeneralSettings_RunningAsAdminText",
|
||||||
"GeneralSettings_RunningAsUserText",
|
"GeneralSettings_RunningAsUserText",
|
||||||
@@ -114,7 +136,7 @@ namespace ViewModelTests
|
|||||||
// Arrange
|
// Arrange
|
||||||
Func<string, int> sendRestartAdminIPCMessage = msg => { return 0; };
|
Func<string, int> sendRestartAdminIPCMessage = msg => { return 0; };
|
||||||
Func<string, int> sendCheckForUpdatesIPCMessage = msg => { return 0; };
|
Func<string, int> sendCheckForUpdatesIPCMessage = msg => { return 0; };
|
||||||
GeneralViewModel viewModel = new GeneralViewModel(
|
GeneralViewModel viewModel = new TestGeneralViewModel(
|
||||||
settingsRepository: SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object),
|
settingsRepository: SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object),
|
||||||
"GeneralSettings_RunningAsAdminText",
|
"GeneralSettings_RunningAsAdminText",
|
||||||
"GeneralSettings_RunningAsUserText",
|
"GeneralSettings_RunningAsUserText",
|
||||||
@@ -145,7 +167,7 @@ namespace ViewModelTests
|
|||||||
Func<string, int> sendCheckForUpdatesIPCMessage = msg => { return 0; };
|
Func<string, int> sendCheckForUpdatesIPCMessage = msg => { return 0; };
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
GeneralViewModel viewModel = new GeneralViewModel(
|
GeneralViewModel viewModel = new TestGeneralViewModel(
|
||||||
settingsRepository: SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object),
|
settingsRepository: SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object),
|
||||||
"GeneralSettings_RunningAsAdminText",
|
"GeneralSettings_RunningAsAdminText",
|
||||||
"GeneralSettings_RunningAsUserText",
|
"GeneralSettings_RunningAsUserText",
|
||||||
@@ -178,7 +200,7 @@ namespace ViewModelTests
|
|||||||
|
|
||||||
Func<string, int> sendRestartAdminIPCMessage = msg => { return 0; };
|
Func<string, int> sendRestartAdminIPCMessage = msg => { return 0; };
|
||||||
Func<string, int> sendCheckForUpdatesIPCMessage = msg => { return 0; };
|
Func<string, int> sendCheckForUpdatesIPCMessage = msg => { return 0; };
|
||||||
viewModel = new GeneralViewModel(
|
viewModel = new TestGeneralViewModel(
|
||||||
settingsRepository: SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object),
|
settingsRepository: SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object),
|
||||||
"GeneralSettings_RunningAsAdminText",
|
"GeneralSettings_RunningAsAdminText",
|
||||||
"GeneralSettings_RunningAsUserText",
|
"GeneralSettings_RunningAsUserText",
|
||||||
@@ -208,7 +230,7 @@ namespace ViewModelTests
|
|||||||
|
|
||||||
Func<string, int> sendRestartAdminIPCMessage = msg => { return 0; };
|
Func<string, int> sendRestartAdminIPCMessage = msg => { return 0; };
|
||||||
Func<string, int> sendCheckForUpdatesIPCMessage = msg => { return 0; };
|
Func<string, int> sendCheckForUpdatesIPCMessage = msg => { return 0; };
|
||||||
GeneralViewModel viewModel = new GeneralViewModel(
|
GeneralViewModel viewModel = new TestGeneralViewModel(
|
||||||
settingsRepository: SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object),
|
settingsRepository: SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object),
|
||||||
"GeneralSettings_RunningAsAdminText",
|
"GeneralSettings_RunningAsAdminText",
|
||||||
"GeneralSettings_RunningAsUserText",
|
"GeneralSettings_RunningAsUserText",
|
||||||
@@ -238,7 +260,7 @@ namespace ViewModelTests
|
|||||||
|
|
||||||
Func<string, int> sendRestartAdminIPCMessage = msg => { return 0; };
|
Func<string, int> sendRestartAdminIPCMessage = msg => { return 0; };
|
||||||
Func<string, int> sendCheckForUpdatesIPCMessage = msg => { return 0; };
|
Func<string, int> sendCheckForUpdatesIPCMessage = msg => { return 0; };
|
||||||
GeneralViewModel viewModel = new(
|
GeneralViewModel viewModel = new TestGeneralViewModel(
|
||||||
settingsRepository: SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object),
|
settingsRepository: SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object),
|
||||||
"GeneralSettings_RunningAsAdminText",
|
"GeneralSettings_RunningAsAdminText",
|
||||||
"GeneralSettings_RunningAsUserText",
|
"GeneralSettings_RunningAsUserText",
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Controls;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
|
using Microsoft.UI.Xaml.Data;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Converters
|
||||||
|
{
|
||||||
|
public partial class EnumToModuleListSortOptionConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
if (value is DashboardSortOrder sortOrder)
|
||||||
|
{
|
||||||
|
return sortOrder switch
|
||||||
|
{
|
||||||
|
DashboardSortOrder.Alphabetical => ModuleListSortOption.Alphabetical,
|
||||||
|
DashboardSortOrder.ByStatus => ModuleListSortOption.ByStatus,
|
||||||
|
_ => ModuleListSortOption.Alphabetical,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return ModuleListSortOption.Alphabetical;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
if (value is ModuleListSortOption sortOption)
|
||||||
|
{
|
||||||
|
return sortOption switch
|
||||||
|
{
|
||||||
|
ModuleListSortOption.Alphabetical => DashboardSortOrder.Alphabetical,
|
||||||
|
ModuleListSortOption.ByStatus => DashboardSortOrder.ByStatus,
|
||||||
|
_ => DashboardSortOrder.Alphabetical,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return DashboardSortOrder.Alphabetical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
91
src/settings-ui/Settings.UI/Helpers/ModuleGpoHelper.cs
Normal file
91
src/settings-ui/Settings.UI/Helpers/ModuleGpoHelper.cs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using global::PowerToys.GPOWrapper;
|
||||||
|
using ManagedCommon;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Views;
|
||||||
|
using Windows.UI;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Helpers
|
||||||
|
{
|
||||||
|
internal sealed class ModuleGpoHelper
|
||||||
|
{
|
||||||
|
public static GpoRuleConfigured GetModuleGpoConfiguration(ModuleType moduleType)
|
||||||
|
{
|
||||||
|
switch (moduleType)
|
||||||
|
{
|
||||||
|
case ModuleType.AdvancedPaste: return GPOWrapper.GetConfiguredAdvancedPasteEnabledValue();
|
||||||
|
case ModuleType.AlwaysOnTop: return GPOWrapper.GetConfiguredAlwaysOnTopEnabledValue();
|
||||||
|
case ModuleType.Awake: return GPOWrapper.GetConfiguredAwakeEnabledValue();
|
||||||
|
case ModuleType.CmdPal: return GPOWrapper.GetConfiguredCmdPalEnabledValue();
|
||||||
|
case ModuleType.ColorPicker: return GPOWrapper.GetConfiguredColorPickerEnabledValue();
|
||||||
|
case ModuleType.CropAndLock: return GPOWrapper.GetConfiguredCropAndLockEnabledValue();
|
||||||
|
case ModuleType.CursorWrap: return GPOWrapper.GetConfiguredCursorWrapEnabledValue();
|
||||||
|
case ModuleType.EnvironmentVariables: return GPOWrapper.GetConfiguredEnvironmentVariablesEnabledValue();
|
||||||
|
case ModuleType.FancyZones: return GPOWrapper.GetConfiguredFancyZonesEnabledValue();
|
||||||
|
case ModuleType.FileLocksmith: return GPOWrapper.GetConfiguredFileLocksmithEnabledValue();
|
||||||
|
case ModuleType.FindMyMouse: return GPOWrapper.GetConfiguredFindMyMouseEnabledValue();
|
||||||
|
case ModuleType.Hosts: return GPOWrapper.GetConfiguredHostsFileEditorEnabledValue();
|
||||||
|
case ModuleType.ImageResizer: return GPOWrapper.GetConfiguredImageResizerEnabledValue();
|
||||||
|
case ModuleType.KeyboardManager: return GPOWrapper.GetConfiguredKeyboardManagerEnabledValue();
|
||||||
|
case ModuleType.MouseHighlighter: return GPOWrapper.GetConfiguredMouseHighlighterEnabledValue();
|
||||||
|
case ModuleType.MouseJump: return GPOWrapper.GetConfiguredMouseJumpEnabledValue();
|
||||||
|
case ModuleType.MousePointerCrosshairs: return GPOWrapper.GetConfiguredMousePointerCrosshairsEnabledValue();
|
||||||
|
case ModuleType.MouseWithoutBorders: return GPOWrapper.GetConfiguredMouseWithoutBordersEnabledValue();
|
||||||
|
case ModuleType.NewPlus: return GPOWrapper.GetConfiguredNewPlusEnabledValue();
|
||||||
|
case ModuleType.Peek: return GPOWrapper.GetConfiguredPeekEnabledValue();
|
||||||
|
case ModuleType.PowerRename: return GPOWrapper.GetConfiguredPowerRenameEnabledValue();
|
||||||
|
case ModuleType.PowerLauncher: return GPOWrapper.GetConfiguredPowerLauncherEnabledValue();
|
||||||
|
case ModuleType.PowerAccent: return GPOWrapper.GetConfiguredQuickAccentEnabledValue();
|
||||||
|
case ModuleType.Workspaces: return GPOWrapper.GetConfiguredWorkspacesEnabledValue();
|
||||||
|
case ModuleType.RegistryPreview: return GPOWrapper.GetConfiguredRegistryPreviewEnabledValue();
|
||||||
|
case ModuleType.MeasureTool: return GPOWrapper.GetConfiguredScreenRulerEnabledValue();
|
||||||
|
case ModuleType.ShortcutGuide: return GPOWrapper.GetConfiguredShortcutGuideEnabledValue();
|
||||||
|
case ModuleType.PowerOCR: return GPOWrapper.GetConfiguredTextExtractorEnabledValue();
|
||||||
|
case ModuleType.ZoomIt: return GPOWrapper.GetConfiguredZoomItEnabledValue();
|
||||||
|
default: return GpoRuleConfigured.Unavailable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static System.Type GetModulePageType(ModuleType moduleType)
|
||||||
|
{
|
||||||
|
return moduleType switch
|
||||||
|
{
|
||||||
|
ModuleType.AdvancedPaste => typeof(AdvancedPastePage),
|
||||||
|
ModuleType.AlwaysOnTop => typeof(AlwaysOnTopPage),
|
||||||
|
ModuleType.Awake => typeof(AwakePage),
|
||||||
|
ModuleType.CmdPal => typeof(CmdPalPage),
|
||||||
|
ModuleType.ColorPicker => typeof(ColorPickerPage),
|
||||||
|
ModuleType.CropAndLock => typeof(CropAndLockPage),
|
||||||
|
ModuleType.CursorWrap => typeof(MouseUtilsPage),
|
||||||
|
ModuleType.LightSwitch => typeof(LightSwitchPage),
|
||||||
|
ModuleType.EnvironmentVariables => typeof(EnvironmentVariablesPage),
|
||||||
|
ModuleType.FancyZones => typeof(FancyZonesPage),
|
||||||
|
ModuleType.FileLocksmith => typeof(FileLocksmithPage),
|
||||||
|
ModuleType.FindMyMouse => typeof(MouseUtilsPage),
|
||||||
|
ModuleType.GeneralSettings => typeof(GeneralPage),
|
||||||
|
ModuleType.Hosts => typeof(HostsPage),
|
||||||
|
ModuleType.ImageResizer => typeof(ImageResizerPage),
|
||||||
|
ModuleType.KeyboardManager => typeof(KeyboardManagerPage),
|
||||||
|
ModuleType.MouseHighlighter => typeof(MouseUtilsPage),
|
||||||
|
ModuleType.MouseJump => typeof(MouseUtilsPage),
|
||||||
|
ModuleType.MousePointerCrosshairs => typeof(MouseUtilsPage),
|
||||||
|
ModuleType.MouseWithoutBorders => typeof(MouseWithoutBordersPage),
|
||||||
|
ModuleType.NewPlus => typeof(NewPlusPage),
|
||||||
|
ModuleType.Peek => typeof(PeekPage),
|
||||||
|
ModuleType.PowerRename => typeof(PowerRenamePage),
|
||||||
|
ModuleType.PowerLauncher => typeof(PowerLauncherPage),
|
||||||
|
ModuleType.PowerAccent => typeof(PowerAccentPage),
|
||||||
|
ModuleType.Workspaces => typeof(WorkspacesPage),
|
||||||
|
ModuleType.RegistryPreview => typeof(RegistryPreviewPage),
|
||||||
|
ModuleType.MeasureTool => typeof(MeasureToolPage),
|
||||||
|
ModuleType.ShortcutGuide => typeof(ShortcutGuidePage),
|
||||||
|
ModuleType.PowerOCR => typeof(PowerOcrPage),
|
||||||
|
ModuleType.ZoomIt => typeof(ZoomItPage),
|
||||||
|
_ => typeof(DashboardPage), // never called, all values listed above
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,196 +0,0 @@
|
|||||||
// Copyright (c) Microsoft Corporation
|
|
||||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
|
||||||
// See the LICENSE file in the project root for more information.
|
|
||||||
|
|
||||||
using global::PowerToys.GPOWrapper;
|
|
||||||
using ManagedCommon;
|
|
||||||
using Microsoft.PowerToys.Settings.UI.Library;
|
|
||||||
using Microsoft.PowerToys.Settings.UI.Views;
|
|
||||||
using Windows.UI;
|
|
||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI.Helpers
|
|
||||||
{
|
|
||||||
internal sealed class ModuleHelper
|
|
||||||
{
|
|
||||||
public static string GetModuleLabelResourceName(ModuleType moduleType)
|
|
||||||
{
|
|
||||||
switch (moduleType)
|
|
||||||
{
|
|
||||||
case ModuleType.Workspaces: return "Workspaces/ModuleTitle";
|
|
||||||
case ModuleType.PowerAccent: return "QuickAccent/ModuleTitle";
|
|
||||||
case ModuleType.PowerOCR: return "TextExtractor/ModuleTitle";
|
|
||||||
case ModuleType.FindMyMouse:
|
|
||||||
case ModuleType.MouseHighlighter:
|
|
||||||
case ModuleType.MouseJump:
|
|
||||||
case ModuleType.MousePointerCrosshairs:
|
|
||||||
case ModuleType.CursorWrap: return $"MouseUtils_{moduleType}/Header";
|
|
||||||
default: return $"{moduleType}/ModuleTitle";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetModuleTypeFluentIconName(ModuleType moduleType)
|
|
||||||
{
|
|
||||||
switch (moduleType)
|
|
||||||
{
|
|
||||||
case ModuleType.AdvancedPaste: return "ms-appx:///Assets/Settings/Icons/AdvancedPaste.png";
|
|
||||||
case ModuleType.Workspaces: return "ms-appx:///Assets/Settings/Icons/Workspaces.png";
|
|
||||||
case ModuleType.PowerOCR: return "ms-appx:///Assets/Settings/Icons/TextExtractor.png";
|
|
||||||
case ModuleType.PowerAccent: return "ms-appx:///Assets/Settings/Icons/QuickAccent.png";
|
|
||||||
case ModuleType.MousePointerCrosshairs: return "ms-appx:///Assets/Settings/Icons/MouseCrosshairs.png";
|
|
||||||
case ModuleType.MeasureTool: return "ms-appx:///Assets/Settings/Icons/ScreenRuler.png";
|
|
||||||
case ModuleType.PowerLauncher: return $"ms-appx:///Assets/Settings/Icons/PowerToysRun.png";
|
|
||||||
default: return $"ms-appx:///Assets/Settings/Icons/{moduleType}.png";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool GetIsModuleEnabled(Library.GeneralSettings generalSettingsConfig, ModuleType moduleType)
|
|
||||||
{
|
|
||||||
switch (moduleType)
|
|
||||||
{
|
|
||||||
case ModuleType.AdvancedPaste: return generalSettingsConfig.Enabled.AdvancedPaste;
|
|
||||||
case ModuleType.AlwaysOnTop: return generalSettingsConfig.Enabled.AlwaysOnTop;
|
|
||||||
case ModuleType.Awake: return generalSettingsConfig.Enabled.Awake;
|
|
||||||
case ModuleType.CmdPal: return generalSettingsConfig.Enabled.CmdPal;
|
|
||||||
case ModuleType.ColorPicker: return generalSettingsConfig.Enabled.ColorPicker;
|
|
||||||
case ModuleType.CropAndLock: return generalSettingsConfig.Enabled.CropAndLock;
|
|
||||||
case ModuleType.CursorWrap: return generalSettingsConfig.Enabled.CursorWrap;
|
|
||||||
case ModuleType.LightSwitch: return generalSettingsConfig.Enabled.LightSwitch;
|
|
||||||
case ModuleType.EnvironmentVariables: return generalSettingsConfig.Enabled.EnvironmentVariables;
|
|
||||||
case ModuleType.FancyZones: return generalSettingsConfig.Enabled.FancyZones;
|
|
||||||
case ModuleType.FileLocksmith: return generalSettingsConfig.Enabled.FileLocksmith;
|
|
||||||
case ModuleType.FindMyMouse: return generalSettingsConfig.Enabled.FindMyMouse;
|
|
||||||
case ModuleType.Hosts: return generalSettingsConfig.Enabled.Hosts;
|
|
||||||
case ModuleType.ImageResizer: return generalSettingsConfig.Enabled.ImageResizer;
|
|
||||||
case ModuleType.KeyboardManager: return generalSettingsConfig.Enabled.KeyboardManager;
|
|
||||||
case ModuleType.MouseHighlighter: return generalSettingsConfig.Enabled.MouseHighlighter;
|
|
||||||
case ModuleType.MouseJump: return generalSettingsConfig.Enabled.MouseJump;
|
|
||||||
case ModuleType.MousePointerCrosshairs: return generalSettingsConfig.Enabled.MousePointerCrosshairs;
|
|
||||||
case ModuleType.MouseWithoutBorders: return generalSettingsConfig.Enabled.MouseWithoutBorders;
|
|
||||||
case ModuleType.NewPlus: return generalSettingsConfig.Enabled.NewPlus;
|
|
||||||
case ModuleType.Peek: return generalSettingsConfig.Enabled.Peek;
|
|
||||||
case ModuleType.PowerRename: return generalSettingsConfig.Enabled.PowerRename;
|
|
||||||
case ModuleType.PowerLauncher: return generalSettingsConfig.Enabled.PowerLauncher;
|
|
||||||
case ModuleType.PowerAccent: return generalSettingsConfig.Enabled.PowerAccent;
|
|
||||||
case ModuleType.Workspaces: return generalSettingsConfig.Enabled.Workspaces;
|
|
||||||
case ModuleType.RegistryPreview: return generalSettingsConfig.Enabled.RegistryPreview;
|
|
||||||
case ModuleType.MeasureTool: return generalSettingsConfig.Enabled.MeasureTool;
|
|
||||||
case ModuleType.ShortcutGuide: return generalSettingsConfig.Enabled.ShortcutGuide;
|
|
||||||
case ModuleType.PowerOCR: return generalSettingsConfig.Enabled.PowerOcr;
|
|
||||||
case ModuleType.ZoomIt: return generalSettingsConfig.Enabled.ZoomIt;
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void SetIsModuleEnabled(GeneralSettings generalSettingsConfig, ModuleType moduleType, bool isEnabled)
|
|
||||||
{
|
|
||||||
switch (moduleType)
|
|
||||||
{
|
|
||||||
case ModuleType.AdvancedPaste: generalSettingsConfig.Enabled.AdvancedPaste = isEnabled; break;
|
|
||||||
case ModuleType.AlwaysOnTop: generalSettingsConfig.Enabled.AlwaysOnTop = isEnabled; break;
|
|
||||||
case ModuleType.Awake: generalSettingsConfig.Enabled.Awake = isEnabled; break;
|
|
||||||
case ModuleType.CmdPal: generalSettingsConfig.Enabled.CmdPal = isEnabled; break;
|
|
||||||
case ModuleType.ColorPicker: generalSettingsConfig.Enabled.ColorPicker = isEnabled; break;
|
|
||||||
case ModuleType.CropAndLock: generalSettingsConfig.Enabled.CropAndLock = isEnabled; break;
|
|
||||||
case ModuleType.CursorWrap: generalSettingsConfig.Enabled.CursorWrap = isEnabled; break;
|
|
||||||
case ModuleType.LightSwitch: generalSettingsConfig.Enabled.LightSwitch = isEnabled; break;
|
|
||||||
case ModuleType.EnvironmentVariables: generalSettingsConfig.Enabled.EnvironmentVariables = isEnabled; break;
|
|
||||||
case ModuleType.FancyZones: generalSettingsConfig.Enabled.FancyZones = isEnabled; break;
|
|
||||||
case ModuleType.FileLocksmith: generalSettingsConfig.Enabled.FileLocksmith = isEnabled; break;
|
|
||||||
case ModuleType.FindMyMouse: generalSettingsConfig.Enabled.FindMyMouse = isEnabled; break;
|
|
||||||
case ModuleType.Hosts: generalSettingsConfig.Enabled.Hosts = isEnabled; break;
|
|
||||||
case ModuleType.ImageResizer: generalSettingsConfig.Enabled.ImageResizer = isEnabled; break;
|
|
||||||
case ModuleType.KeyboardManager: generalSettingsConfig.Enabled.KeyboardManager = isEnabled; break;
|
|
||||||
case ModuleType.MouseHighlighter: generalSettingsConfig.Enabled.MouseHighlighter = isEnabled; break;
|
|
||||||
case ModuleType.MouseJump: generalSettingsConfig.Enabled.MouseJump = isEnabled; break;
|
|
||||||
case ModuleType.MousePointerCrosshairs: generalSettingsConfig.Enabled.MousePointerCrosshairs = isEnabled; break;
|
|
||||||
case ModuleType.MouseWithoutBorders: generalSettingsConfig.Enabled.MouseWithoutBorders = isEnabled; break;
|
|
||||||
case ModuleType.NewPlus: generalSettingsConfig.Enabled.NewPlus = isEnabled; break;
|
|
||||||
case ModuleType.Peek: generalSettingsConfig.Enabled.Peek = isEnabled; break;
|
|
||||||
case ModuleType.PowerRename: generalSettingsConfig.Enabled.PowerRename = isEnabled; break;
|
|
||||||
case ModuleType.PowerLauncher: generalSettingsConfig.Enabled.PowerLauncher = isEnabled; break;
|
|
||||||
case ModuleType.PowerAccent: generalSettingsConfig.Enabled.PowerAccent = isEnabled; break;
|
|
||||||
case ModuleType.Workspaces: generalSettingsConfig.Enabled.Workspaces = isEnabled; break;
|
|
||||||
case ModuleType.RegistryPreview: generalSettingsConfig.Enabled.RegistryPreview = isEnabled; break;
|
|
||||||
case ModuleType.MeasureTool: generalSettingsConfig.Enabled.MeasureTool = isEnabled; break;
|
|
||||||
case ModuleType.ShortcutGuide: generalSettingsConfig.Enabled.ShortcutGuide = isEnabled; break;
|
|
||||||
case ModuleType.PowerOCR: generalSettingsConfig.Enabled.PowerOcr = isEnabled; break;
|
|
||||||
case ModuleType.ZoomIt: generalSettingsConfig.Enabled.ZoomIt = isEnabled; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GpoRuleConfigured GetModuleGpoConfiguration(ModuleType moduleType)
|
|
||||||
{
|
|
||||||
switch (moduleType)
|
|
||||||
{
|
|
||||||
case ModuleType.AdvancedPaste: return GPOWrapper.GetConfiguredAdvancedPasteEnabledValue();
|
|
||||||
case ModuleType.AlwaysOnTop: return GPOWrapper.GetConfiguredAlwaysOnTopEnabledValue();
|
|
||||||
case ModuleType.Awake: return GPOWrapper.GetConfiguredAwakeEnabledValue();
|
|
||||||
case ModuleType.CmdPal: return GPOWrapper.GetConfiguredCmdPalEnabledValue();
|
|
||||||
case ModuleType.ColorPicker: return GPOWrapper.GetConfiguredColorPickerEnabledValue();
|
|
||||||
case ModuleType.CropAndLock: return GPOWrapper.GetConfiguredCropAndLockEnabledValue();
|
|
||||||
case ModuleType.CursorWrap: return GPOWrapper.GetConfiguredCursorWrapEnabledValue();
|
|
||||||
case ModuleType.EnvironmentVariables: return GPOWrapper.GetConfiguredEnvironmentVariablesEnabledValue();
|
|
||||||
case ModuleType.FancyZones: return GPOWrapper.GetConfiguredFancyZonesEnabledValue();
|
|
||||||
case ModuleType.FileLocksmith: return GPOWrapper.GetConfiguredFileLocksmithEnabledValue();
|
|
||||||
case ModuleType.FindMyMouse: return GPOWrapper.GetConfiguredFindMyMouseEnabledValue();
|
|
||||||
case ModuleType.Hosts: return GPOWrapper.GetConfiguredHostsFileEditorEnabledValue();
|
|
||||||
case ModuleType.ImageResizer: return GPOWrapper.GetConfiguredImageResizerEnabledValue();
|
|
||||||
case ModuleType.KeyboardManager: return GPOWrapper.GetConfiguredKeyboardManagerEnabledValue();
|
|
||||||
case ModuleType.MouseHighlighter: return GPOWrapper.GetConfiguredMouseHighlighterEnabledValue();
|
|
||||||
case ModuleType.MouseJump: return GPOWrapper.GetConfiguredMouseJumpEnabledValue();
|
|
||||||
case ModuleType.MousePointerCrosshairs: return GPOWrapper.GetConfiguredMousePointerCrosshairsEnabledValue();
|
|
||||||
case ModuleType.MouseWithoutBorders: return GPOWrapper.GetConfiguredMouseWithoutBordersEnabledValue();
|
|
||||||
case ModuleType.NewPlus: return GPOWrapper.GetConfiguredNewPlusEnabledValue();
|
|
||||||
case ModuleType.Peek: return GPOWrapper.GetConfiguredPeekEnabledValue();
|
|
||||||
case ModuleType.PowerRename: return GPOWrapper.GetConfiguredPowerRenameEnabledValue();
|
|
||||||
case ModuleType.PowerLauncher: return GPOWrapper.GetConfiguredPowerLauncherEnabledValue();
|
|
||||||
case ModuleType.PowerAccent: return GPOWrapper.GetConfiguredQuickAccentEnabledValue();
|
|
||||||
case ModuleType.Workspaces: return GPOWrapper.GetConfiguredWorkspacesEnabledValue();
|
|
||||||
case ModuleType.RegistryPreview: return GPOWrapper.GetConfiguredRegistryPreviewEnabledValue();
|
|
||||||
case ModuleType.MeasureTool: return GPOWrapper.GetConfiguredScreenRulerEnabledValue();
|
|
||||||
case ModuleType.ShortcutGuide: return GPOWrapper.GetConfiguredShortcutGuideEnabledValue();
|
|
||||||
case ModuleType.PowerOCR: return GPOWrapper.GetConfiguredTextExtractorEnabledValue();
|
|
||||||
case ModuleType.ZoomIt: return GPOWrapper.GetConfiguredZoomItEnabledValue();
|
|
||||||
default: return GpoRuleConfigured.Unavailable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static System.Type GetModulePageType(ModuleType moduleType)
|
|
||||||
{
|
|
||||||
return moduleType switch
|
|
||||||
{
|
|
||||||
ModuleType.AdvancedPaste => typeof(AdvancedPastePage),
|
|
||||||
ModuleType.AlwaysOnTop => typeof(AlwaysOnTopPage),
|
|
||||||
ModuleType.Awake => typeof(AwakePage),
|
|
||||||
ModuleType.CmdPal => typeof(CmdPalPage),
|
|
||||||
ModuleType.ColorPicker => typeof(ColorPickerPage),
|
|
||||||
ModuleType.CropAndLock => typeof(CropAndLockPage),
|
|
||||||
ModuleType.CursorWrap => typeof(MouseUtilsPage),
|
|
||||||
ModuleType.LightSwitch => typeof(LightSwitchPage),
|
|
||||||
ModuleType.EnvironmentVariables => typeof(EnvironmentVariablesPage),
|
|
||||||
ModuleType.FancyZones => typeof(FancyZonesPage),
|
|
||||||
ModuleType.FileLocksmith => typeof(FileLocksmithPage),
|
|
||||||
ModuleType.FindMyMouse => typeof(MouseUtilsPage),
|
|
||||||
ModuleType.Hosts => typeof(HostsPage),
|
|
||||||
ModuleType.ImageResizer => typeof(ImageResizerPage),
|
|
||||||
ModuleType.KeyboardManager => typeof(KeyboardManagerPage),
|
|
||||||
ModuleType.MouseHighlighter => typeof(MouseUtilsPage),
|
|
||||||
ModuleType.MouseJump => typeof(MouseUtilsPage),
|
|
||||||
ModuleType.MousePointerCrosshairs => typeof(MouseUtilsPage),
|
|
||||||
ModuleType.MouseWithoutBorders => typeof(MouseWithoutBordersPage),
|
|
||||||
ModuleType.NewPlus => typeof(NewPlusPage),
|
|
||||||
ModuleType.Peek => typeof(PeekPage),
|
|
||||||
ModuleType.PowerRename => typeof(PowerRenamePage),
|
|
||||||
ModuleType.PowerLauncher => typeof(PowerLauncherPage),
|
|
||||||
ModuleType.PowerAccent => typeof(PowerAccentPage),
|
|
||||||
ModuleType.Workspaces => typeof(WorkspacesPage),
|
|
||||||
ModuleType.RegistryPreview => typeof(RegistryPreviewPage),
|
|
||||||
ModuleType.MeasureTool => typeof(MeasureToolPage),
|
|
||||||
ModuleType.ShortcutGuide => typeof(ShortcutGuidePage),
|
|
||||||
ModuleType.PowerOCR => typeof(PowerOcrPage),
|
|
||||||
ModuleType.ZoomIt => typeof(ZoomItPage),
|
|
||||||
_ => typeof(DashboardPage), // never called, all values listed above
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -124,6 +124,7 @@
|
|||||||
<ProjectReference Include="..\..\common\LanguageModelProvider\LanguageModelProvider.csproj" />
|
<ProjectReference Include="..\..\common\LanguageModelProvider\LanguageModelProvider.csproj" />
|
||||||
<ProjectReference Include="..\..\modules\MouseUtils\MouseJump.Common\MouseJump.Common.csproj" />
|
<ProjectReference Include="..\..\modules\MouseUtils\MouseJump.Common\MouseJump.Common.csproj" />
|
||||||
<ProjectReference Include="..\Settings.UI.Library\Settings.UI.Library.csproj" />
|
<ProjectReference Include="..\Settings.UI.Library\Settings.UI.Library.csproj" />
|
||||||
|
<ProjectReference Include="..\Settings.UI.Controls\Settings.UI.Controls.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- XamlIndexBuilder now outputs directly to Assets\Settings -->
|
<!-- XamlIndexBuilder now outputs directly to Assets\Settings -->
|
||||||
|
|||||||
@@ -41,16 +41,14 @@ namespace Microsoft.PowerToys.Settings.UI
|
|||||||
IsUserAdmin,
|
IsUserAdmin,
|
||||||
ShowOobeWindow,
|
ShowOobeWindow,
|
||||||
ShowScoobeWindow,
|
ShowScoobeWindow,
|
||||||
ShowFlyout,
|
|
||||||
ContainsSettingsWindow,
|
ContainsSettingsWindow,
|
||||||
ContainsFlyoutPosition,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private const int RequiredArgumentsSetSettingQty = 4;
|
private const int RequiredArgumentsSetSettingQty = 4;
|
||||||
private const int RequiredArgumentsSetAdditionalSettingsQty = 4;
|
private const int RequiredArgumentsSetAdditionalSettingsQty = 4;
|
||||||
private const int RequiredArgumentsGetSettingQty = 3;
|
private const int RequiredArgumentsGetSettingQty = 3;
|
||||||
|
|
||||||
private const int RequiredArgumentsLaunchedFromRunnerQty = 12;
|
private const int RequiredArgumentsLaunchedFromRunnerQty = 10;
|
||||||
|
|
||||||
// Create an instance of the IPC wrapper.
|
// Create an instance of the IPC wrapper.
|
||||||
private static TwoWayPipeMessageIPCManaged ipcmanager;
|
private static TwoWayPipeMessageIPCManaged ipcmanager;
|
||||||
@@ -63,8 +61,6 @@ namespace Microsoft.PowerToys.Settings.UI
|
|||||||
|
|
||||||
public bool ShowOobe { get; set; }
|
public bool ShowOobe { get; set; }
|
||||||
|
|
||||||
public bool ShowFlyout { get; set; }
|
|
||||||
|
|
||||||
public bool ShowScoobe { get; set; }
|
public bool ShowScoobe { get; set; }
|
||||||
|
|
||||||
public Type StartupPage { get; set; } = typeof(Views.DashboardPage);
|
public Type StartupPage { get; set; } = typeof(Views.DashboardPage);
|
||||||
@@ -194,9 +190,7 @@ namespace Microsoft.PowerToys.Settings.UI
|
|||||||
IsUserAnAdmin = cmdArgs[(int)Arguments.IsUserAdmin] == "true";
|
IsUserAnAdmin = cmdArgs[(int)Arguments.IsUserAdmin] == "true";
|
||||||
ShowOobe = cmdArgs[(int)Arguments.ShowOobeWindow] == "true";
|
ShowOobe = cmdArgs[(int)Arguments.ShowOobeWindow] == "true";
|
||||||
ShowScoobe = cmdArgs[(int)Arguments.ShowScoobeWindow] == "true";
|
ShowScoobe = cmdArgs[(int)Arguments.ShowScoobeWindow] == "true";
|
||||||
ShowFlyout = cmdArgs[(int)Arguments.ShowFlyout] == "true";
|
|
||||||
bool containsSettingsWindow = cmdArgs[(int)Arguments.ContainsSettingsWindow] == "true";
|
bool containsSettingsWindow = cmdArgs[(int)Arguments.ContainsSettingsWindow] == "true";
|
||||||
bool containsFlyoutPosition = cmdArgs[(int)Arguments.ContainsFlyoutPosition] == "true";
|
|
||||||
|
|
||||||
// To keep track of variable arguments
|
// To keep track of variable arguments
|
||||||
int currentArgumentIndex = RequiredArgumentsLaunchedFromRunnerQty;
|
int currentArgumentIndex = RequiredArgumentsLaunchedFromRunnerQty;
|
||||||
@@ -209,15 +203,6 @@ namespace Microsoft.PowerToys.Settings.UI
|
|||||||
currentArgumentIndex++;
|
currentArgumentIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
int flyout_x = 0;
|
|
||||||
int flyout_y = 0;
|
|
||||||
if (containsFlyoutPosition)
|
|
||||||
{
|
|
||||||
// get the flyout position arguments
|
|
||||||
_ = int.TryParse(cmdArgs[currentArgumentIndex++], out flyout_x);
|
|
||||||
_ = int.TryParse(cmdArgs[currentArgumentIndex++], out flyout_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
RunnerHelper.WaitForPowerToysRunner(PowerToysPID, () =>
|
RunnerHelper.WaitForPowerToysRunner(PowerToysPID, () =>
|
||||||
{
|
{
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
@@ -238,7 +223,7 @@ namespace Microsoft.PowerToys.Settings.UI
|
|||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!ShowOobe && !ShowScoobe && !ShowFlyout)
|
if (!ShowOobe && !ShowScoobe)
|
||||||
{
|
{
|
||||||
settingsWindow = new MainWindow();
|
settingsWindow = new MainWindow();
|
||||||
settingsWindow.Activate();
|
settingsWindow.Activate();
|
||||||
@@ -278,16 +263,6 @@ namespace Microsoft.PowerToys.Settings.UI
|
|||||||
WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(WindowNative.GetWindowHandle(settingsWindow));
|
WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(WindowNative.GetWindowHandle(settingsWindow));
|
||||||
SetOobeWindow(scoobeWindow);
|
SetOobeWindow(scoobeWindow);
|
||||||
}
|
}
|
||||||
else if (ShowFlyout)
|
|
||||||
{
|
|
||||||
POINT? p = null;
|
|
||||||
if (containsFlyoutPosition)
|
|
||||||
{
|
|
||||||
p = new POINT(flyout_x, flyout_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
ShellPage.OpenFlyoutCallback(p);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,7 +339,6 @@ namespace Microsoft.PowerToys.Settings.UI
|
|||||||
|
|
||||||
private static MainWindow settingsWindow;
|
private static MainWindow settingsWindow;
|
||||||
private static OobeWindow oobeWindow;
|
private static OobeWindow oobeWindow;
|
||||||
private static FlyoutWindow flyoutWindow;
|
|
||||||
|
|
||||||
public static void ClearSettingsWindow()
|
public static void ClearSettingsWindow()
|
||||||
{
|
{
|
||||||
@@ -381,31 +355,16 @@ namespace Microsoft.PowerToys.Settings.UI
|
|||||||
return oobeWindow;
|
return oobeWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FlyoutWindow GetFlyoutWindow()
|
|
||||||
{
|
|
||||||
return flyoutWindow;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetOobeWindow(OobeWindow window)
|
public static void SetOobeWindow(OobeWindow window)
|
||||||
{
|
{
|
||||||
oobeWindow = window;
|
oobeWindow = window;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetFlyoutWindow(FlyoutWindow window)
|
|
||||||
{
|
|
||||||
flyoutWindow = window;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void ClearOobeWindow()
|
public static void ClearOobeWindow()
|
||||||
{
|
{
|
||||||
oobeWindow = null;
|
oobeWindow = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ClearFlyoutWindow()
|
|
||||||
{
|
|
||||||
flyoutWindow = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Type GetPage(string settingWindow)
|
public static Type GetPage(string settingWindow)
|
||||||
{
|
{
|
||||||
switch (settingWindow)
|
switch (settingWindow)
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ namespace Microsoft.PowerToys.Settings.UI.SettingsXAML.Controls.Dashboard
|
|||||||
settingsCard.DataContext is ModuleHotkeyData moduleData)
|
settingsCard.DataContext is ModuleHotkeyData moduleData)
|
||||||
{
|
{
|
||||||
var moduleType = moduleData.ModuleType;
|
var moduleType = moduleData.ModuleType;
|
||||||
NavigationService.Navigate(ModuleHelper.GetModulePageType(moduleType));
|
NavigationService.Navigate(ModuleGpoHelper.GetModulePageType(moduleType));
|
||||||
this.Close();
|
this.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,103 +0,0 @@
|
|||||||
<!-- Copyright (c) Microsoft Corporation and Contributors. -->
|
|
||||||
<!-- Licensed under the MIT License. -->
|
|
||||||
|
|
||||||
<Page
|
|
||||||
x:Class="Microsoft.PowerToys.Settings.UI.Flyout.AppsListPage"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:viewModels="using:Microsoft.PowerToys.Settings.UI.ViewModels"
|
|
||||||
mc:Ignorable="d">
|
|
||||||
<Grid Background="{ThemeResource LayerOnAcrylicFillColorDefaultBrush}">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Grid Padding="24,32,24,0">
|
|
||||||
<TextBlock
|
|
||||||
x:Uid="AllAppsTxt"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Style="{StaticResource BodyStrongTextBlockStyle}" />
|
|
||||||
<Button
|
|
||||||
x:Uid="BackBtn"
|
|
||||||
Padding="8,4,8,4"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Click="BackButton_Click">
|
|
||||||
<Button.Content>
|
|
||||||
<StackPanel
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Orientation="Horizontal"
|
|
||||||
Spacing="12">
|
|
||||||
<FontIcon
|
|
||||||
Margin="0,2,0,0"
|
|
||||||
FontSize="12"
|
|
||||||
Glyph="" />
|
|
||||||
<TextBlock x:Uid="BackLabel" Style="{StaticResource CaptionTextBlockStyle}" />
|
|
||||||
</StackPanel>
|
|
||||||
</Button.Content>
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
<ListView
|
|
||||||
Grid.Row="1"
|
|
||||||
Margin="0,16,0,0"
|
|
||||||
ItemsSource="{x:Bind ViewModel.FlyoutMenuItems}"
|
|
||||||
SelectionMode="None">
|
|
||||||
<ListView.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<StackPanel Padding="0,0,0,16" Orientation="Vertical" />
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</ListView.ItemsPanel>
|
|
||||||
|
|
||||||
<ListView.ItemTemplate>
|
|
||||||
<DataTemplate x:DataType="viewModels:FlyoutMenuItem">
|
|
||||||
<Grid Height="40" Padding="24,0,24,0">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<!--<ViewBox VerticalAlignment="Center">-->
|
|
||||||
<Image
|
|
||||||
Width="20"
|
|
||||||
Margin="0,0,16,0"
|
|
||||||
VerticalAlignment="Center">
|
|
||||||
<Image.Source>
|
|
||||||
<BitmapImage UriSource="{x:Bind Icon, Mode=OneWay}" />
|
|
||||||
</Image.Source>
|
|
||||||
</Image>
|
|
||||||
<!--</ViewBox>-->
|
|
||||||
<TextBlock
|
|
||||||
Grid.Column="1"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{x:Bind Label, Mode=OneWay}"
|
|
||||||
TextTrimming="CharacterEllipsis" />
|
|
||||||
<FontIcon
|
|
||||||
Grid.Column="2"
|
|
||||||
Width="20"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
FontSize="16"
|
|
||||||
Glyph=""
|
|
||||||
Visibility="{x:Bind IsLocked, Converter={StaticResource ReverseBoolToVisibilityConverter}, ConverterParameter=True, Mode=OneWay}">
|
|
||||||
<ToolTipService.ToolTip>
|
|
||||||
<TextBlock x:Uid="GPO_SettingIsManaged_ToolTip" TextWrapping="WrapWholeWords" />
|
|
||||||
</ToolTipService.ToolTip>
|
|
||||||
</FontIcon>
|
|
||||||
<ToggleSwitch
|
|
||||||
Grid.Column="3"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
AutomationProperties.Name="{x:Bind Label, Mode=OneWay}"
|
|
||||||
IsEnabled="{x:Bind IsLocked, Converter={StaticResource BoolNegationConverter}, ConverterParameter=True, Mode=OneWay}"
|
|
||||||
IsOn="{x:Bind IsEnabled, Mode=TwoWay}"
|
|
||||||
OffContent=""
|
|
||||||
OnContent=""
|
|
||||||
Style="{StaticResource RightAlignedCompactToggleSwitchStyle}" />
|
|
||||||
</Grid>
|
|
||||||
</DataTemplate>
|
|
||||||
</ListView.ItemTemplate>
|
|
||||||
</ListView>
|
|
||||||
</Grid>
|
|
||||||
</Page>
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
// Copyright (c) Microsoft Corporation
|
|
||||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
|
||||||
// See the LICENSE file in the project root for more information.
|
|
||||||
using System;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
using global::Windows.System;
|
|
||||||
using Microsoft.PowerToys.Settings.UI.Library;
|
|
||||||
using Microsoft.PowerToys.Settings.UI.ViewModels;
|
|
||||||
using Microsoft.PowerToys.Settings.UI.Views;
|
|
||||||
using Microsoft.UI.Xaml;
|
|
||||||
using Microsoft.UI.Xaml.Controls;
|
|
||||||
using Microsoft.UI.Xaml.Media.Animation;
|
|
||||||
using PowerToys.Interop;
|
|
||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI.Flyout
|
|
||||||
{
|
|
||||||
public sealed partial class AppsListPage : Page
|
|
||||||
{
|
|
||||||
private AllAppsViewModel ViewModel { get; set; }
|
|
||||||
|
|
||||||
public AppsListPage()
|
|
||||||
{
|
|
||||||
this.InitializeComponent();
|
|
||||||
|
|
||||||
var settingsUtils = SettingsUtils.Default;
|
|
||||||
ViewModel = new AllAppsViewModel(SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), Views.ShellPage.SendDefaultIPCMessage);
|
|
||||||
DataContext = ViewModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BackButton_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
Frame.Navigate(typeof(LaunchPage), null, new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromLeft });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,197 +0,0 @@
|
|||||||
// Copyright (c) Microsoft Corporation
|
|
||||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
|
||||||
// See the LICENSE file in the project root for more information.
|
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
using global::Windows.System;
|
|
||||||
using ManagedCommon;
|
|
||||||
using Microsoft.PowerToys.Settings.UI.Controls;
|
|
||||||
using Microsoft.PowerToys.Settings.UI.Library;
|
|
||||||
using Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events;
|
|
||||||
using Microsoft.PowerToys.Settings.UI.ViewModels;
|
|
||||||
using Microsoft.PowerToys.Settings.UI.Views;
|
|
||||||
using Microsoft.PowerToys.Telemetry;
|
|
||||||
using Microsoft.UI.Xaml;
|
|
||||||
using Microsoft.UI.Xaml.Controls;
|
|
||||||
using Microsoft.UI.Xaml.Media.Animation;
|
|
||||||
using PowerToys.Interop;
|
|
||||||
using WinUIEx;
|
|
||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI.Flyout
|
|
||||||
{
|
|
||||||
public sealed partial class LaunchPage : Page
|
|
||||||
{
|
|
||||||
private LauncherViewModel ViewModel { get; set; }
|
|
||||||
|
|
||||||
public LaunchPage()
|
|
||||||
{
|
|
||||||
this.InitializeComponent();
|
|
||||||
var settingsUtils = SettingsUtils.Default;
|
|
||||||
ViewModel = new LauncherViewModel(SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), Views.ShellPage.SendDefaultIPCMessage);
|
|
||||||
DataContext = ViewModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ModuleButton_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
FlyoutMenuButton selectedModuleBtn = sender as FlyoutMenuButton;
|
|
||||||
bool moduleRun = true;
|
|
||||||
|
|
||||||
// Closing manually the flyout to workaround focus gain problems
|
|
||||||
App.GetFlyoutWindow()?.Hide();
|
|
||||||
|
|
||||||
switch ((ModuleType)selectedModuleBtn.Tag)
|
|
||||||
{
|
|
||||||
case ModuleType.ColorPicker: // Launch ColorPicker
|
|
||||||
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowColorPickerSharedEvent()))
|
|
||||||
{
|
|
||||||
eventHandle.Set();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case ModuleType.EnvironmentVariables: // Launch Environment Variables
|
|
||||||
{
|
|
||||||
bool launchAdmin = SettingsRepository<EnvironmentVariablesSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.LaunchAdministrator;
|
|
||||||
string eventName = !App.IsElevated && launchAdmin
|
|
||||||
? Constants.ShowEnvironmentVariablesAdminSharedEvent()
|
|
||||||
: Constants.ShowEnvironmentVariablesSharedEvent();
|
|
||||||
|
|
||||||
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName))
|
|
||||||
{
|
|
||||||
eventHandle.Set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ModuleType.FancyZones: // Launch FancyZones Editor
|
|
||||||
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.FZEToggleEvent()))
|
|
||||||
{
|
|
||||||
eventHandle.Set();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ModuleType.Hosts: // Launch Hosts
|
|
||||||
{
|
|
||||||
bool launchAdmin = SettingsRepository<HostsSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.LaunchAdministrator;
|
|
||||||
string eventName = !App.IsElevated && launchAdmin
|
|
||||||
? Constants.ShowHostsAdminSharedEvent()
|
|
||||||
: Constants.ShowHostsSharedEvent();
|
|
||||||
|
|
||||||
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName))
|
|
||||||
{
|
|
||||||
eventHandle.Set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ModuleType.RegistryPreview: // Launch Registry Preview
|
|
||||||
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.RegistryPreviewTriggerEvent()))
|
|
||||||
{
|
|
||||||
eventHandle.Set();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case ModuleType.MeasureTool: // Launch Screen Ruler
|
|
||||||
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.MeasureToolTriggerEvent()))
|
|
||||||
{
|
|
||||||
eventHandle.Set();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ModuleType.PowerLauncher: // Launch Run
|
|
||||||
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.PowerLauncherSharedEvent()))
|
|
||||||
{
|
|
||||||
eventHandle.Set();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ModuleType.PowerOCR: // Launch Text Extractor
|
|
||||||
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowPowerOCRSharedEvent()))
|
|
||||||
{
|
|
||||||
eventHandle.Set();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ModuleType.Workspaces: // Launch Workspaces Editor
|
|
||||||
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.WorkspacesLaunchEditorEvent()))
|
|
||||||
{
|
|
||||||
eventHandle.Set();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ModuleType.ShortcutGuide: // Launch Shortcut Guide
|
|
||||||
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShortcutGuideTriggerEvent()))
|
|
||||||
{
|
|
||||||
eventHandle.Set();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ModuleType.CmdPal: // Show CmdPal
|
|
||||||
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowCmdPalEvent()))
|
|
||||||
{
|
|
||||||
eventHandle.Set();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
moduleRun = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moduleRun)
|
|
||||||
{
|
|
||||||
PowerToysTelemetry.Log.WriteEvent(new TrayFlyoutModuleRunEvent() { ModuleName = ((ModuleType)selectedModuleBtn.Tag).ToString() });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SettingsBtn_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
App.OpenSettingsWindow(null, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void DocsBtn_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
await Launcher.LaunchUriAsync(new Uri("https://aka.ms/PowerToysOverview"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AllAppButton_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
Frame.Navigate(typeof(AppsListPage), null, new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromRight });
|
|
||||||
}
|
|
||||||
|
|
||||||
private void QuitButton_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
ViewModel.KillRunner();
|
|
||||||
this.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () =>
|
|
||||||
{
|
|
||||||
Application.Current.Exit();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void ReportBugBtn_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
ViewModel.StartBugReport();
|
|
||||||
|
|
||||||
// Closing manually the flyout since no window will steal the focus
|
|
||||||
App.GetFlyoutWindow()?.Hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateInfoBar_Tapped(object sender, Microsoft.UI.Xaml.Input.TappedRoutedEventArgs e)
|
|
||||||
{
|
|
||||||
// Hide the flyout before opening settings window
|
|
||||||
App.GetFlyoutWindow()?.Hide();
|
|
||||||
|
|
||||||
// Open Settings window directly to General page where update controls are located
|
|
||||||
App.OpenSettingsWindow(typeof(GeneralPage));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
// Copyright (c) Microsoft Corporation
|
|
||||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
|
||||||
// See the LICENSE file in the project root for more information.
|
|
||||||
using Microsoft.UI.Xaml;
|
|
||||||
using Microsoft.UI.Xaml.Controls;
|
|
||||||
using Microsoft.UI.Xaml.Media.Animation;
|
|
||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI.Flyout
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
|
||||||
/// </summary>
|
|
||||||
public sealed partial class ShellPage : Page
|
|
||||||
{
|
|
||||||
public ShellPage()
|
|
||||||
{
|
|
||||||
this.InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void SwitchToLaunchPage()
|
|
||||||
{
|
|
||||||
ContentFrame.Navigate(typeof(LaunchPage), null, new SuppressNavigationTransitionInfo());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Page_Loaded(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
SwitchToLaunchPage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
// Copyright (c) Microsoft Corporation
|
|
||||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
|
||||||
// See the LICENSE file in the project root for more information.
|
|
||||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
|
||||||
using Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events;
|
|
||||||
using Microsoft.PowerToys.Settings.UI.ViewModels.Flyout;
|
|
||||||
using Microsoft.PowerToys.Telemetry;
|
|
||||||
using Microsoft.UI;
|
|
||||||
using Microsoft.UI.Windowing;
|
|
||||||
using Windows.Graphics;
|
|
||||||
using WinUIEx;
|
|
||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// An empty window that can be used on its own or navigated to within a Frame.
|
|
||||||
/// </summary>
|
|
||||||
public sealed partial class FlyoutWindow : WindowEx
|
|
||||||
{
|
|
||||||
private const int WindowWidth = 386;
|
|
||||||
private const int WindowHeight = 486;
|
|
||||||
private const int WindowMargin = 12;
|
|
||||||
|
|
||||||
public FlyoutViewModel ViewModel { get; set; }
|
|
||||||
|
|
||||||
public POINT? FlyoutAppearPosition { get; set; }
|
|
||||||
|
|
||||||
public FlyoutWindow(POINT? initialPosition)
|
|
||||||
{
|
|
||||||
this.InitializeComponent();
|
|
||||||
|
|
||||||
// Remove the caption style from the window style. Windows App SDK 1.6 added it, which made the title bar and borders appear for the Flyout. This code removes it.
|
|
||||||
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
|
|
||||||
var windowStyle = NativeMethods.GetWindowLong(hwnd, NativeMethods.GWL_STYLE);
|
|
||||||
windowStyle &= ~NativeMethods.WS_CAPTION;
|
|
||||||
_ = NativeMethods.SetWindowLong(hwnd, NativeMethods.GWL_STYLE, windowStyle);
|
|
||||||
|
|
||||||
this.Activated += FlyoutWindow_Activated;
|
|
||||||
FlyoutAppearPosition = initialPosition;
|
|
||||||
ViewModel = new FlyoutViewModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FlyoutWindow_Activated(object sender, Microsoft.UI.Xaml.WindowActivatedEventArgs args)
|
|
||||||
{
|
|
||||||
PowerToysTelemetry.Log.WriteEvent(new TrayFlyoutActivatedEvent());
|
|
||||||
if (args.WindowActivationState == Microsoft.UI.Xaml.WindowActivationState.CodeActivated)
|
|
||||||
{
|
|
||||||
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
|
|
||||||
WindowId windowId = Win32Interop.GetWindowIdFromWindow(hwnd);
|
|
||||||
if (!FlyoutAppearPosition.HasValue)
|
|
||||||
{
|
|
||||||
DisplayArea displayArea = DisplayArea.GetFromWindowId(windowId, DisplayAreaFallback.Nearest);
|
|
||||||
double dpiScale = (float)this.GetDpiForWindow() / 96;
|
|
||||||
double x = displayArea.WorkArea.Width - (dpiScale * (WindowWidth + WindowMargin));
|
|
||||||
double y = displayArea.WorkArea.Height - (dpiScale * (WindowHeight + WindowMargin));
|
|
||||||
this.MoveAndResize(x, y, WindowWidth, WindowHeight);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DisplayArea displayArea = DisplayArea.GetFromPoint(new PointInt32(FlyoutAppearPosition.Value.X, FlyoutAppearPosition.Value.Y), DisplayAreaFallback.Nearest);
|
|
||||||
|
|
||||||
// Move the window to the correct screen as a little blob, so we can get the accurate dpi for the screen to calculate the best position to show it.
|
|
||||||
this.MoveAndResize(FlyoutAppearPosition.Value.X, FlyoutAppearPosition.Value.Y, 1, 1);
|
|
||||||
double dpiScale = (float)this.GetDpiForWindow() / 96;
|
|
||||||
|
|
||||||
// Position the window so that it's inside the display are closest to the point.
|
|
||||||
POINT newPosition = new POINT(FlyoutAppearPosition.Value.X - (int)(dpiScale * WindowWidth / 2), FlyoutAppearPosition.Value.Y - (int)(dpiScale * WindowHeight / 2));
|
|
||||||
if (newPosition.X < displayArea.WorkArea.X)
|
|
||||||
{
|
|
||||||
newPosition.X = displayArea.WorkArea.X;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newPosition.Y < displayArea.WorkArea.Y)
|
|
||||||
{
|
|
||||||
newPosition.Y = displayArea.WorkArea.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newPosition.X + (dpiScale * WindowWidth) > displayArea.WorkArea.X + displayArea.WorkArea.Width)
|
|
||||||
{
|
|
||||||
newPosition.X = (int)(displayArea.WorkArea.X + displayArea.WorkArea.Width - (dpiScale * WindowWidth));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newPosition.Y + (dpiScale * WindowHeight) > displayArea.WorkArea.Y + displayArea.WorkArea.Height)
|
|
||||||
{
|
|
||||||
newPosition.Y = (int)(displayArea.WorkArea.Y + displayArea.WorkArea.Height - (dpiScale * WindowHeight));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.MoveAndResize(newPosition.X, newPosition.Y, WindowWidth, WindowHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
FlyoutShellPage.SwitchToLaunchPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.WindowActivationState == Microsoft.UI.Xaml.WindowActivationState.Deactivated)
|
|
||||||
{
|
|
||||||
if (ViewModel.CanHide)
|
|
||||||
{
|
|
||||||
this.Hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,10 +3,12 @@
|
|||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using ManagedCommon;
|
using ManagedCommon;
|
||||||
using Microsoft.PowerLauncher.Telemetry;
|
using Microsoft.PowerLauncher.Telemetry;
|
||||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||||
using Microsoft.PowerToys.Settings.UI.Library;
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||||
using Microsoft.PowerToys.Settings.UI.Views;
|
using Microsoft.PowerToys.Settings.UI.Views;
|
||||||
using Microsoft.PowerToys.Telemetry;
|
using Microsoft.PowerToys.Telemetry;
|
||||||
using Microsoft.UI;
|
using Microsoft.UI;
|
||||||
@@ -89,11 +91,17 @@ namespace Microsoft.PowerToys.Settings.UI
|
|||||||
{
|
{
|
||||||
ModuleHelper.SetIsModuleEnabled(generalSettingsConfig, moduleType, isEnabled);
|
ModuleHelper.SetIsModuleEnabled(generalSettingsConfig, moduleType, isEnabled);
|
||||||
var outgoing = new OutGoingGeneralSettings(generalSettingsConfig);
|
var outgoing = new OutGoingGeneralSettings(generalSettingsConfig);
|
||||||
this.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () =>
|
|
||||||
|
// Save settings to file
|
||||||
|
SettingsUtils.Default.SaveSettings(generalSettingsConfig.ToJsonString());
|
||||||
|
|
||||||
|
// Send IPC message asynchronously to avoid blocking UI and potential recursive calls
|
||||||
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
ShellPage.SendDefaultIPCMessage(outgoing.ToString());
|
ShellPage.SendDefaultIPCMessage(outgoing.ToString());
|
||||||
ShellPage.ShellHandler?.SignalGeneralDataUpdate();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ShellPage.ShellHandler?.SignalGeneralDataUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
return needToUpdate;
|
return needToUpdate;
|
||||||
@@ -125,40 +133,6 @@ namespace Microsoft.PowerToys.Settings.UI
|
|||||||
App.GetOobeWindow().Activate();
|
App.GetOobeWindow().Activate();
|
||||||
});
|
});
|
||||||
|
|
||||||
// open flyout
|
|
||||||
ShellPage.SetOpenFlyoutCallback((POINT? p) =>
|
|
||||||
{
|
|
||||||
this.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () =>
|
|
||||||
{
|
|
||||||
if (App.GetFlyoutWindow() == null)
|
|
||||||
{
|
|
||||||
App.SetFlyoutWindow(new FlyoutWindow(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
FlyoutWindow flyout = App.GetFlyoutWindow();
|
|
||||||
flyout.FlyoutAppearPosition = p;
|
|
||||||
flyout.Activate();
|
|
||||||
|
|
||||||
// https://github.com/microsoft/microsoft-ui-xaml/issues/7595 - Activate doesn't bring window to the foreground
|
|
||||||
// Need to call SetForegroundWindow to actually gain focus.
|
|
||||||
WindowHelpers.BringToForeground(flyout.GetWindowHandle());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// disable flyout hiding
|
|
||||||
ShellPage.SetDisableFlyoutHidingCallback(() =>
|
|
||||||
{
|
|
||||||
this.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () =>
|
|
||||||
{
|
|
||||||
if (App.GetFlyoutWindow() == null)
|
|
||||||
{
|
|
||||||
App.SetFlyoutWindow(new FlyoutWindow(null));
|
|
||||||
}
|
|
||||||
|
|
||||||
App.GetFlyoutWindow().ViewModel.DisableHiding();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.InitializeComponent();
|
this.InitializeComponent();
|
||||||
SetAppTitleBar();
|
SetAppTitleBar();
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,5 @@
|
|||||||
<ResourceDictionary Source="ms-appx:///SettingsXAML/Controls/SettingsGroup/SettingsGroup.xaml" />
|
<ResourceDictionary Source="ms-appx:///SettingsXAML/Controls/SettingsGroup/SettingsGroup.xaml" />
|
||||||
<ResourceDictionary Source="ms-appx:///SettingsXAML/Controls/GPOInfoControl.xaml" />
|
<ResourceDictionary Source="ms-appx:///SettingsXAML/Controls/GPOInfoControl.xaml" />
|
||||||
<ResourceDictionary Source="ms-appx:///SettingsXAML/Controls/IsEnabledTextBlock.xaml" />
|
<ResourceDictionary Source="ms-appx:///SettingsXAML/Controls/IsEnabledTextBlock.xaml" />
|
||||||
<ResourceDictionary Source="ms-appx:///SettingsXAML/Controls/FlyoutMenuButton.xaml" />
|
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:Lib="using:Microsoft.PowerToys.Settings.UI.Library"
|
xmlns:Lib="using:Microsoft.PowerToys.Settings.UI.Library"
|
||||||
|
xmlns:controlConverters="using:Microsoft.PowerToys.Settings.UI.Controls.Converters"
|
||||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||||
xmlns:converters="using:Microsoft.PowerToys.Settings.UI.Converters"
|
xmlns:converters="using:Microsoft.PowerToys.Settings.UI.Converters"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
@@ -19,7 +20,8 @@
|
|||||||
x:Key="ModuleItemTemplateSelector"
|
x:Key="ModuleItemTemplateSelector"
|
||||||
ActivationTemplate="{StaticResource ModuleItemActivationTemplate}"
|
ActivationTemplate="{StaticResource ModuleItemActivationTemplate}"
|
||||||
ShortcutTemplate="{StaticResource ModuleItemShortcutTemplate}" />
|
ShortcutTemplate="{StaticResource ModuleItemShortcutTemplate}" />
|
||||||
<converters:EnumToBooleanConverter x:Key="EnumToBooleanConverter" />
|
<controlConverters:EnumToBooleanConverter x:Key="EnumToBooleanConverter" />
|
||||||
|
<converters:EnumToModuleListSortOptionConverter x:Key="EnumToModuleListSortOptionConverter" />
|
||||||
<DataTemplate x:Key="ModuleItemShortcutTemplate" x:DataType="viewmodels:DashboardModuleShortcutItem">
|
<DataTemplate x:Key="ModuleItemShortcutTemplate" x:DataType="viewmodels:DashboardModuleShortcutItem">
|
||||||
<Grid MinHeight="36" ColumnSpacing="12">
|
<Grid MinHeight="36" ColumnSpacing="12">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@@ -159,64 +161,17 @@
|
|||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<controls:Card x:Uid="QuickAccessTitle" VerticalAlignment="Top">
|
<controls:Card x:Uid="QuickAccessTitle" VerticalAlignment="Top">
|
||||||
<Grid>
|
<Grid>
|
||||||
<ItemsControl
|
<controls:QuickAccessList
|
||||||
x:Name="QuickAccessItemsControl"
|
x:Name="QuickAccessItemsControl"
|
||||||
Margin="8,0,12,12"
|
Margin="8,0,12,12"
|
||||||
ItemsSource="{x:Bind ViewModel.ActionModules, Mode=OneWay}"
|
ItemsSource="{x:Bind ViewModel.QuickAccessItems, Mode=OneWay}"
|
||||||
Visibility="{x:Bind ViewModel.ActionModules.Count, Mode=OneWay, Converter={StaticResource DoubleToVisibilityConverter}}">
|
Visibility="{x:Bind ViewModel.QuickAccessItems.Count, Mode=OneWay, Converter={StaticResource DoubleToVisibilityConverter}}" />
|
||||||
|
|
||||||
<ItemsControl.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<tkcontrols:WrapPanel
|
|
||||||
Padding="12"
|
|
||||||
HorizontalSpacing="16"
|
|
||||||
VerticalSpacing="24" />
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</ItemsControl.ItemsPanel>
|
|
||||||
|
|
||||||
<ItemsControl.ItemTemplate>
|
|
||||||
<DataTemplate x:DataType="viewmodels:DashboardListItem">
|
|
||||||
<ItemsControl IsTabStop="False" ItemsSource="{x:Bind DashboardModuleItems, Mode=OneWay}">
|
|
||||||
<ItemsControl.ItemTemplate>
|
|
||||||
<DataTemplate x:DataType="viewmodels:DashboardModuleButtonItem">
|
|
||||||
<controls:FlyoutMenuButton AutomationProperties.Name="{x:Bind ButtonTitle}" Click="{x:Bind ButtonClickHandler}">
|
|
||||||
<controls:FlyoutMenuButton.Content>
|
|
||||||
<TextBlock
|
|
||||||
Style="{StaticResource CaptionTextBlockStyle}"
|
|
||||||
Text="{x:Bind ButtonTitle}"
|
|
||||||
TextAlignment="Center"
|
|
||||||
TextWrapping="Wrap" />
|
|
||||||
</controls:FlyoutMenuButton.Content>
|
|
||||||
<controls:FlyoutMenuButton.Icon>
|
|
||||||
<Image Width="24">
|
|
||||||
<Image.Source>
|
|
||||||
<BitmapImage UriSource="{x:Bind ButtonGlyph}" />
|
|
||||||
</Image.Source>
|
|
||||||
</Image>
|
|
||||||
</controls:FlyoutMenuButton.Icon>
|
|
||||||
<ToolTipService.ToolTip>
|
|
||||||
<ToolTip Content="{x:Bind ButtonDescription}" />
|
|
||||||
</ToolTipService.ToolTip>
|
|
||||||
</controls:FlyoutMenuButton>
|
|
||||||
</DataTemplate>
|
|
||||||
</ItemsControl.ItemTemplate>
|
|
||||||
|
|
||||||
<ItemsControl.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<StackPanel Spacing="0" />
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</ItemsControl.ItemsPanel>
|
|
||||||
</ItemsControl>
|
|
||||||
</DataTemplate>
|
|
||||||
</ItemsControl.ItemTemplate>
|
|
||||||
</ItemsControl>
|
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
x:Uid="NoActionsToShow"
|
x:Uid="NoActionsToShow"
|
||||||
Margin="12"
|
Margin="12"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||||
Visibility="{x:Bind ViewModel.ActionModules.Count, Mode=OneWay, Converter={StaticResource DoubleToInvertedVisibilityConverter}}" />
|
Visibility="{x:Bind ViewModel.QuickAccessItems.Count, Mode=OneWay, Converter={StaticResource DoubleToInvertedVisibilityConverter}}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</controls:Card>
|
</controls:Card>
|
||||||
<controls:Card
|
<controls:Card
|
||||||
@@ -270,7 +225,6 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</controls:Card>
|
</controls:Card>
|
||||||
<controls:Card
|
<controls:Card
|
||||||
x:Name="ModulesCard"
|
|
||||||
x:Uid="UtilitiesHeader"
|
x:Uid="UtilitiesHeader"
|
||||||
Grid.RowSpan="2"
|
Grid.RowSpan="2"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
@@ -304,68 +258,11 @@
|
|||||||
</Button.Flyout>
|
</Button.Flyout>
|
||||||
</Button>
|
</Button>
|
||||||
</controls:Card.TitleContent>
|
</controls:Card.TitleContent>
|
||||||
|
<controls:ModuleList
|
||||||
<ItemsRepeater
|
x:Name="ModulesCard"
|
||||||
x:Name="DashboardView"
|
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
ItemsSource="{x:Bind ViewModel.AllModules, Mode=OneWay}">
|
ItemsSource="{x:Bind ViewModel.AllModules, Mode=OneWay}"
|
||||||
<ItemsRepeater.Layout>
|
SortOption="{x:Bind ViewModel.DashboardSortOrder, Mode=TwoWay, Converter={StaticResource EnumToModuleListSortOptionConverter}}" />
|
||||||
<StackLayout Orientation="Vertical" Spacing="0" />
|
|
||||||
</ItemsRepeater.Layout>
|
|
||||||
<ItemsRepeater.ItemTemplate>
|
|
||||||
<DataTemplate x:DataType="viewmodels:DashboardListItem">
|
|
||||||
<tkcontrols:SettingsCard
|
|
||||||
MinHeight="0"
|
|
||||||
Padding="12,4,12,4"
|
|
||||||
AutomationProperties.Name="{x:Bind Label}"
|
|
||||||
Background="Transparent"
|
|
||||||
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
|
|
||||||
BorderThickness="0,1,0,0"
|
|
||||||
Click="DashboardListItemClick"
|
|
||||||
CornerRadius="0"
|
|
||||||
IsClickEnabled="True"
|
|
||||||
Tag="{x:Bind Tag}">
|
|
||||||
<tkcontrols:SettingsCard.Resources>
|
|
||||||
<x:Double x:Key="SettingsCardWrapThreshold">0</x:Double>
|
|
||||||
<x:Double x:Key="SettingsCardHeaderIconMaxSize">16</x:Double>
|
|
||||||
</tkcontrols:SettingsCard.Resources>
|
|
||||||
<tkcontrols:SettingsCard.Header>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBlock Text="{x:Bind Label}" />
|
|
||||||
<InfoBadge
|
|
||||||
Margin="4,0,0,0"
|
|
||||||
Style="{StaticResource NewInfoBadge}"
|
|
||||||
Visibility="{x:Bind IsNew, Converter={StaticResource BoolToVisibilityConverter}}" />
|
|
||||||
<FontIcon
|
|
||||||
Grid.Column="2"
|
|
||||||
Width="20"
|
|
||||||
Margin="0,0,-12,0"
|
|
||||||
FontSize="16"
|
|
||||||
Glyph=""
|
|
||||||
Visibility="{x:Bind IsLocked, Converter={StaticResource ReverseBoolToVisibilityConverter}, ConverterParameter=True}">
|
|
||||||
<ToolTipService.ToolTip>
|
|
||||||
<TextBlock x:Uid="GPO_SettingIsManaged_ToolTip" TextWrapping="WrapWholeWords" />
|
|
||||||
</ToolTipService.ToolTip>
|
|
||||||
</FontIcon>
|
|
||||||
</StackPanel>
|
|
||||||
</tkcontrols:SettingsCard.Header>
|
|
||||||
<tkcontrols:SettingsCard.HeaderIcon>
|
|
||||||
<ImageIcon>
|
|
||||||
<ImageIcon.Source>
|
|
||||||
<BitmapImage UriSource="{x:Bind Icon}" />
|
|
||||||
</ImageIcon.Source>
|
|
||||||
</ImageIcon>
|
|
||||||
</tkcontrols:SettingsCard.HeaderIcon>
|
|
||||||
<ToggleSwitch
|
|
||||||
AutomationProperties.Name="{x:Bind Label}"
|
|
||||||
IsEnabled="{x:Bind IsLocked, Converter={StaticResource BoolNegationConverter}, ConverterParameter=True, Mode=OneWay}"
|
|
||||||
IsOn="{x:Bind IsEnabled, Mode=TwoWay}"
|
|
||||||
OffContent=""
|
|
||||||
OnContent="" />
|
|
||||||
</tkcontrols:SettingsCard>
|
|
||||||
</DataTemplate>
|
|
||||||
</ItemsRepeater.ItemTemplate>
|
|
||||||
</ItemsRepeater>
|
|
||||||
</controls:Card>
|
</controls:Card>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -48,11 +48,6 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
|||||||
ViewModel.ModuleEnabledChangedOnSettingsPage();
|
ViewModel.ModuleEnabledChangedOnSettingsPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DashboardListItemClick(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
ViewModel.DashboardListItemClick(sender);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WhatsNewButton_Click(object sender, RoutedEventArgs e)
|
private void WhatsNewButton_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (App.GetOobeWindow() == null)
|
if (App.GetOobeWindow() == null)
|
||||||
|
|||||||
@@ -291,6 +291,28 @@
|
|||||||
Toggled="ShowSystemTrayIcon_Toggled" />
|
Toggled="ShowSystemTrayIcon_Toggled" />
|
||||||
</tkcontrols:SettingsCard>
|
</tkcontrols:SettingsCard>
|
||||||
</controls:GPOInfoControl>
|
</controls:GPOInfoControl>
|
||||||
|
|
||||||
|
<tkcontrols:SettingsExpander
|
||||||
|
Name="GeneralPageEnableQuickAccess"
|
||||||
|
x:Uid="GeneralPage_EnableQuickAccess"
|
||||||
|
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||||
|
IsExpanded="True">
|
||||||
|
<ToggleSwitch
|
||||||
|
x:Uid="ToggleSwitch"
|
||||||
|
AutomationProperties.Name="{Binding ElementName=GeneralPageEnableQuickAccess, Path=Header}"
|
||||||
|
IsOn="{x:Bind ViewModel.EnableQuickAccess, Mode=TwoWay}" />
|
||||||
|
<tkcontrols:SettingsExpander.Items>
|
||||||
|
<!-- HACK: For some weird reason, a ShortcutControl does not work correctly if it's the first or last item in the expander, so we add an invisible card. -->
|
||||||
|
<tkcontrols:SettingsCard Visibility="Collapsed" />
|
||||||
|
<tkcontrols:SettingsCard
|
||||||
|
Name="QuickAccessShortcut"
|
||||||
|
x:Uid="GeneralPage_QuickAccessShortcut"
|
||||||
|
IsEnabled="{x:Bind ViewModel.EnableQuickAccess, Mode=OneWay}">
|
||||||
|
<controls:ShortcutControl HotkeySettings="{x:Bind ViewModel.QuickAccessShortcut, Mode=TwoWay}" />
|
||||||
|
</tkcontrols:SettingsCard>
|
||||||
|
<tkcontrols:SettingsCard Visibility="Collapsed" />
|
||||||
|
</tkcontrols:SettingsExpander.Items>
|
||||||
|
</tkcontrols:SettingsExpander>
|
||||||
</controls:SettingsGroup>
|
</controls:SettingsGroup>
|
||||||
|
|
||||||
<controls:SettingsGroup x:Uid="General_SettingsBackupAndRestoreTitle" Visibility="Visible">
|
<controls:SettingsGroup x:Uid="General_SettingsBackupAndRestoreTitle" Visibility="Visible">
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ using System;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using ManagedCommon;
|
using ManagedCommon;
|
||||||
using Microsoft.PowerToys.Settings.UI.Flyout;
|
|
||||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||||
using Microsoft.PowerToys.Settings.UI.Library;
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
using Microsoft.PowerToys.Settings.UI.ViewModels;
|
using Microsoft.PowerToys.Settings.UI.ViewModels;
|
||||||
@@ -94,6 +93,8 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
|||||||
CheckBugReportStatus();
|
CheckBugReportStatus();
|
||||||
|
|
||||||
doRefreshBackupRestoreStatus(100);
|
doRefreshBackupRestoreStatus(100);
|
||||||
|
|
||||||
|
this.Loaded += (s, e) => ViewModel.OnPageLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OpenColorsSettings_Click(object sender, RoutedEventArgs e)
|
private void OpenColorsSettings_Click(object sender, RoutedEventArgs e)
|
||||||
@@ -176,8 +177,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
|||||||
private void BugReportToolClicked(object sender, RoutedEventArgs e)
|
private void BugReportToolClicked(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
// Start bug report
|
// Start bug report
|
||||||
var launchPage = new LaunchPage();
|
ShellPage.SendDefaultIPCMessage("{\"bugreport\": 0 }");
|
||||||
launchPage.ReportBugBtn_Click(sender, e);
|
|
||||||
|
|
||||||
ViewModel.IsBugReportRunning = true;
|
ViewModel.IsBugReportRunning = true;
|
||||||
|
|
||||||
|
|||||||
@@ -58,16 +58,6 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public delegate void WhatIsNewOpeningCallback();
|
public delegate void WhatIsNewOpeningCallback();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Declaration for opening flyout window callback function.
|
|
||||||
/// </summary>
|
|
||||||
public delegate void FlyoutOpeningCallback(POINT? point);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Declaration for disabling hide of flyout window callback function.
|
|
||||||
/// </summary>
|
|
||||||
public delegate void DisablingFlyoutHidingCallback();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a shell handler to be used to update contents of the shell dynamically from page within the frame.
|
/// Gets or sets a shell handler to be used to update contents of the shell dynamically from page within the frame.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -108,16 +98,6 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static WhatIsNewOpeningCallback OpenWhatIsNewWindowCallback { get; set; }
|
public static WhatIsNewOpeningCallback OpenWhatIsNewWindowCallback { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets callback function for opening flyout window
|
|
||||||
/// </summary>
|
|
||||||
public static FlyoutOpeningCallback OpenFlyoutCallback { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets callback function for disabling hide of flyout window
|
|
||||||
/// </summary>
|
|
||||||
public static DisablingFlyoutHidingCallback DisableFlyoutHidingCallback { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets view model.
|
/// Gets view model.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -261,24 +241,6 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
|||||||
OpenWhatIsNewWindowCallback = implementation;
|
OpenWhatIsNewWindowCallback = implementation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set flyout opening callback function
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="implementation">delegate function implementation.</param>
|
|
||||||
public static void SetOpenFlyoutCallback(FlyoutOpeningCallback implementation)
|
|
||||||
{
|
|
||||||
OpenFlyoutCallback = implementation;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set disable flyout hiding callback function
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="implementation">delegate function implementation.</param>
|
|
||||||
public static void SetDisableFlyoutHidingCallback(DisablingFlyoutHidingCallback implementation)
|
|
||||||
{
|
|
||||||
DisableFlyoutHidingCallback = implementation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetElevationStatus(bool isElevated)
|
public static void SetElevationStatus(bool isElevated)
|
||||||
{
|
{
|
||||||
IsElevated = isElevated;
|
IsElevated = isElevated;
|
||||||
@@ -399,25 +361,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
|||||||
IJsonValue whatToShowJson;
|
IJsonValue whatToShowJson;
|
||||||
if (json.TryGetValue("ShowYourself", out whatToShowJson))
|
if (json.TryGetValue("ShowYourself", out whatToShowJson))
|
||||||
{
|
{
|
||||||
if (whatToShowJson.ValueType == JsonValueType.String && whatToShowJson.GetString().Equals("flyout", StringComparison.Ordinal))
|
if (whatToShowJson.ValueType == JsonValueType.String)
|
||||||
{
|
|
||||||
POINT? p = null;
|
|
||||||
|
|
||||||
IJsonValue flyoutPointX;
|
|
||||||
IJsonValue flyoutPointY;
|
|
||||||
if (json.TryGetValue("x_position", out flyoutPointX) && json.TryGetValue("y_position", out flyoutPointY))
|
|
||||||
{
|
|
||||||
if (flyoutPointX.ValueType == JsonValueType.Number && flyoutPointY.ValueType == JsonValueType.Number)
|
|
||||||
{
|
|
||||||
int flyout_x = (int)flyoutPointX.GetNumber();
|
|
||||||
int flyout_y = (int)flyoutPointY.GetNumber();
|
|
||||||
p = new POINT(flyout_x, flyout_y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenFlyoutCallback(p);
|
|
||||||
}
|
|
||||||
else if (whatToShowJson.ValueType == JsonValueType.String)
|
|
||||||
{
|
{
|
||||||
OpenMainWindowCallback(App.GetPage(whatToShowJson.GetString()));
|
OpenMainWindowCallback(App.GetPage(whatToShowJson.GetString()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5820,6 +5820,15 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
|
|||||||
<value>A modern UI built with Fluent Design</value>
|
<value>A modern UI built with Fluent Design</value>
|
||||||
<comment>Fluent Design is a product name, do not loc</comment>
|
<comment>Fluent Design is a product name, do not loc</comment>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="GeneralPage_EnableQuickAccess.Header" xml:space="preserve">
|
||||||
|
<value>Quick Access flyout</value>
|
||||||
|
</data>
|
||||||
|
<data name="GeneralPage_EnableQuickAccess.Description" xml:space="preserve">
|
||||||
|
<value>Fast access to quick actions and module toggles</value>
|
||||||
|
</data>
|
||||||
|
<data name="GeneralPage_QuickAccessShortcut.Header" xml:space="preserve">
|
||||||
|
<value>Activation shortcut</value>
|
||||||
|
</data>
|
||||||
<data name="LightSwitch_ModeFollowNightLight.Content" xml:space="preserve">
|
<data name="LightSwitch_ModeFollowNightLight.Content" xml:space="preserve">
|
||||||
<value>Follow Night Light</value>
|
<value>Follow Night Light</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -5829,4 +5838,4 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
|
|||||||
<data name="LightSwitch_FollowNightLightCardMessage.Text" xml:space="preserve">
|
<data name="LightSwitch_FollowNightLightCardMessage.Text" xml:space="preserve">
|
||||||
<value>Following Night Light settings.</value>
|
<value>Following Night Light settings.</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -8,44 +8,39 @@ using System.ComponentModel;
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
using ManagedCommon;
|
using ManagedCommon;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Controls;
|
||||||
using Microsoft.UI;
|
using Microsoft.UI;
|
||||||
using Windows.UI;
|
using Windows.UI;
|
||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||||
{
|
{
|
||||||
public partial class DashboardListItem : INotifyPropertyChanged
|
public partial class DashboardListItem : ModuleListItem
|
||||||
{
|
{
|
||||||
private bool _visible;
|
private bool _visible;
|
||||||
private bool _isEnabled;
|
|
||||||
|
|
||||||
public string Label { get; set; }
|
|
||||||
|
|
||||||
public bool IsNew { get; set; }
|
|
||||||
|
|
||||||
public string Icon { get; set; }
|
|
||||||
|
|
||||||
public string ToolTip { get; set; }
|
public string ToolTip { get; set; }
|
||||||
|
|
||||||
public ModuleType Tag { get; set; }
|
public new ModuleType Tag
|
||||||
|
|
||||||
public bool IsLocked { get; set; }
|
|
||||||
|
|
||||||
public bool IsEnabled
|
|
||||||
{
|
{
|
||||||
get => _isEnabled;
|
get => (ModuleType)base.Tag!;
|
||||||
|
set => base.Tag = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action<DashboardListItem> EnabledChangedCallback { get; set; }
|
||||||
|
|
||||||
|
public override bool IsEnabled
|
||||||
|
{
|
||||||
|
get => base.IsEnabled;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (_isEnabled != value)
|
if (base.IsEnabled != value)
|
||||||
{
|
{
|
||||||
_isEnabled = value;
|
base.IsEnabled = value;
|
||||||
OnPropertyChanged();
|
|
||||||
EnabledChangedCallback?.Invoke(this);
|
EnabledChangedCallback?.Invoke(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Action<DashboardListItem> EnabledChangedCallback { get; set; }
|
|
||||||
|
|
||||||
public bool Visible
|
public bool Visible
|
||||||
{
|
{
|
||||||
get => _visible;
|
get => _visible;
|
||||||
@@ -59,13 +54,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
|
||||||
|
|
||||||
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
|
||||||
{
|
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableCollection<DashboardModuleItem> DashboardModuleItems { get; set; } = new ObservableCollection<DashboardModuleItem>();
|
public ObservableCollection<DashboardModuleItem> DashboardModuleItems { get; set; } = new ObservableCollection<DashboardModuleItem>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) Microsoft Corporation
|
// Copyright (c) Microsoft Corporation
|
||||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
@@ -12,6 +12,7 @@ using System.Windows.Threading;
|
|||||||
using CommunityToolkit.WinUI.Controls;
|
using CommunityToolkit.WinUI.Controls;
|
||||||
using global::PowerToys.GPOWrapper;
|
using global::PowerToys.GPOWrapper;
|
||||||
using ManagedCommon;
|
using ManagedCommon;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Controls;
|
||||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||||
using Microsoft.PowerToys.Settings.UI.Library;
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||||
@@ -40,11 +41,16 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
|
|
||||||
public ObservableCollection<DashboardListItem> ActionModules { get; set; } = new ObservableCollection<DashboardListItem>();
|
public ObservableCollection<DashboardListItem> ActionModules { get; set; } = new ObservableCollection<DashboardListItem>();
|
||||||
|
|
||||||
|
public ObservableCollection<QuickAccessItem> QuickAccessItems => _quickAccessViewModel.Items;
|
||||||
|
|
||||||
|
private readonly QuickAccessViewModel _quickAccessViewModel;
|
||||||
|
|
||||||
// Master list of module items that is sorted and projected into AllModules.
|
// Master list of module items that is sorted and projected into AllModules.
|
||||||
private List<DashboardListItem> _moduleItems = new List<DashboardListItem>();
|
private List<DashboardListItem> _moduleItems = new List<DashboardListItem>();
|
||||||
|
|
||||||
// Flag to prevent circular updates when a UI toggle triggers settings changes.
|
// Flag to prevent circular updates when a UI toggle triggers settings changes.
|
||||||
private bool _isUpdatingFromUI;
|
private bool _isUpdatingFromUI;
|
||||||
|
private bool _isUpdatingFromSettings;
|
||||||
|
|
||||||
private AllHotkeyConflictsData _allHotkeyConflictsData = new AllHotkeyConflictsData();
|
private AllHotkeyConflictsData _allHotkeyConflictsData = new AllHotkeyConflictsData();
|
||||||
|
|
||||||
@@ -79,6 +85,10 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
{
|
{
|
||||||
generalSettingsConfig.DashboardSortOrder = value;
|
generalSettingsConfig.DashboardSortOrder = value;
|
||||||
OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(generalSettingsConfig);
|
OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(generalSettingsConfig);
|
||||||
|
|
||||||
|
// Save settings to file
|
||||||
|
SettingsUtils.Default.SaveSettings(generalSettingsConfig.ToJsonString());
|
||||||
|
|
||||||
SendConfigMSG(outgoing.ToString());
|
SendConfigMSG(outgoing.ToString());
|
||||||
SortModuleList();
|
SortModuleList();
|
||||||
}
|
}
|
||||||
@@ -95,6 +105,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
_settingsRepository = settingsRepository;
|
_settingsRepository = settingsRepository;
|
||||||
generalSettingsConfig = settingsRepository.SettingsConfig;
|
generalSettingsConfig = settingsRepository.SettingsConfig;
|
||||||
generalSettingsConfig.AddEnabledModuleChangeNotification(ModuleEnabledChangedOnSettingsPage);
|
generalSettingsConfig.AddEnabledModuleChangeNotification(ModuleEnabledChangedOnSettingsPage);
|
||||||
|
_settingsRepository.SettingsChanged += OnSettingsChanged;
|
||||||
|
|
||||||
// Initialize dashboard sort order from settings
|
// Initialize dashboard sort order from settings
|
||||||
_dashboardSortOrder = generalSettingsConfig.DashboardSortOrder;
|
_dashboardSortOrder = generalSettingsConfig.DashboardSortOrder;
|
||||||
@@ -102,11 +113,27 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
// set the callback functions value to handle outgoing IPC message.
|
// set the callback functions value to handle outgoing IPC message.
|
||||||
SendConfigMSG = ipcMSGCallBackFunc;
|
SendConfigMSG = ipcMSGCallBackFunc;
|
||||||
|
|
||||||
|
_quickAccessViewModel = new QuickAccessViewModel(
|
||||||
|
_settingsRepository,
|
||||||
|
new Microsoft.PowerToys.Settings.UI.Controls.QuickAccessLauncher(App.IsElevated),
|
||||||
|
moduleType => Helpers.ModuleGpoHelper.GetModuleGpoConfiguration(moduleType) == global::PowerToys.GPOWrapper.GpoRuleConfigured.Disabled,
|
||||||
|
resourceLoader);
|
||||||
|
|
||||||
BuildModuleList();
|
BuildModuleList();
|
||||||
SortModuleList();
|
SortModuleList();
|
||||||
RefreshShortcutModules();
|
RefreshShortcutModules();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnSettingsChanged(GeneralSettings newSettings)
|
||||||
|
{
|
||||||
|
dispatcher.BeginInvoke(() =>
|
||||||
|
{
|
||||||
|
generalSettingsConfig = newSettings;
|
||||||
|
generalSettingsConfig.AddEnabledModuleChangeNotification(ModuleEnabledChangedOnSettingsPage);
|
||||||
|
ModuleEnabledChangedOnSettingsPage();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnConflictsUpdated(object sender, AllHotkeyConflictsEventArgs e)
|
protected override void OnConflictsUpdated(object sender, AllHotkeyConflictsEventArgs e)
|
||||||
{
|
{
|
||||||
dispatcher.BeginInvoke(() =>
|
dispatcher.BeginInvoke(() =>
|
||||||
@@ -146,7 +173,12 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
|
|
||||||
foreach (ModuleType moduleType in Enum.GetValues<ModuleType>())
|
foreach (ModuleType moduleType in Enum.GetValues<ModuleType>())
|
||||||
{
|
{
|
||||||
GpoRuleConfigured gpo = ModuleHelper.GetModuleGpoConfiguration(moduleType);
|
if (moduleType == ModuleType.GeneralSettings)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
GpoRuleConfigured gpo = ModuleGpoHelper.GetModuleGpoConfiguration(moduleType);
|
||||||
var newItem = new DashboardListItem()
|
var newItem = new DashboardListItem()
|
||||||
{
|
{
|
||||||
Tag = moduleType,
|
Tag = moduleType,
|
||||||
@@ -156,6 +188,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
Icon = ModuleHelper.GetModuleTypeFluentIconName(moduleType),
|
Icon = ModuleHelper.GetModuleTypeFluentIconName(moduleType),
|
||||||
IsNew = moduleType == ModuleType.CursorWrap,
|
IsNew = moduleType == ModuleType.CursorWrap,
|
||||||
DashboardModuleItems = GetModuleItems(moduleType),
|
DashboardModuleItems = GetModuleItems(moduleType),
|
||||||
|
ClickCommand = new RelayCommand<object>(DashboardListItemClick),
|
||||||
};
|
};
|
||||||
newItem.EnabledChangedCallback = EnabledChangedOnUI;
|
newItem.EnabledChangedCallback = EnabledChangedOnUI;
|
||||||
_moduleItems.Add(newItem);
|
_moduleItems.Add(newItem);
|
||||||
@@ -211,7 +244,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
{
|
{
|
||||||
foreach (var item in _moduleItems)
|
foreach (var item in _moduleItems)
|
||||||
{
|
{
|
||||||
GpoRuleConfigured gpo = ModuleHelper.GetModuleGpoConfiguration(item.Tag);
|
GpoRuleConfigured gpo = ModuleGpoHelper.GetModuleGpoConfiguration(item.Tag);
|
||||||
|
|
||||||
// GPO can force-enable (Enabled) or force-disable (Disabled) a module.
|
// GPO can force-enable (Enabled) or force-disable (Disabled) a module.
|
||||||
// If Enabled: module is on and the user cannot disable it.
|
// If Enabled: module is on and the user cannot disable it.
|
||||||
@@ -244,6 +277,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void EnabledChangedOnUI(DashboardListItem dashboardListItem)
|
private void EnabledChangedOnUI(DashboardListItem dashboardListItem)
|
||||||
{
|
{
|
||||||
|
if (_isUpdatingFromSettings)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_isUpdatingFromUI = true;
|
_isUpdatingFromUI = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -287,6 +325,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_isUpdatingFromSettings = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
RefreshModuleList();
|
RefreshModuleList();
|
||||||
@@ -301,6 +340,10 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
{
|
{
|
||||||
Logger.LogError($"Updating active/disabled modules list failed: {ex.Message}");
|
Logger.LogError($"Updating active/disabled modules list failed: {ex.Message}");
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_isUpdatingFromSettings = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -695,10 +738,21 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
|
|
||||||
internal void DashboardListItemClick(object sender)
|
internal void DashboardListItemClick(object sender)
|
||||||
{
|
{
|
||||||
if (sender is SettingsCard card && card.Tag is ModuleType moduleType)
|
if (sender is ModuleType moduleType)
|
||||||
{
|
{
|
||||||
NavigationService.Navigate(ModuleHelper.GetModulePageType(moduleType));
|
NavigationService.Navigate(ModuleGpoHelper.GetModulePageType(moduleType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
base.Dispose();
|
||||||
|
if (_settingsRepository != null)
|
||||||
|
{
|
||||||
|
_settingsRepository.SettingsChanged -= OnSettingsChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
// Copyright (c) Microsoft Corporation
|
|
||||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
|
||||||
// See the LICENSE file in the project root for more information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
|
|
||||||
using global::PowerToys.GPOWrapper;
|
|
||||||
using ManagedCommon;
|
|
||||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
|
||||||
using Microsoft.PowerToys.Settings.UI.Library;
|
|
||||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
|
||||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
|
||||||
using Microsoft.Windows.ApplicationModel.Resources;
|
|
||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|
||||||
{
|
|
||||||
public partial class AllAppsViewModel : Observable
|
|
||||||
{
|
|
||||||
public ObservableCollection<FlyoutMenuItem> FlyoutMenuItems { get; set; }
|
|
||||||
|
|
||||||
private ISettingsRepository<GeneralSettings> _settingsRepository;
|
|
||||||
private GeneralSettings generalSettingsConfig;
|
|
||||||
private ResourceLoader resourceLoader;
|
|
||||||
|
|
||||||
private Func<string, int> SendConfigMSG { get; }
|
|
||||||
|
|
||||||
public AllAppsViewModel(ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc)
|
|
||||||
{
|
|
||||||
_settingsRepository = settingsRepository;
|
|
||||||
generalSettingsConfig = settingsRepository.SettingsConfig;
|
|
||||||
generalSettingsConfig.AddEnabledModuleChangeNotification(ModuleEnabledChangedOnSettingsPage);
|
|
||||||
|
|
||||||
resourceLoader = Helpers.ResourceLoaderInstance.ResourceLoader;
|
|
||||||
FlyoutMenuItems = new ObservableCollection<FlyoutMenuItem>();
|
|
||||||
|
|
||||||
foreach (ModuleType moduleType in Enum.GetValues<ModuleType>())
|
|
||||||
{
|
|
||||||
AddFlyoutMenuItem(moduleType);
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the callback functions value to handle outgoing IPC message.
|
|
||||||
SendConfigMSG = ipcMSGCallBackFunc;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddFlyoutMenuItem(ModuleType moduleType)
|
|
||||||
{
|
|
||||||
GpoRuleConfigured gpo = ModuleHelper.GetModuleGpoConfiguration(moduleType);
|
|
||||||
FlyoutMenuItems.Add(new FlyoutMenuItem()
|
|
||||||
{
|
|
||||||
Label = resourceLoader.GetString(ModuleHelper.GetModuleLabelResourceName(moduleType)),
|
|
||||||
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, moduleType)),
|
|
||||||
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
|
|
||||||
Tag = moduleType,
|
|
||||||
Icon = ModuleHelper.GetModuleTypeFluentIconName(moduleType),
|
|
||||||
EnabledChangedCallback = EnabledChangedOnUI,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EnabledChangedOnUI(FlyoutMenuItem flyoutMenuItem)
|
|
||||||
{
|
|
||||||
if (Views.ShellPage.UpdateGeneralSettingsCallback(flyoutMenuItem.Tag, flyoutMenuItem.IsEnabled))
|
|
||||||
{
|
|
||||||
Views.ShellPage.DisableFlyoutHidingCallback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ModuleEnabledChangedOnSettingsPage()
|
|
||||||
{
|
|
||||||
generalSettingsConfig = _settingsRepository.SettingsConfig;
|
|
||||||
generalSettingsConfig.AddEnabledModuleChangeNotification(ModuleEnabledChangedOnSettingsPage);
|
|
||||||
foreach (FlyoutMenuItem item in FlyoutMenuItems)
|
|
||||||
{
|
|
||||||
item.IsEnabled = ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, item.Tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
// Copyright (c) Microsoft Corporation
|
|
||||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
|
||||||
// See the LICENSE file in the project root for more information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
using ManagedCommon;
|
|
||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|
||||||
{
|
|
||||||
public partial class FlyoutMenuItem : INotifyPropertyChanged
|
|
||||||
{
|
|
||||||
private bool _visible;
|
|
||||||
private bool _isEnabled;
|
|
||||||
|
|
||||||
public string Label { get; set; }
|
|
||||||
|
|
||||||
public string Icon { get; set; }
|
|
||||||
|
|
||||||
public string ToolTip { get; set; }
|
|
||||||
|
|
||||||
public ModuleType Tag { get; set; }
|
|
||||||
|
|
||||||
public bool IsLocked { get; set; }
|
|
||||||
|
|
||||||
public bool IsEnabled
|
|
||||||
{
|
|
||||||
get => _isEnabled;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_isEnabled != value)
|
|
||||||
{
|
|
||||||
_isEnabled = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
EnabledChangedCallback?.Invoke(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Action<FlyoutMenuItem> EnabledChangedCallback { get; set; }
|
|
||||||
|
|
||||||
public bool Visible
|
|
||||||
{
|
|
||||||
get => _visible;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_visible != value)
|
|
||||||
{
|
|
||||||
_visible = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
|
||||||
|
|
||||||
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
|
||||||
{
|
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
// Copyright (c) Microsoft Corporation
|
|
||||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
|
||||||
// See the LICENSE file in the project root for more information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Timers;
|
|
||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI.ViewModels.Flyout
|
|
||||||
{
|
|
||||||
public partial class FlyoutViewModel : IDisposable
|
|
||||||
{
|
|
||||||
private Timer _hideTimer;
|
|
||||||
private bool _disposed;
|
|
||||||
|
|
||||||
public bool CanHide { get; set; }
|
|
||||||
|
|
||||||
public FlyoutViewModel()
|
|
||||||
{
|
|
||||||
CanHide = true;
|
|
||||||
_hideTimer = new Timer();
|
|
||||||
_hideTimer.Elapsed += HideTimer_Elapsed;
|
|
||||||
_hideTimer.Interval = 1000;
|
|
||||||
_hideTimer.Enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HideTimer_Elapsed(object sender, ElapsedEventArgs e)
|
|
||||||
{
|
|
||||||
CanHide = true;
|
|
||||||
_hideTimer.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void DisableHiding()
|
|
||||||
{
|
|
||||||
CanHide = false;
|
|
||||||
_hideTimer.Stop();
|
|
||||||
_hideTimer.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (!_disposed)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
_hideTimer?.Dispose();
|
|
||||||
_disposed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -31,7 +31,7 @@ using Windows.System.Profile;
|
|||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||||
{
|
{
|
||||||
public partial class GeneralViewModel : Observable
|
public partial class GeneralViewModel : PageViewModelBase
|
||||||
{
|
{
|
||||||
public enum InstallScope
|
public enum InstallScope
|
||||||
{
|
{
|
||||||
@@ -39,6 +39,16 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
PerUser,
|
PerUser,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override string ModuleName => "GeneralSettings";
|
||||||
|
|
||||||
|
public override Dictionary<string, HotkeySettings[]> GetAllHotkeySettings()
|
||||||
|
{
|
||||||
|
return new Dictionary<string, HotkeySettings[]>
|
||||||
|
{
|
||||||
|
{ ModuleName, new HotkeySettings[] { QuickAccessShortcut } },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private GeneralSettings GeneralSettingsConfig { get; set; }
|
private GeneralSettings GeneralSettingsConfig { get; set; }
|
||||||
|
|
||||||
private UpdatingSettings UpdatingSettingsConfig { get; set; }
|
private UpdatingSettings UpdatingSettingsConfig { get; set; }
|
||||||
@@ -75,6 +85,9 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
|
|
||||||
private string _settingsConfigFileFolder = string.Empty;
|
private string _settingsConfigFileFolder = string.Empty;
|
||||||
|
|
||||||
|
private ISettingsRepository<GeneralSettings> _settingsRepository;
|
||||||
|
private Microsoft.UI.Dispatching.DispatcherQueue _dispatcherQueue;
|
||||||
|
|
||||||
private IFileSystemWatcher _fileWatcher;
|
private IFileSystemWatcher _fileWatcher;
|
||||||
|
|
||||||
private Func<Task<string>> PickSingleFolderDialog { get; }
|
private Func<Task<string>> PickSingleFolderDialog { get; }
|
||||||
@@ -100,6 +113,10 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
// To obtain the general settings configuration of PowerToys if it exists, else to create a new file and return the default configurations.
|
// To obtain the general settings configuration of PowerToys if it exists, else to create a new file and return the default configurations.
|
||||||
ArgumentNullException.ThrowIfNull(settingsRepository);
|
ArgumentNullException.ThrowIfNull(settingsRepository);
|
||||||
|
|
||||||
|
_settingsRepository = settingsRepository;
|
||||||
|
_settingsRepository.SettingsChanged += OnSettingsChanged;
|
||||||
|
_dispatcherQueue = GetDispatcherQueue();
|
||||||
|
|
||||||
GeneralSettingsConfig = settingsRepository.SettingsConfig;
|
GeneralSettingsConfig = settingsRepository.SettingsConfig;
|
||||||
UpdatingSettingsConfig = UpdatingSettings.LoadSettings();
|
UpdatingSettingsConfig = UpdatingSettings.LoadSettings();
|
||||||
if (UpdatingSettingsConfig == null)
|
if (UpdatingSettingsConfig == null)
|
||||||
@@ -155,6 +172,12 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
_isElevated = isElevated;
|
_isElevated = isElevated;
|
||||||
_runElevated = GeneralSettingsConfig.RunElevated;
|
_runElevated = GeneralSettingsConfig.RunElevated;
|
||||||
_enableWarningsElevatedApps = GeneralSettingsConfig.EnableWarningsElevatedApps;
|
_enableWarningsElevatedApps = GeneralSettingsConfig.EnableWarningsElevatedApps;
|
||||||
|
_enableQuickAccess = GeneralSettingsConfig.EnableQuickAccess;
|
||||||
|
_quickAccessShortcut = GeneralSettingsConfig.QuickAccessShortcut;
|
||||||
|
if (_quickAccessShortcut != null)
|
||||||
|
{
|
||||||
|
_quickAccessShortcut.PropertyChanged += QuickAccessShortcut_PropertyChanged;
|
||||||
|
}
|
||||||
|
|
||||||
RunningAsUserDefaultText = runAsUserText;
|
RunningAsUserDefaultText = runAsUserText;
|
||||||
RunningAsAdminDefaultText = runAsAdminText;
|
RunningAsAdminDefaultText = runAsAdminText;
|
||||||
@@ -236,6 +259,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
private bool _runElevated;
|
private bool _runElevated;
|
||||||
private bool _isAdmin;
|
private bool _isAdmin;
|
||||||
private bool _enableWarningsElevatedApps;
|
private bool _enableWarningsElevatedApps;
|
||||||
|
private bool _enableQuickAccess;
|
||||||
|
private HotkeySettings _quickAccessShortcut;
|
||||||
private int _themeIndex;
|
private int _themeIndex;
|
||||||
|
|
||||||
private bool _showNewUpdatesToastNotification;
|
private bool _showNewUpdatesToastNotification;
|
||||||
@@ -480,6 +505,57 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool EnableQuickAccess
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _enableQuickAccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_enableQuickAccess != value)
|
||||||
|
{
|
||||||
|
_enableQuickAccess = value;
|
||||||
|
GeneralSettingsConfig.EnableQuickAccess = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public HotkeySettings QuickAccessShortcut
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _quickAccessShortcut;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_quickAccessShortcut != value)
|
||||||
|
{
|
||||||
|
if (_quickAccessShortcut != null)
|
||||||
|
{
|
||||||
|
_quickAccessShortcut.PropertyChanged -= QuickAccessShortcut_PropertyChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
_quickAccessShortcut = value;
|
||||||
|
if (_quickAccessShortcut != null)
|
||||||
|
{
|
||||||
|
_quickAccessShortcut.PropertyChanged += QuickAccessShortcut_PropertyChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
GeneralSettingsConfig.QuickAccessShortcut = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void QuickAccessShortcut_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
NotifyPropertyChanged(nameof(QuickAccessShortcut));
|
||||||
|
}
|
||||||
|
|
||||||
public bool SomeUpdateSettingsAreGpoManaged
|
public bool SomeUpdateSettingsAreGpoManaged
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -1434,5 +1510,35 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
Process.Start("explorer.exe", etwDirPath);
|
Process.Start("explorer.exe", etwDirPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnSettingsChanged(GeneralSettings newSettings)
|
||||||
|
{
|
||||||
|
_dispatcherQueue?.TryEnqueue(() =>
|
||||||
|
{
|
||||||
|
GeneralSettingsConfig = newSettings;
|
||||||
|
|
||||||
|
if (_enableQuickAccess != newSettings.EnableQuickAccess)
|
||||||
|
{
|
||||||
|
_enableQuickAccess = newSettings.EnableQuickAccess;
|
||||||
|
OnPropertyChanged(nameof(EnableQuickAccess));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
base.Dispose();
|
||||||
|
if (_settingsRepository != null)
|
||||||
|
{
|
||||||
|
_settingsRepository.SettingsChanged -= OnSettingsChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual Microsoft.UI.Dispatching.DispatcherQueue GetDispatcherQueue()
|
||||||
|
{
|
||||||
|
return Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ using System.Windows.Threading;
|
|||||||
using ManagedCommon;
|
using ManagedCommon;
|
||||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||||
using Microsoft.PowerToys.Settings.UI.Library;
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||||
using Microsoft.PowerToys.Settings.UI.Library.HotkeyConflicts;
|
using Microsoft.PowerToys.Settings.UI.Library.HotkeyConflicts;
|
||||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||||
using Microsoft.PowerToys.Settings.UI.SerializationContext;
|
using Microsoft.PowerToys.Settings.UI.SerializationContext;
|
||||||
@@ -253,6 +254,9 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
|
|
||||||
// Send IPC notification using the same format as other ViewModels
|
// Send IPC notification using the same format as other ViewModels
|
||||||
SendConfigMSG(settingsConfig, moduleName);
|
SendConfigMSG(settingsConfig, moduleName);
|
||||||
|
|
||||||
|
// Request updated conflicts after changing a hotkey
|
||||||
|
GlobalHotkeyConflictManager.Instance?.RequestAllConflicts();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -273,11 +277,22 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
? JsonSerializer.Serialize(settingsConfig, jsonTypeInfo)
|
? JsonSerializer.Serialize(settingsConfig, jsonTypeInfo)
|
||||||
: JsonSerializer.Serialize(settingsConfig);
|
: JsonSerializer.Serialize(settingsConfig);
|
||||||
|
|
||||||
var ipcMessage = string.Format(
|
string ipcMessage;
|
||||||
CultureInfo.InvariantCulture,
|
if (string.Equals(moduleName, "GeneralSettings", StringComparison.OrdinalIgnoreCase))
|
||||||
"{{ \"powertoys\": {{ \"{0}\": {1} }} }}",
|
{
|
||||||
moduleName,
|
ipcMessage = string.Format(
|
||||||
serializedSettings);
|
CultureInfo.InvariantCulture,
|
||||||
|
"{{ \"general\": {0} }}",
|
||||||
|
serializedSettings);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ipcMessage = string.Format(
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
|
"{{ \"powertoys\": {{ \"{0}\": {1} }} }}",
|
||||||
|
moduleName,
|
||||||
|
serializedSettings);
|
||||||
|
}
|
||||||
|
|
||||||
var result = _ipcMSGCallBackFunc(ipcMessage);
|
var result = _ipcMSGCallBackFunc(ipcMessage);
|
||||||
System.Diagnostics.Debug.WriteLine($"Sent IPC notification for {moduleName}, result: {result}");
|
System.Diagnostics.Debug.WriteLine($"Sent IPC notification for {moduleName}, result: {result}");
|
||||||
|
|||||||
Reference in New Issue
Block a user