mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-24 20:20:38 +01:00
This PR contains a set of bug fixes and general improvements to [Awake](https://awake.den.dev/) and developer experience tooling for building the module. ### Awake Fixes - **#32544** - Fixed an issue where Awake settings became non-functional after the PC wakes from sleep. Added `WM_POWERBROADCAST` handling to detect system resume events (`PBT_APMRESUMEAUTOMATIC`, `PBT_APMRESUMESUSPEND`) and re-apply `SetThreadExecutionState` to restore the awake state. - **#36150** - Fixed an issue where Awake would not prevent sleep when AC power is connected. Added `PBT_APMPOWERSTATUSCHANGE` handling to re-apply `SetThreadExecutionState` when the power source changes (AC/battery transitions). - **#41674** - Fixed silent failure when `SetThreadExecutionState` fails. The monitor thread now handles the return value, logs an error, and reverts to passive mode with updated tray icon. - **#41738** - Fixed `--display-on` CLI flag default from `true` to `false` to align with documentation and PowerToys settings behavior. This is a breaking change for scripts relying on the undocumented default. - **#41918** - Fixed `WM_COMMAND` message processing flaw in `TrayHelper.WndProc` that incorrectly compared enum values against enum count. Added proper bounds checking for custom tray time entries. - **#44134** - Documented that `ES_DISPLAY_REQUIRED` (used when "Keep display on" is enabled) blocks Task Scheduler idle detection, preventing scheduled maintenance tasks like SSD TRIM. Workaround: disable "Keep display on" or manually run `Optimize-Volume -DriveLetter C -ReTrim`. - **#38770** - Fixed tray icon failing to appear after Windows updates. Increased retry attempts and delays for icon Add operations (10 attempts, up to ~15.5 seconds total) while keeping existing fast retry behavior for Update/Delete operations. - **#40501** - Fixed tray icon not disappearing when Awake is disabled. The `SetShellIcon` function was incorrectly requiring an icon for Delete operations, causing the `NIM_DELETE` message to never be sent. - Fixed an issue where toggling "Keep screen on" during an active timed session would disrupt the countdown timer. The display setting now updates directly without restarting the timer, preserving the exact remaining time. ### Performance Optimizations - Fixed O(n²) loop in `TrayHelper.CreateAwakeTimeSubMenu` by replacing `ElementAt(i)` with `foreach` iteration. - Fixed Observable subscription leak in `Manager.cs` by storing `IDisposable` and disposing in `CancelExistingThread()`. Also removed dead `_tokenSource` code that was no longer used. - Reduced allocations in `SingleThreadSynchronizationContext` by changing `Tuple<>` to `ValueTuple`. - Replaced dedicated exit event thread with `ThreadPool.RegisterWaitForSingleObject()` to reduce resource usage. ### Code Quality - Replaced `Console.WriteLine` with `Logger.LogError` in `TrayHelper.cs` for consistent logging. - Added proper error logging to silent exception catches in `AwakeService.cs`. - Removed dead `Math.Min(minutes, int.MaxValue)` code where `minutes` is already an `int`. - Extracted hardcoded tray icon ID to named constant `TrayIconId`. - Standardized null coalescing for `GetSettings<AwakeSettings>()` calls across all files. ### Debugging Experience Fixes - Fixed first-chance exceptions in `settings_window.cpp` during debugging. Added `HasKey()` check before accessing `hotkey_changed` property to prevent `hresult_error` exceptions when the property doesn't exist in module settings. - Fixed first-chance exceptions in FindMyMouse `parse_settings` during debugging. Refactored to extract the properties object once and added `HasKey()` checks before all `GetNamedObject()` calls. This prevents `winrt::hresult_error` exceptions when optional settings keys (like legacy `overlay_opacity`) don't exist, improving the debugging experience by eliminating spurious exception breaks. - Fixed LightSwitch.UITests build failures when building from a clean state. Added missing project references (`ManagedCommon`, `LightSwitchModuleInterface`) with `ReferenceOutputAssembly=false` to ensure proper build ordering, and added existence check for the native DLL copy operation. ### Developer Experience - Added `setup-dev-environment.ps1` script to automate development environment setup. - Added `clean-artifacts.ps1` script to resolve build errors from corrupted build state or missing image files. - Added build script that allows standalone command line build of the Awake module. - Added troubleshooting section to `doc/devdocs/development/debugging.md` with guidance on resolving common build errors.
292 lines
12 KiB
PowerShell
292 lines
12 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Sets up the development environment for building PowerToys.
|
|
|
|
.DESCRIPTION
|
|
This script automates the setup of prerequisites needed to build PowerToys locally:
|
|
- Enables Windows long path support (requires elevation)
|
|
- Enables Windows Developer Mode (requires elevation)
|
|
- Installs required Visual Studio workloads from .vsconfig
|
|
- Initializes git submodules
|
|
|
|
Run this script once after cloning the repository to prepare your development environment.
|
|
|
|
.PARAMETER SkipLongPaths
|
|
Skip enabling long path support in Windows.
|
|
|
|
.PARAMETER SkipDevMode
|
|
Skip enabling Windows Developer Mode.
|
|
|
|
.PARAMETER SkipVSComponents
|
|
Skip installing Visual Studio components from .vsconfig.
|
|
|
|
.PARAMETER SkipSubmodules
|
|
Skip initializing git submodules.
|
|
|
|
.PARAMETER VSInstallPath
|
|
Path to Visual Studio installation. Default: auto-detected.
|
|
|
|
.PARAMETER Help
|
|
Show this help message.
|
|
|
|
.EXAMPLE
|
|
.\tools\build\setup-dev-environment.ps1
|
|
Runs the full setup process.
|
|
|
|
.EXAMPLE
|
|
.\tools\build\setup-dev-environment.ps1 -SkipVSComponents
|
|
Runs setup but skips Visual Studio component installation.
|
|
|
|
.EXAMPLE
|
|
.\tools\build\setup-dev-environment.ps1 -VSInstallPath "C:\Program Files\Microsoft Visual Studio\2022\Enterprise"
|
|
Runs setup with a custom Visual Studio installation path.
|
|
|
|
.NOTES
|
|
- Some operations require administrator privileges (long paths, VS component installation).
|
|
- If not running as administrator, the script will prompt for elevation for those steps.
|
|
- The script is idempotent and safe to run multiple times.
|
|
#>
|
|
|
|
param (
|
|
[switch]$SkipLongPaths,
|
|
[switch]$SkipDevMode,
|
|
[switch]$SkipVSComponents,
|
|
[switch]$SkipSubmodules,
|
|
[string]$VSInstallPath = '',
|
|
[switch]$Help
|
|
)
|
|
|
|
if ($Help) {
|
|
Get-Help $MyInvocation.MyCommand.Path -Detailed
|
|
exit 0
|
|
}
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
# Find repository root
|
|
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
|
$repoRoot = $scriptDir
|
|
while ($repoRoot -and -not (Test-Path (Join-Path $repoRoot "PowerToys.slnx"))) {
|
|
$parent = Split-Path -Parent $repoRoot
|
|
if ($parent -eq $repoRoot) {
|
|
Write-Error "Could not find PowerToys repository root. Ensure this script is in the PowerToys repository."
|
|
exit 1
|
|
}
|
|
$repoRoot = $parent
|
|
}
|
|
|
|
Write-Host "Repository: $repoRoot"
|
|
Write-Host ""
|
|
|
|
function Test-Administrator {
|
|
$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
|
|
$principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
|
|
return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
|
}
|
|
|
|
$isAdmin = Test-Administrator
|
|
|
|
# Step 1: Enable Long Paths
|
|
if (-not $SkipLongPaths) {
|
|
Write-Host "[1/4] Checking Windows long path support"
|
|
|
|
$longPathsEnabled = $false
|
|
try {
|
|
$regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -ErrorAction SilentlyContinue
|
|
$longPathsEnabled = ($regValue.LongPathsEnabled -eq 1)
|
|
} catch {
|
|
$longPathsEnabled = $false
|
|
}
|
|
|
|
if ($longPathsEnabled) {
|
|
Write-Host " Long paths already enabled" -ForegroundColor Green
|
|
} elseif ($isAdmin) {
|
|
Write-Host " Enabling long paths..."
|
|
try {
|
|
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -Type DWord
|
|
Write-Host " Long paths enabled" -ForegroundColor Green
|
|
} catch {
|
|
Write-Warning " Failed to enable long paths: $_"
|
|
}
|
|
} else {
|
|
Write-Warning " Long paths not enabled. Run as Administrator to enable, or run manually:"
|
|
Write-Host " Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -Value 1" -ForegroundColor DarkGray
|
|
}
|
|
} else {
|
|
Write-Host "[1/4] Skipping long path check" -ForegroundColor DarkGray
|
|
}
|
|
|
|
Write-Host ""
|
|
|
|
# Step 2: Enable Developer Mode
|
|
if (-not $SkipDevMode) {
|
|
Write-Host "[2/4] Checking Windows Developer Mode"
|
|
|
|
$devModeEnabled = $false
|
|
try {
|
|
$regValue = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" -Name "AllowDevelopmentWithoutDevLicense" -ErrorAction SilentlyContinue
|
|
$devModeEnabled = ($regValue.AllowDevelopmentWithoutDevLicense -eq 1)
|
|
} catch {
|
|
$devModeEnabled = $false
|
|
}
|
|
|
|
if ($devModeEnabled) {
|
|
Write-Host " Developer Mode already enabled" -ForegroundColor Green
|
|
} elseif ($isAdmin) {
|
|
Write-Host " Enabling Developer Mode..."
|
|
try {
|
|
$regPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock"
|
|
if (-not (Test-Path $regPath)) {
|
|
New-Item -Path $regPath -Force | Out-Null
|
|
}
|
|
Set-ItemProperty -Path $regPath -Name "AllowDevelopmentWithoutDevLicense" -Value 1 -Type DWord
|
|
Write-Host " Developer Mode enabled" -ForegroundColor Green
|
|
} catch {
|
|
Write-Warning " Failed to enable Developer Mode: $_"
|
|
}
|
|
} else {
|
|
Write-Warning " Developer Mode not enabled. Run as Administrator to enable, or enable manually:"
|
|
Write-Host " Settings > System > For developers > Developer Mode" -ForegroundColor DarkGray
|
|
}
|
|
} else {
|
|
Write-Host "[2/4] Skipping Developer Mode check" -ForegroundColor DarkGray
|
|
}
|
|
|
|
Write-Host ""
|
|
|
|
# Step 3: Install Visual Studio Components
|
|
if (-not $SkipVSComponents) {
|
|
Write-Host "[3/4] Checking Visual Studio components"
|
|
|
|
$vsConfigPath = Join-Path $repoRoot ".vsconfig"
|
|
if (-not (Test-Path $vsConfigPath)) {
|
|
Write-Warning " .vsconfig not found at $vsConfigPath"
|
|
} else {
|
|
$vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
|
|
|
|
if (-not $VSInstallPath -and (Test-Path $vsWhere)) {
|
|
$VSInstallPath = & $vsWhere -latest -property installationPath 2>$null
|
|
}
|
|
|
|
if (-not $VSInstallPath) {
|
|
$commonPaths = @(
|
|
"${env:ProgramFiles}\Microsoft Visual Studio\2022\Enterprise",
|
|
"${env:ProgramFiles}\Microsoft Visual Studio\2022\Professional",
|
|
"${env:ProgramFiles}\Microsoft Visual Studio\2022\Community"
|
|
)
|
|
foreach ($path in $commonPaths) {
|
|
if (Test-Path $path) {
|
|
$VSInstallPath = $path
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
if (-not $VSInstallPath -or -not (Test-Path $VSInstallPath)) {
|
|
Write-Warning " Could not find Visual Studio 2022 installation"
|
|
Write-Warning " Please install Visual Studio 2022 and try again, or import .vsconfig manually"
|
|
} else {
|
|
Write-Host " Found: $VSInstallPath" -ForegroundColor DarkGray
|
|
|
|
$vsInstaller = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vs_installer.exe"
|
|
|
|
if (Test-Path $vsInstaller) {
|
|
Write-Host ""
|
|
Write-Host " To install required components:"
|
|
Write-Host ""
|
|
Write-Host " Option A - Visual Studio Installer GUI:"
|
|
Write-Host " 1. Open Visual Studio Installer"
|
|
Write-Host " 2. Click 'More' > 'Import configuration'"
|
|
Write-Host " 3. Select: $vsConfigPath"
|
|
Write-Host ""
|
|
Write-Host " Option B - Command line (close VS first):"
|
|
Write-Host " & `"$vsInstaller`" modify --installPath `"$VSInstallPath`" --config `"$vsConfigPath`"" -ForegroundColor DarkGray
|
|
Write-Host ""
|
|
|
|
$choices = @(
|
|
[System.Management.Automation.Host.ChoiceDescription]::new("&Install", "Run VS Installer now"),
|
|
[System.Management.Automation.Host.ChoiceDescription]::new("&Skip", "Continue without installing")
|
|
)
|
|
|
|
try {
|
|
$decision = $Host.UI.PromptForChoice("", "Install VS components now?", $choices, 1)
|
|
|
|
if ($decision -eq 0) {
|
|
# Check if VS Installer is already running (it runs as setup.exe from the Installer folder)
|
|
$vsInstallerDir = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer"
|
|
$vsInstallerRunning = Get-Process -Name "setup" -ErrorAction SilentlyContinue |
|
|
Where-Object { $_.Path -and $_.Path.StartsWith($vsInstallerDir, [System.StringComparison]::OrdinalIgnoreCase) }
|
|
if ($vsInstallerRunning) {
|
|
Write-Warning " Visual Studio Installer is already running"
|
|
Write-Host " Close it and run this script again, or import .vsconfig manually" -ForegroundColor DarkGray
|
|
} else {
|
|
Write-Host " Launching Visual Studio Installer..."
|
|
Write-Host " Close Visual Studio if it's running." -ForegroundColor DarkGray
|
|
$process = Start-Process -FilePath $vsInstaller -ArgumentList "modify", "--installPath", "`"$VSInstallPath`"", "--config", "`"$vsConfigPath`"" -Wait -PassThru
|
|
if ($process.ExitCode -eq 0) {
|
|
Write-Host " VS component installation completed" -ForegroundColor Green
|
|
} elseif ($process.ExitCode -eq 3010) {
|
|
Write-Host " VS component installation completed (restart may be required)" -ForegroundColor Green
|
|
} else {
|
|
Write-Warning " VS Installer exited with code $($process.ExitCode)"
|
|
Write-Host " You may need to run the installer manually" -ForegroundColor DarkGray
|
|
}
|
|
}
|
|
} else {
|
|
Write-Host " Skipped VS component installation"
|
|
}
|
|
} catch {
|
|
Write-Host " Non-interactive mode. Run the command above manually if needed." -ForegroundColor DarkGray
|
|
}
|
|
} else {
|
|
Write-Warning " Visual Studio Installer not found"
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
Write-Host "[3/4] Skipping VS component check" -ForegroundColor DarkGray
|
|
}
|
|
|
|
Write-Host ""
|
|
|
|
# Step 4: Initialize Git Submodules
|
|
if (-not $SkipSubmodules) {
|
|
Write-Host "[4/4] Initializing git submodules"
|
|
|
|
Push-Location $repoRoot
|
|
try {
|
|
$submoduleStatus = git submodule status 2>&1
|
|
$uninitializedCount = ($submoduleStatus | Where-Object { $_ -match '^\-' }).Count
|
|
|
|
if ($uninitializedCount -eq 0 -and $submoduleStatus) {
|
|
Write-Host " Submodules already initialized" -ForegroundColor Green
|
|
} else {
|
|
Write-Host " Running: git submodule update --init --recursive" -ForegroundColor DarkGray
|
|
git submodule update --init --recursive
|
|
if ($LASTEXITCODE -eq 0) {
|
|
Write-Host " Submodules initialized" -ForegroundColor Green
|
|
} else {
|
|
Write-Warning " Submodule initialization may have encountered issues (exit code: $LASTEXITCODE)"
|
|
}
|
|
}
|
|
} catch {
|
|
Write-Warning " Failed to initialize submodules: $_"
|
|
} finally {
|
|
Pop-Location
|
|
}
|
|
} else {
|
|
Write-Host "[4/4] Skipping submodule initialization" -ForegroundColor DarkGray
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "Setup complete" -ForegroundColor Green
|
|
Write-Host ""
|
|
Write-Host "Next steps:"
|
|
Write-Host " 1. Open PowerToys.slnx in Visual Studio 2022"
|
|
Write-Host " 2. If prompted to install additional components, click Install"
|
|
Write-Host " 3. Build the solution (Ctrl+Shift+B)"
|
|
Write-Host ""
|
|
Write-Host "Or build from command line:"
|
|
Write-Host " .\tools\build\build.ps1" -ForegroundColor DarkGray
|
|
Write-Host ""
|