mirror of
https://github.com/microsoft/PowerToys
synced 2025-08-31 14:35:18 +00:00
[DevDocs] More content and restructure (#40165)
## Summary of the Pull Request Accumulated information from internal transition about the modules development, and reworked it to be added in dev docs. Also the dev docs intself was restructured to be more organized. New pages was verified by transition team. ## PR Checklist - [x] **Dev docs:** Added/updated --------- Co-authored-by: Zhaopeng Wang (from Dev Box) <zhaopengwang@microsoft.com> Co-authored-by: Hao Liu <liuhao3418@gmail.com> Co-authored-by: Peiyao Zhao <105847726+zhaopy536@users.noreply.github.com> Co-authored-by: Mengyuan <162882040+chenmy77@users.noreply.github.com> Co-authored-by: zhaopeng wang <33367956+wang563681252@users.noreply.github.com> Co-authored-by: Jaylyn Barbee <51131738+Jaylyn-Barbee@users.noreply.github.com>
This commit is contained in:
78
doc/devdocs/core/architecture.md
Normal file
78
doc/devdocs/core/architecture.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# PowerToys Architecture
|
||||
|
||||
## Module Interface Overview
|
||||
|
||||
Each PowerToys utility is defined by a module interface (DLL) that provides a standardized way for the PowerToys Runner to interact with it. The module interface defines:
|
||||
|
||||
- Structure for hotkeys
|
||||
- Name and key for the utility
|
||||
- Configuration management
|
||||
- Enable/disable functionality
|
||||
- Telemetry settings
|
||||
- Group Policy Object (GPO) configuration
|
||||
|
||||
### Types of Modules
|
||||
|
||||
1. **Simple Modules** (like Mouse Pointer Crosshairs, Find My Mouse)
|
||||
- Entirely contained in the module interface
|
||||
- No external application
|
||||
- Example: Mouse Pointer Crosshairs implements the module interface directly
|
||||
|
||||
2. **External Application Launchers** (like Color Picker)
|
||||
- Start a separate application (e.g., WPF application in C#)
|
||||
- Handle events when hotkeys are pressed
|
||||
- Communication via named pipes or other IPC mechanisms
|
||||
|
||||
3. **Context Handler Modules** (like Power Rename)
|
||||
- Shell extensions for File Explorer
|
||||
- Add right-click context menu entries
|
||||
- Windows 11 context menu integration through MSIX
|
||||
|
||||
4. **Registry-based Modules** (like Power Preview)
|
||||
- Register preview handlers and thumbnail providers
|
||||
- Modify registry keys during enable/disable operations
|
||||
|
||||
## Common Dependencies and Libraries
|
||||
|
||||
- SPD logs for C++ (centralized logging system)
|
||||
- CPP Win RT (used by most utilities)
|
||||
- Common utilities in `common` folder for reuse across modules
|
||||
- Interop library for C++/C# communication (converted to C++ Win RT)
|
||||
- Common.UI library has WPF and WinForms dependencies
|
||||
|
||||
## Resource Management
|
||||
|
||||
- For C++ applications and module interfaces:
|
||||
- Resource files (.resx) need to be converted to .rc
|
||||
- Use conversion tools before building
|
||||
|
||||
- Different resource approaches:
|
||||
- WPF applications use .resx files
|
||||
- WinUI 3 apps use .resw files
|
||||
|
||||
- PRI file naming requirements:
|
||||
- Need to override default names to avoid conflicts during flattening
|
||||
|
||||
## Implementation details
|
||||
|
||||
### [`Runner`](runner.md)
|
||||
|
||||
The PowerToys Runner contains the project for the PowerToys.exe executable.
|
||||
It's responsible for:
|
||||
|
||||
- Loading the individual PowerToys modules.
|
||||
- Passing registered events to the PowerToys.
|
||||
- Showing a system tray icon to manage the PowerToys.
|
||||
- Bridging between the PowerToys modules and the Settings editor.
|
||||
|
||||
### [`Interface`](../modules/interface.md)
|
||||
|
||||
The definition of the interface used by the [`runner`](/src/runner) to manage the PowerToys. All PowerToys must implement this interface.
|
||||
|
||||
### [`Common`](../common.md)
|
||||
|
||||
The common lib, as the name suggests, contains code shared by multiple PowerToys components and modules, e.g. [json parsing](/src/common/utils/json.h) and [IPC primitives](/src/common/interop/two_way_pipe_message_ipc.h).
|
||||
|
||||
### [`Settings`](settings/readme.md)
|
||||
|
||||
Settings v2 is our current settings implementation. Please head over to the dev docs that describe the current settings system.
|
135
doc/devdocs/core/installer.md
Normal file
135
doc/devdocs/core/installer.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# PowerToys Installer
|
||||
|
||||
## Installer Architecture (WiX 3)
|
||||
|
||||
- Uses a bootstrapper to check dependencies and close PowerToys
|
||||
- MSI defined in product.wxs
|
||||
- Custom actions in C++ for special operations:
|
||||
- Getting install folder
|
||||
- User impersonation
|
||||
- PowerShell module path retrieval
|
||||
- GPO checking
|
||||
- Process termination
|
||||
|
||||
### Installer Components
|
||||
|
||||
- Separate builds for machine-wide and user-scope installation
|
||||
- Supports x64 and ARM64
|
||||
- Custom actions DLL must be signed separately before installer build
|
||||
- WXS files generated during build process for file components
|
||||
- Localization handling for resource DLLs
|
||||
- Firewall exceptions for certain modules
|
||||
|
||||
### MSI Installer Build Process
|
||||
|
||||
- First builds `PowerToysSetupCustomActions` DLL and signs it
|
||||
- Then builds the installer without cleaning, to reuse the signed DLL
|
||||
- Uses PowerShell scripts to modify .wxs files before build
|
||||
- Restores original .wxs files after build completes
|
||||
- Scripts (`applyBuildInfo.ps1` and `generateFileList.ps1`) dynamically update files list for installer
|
||||
- Helps manage all self-contained dependencies (.NET, WinAppSDK DLLs, etc.)
|
||||
- Avoids manual maintenance of file lists
|
||||
|
||||
### Special Build Processes
|
||||
|
||||
- .NET applications need publishing for correct WebView2 DLL inclusion
|
||||
- WXS files backed up and regenerated during build
|
||||
- Monaco UI components (JavaScript/HTML) generated during build
|
||||
- Localization files downloaded from server during CI release builds
|
||||
|
||||
## Per-User vs Per-Machine Installation
|
||||
|
||||
- Functionality is identical
|
||||
- Differences:
|
||||
- Per-User:
|
||||
- Installed to `%LOCALAPPDATA%\PowerToys`
|
||||
- Registry entries in HKCU
|
||||
- Different users can have different installations/settings
|
||||
- Per-Machine:
|
||||
- Installed to `Program Files\PowerToys`
|
||||
- Registry entries in HKLM
|
||||
- Single installation shared by all users
|
||||
- Default is now Per-User installation
|
||||
- Guards prevent installing both types simultaneously
|
||||
|
||||
## MSIX Usage in PowerToys
|
||||
|
||||
- Context menu handlers for Windows 11 use sparse MSIX packages
|
||||
- Previous attempts to create full MSIX installers were abandoned
|
||||
- Command Palette will use MSIX when merged into PowerToys
|
||||
- The main PowerToys application still uses MSI for installation
|
||||
|
||||
### MSIX Packaging and Extensions
|
||||
|
||||
- MSIX packages for extensions (like context menus) are included in the PowerToys installer
|
||||
- The MSIX files are built as part of the PowerToys build process
|
||||
- MSIX files are saved directly into the root folder with base application files
|
||||
- The installer includes MSIX files but doesn't install them automatically
|
||||
- Packages are registered when a module is enabled
|
||||
- Code in `package.h` checks if a package is registered and verifies the version
|
||||
- Packages will be installed if a version mismatch is detected
|
||||
- When uninstalling PowerToys, the system checks for installed packages with matching display names and attempts to uninstall them
|
||||
|
||||
## GPO Files (Group Policy Objects)
|
||||
|
||||
- GPO files for x64 and ARM64 are identical
|
||||
- Only one set is needed
|
||||
- GPO files in pipeline are copies of files in source
|
||||
|
||||
## Installer Debugging
|
||||
|
||||
- Can only build installer in Release mode
|
||||
- Typically debug using logs and message boxes
|
||||
- Logs located in:
|
||||
- `%LOCALAPPDATA%\Temp\PowerToys_bootstrapper_*.log` - MSI tool logs
|
||||
- `%LOCALAPPDATA%\Temp\PowerToys_*.log` - Custom installer logs
|
||||
- Logs in Bug Reports are useful for troubleshooting installation issues
|
||||
|
||||
### Building PowerToys Locally
|
||||
|
||||
#### Prerequisites for building the MSI installer
|
||||
|
||||
1. Install the [WiX Toolset Visual Studio 2022 Extension](https://marketplace.visualstudio.com/items?itemName=WixToolset.WixToolsetVisualStudio2022Extension).
|
||||
1. Install the [WiX Toolset build tools](https://github.com/wixtoolset/wix3/releases/tag/wix3141rtm). (installer [direct link](https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314.exe))
|
||||
1. Download [WiX binaries](https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314-binaries.zip) and extract `wix.targets` to `C:\Program Files (x86)\WiX Toolset v3.14`.
|
||||
|
||||
#### Building prerequisite projects
|
||||
|
||||
##### From the command line
|
||||
|
||||
1. From the start menu, open a `Developer Command Prompt for VS 2022`
|
||||
1. Ensure `nuget.exe` is in your `%path%`
|
||||
1. In the repo root, run these commands:
|
||||
|
||||
```
|
||||
nuget restore .\tools\BugReportTool\BugReportTool.sln
|
||||
msbuild -p:Platform=x64 -p:Configuration=Release .\tools\BugReportTool\BugReportTool.sln
|
||||
|
||||
nuget restore .\tools\StylesReportTool\StylesReportTool.sln
|
||||
msbuild -p:Platform=x64 -p:Configuration=Release .\tools\StylesReportTool\StylesReportTool.sln
|
||||
```
|
||||
|
||||
##### From Visual Studio
|
||||
|
||||
If you prefer, you can alternatively build prerequisite projects for the installer using the Visual Studio UI.
|
||||
|
||||
1. Open `tools\BugReportTool\BugReportTool.sln`
|
||||
1. In Visual Studio, in the `Solutions Configuration` drop-down menu select `Release`
|
||||
1. From the `Build` menu, choose `Build Solution`.
|
||||
1. Open `tools\StylesReportTool\StylesReportTool.sln`
|
||||
1. In Visual Studio, in the `Solutions Configuration` drop-down menu select `Release`
|
||||
1. From the `Build` menu, choose `Build Solution`.
|
||||
|
||||
#### Locally compiling the installer
|
||||
|
||||
1. Open `installer\PowerToysSetup.sln`
|
||||
1. In Visual Studio, in the `Solutions Configuration` drop-down menu select `Release`
|
||||
1. From the `Build` menu choose `Build Solution`.
|
||||
|
||||
The resulting `PowerToysSetup.msi` installer will be available in the `installer\PowerToysSetup\x64\Release\` folder.
|
||||
|
||||
### Supported arguments for the .EXE Bootstrapper installer
|
||||
|
||||
Head over to the wiki to see the [full list of supported installer arguments][installerArgWiki].
|
||||
|
||||
[installerArgWiki]: https://github.com/microsoft/PowerToys/wiki/Installer-arguments
|
197
doc/devdocs/core/runner.md
Normal file
197
doc/devdocs/core/runner.md
Normal file
@@ -0,0 +1,197 @@
|
||||
# PowerToys Runner
|
||||
|
||||
The PowerToys Runner is the main executable (`PowerToys.exe`) that loads and manages all PowerToys modules.
|
||||
|
||||
## Runner Architecture
|
||||
|
||||
The Runner is responsible for:
|
||||
- Managing the tray icon
|
||||
- Loading and managing module interfaces
|
||||
- Handling enabling/disabling modules
|
||||
- Processing global hotkeys
|
||||
- Managing updates and settings
|
||||
|
||||
### Key Components
|
||||
|
||||
- Main CPP file manages the tray icon and modules
|
||||
- Creates a list of modules with DLL paths
|
||||
- Special handling for WinUI 3 apps (separated in different folder)
|
||||
- DLLs flattening for consistent versions
|
||||
- Runs as part of the Windows message loop
|
||||
- Creates a window handle with a specific class name
|
||||
- Registers itself as the window handler for components requiring a window handler
|
||||
|
||||
### Process Flow
|
||||
|
||||
1. Initialize logger
|
||||
2. Create single instance application mutex
|
||||
3. Initialize common utility code
|
||||
4. Parse command line arguments
|
||||
5. Start the tray icon
|
||||
6. Initialize low-level keyboard hooks
|
||||
7. Load module interfaces from DLLs
|
||||
8. Start enabled modules
|
||||
9. Enter Windows message loop
|
||||
10. On exit, stop modules and clean up resources
|
||||
|
||||
## System Tray Icon Implementation
|
||||
|
||||
The system tray icon is one of the first components that starts when calling the `render_main` function:
|
||||
|
||||
- Defined in `tray_icon.h` and `tray_icon.cpp`
|
||||
- Creates a popup window and registers as window handler via `start_tray_icon()`
|
||||
- Processes window messages through `tray_icon_window_proc()`
|
||||
- Uses `WM_COMMAND` and tray icon notifications for handling menu options
|
||||
- Handles left mouse clicks (distinguishes between single and double clicks)
|
||||
- Monitors taskbar creation to re-register the icon if needed
|
||||
- Uses `shell_notify_icon` to register with the system tray
|
||||
|
||||
### Tray Icon Initialization and Message Processing
|
||||
|
||||
- `start_tray_icon()` initializes the tray icon by:
|
||||
- Creating a window with the specified class name
|
||||
- Setting up the notification icon data structure (NOTIFYICONDATA)
|
||||
- Registering for taskbar recreate messages
|
||||
- Adding the icon to the system tray
|
||||
|
||||
- `tray_icon_window_proc()` processes window messages, including:
|
||||
- Handling `wm_icon_notify` messages from tray icon interactions
|
||||
- Distinguishing between left-click, double-click, and right-click actions
|
||||
- Showing context menus or opening Settings windows based on interaction type
|
||||
|
||||
### Communication with Settings UI
|
||||
|
||||
When the tray icon is clicked or a menu option is selected, the Runner communicates with the Settings UI:
|
||||
|
||||
- For quick access flyout (left-click):
|
||||
```cpp
|
||||
current_settings_ipc->send(L"{\"ShowYourself\":\"flyout\"}");
|
||||
```
|
||||
|
||||
- For the main dashboard (menu option or double-click):
|
||||
```cpp
|
||||
current_settings_ipc->send(L"{\"ShowYourself\":\"Dashboard\"}");
|
||||
```
|
||||
|
||||
### IPC Communication Mechanism
|
||||
|
||||
- The Runner and Settings UI communicate through Windows Named Pipes
|
||||
- A two-way pipe (TwoWayPipeMessageIPC) is established between processes
|
||||
- JSON messages are sent through this pipe to control UI behavior
|
||||
- The Settings UI initializes the pipe connection on startup:
|
||||
```csharp
|
||||
ipcmanager = new TwoWayPipeMessageIPCManaged(cmdArgs[(int)Arguments.SettingsPipeName],
|
||||
cmdArgs[(int)Arguments.PTPipeName],
|
||||
(string message) => {
|
||||
if (IPCMessageReceivedCallback != null && message.Length > 0) {
|
||||
IPCMessageReceivedCallback(message);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Settings UI Message Processing
|
||||
|
||||
The Settings UI processes incoming IPC messages through a callback chain:
|
||||
|
||||
1. Messages from the Runner are received through the IPC callback
|
||||
2. Messages are parsed as JSON objects
|
||||
3. Registered handlers in `ShellPage.ShellHandler.IPCResponseHandleList` process the messages
|
||||
4. The `ReceiveMessage` method in `ShellPage` interprets commands:
|
||||
- For flyout display: `"ShowYourself": "flyout"`
|
||||
- For main window: `"ShowYourself": "Dashboard"` or other page names
|
||||
|
||||
When showing the flyout, the tray icon can also send position coordinates to place the flyout near the tray icon:
|
||||
```json
|
||||
{
|
||||
"ShowYourself": "flyout",
|
||||
"x_position": 1234,
|
||||
"y_position": 567
|
||||
}
|
||||
```
|
||||
|
||||
The flyout window is then activated and brought to the foreground using native Windows APIs to ensure visibility.
|
||||
|
||||
### Tray Icon Menu
|
||||
- Menus are defined in `.RC` files (Resource files)
|
||||
- `base.h` defines IDs
|
||||
- `resources.resx` contains localized strings
|
||||
- The tray icon window proc handles showing the popup menu
|
||||
|
||||
## Centralized Keyboard Hook
|
||||
|
||||
- Located in "centralized_keyboard_hook.cpp"
|
||||
- Handles hotkeys for multiple modules to prevent performance issues
|
||||
- Contains optimizations to exit early when possible:
|
||||
- Ignores keystrokes generated by PowerToys itself
|
||||
- Ignores when no keys are actually pressed
|
||||
- Uses metadata to avoid re-processing modified inputs
|
||||
- Performance consideration: handler must run very fast as it's called on every keystroke
|
||||
|
||||
## Module Loading Process
|
||||
|
||||
1. Scan module directory for DLLs
|
||||
2. Create the module interface object for each module
|
||||
3. Load settings for each module
|
||||
4. Initialize each module
|
||||
5. Check GPO policies to determine which modules can start
|
||||
6. Start enabled modules that aren't disabled by policy
|
||||
|
||||
## Finding and Messaging the Tray Icon
|
||||
|
||||
The tray icon class is used when sending messages to the runner. For example, to close the runner:
|
||||
|
||||
```cpp
|
||||
// Find the window with the PowerToys tray icon class and send it a close message
|
||||
WM_CLOSE
|
||||
```
|
||||
|
||||
## Key Files and Their Purposes
|
||||
|
||||
#### [`main.cpp`](/src/runner/main.cpp)
|
||||
Contains the executable starting point, initialization code and the list of known PowerToys. All singletons are also initialized here at the start. Loads all the powertoys by scanning the `./modules` folder and `enable()`s those marked as enabled in `%LOCALAPPDATA%\Microsoft\PowerToys\settings.json` config. Then it runs [a message loop](https://learn.microsoft.com/windows/win32/winmsg/using-messages-and-message-queues) for the tray UI. Note that this message loop also [handles lowlevel_keyboard_hook events](https://github.com/microsoft/PowerToys/blob/1760af50c8803588cb575167baae0439af38a9c1/src/runner/lowlevel_keyboard_event.cpp#L24).
|
||||
|
||||
#### [`powertoy_module.h`](/src/runner/powertoy_module.h) and [`powertoy_module.cpp`](/src/runner/powertoy_module.cpp)
|
||||
Contains code for initializing and managing the PowerToy modules. `PowertoyModule` is a RAII-style holder for the `PowertoyModuleIface` pointer, which we got by [invoking module DLL's `powertoy_create` function](https://github.com/microsoft/PowerToys/blob/1760af50c8803588cb575167baae0439af38a9c1/src/runner/powertoy_module.cpp#L13-L24).
|
||||
|
||||
#### [`tray_icon.cpp`](/src/runner/tray_icon.cpp)
|
||||
Contains code for managing the PowerToys tray icon and its menu commands. Note that `dispatch_run_on_main_ui_thread` is used to
|
||||
transfer received json message from the [Settings window](/doc/devdocs/settings.md) to the main thread, since we're communicating with it from [a dedicated thread](https://github.com/microsoft/PowerToys/blob/7357e40d3f54de51176efe54fda6d57028837b8c/src/runner/settings_window.cpp#L267-L271).
|
||||
|
||||
#### [`settings_window.cpp`](/src/runner/settings_window.cpp)
|
||||
Contains code for starting the PowerToys settings window and communicating with it. Settings window is a separate process, so we're using [Windows pipes](https://learn.microsoft.com/windows/win32/ipc/pipes) as a transport for json messages.
|
||||
|
||||
#### [`general_settings.cpp`](/src/runner/general_settings.cpp)
|
||||
Contains code for loading, saving and applying the general settings.
|
||||
|
||||
#### [`auto_start_helper.cpp`](/src/runner/auto_start_helper.cpp)
|
||||
Contains helper code for registering and unregistering PowerToys to run when the user logs in.
|
||||
|
||||
#### [`unhandled_exception_handler.cpp`](/src/runner/unhandled_exception_handler.cpp)
|
||||
Contains helper code to get stack traces in builds. Can be used by adding a call to `init_global_error_handlers` in [`WinMain`](./main.cpp).
|
||||
|
||||
#### [`trace.cpp`](/src/runner/trace.cpp)
|
||||
Contains code for telemetry.
|
||||
|
||||
#### [`svgs`](/src/runner/svgs/)
|
||||
Contains the SVG assets used by the PowerToys modules.
|
||||
|
||||
#### [`bug_report.cpp`](/src/runner/bug_report.cpp)
|
||||
Contains logic to start bug report tool.
|
||||
|
||||
#### [`centralized_hotkeys.cpp`](/src/runner/centralized_hotkeys.cpp)
|
||||
Contains hot key logic registration and un-registration.
|
||||
|
||||
#### [`centralized_kb_hook.cpp`](/src/runner/centralized_kb_hook.cpp)
|
||||
Contains logic to handle PowerToys' keyboard shortcut functionality.
|
||||
|
||||
#### [`restart_elevated.cpp`](/src/runner/restart_elevated.cpp)
|
||||
Contains logic for restarting the current process with different elevation levels.
|
||||
|
||||
#### [`RestartManagement.cpp`](/src/runner/RestartManagement.cpp)
|
||||
Contains code for restarting a process.
|
||||
|
||||
#### [`settings_telemetry.cpp`](/src/runner/settings_telemetry.cpp)
|
||||
Contains logic that periodically triggers module-specific setting's telemetry delivery and manages timing and error handling for the process.
|
||||
|
||||
#### [`UpdateUtils.cpp`](/src/runner/UpdateUtils.cpp)
|
||||
Contains code to handle the automatic update checking, notification, and installation process for PowerToys.
|
15
doc/devdocs/core/settings/communication-with-modules.md
Normal file
15
doc/devdocs/core/settings/communication-with-modules.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Communication with modules
|
||||
|
||||
## Through runner
|
||||
- The settings process communicates changes in the UI to most modules using the runner through delegates.
|
||||
- More details on this are mentioned in [`runner-ipc.md`](runner-ipc.md).
|
||||
|
||||
## PT Run
|
||||
- Any changes to the UI are saved by the settings process in the `settings.json` file located within the `/Local/Microsoft/PowerToys/Launcher/` folder.
|
||||
- PT Run watches for any changes within this file and updates its general settings or propagates the information to the plugins, depending on the type of information.
|
||||
Eg: The maximum number of results drop down updates the maximum number of rows in the results list which updates the general settings of PT Run whereas the drive detection checkbox details are dispatched to the indexer plugin.
|
||||
|
||||
## Keyboard Manager
|
||||
- The Settings process and keyboard manager share access to a common `default.json` file which contains information about the remapped keys and shortcuts.
|
||||
- To ensure that there is no contention while both processes try to access the common file, there is a named file mutex.
|
||||
- The settings process expects the keyboard manager process to create the `default.json` file if it does not exist. It does not create the file in case it is not present.
|
12
doc/devdocs/core/settings/compatibility-legacy-settings.md
Normal file
12
doc/devdocs/core/settings/compatibility-legacy-settings.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# Compatibility with legacy settings and runner
|
||||
The following must be kept in mind regarding compatibility with settings v1 and runner.
|
||||
|
||||
### 1. Folder Naming structure
|
||||
- Each of the modules has a folder within the `Local/Microsoft/PowerToys` directory which contains the module configurations within the `settings.json` file. The name of this folder must be the same across settingsv1 and settingsv2.
|
||||
- The name of the settings folder for each powertoy is the same as the `ModuleName`. It is set within each of the viewModel files. This name must not be changed to ensure that the user configurations for each of the powertoys rolls over on update.
|
||||
|
||||
### 2. Communication with runner
|
||||
- The status of each of the modules is communicated with the runner in the form of a json object. The names of all the powerToys is set in the [`EnableModules.cs`](src/settings-ui/Settings.UI.Library/EnabledModules.cs) file. The `JsonPropertyName` must not be changed to ensure that the information is dispatched properly to all the modules by the runner.
|
||||
|
||||
### ImageResizer anomaly
|
||||
All the powertoys have the same folder name as well as JsonPropertyName to communicate information with the runner. However that is not the case with ImageResizer. The folder name is `ImageResizer` whereas the JsonPropertyName is `Image Resizer`(Note the additional space). This should not be changed to ensure backward compatibility as well as proper functioning of the module.
|
98
doc/devdocs/core/settings/dsc-configure.md
Normal file
98
doc/devdocs/core/settings/dsc-configure.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# What is it
|
||||
|
||||
We would like to enable our users to use [`winget configure`](https://learn.microsoft.com/en-us/windows/package-manager/winget/configure) command to install PowerToys and configure its settings with a [Winget configuration file](https://learn.microsoft.com/en-us/windows/package-manager/configuration/create). For example:
|
||||
|
||||
```yaml
|
||||
properties:
|
||||
resources:
|
||||
- resource: Microsoft.WinGet.DSC/WinGetPackage
|
||||
directives:
|
||||
description: Install PowerToys
|
||||
allowPrerelease: true
|
||||
settings:
|
||||
id: PowerToys (Preview)
|
||||
source: winget
|
||||
|
||||
- resource: PowerToysConfigure
|
||||
directives:
|
||||
description: Configure PowerToys
|
||||
settings:
|
||||
ShortcutGuide:
|
||||
Enabled: false
|
||||
OverlayOpacity: 1
|
||||
FancyZones:
|
||||
Enabled: true
|
||||
FancyzonesEditorHotkey: "Shift+Ctrl+Alt+F"
|
||||
configurationVersion: 0.2.0
|
||||
```
|
||||
|
||||
This should install PowerToys and make `PowerToysConfigure` resource available. We can use it in the same file.
|
||||
|
||||
# How it works
|
||||
|
||||
`PowerToysConfigure` is a [class-based DSC resource](https://learn.microsoft.com/en-us/powershell/dsc/concepts/class-based-resources?view=dsc-2.0). It looks up whether each setting was specified or not by checking whether it's `$null` or `0` for `enum`s and invokes `PowerToys.Settings.exe` with the updated value like so:
|
||||
```
|
||||
PowerToys.Settings.exe set <ModuleName>.<SettingName> <SettingValue>
|
||||
```
|
||||
|
||||
So for the example the config above should perform 3 following invocations:
|
||||
```
|
||||
PowerToys.Settings.exe set ShortcutGuide.Enabled false
|
||||
PowerToys.Settings.exe set FancyZones.Enabled true
|
||||
PowerToys.Settings.exe set FancyZones.FancyzonesEditorHotkey "Shift+Ctrl+Alt+F"
|
||||
```
|
||||
|
||||
`PowerToys.Settings` uses dotnet reflection capabilities to determine `SettingName` type and tries to convert the supplied `SettingValue` string accordingly. We use `ICmdReprParsable` for custom setting types.
|
||||
|
||||
|
||||
# How DSC is implemented
|
||||
|
||||
We use `PowerToys.Settings.DSC.Schema.Generator` to generate the bulk of `PowerToysConfigure.psm1` and `PowerToysConfigure.psd1` files. It also uses dotnet reflection capabilities to inspect `PowerToys.Settings.UI.Lib.dll` assembly and generate properties for the modules we have. The actual generation is done as a `PowerToys.Settings.DSC.Schema.Generator.csproj` post-build action.
|
||||
|
||||
# Debugging DSC resources
|
||||
|
||||
First, make sure that PowerShell 7.4+ is installed. Then make sure that you have DSC installed:
|
||||
|
||||
```ps
|
||||
Install-Module -Name PSDesiredStateConfiguration -RequiredVersion 2.0.7
|
||||
```
|
||||
|
||||
After that, start a new `pwsh` session and `cd` to `src\dsc\Microsoft.PowerToys.Configure\Generated` directory. From there, you should execute:
|
||||
```ps
|
||||
$env:PSModulePath += ";$pwd"
|
||||
```
|
||||
|
||||
You should have the generated `Microsoft.PowerToys.Configure.psm1` and `Microsoft.PowerToys.Configure.psd1` files inside the `src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\0.0.1\` folder.
|
||||
|
||||
This will allow DSC to discover our DSC Resource module. See [PSModulePath](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_psmodulepath?view=powershell-7.4#long-description) for more info.
|
||||
|
||||
If everything works, you should see that your module is discovered by executing the following command:
|
||||
|
||||
```ps
|
||||
Get-Module -ListAvailable | grep PowerToys
|
||||
```
|
||||
|
||||
The resource itself should also be available:
|
||||
```ps
|
||||
Get-DSCResource | grep PowerToys
|
||||
```
|
||||
|
||||
Otherwise, you can force-import the module to diagnose issues:
|
||||
|
||||
```
|
||||
Import-Module .\Microsoft.PowerToys.Configure.psd1
|
||||
```
|
||||
|
||||
If it's imported successfully, you could also try to invoke it directly:
|
||||
|
||||
```ps
|
||||
Invoke-DscResource -Name PowerToysConfigure -Method Set -ModuleName Microsoft.PowerToys.Configure -Property @{ Debug = $true; Awake = @{ Enabled = $false; Mode = "TIMED"; IntervalMinutes = "10" } }
|
||||
```
|
||||
|
||||
Note that we've supplied `Debug` option, so a `%TEMP\PowerToys.DSC.TestConfigure.txt` is created with the supplied properties, a current timestamp, and other debug output.
|
||||
|
||||
Finally, you can test it with winget by invoking it as such:
|
||||
|
||||
```ps
|
||||
winget configure .\configuration.winget --accept-configuration-agreements --disable-interactivity
|
||||
```
|
64
doc/devdocs/core/settings/gpo-integration.md
Normal file
64
doc/devdocs/core/settings/gpo-integration.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Group Policy Integration
|
||||
|
||||
PowerToys settings can be controlled and enforced via Group Policy. This document describes how Group Policy integration is implemented in the settings system.
|
||||
|
||||
## Overview
|
||||
|
||||
Group Policy settings for PowerToys allow administrators to:
|
||||
|
||||
- Enable or disable PowerToys entirely
|
||||
- Control which modules are available
|
||||
- Configure specific settings for individual modules
|
||||
- Enforce settings across an organization
|
||||
|
||||
## Implementation Details
|
||||
|
||||
When a setting is controlled by Group Policy:
|
||||
|
||||
1. The UI shows the setting as locked (disabled)
|
||||
2. The module checks GPO settings before applying user settings
|
||||
3. GPO settings take precedence over user settings
|
||||
|
||||
## Group Policy Settings Detection
|
||||
|
||||
The settings UI checks for Group Policy settings during initialization:
|
||||
|
||||
```csharp
|
||||
// Example code for checking if a setting is controlled by GPO
|
||||
bool isControlledByPolicy = RegistryHelper.GetGPOValue("PolicyKeyPath", "PolicyValueName", out object value);
|
||||
if (isControlledByPolicy)
|
||||
{
|
||||
// Use the policy value and disable UI controls
|
||||
setting.IsEnabled = false;
|
||||
setting.Value = (bool)value;
|
||||
}
|
||||
```
|
||||
|
||||
## UI Indication for Managed Settings
|
||||
|
||||
When a setting is managed by Group Policy, the UI indicates this to the user:
|
||||
|
||||
- Controls are disabled (grayed out)
|
||||
- A tooltip indicates the setting is managed by policy
|
||||
- The actual policy value is displayed
|
||||
|
||||
## Testing Group Policy Settings
|
||||
|
||||
To test Group Policy integration:
|
||||
|
||||
1. Create a test GPO using the PowerToys ADMX template
|
||||
2. Apply settings in the Group Policy Editor
|
||||
3. Verify that the settings UI correctly reflects the policy settings
|
||||
4. Verify that the modules honor the policy settings
|
||||
|
||||
## GPO Settings vs. User Settings
|
||||
|
||||
The precedence order for settings is:
|
||||
|
||||
1. Group Policy settings (highest priority)
|
||||
2. User settings (lower priority)
|
||||
3. Default settings (lowest priority)
|
||||
|
||||
When a setting is controlled by Group Policy, attempts to modify it through the settings UI or programmatically will not persist, as the policy value will always take precedence.
|
||||
|
||||
For more information on PowerToys Group Policy implementation, see the [GPO Implementation](/doc/devdocs/processes/gpo.md) documentation.
|
46
doc/devdocs/core/settings/hotkeycontrol.md
Normal file
46
doc/devdocs/core/settings/hotkeycontrol.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# Custom HotKey Control
|
||||
|
||||
The Settings project provides a custom hotkey control which consumes key presses. This control can be used to set the hotkey of any PowerToy.
|
||||
|
||||
## HotKey Control in FancyZones
|
||||

|
||||
|
||||
## Hotkey related files
|
||||
|
||||
#### [`HotkeySettingsControlHook.cs`](/src/settings-ui/Settings.UI.Library/HotkeySettingsControlHook.cs)
|
||||
|
||||
- This function initializes and starts the [`keyboardHook`](src/common/interop/KeyboardHook.cpp) for the hotkey control.
|
||||
|
||||
```csharp
|
||||
public HotkeySettingsControlHook(KeyEvent keyDown, KeyEvent keyUp, IsActive isActive, FilterAccessibleKeyboardEvents filterAccessibleKeyboardEvents)
|
||||
{
|
||||
_keyDown = keyDown;
|
||||
_keyUp = keyUp;
|
||||
_isActive = isActive;
|
||||
_filterKeyboardEvent = filterAccessibleKeyboardEvents;
|
||||
_hook = new KeyboardHook(HotkeySettingsHookCallback, IsActive, FilterKeyboardEvents);
|
||||
_hook.Start();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### [`HotkeySettingsControl.xaml.cs`](/src/settings-ui/Settings.UI/HotkeySettingsControl.xaml.cs)
|
||||
|
||||
- The function of this class is to update the state of the keys being pressed within the custom control. This information is stored in `internalSettings`.
|
||||
|
||||
- It provides the following callbacks to the `HotKeySettingsControlHook`:
|
||||
|
||||
- `KeyUp`: Resets the key state in `internalSettings` when a key is released.
|
||||
- `KeyDown`: Updates the user facing text of the hotkey control as soon as a key is pressed.
|
||||
- `isActive`: Sets the current status of the keyboard hook.
|
||||
- `FilterAccessibleKeyboardEvents`: This function is used to ignore the `Tab` and `Shift+Tab` key presses to meet the accessibility requirements.
|
||||
|
||||
#### [`HotkeySettings.cs`](/src/settings-ui/Settings.UI.Library/HotkeySettings.cs)
|
||||
|
||||
- Contains the structure of a HotKey where it is represented as a combination of one of the modifier keys (`Alt`, `Shift`, `Win` and `Ctrl`) and a non-modifier key.
|
||||
|
||||
#### Note
|
||||
- The control displays all key presses to the user (except Tab and Shift+Tab which move focus out of the control). However, when the focus is being lost from the control, the `lastValidHotkeySettings` is set as the user facing text.
|
||||
|
||||
|
||||
|
17
doc/devdocs/core/settings/project-overview.md
Normal file
17
doc/devdocs/core/settings/project-overview.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Overview
|
||||
`Settings` is Windows App Sdk WinUI3 .Net Unpackaged desktop application. More details about Windows App Sdk can be found in [Windows App SDK - Calling all Windows developers!](https://github.com/microsoft/WindowsAppSDK#windows-app-sdk---calling-all-windows-developers). More details about WinUI can be found in [Build apps with WinUI](https://developer.microsoft.com/en-us/windows/develop/).
|
||||
|
||||
## Settings V2 Project structure
|
||||
The Settings project .Net WinUI3 based project which
|
||||
follows the [MVVM architectural pattern][MVVM] where the graphical user interface is separated from the view models.
|
||||
|
||||
#### [UI Components:](/src/settings-ui/Settings.UI/)
|
||||
The UI Components are part of PowerToys.Settings project. It contains the xaml files for each of the UI components. It also contains the Hotkey logic for the settings control.
|
||||
|
||||
#### [Viewmodels:](/src/settings-ui/Settings.UI.Library)
|
||||
The Settings.UI.Library project contains the data that is to be rendered by the UI components.
|
||||
|
||||
#### [Settings Runner:](/src/settings-ui/Settings.UI)
|
||||
The function of the settings runner project is to communicate all changes that the user makes in the user interface, to the runner so that it can be dispatched and reflected in all the modules.
|
||||
|
||||
[MVVM]: https://learn.microsoft.com/windows/uwp/data-binding/data-binding-and-mvvm
|
19
doc/devdocs/core/settings/readme.md
Normal file
19
doc/devdocs/core/settings/readme.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# PowerToys Settings System
|
||||
|
||||
PowerToys provides a comprehensive settings system that allows users to configure various aspects of the application and its modules. This document provides an overview of the settings system architecture and links to more detailed documentation.
|
||||
|
||||
# Table of Contents
|
||||
1. [Settings overview](/doc/devdocs/core/settings/project-overview.md)
|
||||
2. [UI Architecture](/doc/devdocs/core/settings/ui-architecture.md)
|
||||
3. [ViewModels](/doc/devdocs/core/settings/viewmodels.md)
|
||||
4. [Settings Implementation](/doc/devdocs/core/settings/settings-implementation.md)
|
||||
5. [Group Policy Integration](/doc/devdocs/core/settings/gpo-integration.md)
|
||||
6. Data flow
|
||||
- [Inter-Process Communication with runner](/doc/devdocs/core/settings/runner-ipc.md)
|
||||
- [Communication with modules](/doc/devdocs/core/settings/communication-with-modules.md)
|
||||
7. [Settings Utilities](/doc/devdocs/core/settings/settings-utilities.md)
|
||||
8. [Custom Hotkey control and keyboard hook handling](hotkeycontrol.md)
|
||||
9. [Compatibility with legacy settings and runner](/doc/devdocs/core/settings/compatibility-legacy-settings.md)
|
||||
10. [XAML Island tweaks](/doc/devdocs/core/settings/xaml-island-tweaks.md)
|
||||
11. [Telemetry](/doc/devdocs/core/settings/telemetry.md)
|
||||
12. [DSC Configuration](/doc/devdocs/core/settings/dsc-configure.md)
|
46
doc/devdocs/core/settings/runner-ipc.md
Normal file
46
doc/devdocs/core/settings/runner-ipc.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# Inter-Process Communication with Runner
|
||||
|
||||
The Settings v2 process uses two way IPC to communicate with the runner process.
|
||||
|
||||
## Initialization
|
||||
- On the settings' side, the two way IPC delegates are contained with the [`ShellPage.xaml.cs`](/src/settings-ui/Settings.UI/SettingsXAML/Views/ShellPage.xaml.cs) file. The delegates are static and the views for all the powerToys send the ipc information to the viewmodels as `ShellPage.DefaultSndMSGCallBack`.
|
||||
- These delegates are initialized within the [`MainWindow.xaml.cs`](/src/settings-ui/Settings.UI/SettingsXAML/MainWindow.xaml.cs) file in the `Settings.Runner` project.
|
||||
|
||||
|
||||
## Types of IPC delegates
|
||||
- There are three types of delegates for the settings to communicate with the runner:
|
||||
1. `SendDefaultMessage` - This is used by all the viewmodels to communicate changes in the UI to the runner so that the information can be dispatched to the modules.
|
||||
2. `RestartAsAdmin`
|
||||
3. `CheckForUpdates`
|
||||
|
||||
## Sending information to runner
|
||||
- The settings process communicates with the runner by using the delegates defined within the [`ShellPage.xaml.cs`](/src/settings-ui/Settings.UI/SettingsXAML/Views/ShellPage.xaml.cs) file.
|
||||
- Depending on the type of object sending the information, the json is created accordingly.
|
||||
- If any information has been modified by the user in the GeneralSettings page, then the json file sent to the runner has the name set to `general`, whereas if any information has been modified by the user in any powertoy related settings page, the name of the json file being communicated with the runner is set to `powertoy`.
|
||||
|
||||
## Receiving information from runner
|
||||
- The `ShellPage` object has a `IPCResponseHandleList` which is a list of functions which handle IPC responses.
|
||||
|
||||
```csharp
|
||||
// receive IPC Message
|
||||
Program.IPCMessageReceivedCallback = (string msg) =>
|
||||
{
|
||||
if (ShellPage.ShellHandler.IPCResponseHandleList != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
JsonObject json = JsonObject.Parse(msg);
|
||||
foreach (Action<JsonObject> handle in ShellPage.ShellHandler.IPCResponseHandleList)
|
||||
{
|
||||
handle(json);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
- Whenever any information is sent from the runner each of the functions in the handle list perform their action on that json object.
|
||||
- One example of where information sent from the runner is being processed by the settings is in [`GeneralPage.xaml.cs`](/src/settings-ui/Settings.UI/SettingsXAML/Views/GeneralPage.xaml.cs) when the user clicks the check for updates button. The information displayed after, such as the user has the latest version installed is a result of this handle.
|
158
doc/devdocs/core/settings/settings-implementation.md
Normal file
158
doc/devdocs/core/settings/settings-implementation.md
Normal file
@@ -0,0 +1,158 @@
|
||||
# Settings Implementation
|
||||
|
||||
This document describes how settings are implemented in PowerToys modules, including code examples for C++ and C# modules, and details on debugging settings issues.
|
||||
|
||||
## C++ Settings Implementation
|
||||
|
||||
For C++ modules, the settings system is implemented in the following files:
|
||||
|
||||
- `settings_objects.h` and `settings_objects.cpp`: Define the basic settings objects
|
||||
- `settings_helpers.h` and `settings_helpers.cpp`: Helper functions for reading/writing settings
|
||||
- `settings_manager.h` and `settings_manager.cpp`: Main interface for managing settings
|
||||
|
||||
### Reading Settings in C++
|
||||
|
||||
```cpp
|
||||
#include <common/settings_objects.h>
|
||||
#include <common/settings_helpers.h>
|
||||
|
||||
auto settings = PowerToysSettings::Settings::LoadSettings(L"ModuleName");
|
||||
bool enabled = settings.GetValue(L"enabled", true);
|
||||
```
|
||||
|
||||
### Writing Settings in C++
|
||||
|
||||
```cpp
|
||||
PowerToysSettings::Settings settings(L"ModuleName");
|
||||
settings.SetValue(L"setting_name", true);
|
||||
settings.Save();
|
||||
```
|
||||
|
||||
## C# Settings Implementation
|
||||
|
||||
For C# modules, the settings are accessed through the `SettingsUtils` class in the `Microsoft.PowerToys.Settings.UI.Library` namespace:
|
||||
|
||||
### Reading Settings in C#
|
||||
|
||||
```csharp
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
|
||||
// Read settings
|
||||
var settings = SettingsUtils.GetSettings<ModuleSettings>("ModuleName");
|
||||
bool enabled = settings.Enabled;
|
||||
```
|
||||
|
||||
### Writing Settings in C#
|
||||
|
||||
```csharp
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
|
||||
// Write settings
|
||||
settings.Enabled = true;
|
||||
SettingsUtils.SaveSettings(settings.ToJsonString(), "ModuleName");
|
||||
```
|
||||
|
||||
## Settings Handling in Modules
|
||||
|
||||
Each PowerToys module must implement settings-related functions in its module interface:
|
||||
|
||||
```cpp
|
||||
// Get the module's settings
|
||||
virtual PowertoyModuleSettings get_settings() = 0;
|
||||
|
||||
// Called when settings are changed
|
||||
virtual void set_config(const wchar_t* config_string) = 0;
|
||||
```
|
||||
|
||||
When the user changes settings in the UI:
|
||||
|
||||
1. The settings UI serializes the settings to JSON
|
||||
2. The JSON is sent to the PowerToys runner via IPC
|
||||
3. The runner calls the `set_config` function on the appropriate module
|
||||
4. The module parses the JSON and applies the new settings
|
||||
|
||||
## Debugging Settings
|
||||
|
||||
To debug settings issues:
|
||||
|
||||
1. Check the settings files in `%LOCALAPPDATA%\Microsoft\PowerToys\`
|
||||
2. Ensure JSON is well-formed
|
||||
3. Monitor IPC communication between settings UI and runner using debugger breakpoints at key points:
|
||||
- In the Settings UI when sending configuration changes
|
||||
- In the Runner when receiving and dispatching changes
|
||||
- In the Module when applying changes
|
||||
4. Look for log messages related to settings changes in the PowerToys logs
|
||||
|
||||
### Common Issues
|
||||
|
||||
- **Settings not saving**: Check file permissions or conflicts with other processes accessing the file
|
||||
- **Settings not applied**: Verify IPC communication is working and the module is properly handling the configuration
|
||||
- **Incorrect settings values**: Check JSON parsing and type conversion in the module code
|
||||
|
||||
## Adding a New Module with Settings
|
||||
|
||||
Adding a new module with settings requires changes across multiple projects. Here's a step-by-step guide with references to real implementation examples:
|
||||
|
||||
### 1. Settings UI Library (Data Models)
|
||||
|
||||
Define the data models for your module's settings in the Settings UI Library project. These data models will be serialized to JSON configuration files stored in `%LOCALAPPDATA%\Microsoft\PowerToys\`.
|
||||
|
||||
Example: [Settings UI Library implementation](https://github.com/shuaiyuanxx/PowerToys/pull/3/files#diff-9be1cb88a52ce119e5ff990811e5fbb476c15d0d6b7d5de4877b1fd51d9241c3)
|
||||
|
||||
### 2. Settings UI (User Interface)
|
||||
|
||||
#### 2.1 Add a navigation item in ShellPage.xaml
|
||||
|
||||
The ShellPage.xaml is the entry point for the PowerToys settings, providing a navigation view of all modules. Add a navigation item for your new module.
|
||||
|
||||
Example: [Adding navigation item](https://github.com/shuaiyuanxx/PowerToys/pull/3/files#diff-5a06e6e7a5c99ae327c350c9dcc10036b49a2d66d66eac79a8364b4c99719c6b)
|
||||
|
||||
#### 2.2 Create a settings page for your module
|
||||
|
||||
Create a new XAML page that contains all the settings controls for your module.
|
||||
|
||||
Example: [New settings page](https://github.com/shuaiyuanxx/PowerToys/pull/3/files#diff-310fd49eba464ddf6a876dcf61f06a6f000ca6744f3a1f915c48c58384d7bacb)
|
||||
|
||||
#### 2.3 Implement the ViewModel
|
||||
|
||||
Create a ViewModel class that handles the settings data and operations for your module.
|
||||
|
||||
Example: [ViewModel implementation](https://github.com/shuaiyuanxx/PowerToys/pull/3/files#diff-409472a53326f2288c5b76b87c7ea8b5527c43ede12214a15b6caabe0403c1d0)
|
||||
|
||||
### 3. Module Implementation
|
||||
|
||||
#### 3.1 Implement PowertoyModuleIface in dllmain.cpp
|
||||
|
||||
The module interface must implement the PowertoyModuleIface to allow the runner to interact with it.
|
||||
|
||||
Reference: [PowertoyModuleIface definition](https://github.com/microsoft/PowerToys/blob/cc644b19982d09fcd2122fe7590c77496c4973b9/src/modules/interface/powertoy_module_interface.h#L6C1-L35C4)
|
||||
|
||||
#### 3.2 Implement Module UI
|
||||
|
||||
Create a UI for your module using either WPF (like ColorPicker) or WinUI3 (like Advanced Paste).
|
||||
|
||||
### 4. Runner Integration
|
||||
|
||||
Add your module to the known modules list in the runner so it can be brought up and initialized.
|
||||
|
||||
Example: [Runner integration](https://github.com/shuaiyuanxx/PowerToys/pull/3/files#diff-c07e4e5e9ce3c371d4c47f496b5f66734978a3c4f355c7e446c1ef19e086a4d6)
|
||||
|
||||
### 5. Testing and Debugging
|
||||
|
||||
1. Test each component individually:
|
||||
- Verify settings serialization/deserialization
|
||||
- Test module activation/deactivation
|
||||
- Test IPC communication
|
||||
|
||||
2. For signal-related issues, ensure all modules work correctly before debugging signal handling.
|
||||
|
||||
3. You can debug each module directly in Visual Studio or by attaching to running processes.
|
||||
|
||||
### Recommended Implementation Order
|
||||
|
||||
1. Module/ModuleUI implementation
|
||||
2. Module interface (dllmain.cpp)
|
||||
3. Runner integration
|
||||
4. Settings UI implementation
|
||||
5. OOBE (Out of Box Experience) integration
|
||||
6. Other components
|
13
doc/devdocs/core/settings/settings-utilities.md
Normal file
13
doc/devdocs/core/settings/settings-utilities.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Settings Utilities
|
||||
|
||||
- Abstractions for each of the file/folder related operations are present in [`SettingsUtils.cs`](src/settings-ui/Settings.UI.Library/SettingsUtils.cs).
|
||||
- To reduce contention between the settings process and runner while trying to access the `settings.json` file of any powertoy, the settings process tries to access the file only when it needs to load the information for the first time. However, there is still no mechanism in place which ensures that both the settings and runner processes do not access the information simultaneously leading to `IOExceptions`.
|
||||
|
||||
## Utilities
|
||||
|
||||
### `GetSettings<T>(powertoy, filename)`
|
||||
|
||||
- The GetSettings function tries to read the file in the powertoy settings folder and creates a new file with default configurations if it does not exist.
|
||||
- Ideally this function should only be called by the [`SettingsRepository`](src/settings-ui/Settings.UI.Library/SettingsRepository`1.cs) which would be accessed only when a powertoy settings object is being loaded for the first time.
|
||||
- The reason behind ensuring that it is not accessed elsewhere is to avoid contention with the runner during file access.
|
||||
- Each of the objects which are deserialized using this function must implement the `ISettingsConfig` interface.
|
8
doc/devdocs/core/settings/telemetry.md
Normal file
8
doc/devdocs/core/settings/telemetry.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# Telemetry
|
||||
## Overview
|
||||
[`Settings.UI.Library/Telemetry`](/src/settings-ui/Settings.UI.Library/Telemetry) contains telemetry events generated by `Settingsv2.` These event classes are derived from the [`EventBase`](/src/common/ManagedTelemetry/Telemetry/Events/EventBase.cs) class and [`IEvent`](/src/common/ManagedTelemetry/Telemetry/Events/IEvent.cs) class. [`IEvent`](/src/common/ManagedTelemetry/Telemetry/Events/IEvent.cs) class provides the lowest level abstraction, containing attributes such as privacy tags needed for every telemetry data. [`EventBase`](/src/common/ManagedTelemetry/Telemetry/Events/EventBase.cs) class provides a higher-level abstraction, having attributes common to all `PowerToys` telemetry events.
|
||||
|
||||
## Events
|
||||
The following events are generated by `Settingsv2`:
|
||||
1. [`SettingsBootEvent`](/src/settings-ui/Settings.UI.Library/Telemetry/Events/SettingsBootEvent.cs): This event captures the time taken by `Settingsv2` to initialize `MainWindow` UI control.
|
||||
2. [`SettingsEnabledEvent.cs`](/src/settings-ui/Settings.UI.Library/Telemetry/Events/SettingsEnabledEvent.cs): This event is generated when a module is enabled or disabled.
|
7
doc/devdocs/core/settings/ui-architecture.md
Normal file
7
doc/devdocs/core/settings/ui-architecture.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# UI Architecture
|
||||
|
||||
The UI code is distributed between two projects: [`PowerToys.Settings`](/src/settings-ui/Settings.UI) and [`Settings.UI`](/src/settings-ui/Settings.UI.Library). [`PowerToys.Settings`](/src/settings-ui/Settings.UI) is a Windows App Sdk .net Unpackaged application. It contains the views for base navigation and modules. Parent display window and corresponding code is present in [`MainWindow.xaml`](/src/settings-ui/Settings.UI/SettingsXAML/MainWindow.xaml). Fig 1 provides a description of the UI controls hierarchy and each of the controls have been summarized below :
|
||||
- [`ShellPage.xaml`](/src/settings-ui/Settings.UI/SettingsXAML/Views/ShellPage.xaml) is a WinUI control, consisting of a side navigation panel with an icon for each module. Clicking on a module icon loads the corresponding `setting.json` file and displays the data in the UI.
|
||||
|
||||

|
||||
**Fig 1: UI Architecture for settingsv2**
|
26
doc/devdocs/core/settings/viewmodels.md
Normal file
26
doc/devdocs/core/settings/viewmodels.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Viewmodels
|
||||
The viewmodels are located within the [`Settings.UI.Library`](/src/settings-ui/Settings.UI.Library) project.
|
||||
|
||||
## Components
|
||||
- Each viewmodel takes in the general `settingsRepository`, the `moduleSettingsRepository` if it exists and the delegates for IPC communication.
|
||||
- The general `settingsRepository` contains the general configurations of all powertoys whereas the `moduleSettingsRepository` is specific to the module. This is to ensure that the configuration details are shared amongst the viewmodels without having to re-open the `settings.json` file.
|
||||
- Whenever there is a change in the UI, the `OnPropertyChanged` event is invoked and the viewmodel sends a corresponding IPC message to the runner which would perform the designated action such as dispatching the change to the modules or enabling/disabling the powertoy etc.
|
||||
|
||||
#### Difference between viewmodels
|
||||
- The [`GeneralViewModel`](/src/settings-ui/Settings.UI.Library/ViewModels/GeneralViewModel.cs) is different from the rest of the view models with regard to the IPC communication wherein it sends special IPC messages to the runner to check for updates and to restart as admin.
|
||||
- Each of the powerToy viewmodels have two types of IPC communications, one for the general status of the powerToy and the other for communication powerToy specific change in properties to the runner.
|
||||
|
||||
## [`SettingsRepository`](src/settings-ui/Settings.UI.Library/SettingsRepository`1.cs)
|
||||
- The [`SettingsRepository`](src/settings-ui/Settings.UI.Library/SettingsRepository`1.cs) is a generic singleton which contains the configurations for each viewmodel.
|
||||
- As it is a generic singleton, there can only be one instance of the settings repository of a particular type. This ensures that all the viewmodels are modifying a common object and a change made in one locations reflects everywhere.
|
||||
- The singleton implementation is thread-safe. Unit tests have been added for the same.
|
||||
|
||||
### Settings viewmodel anomalies
|
||||
- The reason behind using the `SettingsRepository` is to ensure that the settings process does not try to access the `settings.json` files directly but rather does it through this class which encapsulates all the file operations from the viewmodels.
|
||||
- However, this could not be expanded to all the viewmodels directly for the following reasons. Some refactoring must be done to unify these cases and to bring them under the same model:
|
||||
- The PowerRename viewmodel does not save the settings configurations in the same format as the rest of the powertoys, ie. {name, version, properties}. However, it only stores the properties directly.
|
||||
- Some viewmodels expect the runner to create the file instead of creating the file themselves, like in keyboard manager.
|
||||
- The colorpicker powertoy creates the `settings.json` within the module. This must be taken care of when encapsulated within the settingsRepository.
|
||||
- Currently, all modules use the `SettingsRepository` to access the General Settings config.
|
||||
- However, only FancyZones, ShortcutGuide and PowerPreview use the `SettingsRepository` to access the module properties.
|
||||
|
Reference in New Issue
Block a user