mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-01-06 04:17:04 +01:00
Compare commits
17 Commits
dev/vanzue
...
niels9001/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5dbfe10f24 | ||
|
|
6cc0feb711 | ||
|
|
83ef89f1f2 | ||
|
|
c0c55112c4 | ||
|
|
4d04a5abbf | ||
|
|
d793398aa5 | ||
|
|
15be2f3b25 | ||
|
|
a668659d47 | ||
|
|
d16cdd50ed | ||
|
|
ae3d0606f0 | ||
|
|
7be9f73d04 | ||
|
|
95d6598295 | ||
|
|
9b04ad9b30 | ||
|
|
4bb2158d9c | ||
|
|
6d5e958eeb | ||
|
|
5fb1759079 | ||
|
|
b9e0c20256 |
7
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
7
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -7,13 +7,6 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: Please make sure to [search for existing issues](https://github.com/microsoft/PowerToys/issues) before filing a new one!
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
We are aware of the following high-volume issues and are actively working on them. Please check if your issue is one of these before filing a new bug report:
|
||||
* **PowerToys Run crash related to "Desktop composition is disabled"**: This may appear as `COMException: 0x80263001`. For more details, see issue [#31226](https://github.com/microsoft/PowerToys/issues/31226).
|
||||
* **PowerToys Run crash with `COMException (0xD0000701)`**: For more details, see issue [#30769](https://github.com/microsoft/PowerToys/issues/30769).
|
||||
* **PowerToys Run crash with a "Cyclic reference" error**: This `System.InvalidOperationException` is detailed in issue [#36451](https://github.com/microsoft/PowerToys/issues/36451).
|
||||
- id: version
|
||||
type: input
|
||||
attributes:
|
||||
|
||||
1
.github/actions/spell-check/excludes.txt
vendored
1
.github/actions/spell-check/excludes.txt
vendored
@@ -105,7 +105,6 @@
|
||||
^src/common/notifications/BackgroundActivatorDLL/cpp\.hint$
|
||||
^src/common/sysinternals/Eula/
|
||||
^src/modules/cmdpal/doc/initial-sdk-spec/list-elements-mock-002\.pdn$
|
||||
^src/modules/cmdpal/ext/SamplePagesExtension/Pages/SampleMarkdownImagesPage\.cs$
|
||||
^src/modules/colorPicker/ColorPickerUI/Shaders/GridShader\.cso$
|
||||
^src/modules/launcher/Plugins/Microsoft\.PowerToys\.Run\.Plugin\.TimeDate/Properties/
|
||||
^src/modules/MouseUtils/MouseJumpUI/MainForm\.resx$
|
||||
|
||||
9
.github/actions/spell-check/expect.txt
vendored
9
.github/actions/spell-check/expect.txt
vendored
@@ -22,7 +22,6 @@ ADate
|
||||
ADDSTRING
|
||||
ADDUNDORECORD
|
||||
ADifferent
|
||||
adjacents
|
||||
ADMINS
|
||||
adml
|
||||
admx
|
||||
@@ -101,6 +100,7 @@ ATX
|
||||
ATRIOX
|
||||
aumid
|
||||
authenticode
|
||||
Authenticode
|
||||
AUTOBUDDY
|
||||
AUTOCHECKBOX
|
||||
AUTOHIDE
|
||||
@@ -257,7 +257,6 @@ cominterop
|
||||
commandnotfound
|
||||
commandpalette
|
||||
compmgmt
|
||||
COMPOSITIONDISABLED
|
||||
COMPOSITIONFULL
|
||||
CONFIGW
|
||||
CONFLICTINGMODIFIERKEY
|
||||
@@ -314,7 +313,6 @@ CURRENTDIR
|
||||
CURSORINFO
|
||||
cursorpos
|
||||
CURSORSHOWING
|
||||
CURSORWRAP
|
||||
customaction
|
||||
CUSTOMACTIONTEST
|
||||
CUSTOMFORMATPLACEHOLDER
|
||||
@@ -430,6 +428,7 @@ DSTINVERT
|
||||
DString
|
||||
DSVG
|
||||
dto
|
||||
DTo
|
||||
DUMMYUNIONNAME
|
||||
dutil
|
||||
DVASPECT
|
||||
@@ -463,6 +462,7 @@ EDITKEYBOARD
|
||||
EDITSHORTCUTS
|
||||
EDITTEXT
|
||||
EFile
|
||||
ekus
|
||||
eku
|
||||
emojis
|
||||
ENABLEDELAYEDEXPANSION
|
||||
@@ -1148,6 +1148,7 @@ NONCLIENTMETRICSW
|
||||
NONELEVATED
|
||||
nonspace
|
||||
nonstd
|
||||
nullrefs
|
||||
NOOWNERZORDER
|
||||
NOPARENTNOTIFY
|
||||
NOPREFIX
|
||||
@@ -1187,8 +1188,8 @@ ntfs
|
||||
NTSTATUS
|
||||
NTSYSAPI
|
||||
NULLCURSOR
|
||||
nullonfailure
|
||||
nullref
|
||||
nullonfailure
|
||||
numberbox
|
||||
nwc
|
||||
ocr
|
||||
|
||||
2
.github/actions/spell-check/patterns.txt
vendored
2
.github/actions/spell-check/patterns.txt
vendored
@@ -253,7 +253,7 @@ _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING
|
||||
|
||||
# hit-count: 1 file-count: 1
|
||||
# Amazon
|
||||
\bamazon\.com/[-\w]+/(?:dp/[0-9A-Z]+|)
|
||||
\bamazon\.com/[-\w]+/(?:dp/[0-9A-Z]+|)[^"'\s]+
|
||||
|
||||
# hit-count: 3 file-count: 3
|
||||
# imgur
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -349,7 +349,10 @@ src/common/Telemetry/*.etl
|
||||
/src/modules/powerrename/ui/RCb24464
|
||||
|
||||
# Generated installer file for Monaco source files.
|
||||
/installer/PowerToysSetup/MonacoSRC.wxs
|
||||
/installer/PowerToysSetup/DscResources.wxs
|
||||
/installer/PowerToysSetupVNext/MonacoSRC.wxs
|
||||
/installer/PowerToysSetupVNext/DscResources.wxs
|
||||
|
||||
# MSBuildCache
|
||||
/MSBuildCacheLogs/
|
||||
|
||||
@@ -181,7 +181,6 @@
|
||||
"PowerToys.MousePointerCrosshairs.dll",
|
||||
"PowerToys.MouseJumpUI.dll",
|
||||
"PowerToys.MouseJumpUI.exe",
|
||||
"PowerToys.CursorWrap.dll",
|
||||
|
||||
"PowerToys.MouseWithoutBorders.dll",
|
||||
"PowerToys.MouseWithoutBorders.exe",
|
||||
|
||||
@@ -65,28 +65,21 @@ if (-not (Test-Path $outputDir)) {
|
||||
New-Item -Path $outputDir -ItemType Directory -Force | Out-Null
|
||||
}
|
||||
|
||||
# DSC v3 manifests go to DSCModules subfolder
|
||||
$dscOutputDir = Join-Path $outputDir 'DSCModules'
|
||||
if (-not (Test-Path $dscOutputDir)) {
|
||||
Write-Host "Creating DSCModules subfolder at '$dscOutputDir'."
|
||||
New-Item -Path $dscOutputDir -ItemType Directory -Force | Out-Null
|
||||
}
|
||||
Write-Host "DSC manifests will be generated to: '$outputDir'"
|
||||
|
||||
Write-Host "DSC manifests will be generated to: '$dscOutputDir'"
|
||||
Write-Host "Cleaning previously generated DSC manifest files from '$outputDir'."
|
||||
Get-ChildItem -Path $outputDir -Filter 'microsoft.powertoys.*.settings.dsc.resource.json' -ErrorAction SilentlyContinue | Remove-Item -Force
|
||||
|
||||
Write-Host "Cleaning previously generated DSC manifest files from '$dscOutputDir'."
|
||||
Get-ChildItem -Path $dscOutputDir -Filter 'microsoft.powertoys.*.settings.dsc.resource.json' -ErrorAction SilentlyContinue | Remove-Item -Force
|
||||
|
||||
$arguments = @('manifest', '--resource', 'settings', '--outputDir', $dscOutputDir)
|
||||
$arguments = @('manifest', '--resource', 'settings', '--outputDir', $outputDir)
|
||||
Write-Host "Invoking DSC manifest generator: '$exePath' $($arguments -join ' ')"
|
||||
& $exePath @arguments
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "PowerToys.DSC.exe exited with code $LASTEXITCODE"
|
||||
}
|
||||
|
||||
$generatedFiles = Get-ChildItem -Path $dscOutputDir -Filter 'microsoft.powertoys.*.settings.dsc.resource.json' -ErrorAction Stop
|
||||
$generatedFiles = Get-ChildItem -Path $outputDir -Filter 'microsoft.powertoys.*.settings.dsc.resource.json' -ErrorAction Stop
|
||||
if ($generatedFiles.Count -eq 0) {
|
||||
throw "No DSC manifest files were generated in '$dscOutputDir'."
|
||||
throw "No DSC manifest files were generated in '$outputDir'."
|
||||
}
|
||||
|
||||
Write-Host "Generated $($generatedFiles.Count) DSC manifest file(s):"
|
||||
|
||||
@@ -52,6 +52,8 @@ extends:
|
||||
name: SHINE-INT-S
|
||||
${{ if eq(parameters.useVSPreview, true) }}:
|
||||
demands: ImageOverride -equals SHINE-VS17-Preview
|
||||
${{ else }}:
|
||||
image: SHINE-VS17-Latest
|
||||
os: windows
|
||||
sdl:
|
||||
tsa:
|
||||
@@ -73,6 +75,7 @@ extends:
|
||||
name: SHINE-INT-L
|
||||
demands:
|
||||
# Our INT agents have a large disk mounted at P:\
|
||||
- WorkFolder -equals P:\_work
|
||||
- ${{ if eq(parameters.useVSPreview, true) }}:
|
||||
- ImageOverride -equals SHINE-VS17-Preview
|
||||
os: windows
|
||||
@@ -123,6 +126,7 @@ extends:
|
||||
parameters:
|
||||
pool:
|
||||
name: SHINE-INT-L
|
||||
image: SHINE-VS17-Latest
|
||||
os: windows
|
||||
official: true
|
||||
codeSign: true
|
||||
|
||||
@@ -111,7 +111,6 @@ jobs:
|
||||
${{ else }}:
|
||||
OutputBuildPlatform: ${{ platform }}
|
||||
variables:
|
||||
NUGET_PACKAGES: 'C:\NuGetPackages' # Some of our build steps cache these here... and it was apparently part of the global environment
|
||||
MakeAppxPath: 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x86\MakeAppx.exe'
|
||||
# Azure DevOps abhors a vacuum
|
||||
# If these are blank, expansion will fail later on... which will result in direct substitution of the variable *names*
|
||||
@@ -140,10 +139,6 @@ jobs:
|
||||
- output: pipelineArtifact
|
||||
artifactName: $(JobOutputArtifactName)
|
||||
targetPath: $(Build.ArtifactStagingDirectory)
|
||||
- output: pipelineArtifact
|
||||
artifactName: $(JobOutputArtifactName)-failure-$(System.JobAttempt)
|
||||
targetPath: $(LogOutputDirectory)
|
||||
condition: or(failed(), canceled())
|
||||
steps:
|
||||
- checkout: self
|
||||
clean: true
|
||||
@@ -400,7 +395,7 @@ jobs:
|
||||
### HACK: On ARM64 builds, building an app with Windows App SDK copies the x64 WebView2 dll instead of the ARM64 one. This task makes sure the right dll is used.
|
||||
- task: CopyFiles@2
|
||||
displayName: HACK Copy core WebView2 ARM64 dll to output directory
|
||||
condition: and(succeeded(), eq(variables['BuildPlatform'], 'arm64'))
|
||||
condition: eq(variables['BuildPlatform'],'arm64')
|
||||
inputs:
|
||||
contents: packages/Microsoft.Web.WebView2.1.0.2903.40/runtimes/win-ARM64/native_uap/Microsoft.Web.WebView2.Core.dll
|
||||
targetFolder: $(Build.SourcesDirectory)/ARM64/Release/WinUI3Apps/
|
||||
@@ -439,11 +434,11 @@ jobs:
|
||||
inputs:
|
||||
testResultsFormat: VSTest
|
||||
testResultsFiles: '**/*.trx'
|
||||
condition: and(succeeded(), ne(variables['BuildPlatform'], 'arm64'))
|
||||
condition: ne(variables['BuildPlatform'],'arm64')
|
||||
|
||||
# Native dlls
|
||||
- task: VSTest@2
|
||||
condition: and(succeeded(), ne(variables['BuildPlatform'], 'arm64')) # No arm64 agents to run the tests.
|
||||
condition: ne(variables['BuildPlatform'],'arm64') # No arm64 agents to run the tests.
|
||||
displayName: 'Native Tests'
|
||||
inputs:
|
||||
platform: '$(BuildPlatform)'
|
||||
|
||||
@@ -34,20 +34,20 @@
|
||||
<!-- Including MessagePack to force version, since it's used by StreamJsonRpc but contains vulnerabilities. After StreamJsonRpc updates the version of MessagePack, we can upgrade StreamJsonRpc instead. -->
|
||||
<PackageVersion Include="MessagePack" Version="3.1.3" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="9.0.0" />
|
||||
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.10" />
|
||||
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.8" />
|
||||
<!-- Including Microsoft.Bcl.AsyncInterfaces to force version, since it's used by Microsoft.SemanticKernel. -->
|
||||
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.10" />
|
||||
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.Windows.CppWinRT" Version="2.0.240111.5" />
|
||||
<PackageVersion Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="3.1.16" />
|
||||
<PackageVersion Include="Microsoft.Extensions.AI" Version="9.9.1" />
|
||||
<PackageVersion Include="Microsoft.Extensions.AI.OpenAI" Version="9.9.1-preview.1.25474.6" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.10" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="9.0.10" />
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.10" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.10" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.10" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.10" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.10" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.9" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="9.0.9" />
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.9" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.9" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.9" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.AI.Foundry.Local" Version="0.3.0" />
|
||||
<PackageVersion Include="Microsoft.SemanticKernel" Version="1.66.0" />
|
||||
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.OpenAI" Version="1.66.0" />
|
||||
@@ -60,9 +60,9 @@
|
||||
<PackageVersion Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
|
||||
<PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.3179.45" />
|
||||
<!-- Package Microsoft.Win32.SystemEvents added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Drawing.Common but the 8.0.1 version wasn't published to nuget. -->
|
||||
<PackageVersion Include="Microsoft.Win32.SystemEvents" Version="9.0.10" />
|
||||
<PackageVersion Include="Microsoft.Win32.SystemEvents" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.WindowsPackageManager.ComInterop" Version="1.10.340" />
|
||||
<PackageVersion Include="Microsoft.Windows.Compatibility" Version="9.0.10" />
|
||||
<PackageVersion Include="Microsoft.Windows.Compatibility" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.Windows.CsWin32" Version="0.3.183" />
|
||||
<!-- CsWinRT version needs to be set to have a WinRT.Runtime.dll at the same version contained inside the NET SDK we're currently building on CI. -->
|
||||
<!--
|
||||
@@ -95,29 +95,29 @@
|
||||
<PackageVersion Include="StreamJsonRpc" Version="2.21.69" />
|
||||
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
|
||||
<!-- Package System.CodeDom added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Management but the 8.0.1 version wasn't published to nuget. -->
|
||||
<PackageVersion Include="System.CodeDom" Version="9.0.10" />
|
||||
<PackageVersion Include="System.CodeDom" Version="9.0.8" />
|
||||
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
|
||||
<PackageVersion Include="System.ComponentModel.Composition" Version="9.0.10" />
|
||||
<PackageVersion Include="System.Configuration.ConfigurationManager" Version="9.0.10" />
|
||||
<PackageVersion Include="System.Data.OleDb" Version="9.0.10" />
|
||||
<PackageVersion Include="System.ComponentModel.Composition" Version="9.0.8" />
|
||||
<PackageVersion Include="System.Configuration.ConfigurationManager" Version="9.0.8" />
|
||||
<PackageVersion Include="System.Data.OleDb" Version="9.0.8" />
|
||||
<!-- Package System.Data.SqlClient added to force it as a dependency of Microsoft.Windows.Compatibility to the latest version available at this time. -->
|
||||
<PackageVersion Include="System.Data.SqlClient" Version="4.9.0" />
|
||||
<!-- Package System.Diagnostics.EventLog added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Data.OleDb but the 8.0.1 version wasn't published to nuget. -->
|
||||
<PackageVersion Include="System.Diagnostics.EventLog" Version="9.0.10" />
|
||||
<PackageVersion Include="System.Diagnostics.EventLog" Version="9.0.8" />
|
||||
<!-- Package System.Diagnostics.PerformanceCounter added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.11. -->
|
||||
<PackageVersion Include="System.Diagnostics.PerformanceCounter" Version="9.0.10" />
|
||||
<PackageVersion Include="System.Diagnostics.PerformanceCounter" Version="9.0.8" />
|
||||
<PackageVersion Include="System.ClientModel" Version="1.7.0" />
|
||||
<PackageVersion Include="System.Drawing.Common" Version="9.0.10" />
|
||||
<PackageVersion Include="System.Drawing.Common" Version="9.0.8" />
|
||||
<PackageVersion Include="System.IO.Abstractions" Version="22.0.13" />
|
||||
<PackageVersion Include="System.IO.Abstractions.TestingHelpers" Version="22.0.13" />
|
||||
<PackageVersion Include="System.Management" Version="9.0.10" />
|
||||
<PackageVersion Include="System.Management" Version="9.0.8" />
|
||||
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
|
||||
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
|
||||
<PackageVersion Include="System.Reactive" Version="6.0.1" />
|
||||
<PackageVersion Include="System.Runtime.Caching" Version="9.0.10" />
|
||||
<PackageVersion Include="System.ServiceProcess.ServiceController" Version="9.0.10" />
|
||||
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.10" />
|
||||
<PackageVersion Include="System.Text.Json" Version="9.0.10" />
|
||||
<PackageVersion Include="System.Runtime.Caching" Version="9.0.8" />
|
||||
<PackageVersion Include="System.ServiceProcess.ServiceController" Version="9.0.8" />
|
||||
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.8" />
|
||||
<PackageVersion Include="System.Text.Json" Version="9.0.8" />
|
||||
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
|
||||
<PackageVersion Include="UnicodeInformation" Version="2.6.0" />
|
||||
<PackageVersion Include="UnitsNet" Version="5.56.0" />
|
||||
|
||||
@@ -822,8 +822,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.WebSea
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Shell.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.Shell.UnitTests\Microsoft.CmdPal.Ext.Shell.UnitTests.csproj", "{E816D7B4-4688-4ECB-97CC-3D8E798F3833}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CursorWrap", "src\modules\MouseUtils\CursorWrap\CursorWrap.vcxproj", "{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{3DCCD936-D085-4869-A1DE-CA6A64152C94}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightSwitch.UITests", "src\modules\LightSwitch\Tests\LightSwitch.UITests\LightSwitch.UITests.csproj", "{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}"
|
||||
@@ -2992,14 +2990,6 @@ Global
|
||||
{E816D7B4-4688-4ECB-97CC-3D8E798F3833}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{E816D7B4-4688-4ECB-97CC-3D8E798F3833}.Release|x64.ActiveCfg = Release|x64
|
||||
{E816D7B4-4688-4ECB-97CC-3D8E798F3833}.Release|x64.Build.0 = Release|x64
|
||||
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Debug|x64.Build.0 = Debug|x64
|
||||
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Release|x64.ActiveCfg = Release|x64
|
||||
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Release|x64.Build.0 = Release|x64
|
||||
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}.Debug|ARM64.Deploy.0 = Debug|ARM64
|
||||
@@ -3361,7 +3351,6 @@ Global
|
||||
{E816D7B3-4688-4ECB-97CC-3D8E798F3832} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
{E816D7B2-4688-4ECB-97CC-3D8E798F3831} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
{E816D7B4-4688-4ECB-97CC-3D8E798F3833} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5} = {322566EF-20DC-43A6-B9F8-616AF942579A}
|
||||
{3DCCD936-D085-4869-A1DE-CA6A64152C94} = {5B201255-53C8-490B-A34F-01F05D48A477}
|
||||
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F} = {3DCCD936-D085-4869-A1DE-CA6A64152C94}
|
||||
{4E0FCF69-B06B-D272-76BF-ED3A559B4EDA} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
|
||||
@@ -54,7 +54,6 @@
|
||||
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\CmdPal.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\CmdPal.wxs.bk""""
|
||||
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\ColorPicker.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\ColorPicker.wxs.bk""""
|
||||
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\Core.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\Core.wxs.bk""""
|
||||
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\DscResources.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\DscResources.wxs.bk""""
|
||||
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\EnvironmentVariables.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\EnvironmentVariables.wxs.bk""""
|
||||
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\FileExplorerPreview.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\FileExplorerPreview.wxs.bk""""
|
||||
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\FileLocksmith.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\FileLocksmith.wxs.bk""""
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="powertoys_env_path_user" Value="" KeyPath="yes" />
|
||||
</RegistryKey>
|
||||
<!-- Append DSCModules folder to current user's PATH for DSC v3 usage -->
|
||||
<Environment Id="AddPowerToysToUserPath" Name="PATH" Action="set" Part="last" System="no" Value="[DSCModulesReferenceFolder]" />
|
||||
<!-- Append install folder to current user's PATH -->
|
||||
<Environment Id="AddPowerToysToUserPath" Name="PATH" Action="set" Part="last" System="no" Value="[INSTALLFOLDER]" />
|
||||
</Component>
|
||||
<?else?>
|
||||
<Component Id="powertoys_env_path_machine" Bitness="always64">
|
||||
@@ -24,8 +24,8 @@
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="powertoys_env_path_machine" Value="" KeyPath="yes" />
|
||||
</RegistryKey>
|
||||
<!-- Append DSCModules folder to machine PATH for DSC v3 usage -->
|
||||
<Environment Id="AddPowerToysToMachinePath" Name="PATH" Action="set" Part="last" System="yes" Value="[DSCModulesReferenceFolder]" />
|
||||
<!-- Append install folder to machine PATH -->
|
||||
<Environment Id="AddPowerToysToMachinePath" Name="PATH" Action="set" Part="last" System="yes" Value="[INSTALLFOLDER]" />
|
||||
</Component>
|
||||
<?endif?>
|
||||
<Component Id="powertoys_toast_clsid" Bitness="always64">
|
||||
@@ -63,6 +63,16 @@
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<DirectoryRef Id="DSCModulesReferenceFolder">
|
||||
<Component Id="PowerToysDSCReference" Guid="40869ACB-0BEB-4911-AE41-5E73BC1586A9" Bitness="always64">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="DSCModulesReference" Value="" KeyPath="yes" />
|
||||
</RegistryKey>
|
||||
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version).0\Microsoft.PowerToys.Configure.psd1" Id="PTConfReference.psd1" />
|
||||
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version).0\Microsoft.PowerToys.Configure.psm1" Id="PTConfReference.psm1" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<?if $(var.PerUser) = "true" ?>
|
||||
<!-- DSC module files for PerUser handled in InstallDSCModule custom action. -->
|
||||
<?else?>
|
||||
@@ -110,6 +120,7 @@
|
||||
<RegistryValue Type="string" Name="RemoveCoreFolder" Value="" KeyPath="yes" />
|
||||
</RegistryKey>
|
||||
<RemoveFolder Id="RemoveBaseApplicationsAssetsFolder" Directory="BaseApplicationsAssetsFolder" On="uninstall" />
|
||||
<RemoveFolder Id="RemoveDSCModulesReferenceFolder" Directory="DSCModulesReferenceFolder" On="uninstall" />
|
||||
<RemoveFolder Id="RemoveWinUI3AppsInstallFolder" Directory="WinUI3AppsInstallFolder" On="uninstall" />
|
||||
<RemoveFolder Id="RemoveWinUI3AppsAssetsFolder" Directory="WinUI3AppsAssetsFolder" On="uninstall" />
|
||||
<RemoveFolder Id="RemoveINSTALLFOLDER" Directory="INSTALLFOLDER" On="uninstall" />
|
||||
@@ -117,15 +128,16 @@
|
||||
<ComponentRef Id="powertoys_exe" />
|
||||
<ComponentRef Id="PowerToysStartMenuShortcut" />
|
||||
<ComponentRef Id="powertoys_per_machine_comp" />
|
||||
<?if $(var.PerUser) = "true" ?>
|
||||
<ComponentRef Id="powertoys_env_path_user" />
|
||||
<?else?>
|
||||
<ComponentRef Id="powertoys_env_path_machine" />
|
||||
<?endif?>
|
||||
<ComponentRef Id="powertoys_toast_clsid" />
|
||||
<ComponentRef Id="License_rtf" />
|
||||
<ComponentRef Id="Notice_md" />
|
||||
<ComponentRef Id="DesktopShortcut" />
|
||||
<?if $(var.PerUser) = "true" ?>
|
||||
<ComponentRef Id="powertoys_env_path_user" />
|
||||
<?else?>
|
||||
<ComponentRef Id="powertoys_env_path_machine" />
|
||||
<?endif?>
|
||||
<ComponentRef Id="PowerToysDSCReference" />
|
||||
<?if $(var.PerUser) = "false" ?>
|
||||
<ComponentRef Id="PowerToysDSC" />
|
||||
<?endif?>
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
|
||||
|
||||
<?include $(sys.CURRENTDIR)\Common.wxi?>
|
||||
|
||||
<?define DscJsonFiles=?>
|
||||
<?define DscJsonFilesPath=$(var.BinDir)\DSCModules?>
|
||||
|
||||
<Fragment>
|
||||
<DirectoryRef Id="DSCModulesReferenceFolder" FileSource="$(var.DscJsonFilesPath)">
|
||||
<!-- DSC v2 PowerShell module files -->
|
||||
<Component Id="PowerToysDSCReference" Guid="40869ACB-0BEB-4911-AE41-5E73BC1586A9" Bitness="always64">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="DSCModulesReference" Value="" KeyPath="yes" />
|
||||
</RegistryKey>
|
||||
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version).0\Microsoft.PowerToys.Configure.psd1" Id="PTConfReference.psd1" />
|
||||
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version).0\Microsoft.PowerToys.Configure.psm1" Id="PTConfReference.psm1" />
|
||||
</Component>
|
||||
|
||||
<!-- DSC v3 JSON manifest files - Generated by generateAllFileComponents.ps1 -->
|
||||
<!--DscJsonFiles_Component_Def-->
|
||||
</DirectoryRef>
|
||||
|
||||
<ComponentGroup Id="DscResourcesComponentGroup">
|
||||
<ComponentRef Id="PowerToysDSCReference" />
|
||||
<Component Id="RemoveDSCModulesFolder" Guid="A3C77D92-4E97-4C1A-9F2E-8B3C5D6E7F80" Directory="DSCModulesReferenceFolder">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="RemoveDSCModulesFolder" Value="" KeyPath="yes" />
|
||||
</RegistryKey>
|
||||
<RemoveFolder Id="RemoveDSCModulesReferenceFolder" Directory="DSCModulesReferenceFolder" On="uninstall" />
|
||||
</Component>
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
||||
@@ -14,6 +14,7 @@ SET PTRoot=$(SolutionDir)\..
|
||||
call "..\..\..\publish.cmd" x64
|
||||
)
|
||||
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateMonacoWxs.ps1 -monacoWxsFile "$(MSBuildThisFileDirectory)\MonacoSRC.wxs" -Platform "$(Platform)" -nugetHeatPath "$(NUGET_PACKAGES)\wixtoolset.heat\5.0.2"
|
||||
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateDscResourcesWxs.ps1 -dscWxsFile "$(MSBuildThisFileDirectory)\DscResources.wxs" -Platform "$(Platform)" -Configuration "$(Configuration)"
|
||||
</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Platform)' != 'x64'">
|
||||
@@ -24,6 +25,7 @@ SET PTRoot=$(SolutionDir)\..
|
||||
call "..\..\..\publish.cmd" arm64
|
||||
)
|
||||
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateMonacoWxs.ps1 -monacoWxsFile "$(MSBuildThisFileDirectory)\MonacoSRC.wxs" -Platform "$(Platform)" -nugetHeatPath "$(NUGET_PACKAGES)\wixtoolset.heat\5.0.2"
|
||||
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateDscResourcesWxs.ps1 -dscWxsFile "$(MSBuildThisFileDirectory)\DscResources.wxs" -Platform "$(Platform)" -Configuration "$(Configuration)"
|
||||
</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
@@ -35,7 +37,6 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
|
||||
call move /Y ..\..\..\CmdPal.wxs.bk ..\..\..\CmdPal.wxs
|
||||
call move /Y ..\..\..\ColorPicker.wxs.bk ..\..\..\ColorPicker.wxs
|
||||
call move /Y ..\..\..\Core.wxs.bk ..\..\..\Core.wxs
|
||||
call move /Y ..\..\..\DscResources.wxs.bk ..\..\..\DscResources.wxs
|
||||
call move /Y ..\..\..\EnvironmentVariables.wxs.bk ..\..\..\EnvironmentVariables.wxs
|
||||
call move /Y ..\..\..\FileExplorerPreview.wxs.bk ..\..\..\FileExplorerPreview.wxs
|
||||
call move /Y ..\..\..\FileLocksmith.wxs.bk ..\..\..\FileLocksmith.wxs
|
||||
|
||||
@@ -317,7 +317,3 @@ Generate-FileComponents -fileListName "SettingsV2IconsModelsFiles" -wxsFilePath
|
||||
#Workspaces
|
||||
Generate-FileList -fileDepsJson "" -fileListName WorkspacesImagesComponentFiles -wxsFilePath $PSScriptRoot\Workspaces.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\Workspaces\"
|
||||
Generate-FileComponents -fileListName "WorkspacesImagesComponentFiles" -wxsFilePath $PSScriptRoot\Workspaces.wxs
|
||||
|
||||
#DSC Resources - JSON manifest files in DSCModules subfolder
|
||||
Generate-FileList -fileDepsJson "" -fileListName DscJsonFiles -wxsFilePath $PSScriptRoot\DscResources.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\DSCModules\"
|
||||
Generate-FileComponents -fileListName "DscJsonFiles" -wxsFilePath $PSScriptRoot\DscResources.wxs
|
||||
|
||||
102
installer/PowerToysSetupVNext/generateDscResourcesWxs.ps1
Normal file
102
installer/PowerToysSetupVNext/generateDscResourcesWxs.ps1
Normal file
@@ -0,0 +1,102 @@
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[Parameter(Mandatory = $True)]
|
||||
[string]$dscWxsFile,
|
||||
[Parameter(Mandatory = $True)]
|
||||
[string]$Platform,
|
||||
[Parameter(Mandatory = $True)]
|
||||
[string]$Configuration
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
|
||||
# Find build output directory
|
||||
$buildOutputDir = Join-Path $scriptDir "..\..\$Platform\$Configuration"
|
||||
|
||||
if (-not (Test-Path $buildOutputDir)) {
|
||||
Write-Error "Build output directory not found: '$buildOutputDir'"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Find all DSC manifest JSON files
|
||||
$dscFiles = Get-ChildItem -Path $buildOutputDir -Filter "microsoft.powertoys.*.settings.dsc.resource.json" -File
|
||||
|
||||
if (-not $dscFiles) {
|
||||
Write-Warning "No DSC manifest files found in '$buildOutputDir'"
|
||||
# Create empty component group
|
||||
$wxsContent = @"
|
||||
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
|
||||
|
||||
<?include `$(sys.CURRENTDIR)\Common.wxi?>
|
||||
|
||||
<Fragment>
|
||||
<ComponentGroup Id="DscResourcesComponentGroup">
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
||||
"@
|
||||
Set-Content -Path $dscWxsFile -Value $wxsContent
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "Found $($dscFiles.Count) DSC manifest file(s)"
|
||||
|
||||
# Generate WiX fragment
|
||||
$wxsContent = @"
|
||||
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
|
||||
|
||||
<?include `$(sys.CURRENTDIR)\Common.wxi?>
|
||||
|
||||
<Fragment>
|
||||
<DirectoryRef Id="DSCModulesReferenceFolder">
|
||||
"@
|
||||
|
||||
$componentRefs = @()
|
||||
|
||||
foreach ($file in $dscFiles) {
|
||||
$componentId = "DscResource_" + ($file.BaseName -replace '[^A-Za-z0-9_]', '_')
|
||||
$fileId = $componentId + "_File"
|
||||
$guid = [System.Guid]::NewGuid().ToString().ToUpper()
|
||||
|
||||
$componentRefs += $componentId
|
||||
|
||||
$wxsContent += @"
|
||||
|
||||
<Component Id="$componentId" Guid="{$guid}" Directory="DSCModulesReferenceFolder">
|
||||
<RegistryKey Root="`$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="$componentId" Value="" KeyPath="yes"/>
|
||||
</RegistryKey>
|
||||
<File Id="$fileId" Source="`$(var.BinDir)$($file.Name)" Vital="no"/>
|
||||
</Component>
|
||||
"@
|
||||
}
|
||||
|
||||
$wxsContent += @"
|
||||
|
||||
</DirectoryRef>
|
||||
</Fragment>
|
||||
|
||||
<Fragment>
|
||||
<ComponentGroup Id="DscResourcesComponentGroup">
|
||||
"@
|
||||
|
||||
foreach ($componentId in $componentRefs) {
|
||||
$wxsContent += @"
|
||||
|
||||
<ComponentRef Id="$componentId"/>
|
||||
"@
|
||||
}
|
||||
|
||||
$wxsContent += @"
|
||||
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
||||
"@
|
||||
|
||||
# Write the WiX file
|
||||
Set-Content -Path $dscWxsFile -Value $wxsContent
|
||||
|
||||
Write-Host "Generated DSC resources WiX fragment: '$dscWxsFile'"
|
||||
@@ -112,10 +112,6 @@ namespace winrt::PowerToys::GPOWrapper::implementation
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredMousePointerCrosshairsEnabledValue());
|
||||
}
|
||||
GpoRuleConfigured GPOWrapper::GetConfiguredCursorWrapEnabledValue()
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredCursorWrapEnabledValue());
|
||||
}
|
||||
GpoRuleConfigured GPOWrapper::GetConfiguredPowerRenameEnabledValue()
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredPowerRenameEnabledValue());
|
||||
|
||||
@@ -35,7 +35,6 @@ namespace winrt::PowerToys::GPOWrapper::implementation
|
||||
static GpoRuleConfigured GetConfiguredMouseHighlighterEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredMouseJumpEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredMousePointerCrosshairsEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredCursorWrapEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredPowerRenameEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredPowerLauncherEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredQuickAccentEnabledValue();
|
||||
|
||||
@@ -38,7 +38,6 @@ namespace PowerToys
|
||||
static GpoRuleConfigured GetConfiguredMouseHighlighterEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredMouseJumpEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredMousePointerCrosshairsEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredCursorWrapEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredMouseWithoutBordersEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredPowerRenameEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredPowerLauncherEnabledValue();
|
||||
|
||||
@@ -12,7 +12,6 @@ namespace ManagedCommon
|
||||
ColorPicker,
|
||||
CmdPal,
|
||||
CropAndLock,
|
||||
CursorWrap,
|
||||
EnvironmentVariables,
|
||||
FancyZones,
|
||||
FileLocksmith,
|
||||
|
||||
@@ -1,175 +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.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
||||
|
||||
namespace Microsoft.PowerToys.UITest
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class for configuring PowerToys settings for UI tests.
|
||||
/// </summary>
|
||||
public class SettingsConfigHelper
|
||||
{
|
||||
private static readonly JsonSerializerOptions IndentedJsonOptions = new() { WriteIndented = true };
|
||||
private static readonly SettingsUtils SettingsUtils = new SettingsUtils();
|
||||
|
||||
/// <summary>
|
||||
/// Configures global PowerToys settings to enable only specified modules and disable all others.
|
||||
/// </summary>
|
||||
/// <param name="modulesToEnable">Array of module names to enable (e.g., "Peek", "FancyZones"). All other modules will be disabled.</param>
|
||||
/// <exception cref="ArgumentNullException">Thrown when modulesToEnable is null.</exception>
|
||||
/// <exception cref="InvalidOperationException">Thrown when settings file operations fail.</exception>
|
||||
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "This is test code and will not be trimmed")]
|
||||
[UnconditionalSuppressMessage("AOT", "IL3050", Justification = "This is test code and will not be AOT compiled")]
|
||||
public static void ConfigureGlobalModuleSettings(params string[] modulesToEnable)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(modulesToEnable);
|
||||
|
||||
try
|
||||
{
|
||||
GeneralSettings settings;
|
||||
try
|
||||
{
|
||||
settings = SettingsUtils.GetSettingsOrDefault<GeneralSettings>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"Failed to load settings, creating defaults: {ex.Message}");
|
||||
settings = new GeneralSettings();
|
||||
}
|
||||
|
||||
string settingsJson = settings.ToJsonString();
|
||||
using (JsonDocument doc = JsonDocument.Parse(settingsJson))
|
||||
{
|
||||
var options = new JsonSerializerOptions { WriteIndented = true };
|
||||
var root = doc.RootElement.Clone();
|
||||
|
||||
if (root.TryGetProperty("enabled", out var enabledElement))
|
||||
{
|
||||
var enabledModules = new Dictionary<string, bool>();
|
||||
|
||||
foreach (var property in enabledElement.EnumerateObject())
|
||||
{
|
||||
string moduleName = property.Name;
|
||||
|
||||
bool shouldEnable = Array.Exists(modulesToEnable, m => string.Equals(m, moduleName, StringComparison.Ordinal));
|
||||
enabledModules[moduleName] = shouldEnable;
|
||||
}
|
||||
|
||||
var settingsDict = JsonSerializer.Deserialize<Dictionary<string, object>>(settingsJson);
|
||||
if (settingsDict != null)
|
||||
{
|
||||
settingsDict["enabled"] = enabledModules;
|
||||
settingsJson = JsonSerializer.Serialize(settingsDict, IndentedJsonOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsUtils.SaveSettings(settingsJson);
|
||||
|
||||
string enabledList = modulesToEnable.Length > 0 ? string.Join(", ", modulesToEnable) : "none";
|
||||
Debug.WriteLine($"Successfully updated global settings");
|
||||
Debug.WriteLine($"Enabled modules: {enabledList}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"ERROR in ConfigureGlobalModuleSettings: {ex.Message}");
|
||||
throw new InvalidOperationException($"Failed to configure global module settings: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates a module's settings file. If the file doesn't exist, creates it with default content.
|
||||
/// If the file exists, reads it and applies the provided update function to modify the settings.
|
||||
/// </summary>
|
||||
/// <param name="moduleName">The name of the module (e.g., "Peek", "FancyZones").</param>
|
||||
/// <param name="defaultSettingsContent">The default JSON content to use if the settings file doesn't exist.</param>
|
||||
/// <param name="updateSettingsAction">
|
||||
/// A callback function that modifies the settings dictionary. The function receives the deserialized settings
|
||||
/// and should modify it in-place. The function should accept a Dictionary<string, object> and not return a value.
|
||||
/// Example: (settings) => { ((Dictionary<string, object>)settings["properties"])["SomeSetting"] = newValue; }
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">Thrown when moduleName or updateSettingsAction is null.</exception>
|
||||
/// <exception cref="InvalidOperationException">Thrown when settings file operations fail.</exception>
|
||||
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "This is test code and will not be trimmed")]
|
||||
[UnconditionalSuppressMessage("AOT", "IL3050", Justification = "This is test code and will not be AOT compiled")]
|
||||
public static void UpdateModuleSettings(
|
||||
string moduleName,
|
||||
string defaultSettingsContent,
|
||||
Action<Dictionary<string, object>> updateSettingsAction)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(moduleName);
|
||||
ArgumentNullException.ThrowIfNull(updateSettingsAction);
|
||||
|
||||
try
|
||||
{
|
||||
// Build the path to the module settings file
|
||||
string powerToysSettingsDirectory = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||
"Microsoft",
|
||||
"PowerToys");
|
||||
|
||||
string moduleDirectory = Path.Combine(powerToysSettingsDirectory, moduleName);
|
||||
string settingsPath = Path.Combine(moduleDirectory, "settings.json");
|
||||
|
||||
// Ensure directory exists
|
||||
Directory.CreateDirectory(moduleDirectory);
|
||||
|
||||
// Read existing settings or use default
|
||||
string existingJson = string.Empty;
|
||||
if (File.Exists(settingsPath))
|
||||
{
|
||||
existingJson = File.ReadAllText(settingsPath);
|
||||
}
|
||||
|
||||
Dictionary<string, object>? settings;
|
||||
|
||||
// If file doesn't exist or is empty, create from defaults
|
||||
if (string.IsNullOrWhiteSpace(existingJson))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(defaultSettingsContent))
|
||||
{
|
||||
throw new ArgumentException("Default settings content must be provided when file doesn't exist.", nameof(defaultSettingsContent));
|
||||
}
|
||||
|
||||
settings = JsonSerializer.Deserialize<Dictionary<string, object>>(defaultSettingsContent)
|
||||
?? throw new InvalidOperationException($"Failed to deserialize default settings for {moduleName}");
|
||||
|
||||
Debug.WriteLine($"Created default settings for {moduleName} at {settingsPath}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Parse existing settings
|
||||
settings = JsonSerializer.Deserialize<Dictionary<string, object>>(existingJson)
|
||||
?? throw new InvalidOperationException($"Failed to deserialize existing settings for {moduleName}");
|
||||
|
||||
Debug.WriteLine($"Loaded existing settings for {moduleName} from {settingsPath}");
|
||||
}
|
||||
|
||||
// Apply the update action to modify settings
|
||||
updateSettingsAction(settings);
|
||||
|
||||
// Serialize and save the updated settings using SettingsUtils
|
||||
string updatedJson = JsonSerializer.Serialize(settings, IndentedJsonOptions);
|
||||
SettingsUtils.SaveSettings(updatedJson, moduleName);
|
||||
|
||||
Debug.WriteLine($"Successfully updated settings for {moduleName}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"ERROR in UpdateModuleSettings for {moduleName}: {ex.Message}");
|
||||
throw new InvalidOperationException($"Failed to update settings for {moduleName}: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<PublishAot>true</PublishAot>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
<TargetFramework>net9.0-windows10.0.26100.0</TargetFramework>
|
||||
<TargetFramework>net9.0-windows10.0.22621.0</TargetFramework>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<PublishTrimmed>false</PublishTrimmed>
|
||||
</PropertyGroup>
|
||||
@@ -21,8 +21,4 @@
|
||||
<PackageReference Include="CoenM.ImageSharp.ImageHash" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -59,7 +59,6 @@ struct LogSettings
|
||||
inline const static std::string mouseHighlighterLoggerName = "mouse-highlighter";
|
||||
inline const static std::string mouseJumpLoggerName = "mouse-jump";
|
||||
inline const static std::string mousePointerCrosshairsLoggerName = "mouse-pointer-crosshairs";
|
||||
inline const static std::string cursorWrapLoggerName = "cursor-wrap";
|
||||
inline const static std::string imageResizerLoggerName = "imageresizer";
|
||||
inline const static std::string powerRenameLoggerName = "powerrename";
|
||||
inline const static std::string alwaysOnTopLoggerName = "always-on-top";
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <Windows.h>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace powertoys_gpo
|
||||
{
|
||||
@@ -52,7 +51,6 @@ namespace powertoys_gpo
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_HIGHLIGHTER = L"ConfigureEnabledUtilityMouseHighlighter";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_JUMP = L"ConfigureEnabledUtilityMouseJump";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_POINTER_CROSSHAIRS = L"ConfigureEnabledUtilityMousePointerCrosshairs";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_CURSOR_WRAP = L"ConfigureEnabledUtilityCursorWrap";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_POWER_RENAME = L"ConfigureEnabledUtilityPowerRename";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_POWER_LAUNCHER = L"ConfigureEnabledUtilityPowerLauncher";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_QUICK_ACCENT = L"ConfigureEnabledUtilityQuickAccent";
|
||||
@@ -411,11 +409,6 @@ namespace powertoys_gpo
|
||||
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_MOUSE_POINTER_CROSSHAIRS);
|
||||
}
|
||||
|
||||
inline gpo_rule_configured_t getConfiguredCursorWrapEnabledValue()
|
||||
{
|
||||
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_CURSOR_WRAP);
|
||||
}
|
||||
|
||||
inline gpo_rule_configured_t getConfiguredPowerRenameEnabledValue()
|
||||
{
|
||||
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_POWER_RENAME);
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace PowerToys.DSC.Models;
|
||||
public sealed class DscManifest
|
||||
{
|
||||
private const string Schema = "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.vscode.json";
|
||||
private const string Executable = @"..\PowerToys.DSC.exe";
|
||||
private const string Executable = @"PowerToys.DSC.exe";
|
||||
|
||||
private readonly string _type;
|
||||
private readonly string _version;
|
||||
|
||||
@@ -40,11 +40,9 @@
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Generate the DSC resource JSON files to DSCModules subfolder -->
|
||||
<!-- Skip generation in CI/CD builds (CIBuild=true) to avoid unnecessary work during pipeline -->
|
||||
<Target Name="GenerateDscResourceJsonFiles" AfterTargets="Build" Condition="'$(CIBuild)' != 'true'">
|
||||
<Message Text="Generating DSC resource JSON files to DSCModules subfolder..." Importance="high" />
|
||||
<MakeDir Directories="$(TargetDir)DSCModules" />
|
||||
<Exec Command="dotnet "$(TargetPath)" manifest --resource settings --outputDir "$(TargetDir)DSCModules"" />
|
||||
<!-- In debug mode, generate the DSC resource JSON files -->
|
||||
<Target Name="GenerateDscResourceJsonFiles" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug'">
|
||||
<Message Text="Generating DSC resource JSON files inside ..." Importance="high" />
|
||||
<Exec Command="dotnet "$(TargetPath)" manifest --resource settings --outputDir "$(TargetDir)\"" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -14,13 +14,28 @@
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
|
||||
<LinearGradientBrush x:Name="IntelligentUnderlineGradient" StartPoint="0,0.5" EndPoint="1,0.5">
|
||||
<GradientStop Offset="0.0" Color="#FF0078D4" />
|
||||
<GradientStop Offset="0.42" Color="#FF464FEB" />
|
||||
<GradientStop Offset="0.87" Color="#FFD660FF" />
|
||||
<GradientStop Offset="1.0" Color="#FFFEA874" />
|
||||
</LinearGradientBrush>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Default">
|
||||
<Color x:Key="AccentGradientColor">#65C8F2</Color>
|
||||
<LinearGradientBrush x:Key="AccentGradientBrush" StartPoint="0,0" EndPoint="1,1">
|
||||
<GradientStop Offset="0.0" Color="#98EFFE" />
|
||||
<GradientStop Offset="0.25" Color="#48B1E9" />
|
||||
<GradientStop Offset="1.0" Color="{StaticResource AccentGradientColor}" />
|
||||
</LinearGradientBrush>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<Color x:Key="AccentGradientColor">#005FB8</Color>
|
||||
<LinearGradientBrush x:Key="AccentGradientBrush" StartPoint="0,0" EndPoint="1,1">
|
||||
<GradientStop Offset="0.0" Color="#4992C7" />
|
||||
<GradientStop Offset="0.25" Color="#1353A0" />
|
||||
<GradientStop Offset="1.0" Color="{StaticResource AccentGradientColor}" />
|
||||
</LinearGradientBrush>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<Color x:Key="AccentGradientColor">#48B1E9</Color>
|
||||
<SolidColorBrush x:Key="AccentGradientBrush" Color="{StaticResource AccentGradientColor}" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
<x:Double x:Key="ModelSelectorButtonWidth">44</x:Double>
|
||||
<Style x:Key="CustomTextBoxStyle" TargetType="TextBox">
|
||||
<Setter Property="Foreground" Value="{ThemeResource TextControlForeground}" />
|
||||
@@ -156,19 +171,6 @@
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Control.IsTemplateFocusTarget="True"
|
||||
CornerRadius="{TemplateBinding CornerRadius}" />
|
||||
<Rectangle
|
||||
x:Name="FocusHighlighter"
|
||||
Grid.Row="1"
|
||||
Grid.RowSpan="1"
|
||||
Grid.ColumnSpan="4"
|
||||
Height="2"
|
||||
Margin="12,0,12,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Bottom"
|
||||
Fill="{StaticResource IntelligentUnderlineGradient}"
|
||||
RadiusX="1"
|
||||
RadiusY="1"
|
||||
Visibility="Collapsed" />
|
||||
<Grid Grid.Row="1" Width="{StaticResource ModelSelectorButtonWidth}">
|
||||
<ProgressRing
|
||||
Width="20"
|
||||
@@ -280,10 +282,7 @@
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBackgroundFocused}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="FocusHighlighter" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<!--<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderBrush">
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<LinearGradientBrush MappingMode="Absolute" StartPoint="0,0" EndPoint="0,2">
|
||||
@@ -300,7 +299,7 @@
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderThickness">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBorderThemeThicknessFocused}" />
|
||||
</ObjectAnimationUsingKeyFrames>-->
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentElement" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlForegroundFocused}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
@@ -542,10 +541,7 @@
|
||||
Source="{x:Bind ViewModel.ActiveAIProvider?.ServiceType, Mode=OneWay, Converter={StaticResource ServiceTypeToIconConverter}}" />
|
||||
</DropDownButton.Content>
|
||||
<DropDownButton.Flyout>
|
||||
<Flyout
|
||||
Opened="AIProviderFlyout_Opened"
|
||||
Placement="Bottom"
|
||||
ShouldConstrainToRootBounds="False">
|
||||
<Flyout Placement="Bottom" ShouldConstrainToRootBounds="False">
|
||||
<Grid
|
||||
Width="386"
|
||||
Margin="-4"
|
||||
@@ -744,8 +740,8 @@
|
||||
x:Name="LoadingText"
|
||||
x:Uid="LoadingText"
|
||||
Grid.Row="1"
|
||||
Margin="4,4,0,0"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource AccentGradientBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Visibility="Collapsed">
|
||||
<animations:Implicit.ShowAnimations>
|
||||
|
||||
@@ -22,8 +22,6 @@ namespace AdvancedPaste.Controls
|
||||
{
|
||||
public OptionsViewModel ViewModel { get; private set; }
|
||||
|
||||
private bool _syncingProviderSelection;
|
||||
|
||||
public static readonly DependencyProperty PlaceholderTextProperty = DependencyProperty.Register(
|
||||
nameof(PlaceholderText),
|
||||
typeof(string),
|
||||
@@ -76,11 +74,6 @@ namespace AdvancedPaste.Controls
|
||||
var state = ViewModel.IsBusy ? "LoadingState" : ViewModel.PasteActionError.HasText ? "ErrorState" : "DefaultState";
|
||||
VisualStateManager.GoToState(this, state, true);
|
||||
}
|
||||
|
||||
if (e.PropertyName is nameof(ViewModel.ActiveAIProvider) or nameof(ViewModel.AIProviders))
|
||||
{
|
||||
SyncProviderSelection();
|
||||
}
|
||||
}
|
||||
|
||||
private void ViewModel_PreviewRequested(object sender, EventArgs e)
|
||||
@@ -94,7 +87,6 @@ namespace AdvancedPaste.Controls
|
||||
private void Grid_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
InputTxtBox.Focus(FocusState.Programmatic);
|
||||
SyncProviderSelection();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
@@ -134,56 +126,18 @@ namespace AdvancedPaste.Controls
|
||||
Loader.IsLoading = loading;
|
||||
}
|
||||
|
||||
private void SyncProviderSelection()
|
||||
{
|
||||
if (AIProviderListView is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_syncingProviderSelection = true;
|
||||
AIProviderListView.SelectedItem = ViewModel.ActiveAIProvider;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_syncingProviderSelection = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void AIProviderFlyout_Opened(object sender, object e)
|
||||
{
|
||||
SyncProviderSelection();
|
||||
}
|
||||
|
||||
private async void AIProviderListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (_syncingProviderSelection)
|
||||
if (AIProviderListView.SelectedItem is PasteAIProviderDefinition provider)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (ViewModel.SetActiveProviderCommand.CanExecute(provider))
|
||||
{
|
||||
await ViewModel.SetActiveProviderCommand.ExecuteAsync(provider);
|
||||
}
|
||||
|
||||
var flyout = FlyoutBase.GetAttachedFlyout(AIProviderButton);
|
||||
|
||||
if (AIProviderListView.SelectedItem is not PasteAIProviderDefinition provider)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(ViewModel.ActiveAIProvider?.Id, provider.Id, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var flyout = FlyoutBase.GetAttachedFlyout(AIProviderButton);
|
||||
flyout?.Hide();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ViewModel.SetActiveProviderCommand.CanExecute(provider))
|
||||
{
|
||||
await ViewModel.SetActiveProviderCommand.ExecuteAsync(provider);
|
||||
SyncProviderSelection();
|
||||
}
|
||||
|
||||
flyout?.Hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,15 +280,13 @@
|
||||
x:Uid="TermsLink"
|
||||
Padding="0"
|
||||
FontSize="12"
|
||||
NavigateUri="{x:Bind ViewModel.TermsLinkUri, Mode=OneWay}"
|
||||
Visibility="{x:Bind ViewModel.HasTermsLink, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
NavigateUri="https://openai.com/policies/terms-of-use" />
|
||||
<HyperlinkButton
|
||||
x:Name="PrivacyHyperLink"
|
||||
x:Uid="PrivacyLink"
|
||||
Padding="0"
|
||||
FontSize="12"
|
||||
NavigateUri="{x:Bind ViewModel.PrivacyLinkUri, Mode=OneWay}"
|
||||
Visibility="{x:Bind ViewModel.HasPrivacyLink, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
NavigateUri="https://openai.com/policies/privacy-policy" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Flyout>
|
||||
|
||||
@@ -71,11 +71,6 @@ namespace AdvancedPaste.ViewModels
|
||||
[NotifyPropertyChangedFor(nameof(IsCustomAIAvailable))]
|
||||
[NotifyPropertyChangedFor(nameof(AllowedAIProviders))]
|
||||
[NotifyPropertyChangedFor(nameof(ActiveAIProvider))]
|
||||
[NotifyPropertyChangedFor(nameof(ActiveAIProviderTooltip))]
|
||||
[NotifyPropertyChangedFor(nameof(TermsLinkUri))]
|
||||
[NotifyPropertyChangedFor(nameof(PrivacyLinkUri))]
|
||||
[NotifyPropertyChangedFor(nameof(HasTermsLink))]
|
||||
[NotifyPropertyChangedFor(nameof(HasPrivacyLink))]
|
||||
private bool _isAllowedByGPO;
|
||||
|
||||
[ObservableProperty]
|
||||
@@ -192,35 +187,6 @@ namespace AdvancedPaste.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
private AIServiceTypeMetadata GetActiveProviderMetadata()
|
||||
{
|
||||
var provider = ActiveAIProvider ?? AllowedAIProviders.FirstOrDefault();
|
||||
var serviceType = provider?.ServiceTypeKind ?? AIServiceType.OpenAI;
|
||||
return AIServiceTypeRegistry.GetMetadata(serviceType);
|
||||
}
|
||||
|
||||
public Uri TermsLinkUri
|
||||
{
|
||||
get
|
||||
{
|
||||
var metadata = GetActiveProviderMetadata();
|
||||
return metadata.HasTermsLink ? metadata.TermsUri : null;
|
||||
}
|
||||
}
|
||||
|
||||
public Uri PrivacyLinkUri
|
||||
{
|
||||
get
|
||||
{
|
||||
var metadata = GetActiveProviderMetadata();
|
||||
return metadata.HasPrivacyLink ? metadata.PrivacyUri : null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasTermsLink => GetActiveProviderMetadata().HasTermsLink;
|
||||
|
||||
public bool HasPrivacyLink => GetActiveProviderMetadata().HasPrivacyLink;
|
||||
|
||||
public bool ClipboardHasData => AvailableClipboardFormats != ClipboardFormat.None;
|
||||
|
||||
public bool ClipboardHasDataForCustomAI => PasteFormat.SupportsClipboardFormats(CustomAIFormat, AvailableClipboardFormats);
|
||||
@@ -310,8 +276,8 @@ namespace AdvancedPaste.ViewModels
|
||||
OnPropertyChanged(nameof(IsAdvancedAIEnabled));
|
||||
OnPropertyChanged(nameof(AIProviders));
|
||||
OnPropertyChanged(nameof(AllowedAIProviders));
|
||||
|
||||
NotifyActiveProviderChanged();
|
||||
OnPropertyChanged(nameof(ActiveAIProvider));
|
||||
OnPropertyChanged(nameof(ActiveAIProviderTooltip));
|
||||
|
||||
EnqueueRefreshPasteFormats();
|
||||
}
|
||||
@@ -350,17 +316,8 @@ namespace AdvancedPaste.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
NotifyActiveProviderChanged();
|
||||
}
|
||||
|
||||
private void NotifyActiveProviderChanged()
|
||||
{
|
||||
OnPropertyChanged(nameof(ActiveAIProvider));
|
||||
OnPropertyChanged(nameof(ActiveAIProviderTooltip));
|
||||
OnPropertyChanged(nameof(TermsLinkUri));
|
||||
OnPropertyChanged(nameof(PrivacyLinkUri));
|
||||
OnPropertyChanged(nameof(HasTermsLink));
|
||||
OnPropertyChanged(nameof(HasPrivacyLink));
|
||||
}
|
||||
|
||||
private void RefreshPasteFormats()
|
||||
@@ -880,7 +837,6 @@ namespace AdvancedPaste.ViewModels
|
||||
|
||||
UpdateAIProviderActiveFlags();
|
||||
OnPropertyChanged(nameof(AIProviders));
|
||||
NotifyActiveProviderChanged();
|
||||
EnqueueRefreshPasteFormats();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <logger/logger_settings.h>
|
||||
#include <logger/logger.h>
|
||||
#include <utils/logger_helper.h>
|
||||
#include <LightSwitchServiceObserver.h>
|
||||
|
||||
SERVICE_STATUS g_ServiceStatus = {};
|
||||
SERVICE_STATUS_HANDLE g_StatusHandle = nullptr;
|
||||
@@ -19,7 +20,6 @@ extern int g_lastUpdatedDay = -1;
|
||||
static ScheduleMode prevMode = ScheduleMode::Off;
|
||||
static std::wstring prevLat, prevLon;
|
||||
static int prevMinutes = -1;
|
||||
static bool lastOverrideStatus = false;
|
||||
|
||||
VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv);
|
||||
VOID WINAPI ServiceCtrlHandler(DWORD dwCtrl);
|
||||
@@ -164,8 +164,48 @@ DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
|
||||
|
||||
LightSwitchSettings::instance().InitFileWatcher();
|
||||
|
||||
LightSwitchServiceObserver observer({ SettingId::LightTime,
|
||||
SettingId::DarkTime,
|
||||
SettingId::ScheduleMode,
|
||||
SettingId::Sunrise_Offset,
|
||||
SettingId::Sunset_Offset });
|
||||
|
||||
HANDLE hManualOverride = OpenEventW(SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, L"POWERTOYS_LIGHTSWITCH_MANUAL_OVERRIDE");
|
||||
|
||||
auto applyTheme = [](int nowMinutes, int lightMinutes, int darkMinutes, const auto& settings) {
|
||||
bool isLightActive = (lightMinutes < darkMinutes) ? (nowMinutes >= lightMinutes && nowMinutes < darkMinutes) : (nowMinutes >= lightMinutes || nowMinutes < darkMinutes);
|
||||
|
||||
bool isSystemCurrentlyLight = GetCurrentSystemTheme();
|
||||
bool isAppsCurrentlyLight = GetCurrentAppsTheme();
|
||||
|
||||
if (isLightActive)
|
||||
{
|
||||
if (settings.changeSystem && !isSystemCurrentlyLight)
|
||||
{
|
||||
SetSystemTheme(true);
|
||||
Logger::info(L"[LightSwitchService] Changing system theme to light mode.");
|
||||
}
|
||||
if (settings.changeApps && !isAppsCurrentlyLight)
|
||||
{
|
||||
SetAppsTheme(true);
|
||||
Logger::info(L"[LightSwitchService] Changing apps theme to light mode.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (settings.changeSystem && isSystemCurrentlyLight)
|
||||
{
|
||||
SetSystemTheme(false);
|
||||
Logger::info(L"[LightSwitchService] Changing system theme to dark mode.");
|
||||
}
|
||||
if (settings.changeApps && isAppsCurrentlyLight)
|
||||
{
|
||||
SetAppsTheme(false);
|
||||
Logger::info(L"[LightSwitchService] Changing apps theme to dark mode.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
LightSwitchSettings::instance().LoadSettings();
|
||||
auto& settings = LightSwitchSettings::instance().settings();
|
||||
|
||||
@@ -173,22 +213,22 @@ DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
|
||||
GetLocalTime(&st);
|
||||
int nowMinutes = st.wHour * 60 + st.wMinute;
|
||||
|
||||
// Handle initial theme application if necessary
|
||||
if (settings.scheduleMode != ScheduleMode::Off)
|
||||
{
|
||||
Logger::info(L"[LightSwitchService] Schedule mode is set to {}. Applying theme if necessary.", settings.scheduleMode);
|
||||
LightSwitchSettings::instance().ApplyThemeIfNecessary();
|
||||
applyTheme(nowMinutes,
|
||||
settings.lightTime + settings.sunrise_offset,
|
||||
settings.darkTime + settings.sunset_offset,
|
||||
settings);
|
||||
Logger::trace(L"[LightSwitchService] Initialized g_lastUpdatedDay = {}", g_lastUpdatedDay);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::info(L"[LightSwitchService] Schedule mode is set to Off.");
|
||||
Logger::info(L"[LightSwitchService] Schedule mode is OFF - ticker suspended, waiting for manual action or mode change.");
|
||||
}
|
||||
|
||||
g_lastUpdatedDay = st.wDay;
|
||||
Logger::info(L"[LightSwitchService] Initializing g_lastUpdatedDay to {}.", g_lastUpdatedDay);
|
||||
ULONGLONG lastSettingsReload = 0;
|
||||
|
||||
// ticker loop
|
||||
for (;;)
|
||||
{
|
||||
HANDLE waits[2] = { g_ServiceStopEvent, hParent };
|
||||
@@ -197,10 +237,13 @@ DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
|
||||
|
||||
const auto& settings = LightSwitchSettings::instance().settings();
|
||||
|
||||
// If the mode is set to Off, suspend the scheduler and avoid extra work
|
||||
bool scheduleJustEnabled = (prevMode == ScheduleMode::Off && settings.scheduleMode != ScheduleMode::Off);
|
||||
prevMode = settings.scheduleMode;
|
||||
|
||||
// ─── Handle "Schedule Off" Mode ─────────────────────────────────────────────
|
||||
if (settings.scheduleMode == ScheduleMode::Off)
|
||||
{
|
||||
Logger::info(L"[LightSwitchService] Schedule mode is OFF - suspending scheduler but keeping service alive.");
|
||||
Logger::info(L"[LightSwitchService] Schedule mode OFF - suspending scheduler but keeping service alive.");
|
||||
|
||||
if (!hManualOverride)
|
||||
hManualOverride = OpenEventW(SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, L"POWERTOYS_LIGHTSWITCH_MANUAL_OVERRIDE");
|
||||
@@ -240,6 +283,7 @@ DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
|
||||
{
|
||||
Logger::trace(L"[LightSwitchService] Settings change event triggered, reloading settings...");
|
||||
ResetEvent(LightSwitchSettings::instance().GetSettingsChangedEvent());
|
||||
LightSwitchSettings::instance().LoadSettings();
|
||||
const auto& newSettings = LightSwitchSettings::instance().settings();
|
||||
lastSettingsReload = GetTickCount64();
|
||||
|
||||
@@ -254,150 +298,73 @@ DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
|
||||
continue;
|
||||
}
|
||||
|
||||
bool scheduleJustEnabled = (prevMode == ScheduleMode::Off && settings.scheduleMode != ScheduleMode::Off);
|
||||
prevMode = settings.scheduleMode;
|
||||
|
||||
// ─── Normal Schedule Loop ───────────────────────────────────────────────────
|
||||
ULONGLONG nowTick = GetTickCount64();
|
||||
bool recentSettingsReload = (nowTick - lastSettingsReload < 2000);
|
||||
bool recentSettingsReload = (nowTick - lastSettingsReload < 5000);
|
||||
|
||||
Logger::debug(L"[LightSwitchService] Current g_lastUpdatedDay value = {}.", g_lastUpdatedDay);
|
||||
|
||||
// Manual Override Detection Logic
|
||||
bool manualOverrideActive = (hManualOverride && WaitForSingleObject(hManualOverride, 0) == WAIT_OBJECT_0);
|
||||
|
||||
if (manualOverrideActive != lastOverrideStatus)
|
||||
if (g_lastUpdatedDay != -1)
|
||||
{
|
||||
Logger::debug(L"[LightSwitchService] Manual override active = {}", manualOverrideActive);
|
||||
lastOverrideStatus = manualOverrideActive;
|
||||
}
|
||||
bool manualOverrideActive = (hManualOverride && WaitForSingleObject(hManualOverride, 0) == WAIT_OBJECT_0);
|
||||
|
||||
if (settings.scheduleMode != ScheduleMode::Off && !recentSettingsReload && !scheduleJustEnabled && !manualOverrideActive)
|
||||
{
|
||||
bool currentSystemTheme = GetCurrentSystemTheme();
|
||||
bool currentAppsTheme = GetCurrentAppsTheme();
|
||||
|
||||
SYSTEMTIME st;
|
||||
GetLocalTime(&st);
|
||||
int nowMinutes = st.wHour * 60 + st.wMinute;
|
||||
|
||||
int lightBoundary = 0;
|
||||
int darkBoundary = 0;
|
||||
|
||||
if (settings.scheduleMode == ScheduleMode::SunsetToSunrise)
|
||||
if (settings.scheduleMode != ScheduleMode::Off && !recentSettingsReload && !scheduleJustEnabled)
|
||||
{
|
||||
lightBoundary = (settings.lightTime + settings.sunrise_offset) % 1440;
|
||||
darkBoundary = (settings.darkTime + settings.sunset_offset) % 1440;
|
||||
Logger::debug(L"[LightSwitchService] Checking if manual override is active...");
|
||||
bool manualOverrideActive = (hManualOverride && WaitForSingleObject(hManualOverride, 0) == WAIT_OBJECT_0);
|
||||
Logger::debug(L"[LightSwitchService] Manual override active = {}", manualOverrideActive);
|
||||
|
||||
if (!manualOverrideActive)
|
||||
{
|
||||
bool currentSystemTheme = GetCurrentSystemTheme();
|
||||
bool currentAppsTheme = GetCurrentAppsTheme();
|
||||
|
||||
SYSTEMTIME st;
|
||||
GetLocalTime(&st);
|
||||
int nowMinutes = st.wHour * 60 + st.wMinute;
|
||||
|
||||
bool shouldBeLight = (settings.lightTime < settings.darkTime) ? (nowMinutes >= settings.lightTime && nowMinutes < settings.darkTime) : (nowMinutes >= settings.lightTime || nowMinutes < settings.darkTime);
|
||||
|
||||
Logger::debug(L"[LightSwitchService] shouldBeLight = {}", shouldBeLight);
|
||||
|
||||
if ((settings.changeSystem && (currentSystemTheme != shouldBeLight)) ||
|
||||
(settings.changeApps && (currentAppsTheme != shouldBeLight)))
|
||||
{
|
||||
Logger::debug(L"[LightSwitchService] External theme change detected - enabling manual override");
|
||||
|
||||
if (!hManualOverride)
|
||||
{
|
||||
hManualOverride = OpenEventW(SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, L"POWERTOYS_LIGHTSWITCH_MANUAL_OVERRIDE");
|
||||
if (!hManualOverride)
|
||||
hManualOverride = CreateEventW(nullptr, TRUE, FALSE, L"POWERTOYS_LIGHTSWITCH_MANUAL_OVERRIDE");
|
||||
}
|
||||
|
||||
if (hManualOverride)
|
||||
{
|
||||
SetEvent(hManualOverride);
|
||||
Logger::info(L"[LightSwitchService] Detected manual theme change outside of LightSwitch. Triggering manual override.");
|
||||
skipRest = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lightBoundary = settings.lightTime;
|
||||
darkBoundary = settings.darkTime;
|
||||
}
|
||||
|
||||
bool shouldBeLight = (lightBoundary < darkBoundary) ? (nowMinutes >= lightBoundary && nowMinutes < darkBoundary) : (nowMinutes >= lightBoundary || nowMinutes < darkBoundary);
|
||||
|
||||
Logger::debug(L"[LightSwitchService] shouldBeLight = {}", shouldBeLight);
|
||||
|
||||
bool systemMismatch = settings.changeSystem && (currentSystemTheme != shouldBeLight);
|
||||
bool appsMismatch = settings.changeApps && (currentAppsTheme != shouldBeLight);
|
||||
|
||||
if (systemMismatch || appsMismatch)
|
||||
{
|
||||
// Make sure this is not because we crossed a boundary
|
||||
bool crossedBoundary = false;
|
||||
if (prevMinutes != -1)
|
||||
{
|
||||
if (nowMinutes < prevMinutes)
|
||||
{
|
||||
// wrapped around midnight
|
||||
crossedBoundary = (prevMinutes <= lightBoundary || nowMinutes >= lightBoundary) ||
|
||||
(prevMinutes <= darkBoundary || nowMinutes >= darkBoundary);
|
||||
}
|
||||
else
|
||||
{
|
||||
crossedBoundary = (prevMinutes < lightBoundary && nowMinutes >= lightBoundary) ||
|
||||
(prevMinutes < darkBoundary && nowMinutes >= darkBoundary);
|
||||
}
|
||||
}
|
||||
|
||||
if (crossedBoundary)
|
||||
{
|
||||
Logger::info(L"[LightSwitchService] Missed boundary detected. Applying theme instead of triggering manual override.");
|
||||
LightSwitchSettings::instance().ApplyThemeIfNecessary();
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::info(L"[LightSwitchService] External {} theme change detected, enabling manual override.",
|
||||
systemMismatch && appsMismatch ? L"system/app" :
|
||||
systemMismatch ? L"system" :
|
||||
L"app");
|
||||
SetEvent(hManualOverride);
|
||||
skipRest = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::debug(L"[LightSwitchService] Skipping external-change detection (schedule off, recent reload, or just enabled).");
|
||||
}
|
||||
|
||||
if (hManualOverride)
|
||||
manualOverrideActive = (WaitForSingleObject(hManualOverride, 0) == WAIT_OBJECT_0);
|
||||
|
||||
if (manualOverrideActive)
|
||||
{
|
||||
int lightBoundary = (settings.lightTime + settings.sunrise_offset) % 1440;
|
||||
int darkBoundary = (settings.darkTime + settings.sunset_offset) % 1440;
|
||||
|
||||
SYSTEMTIME st;
|
||||
GetLocalTime(&st);
|
||||
nowMinutes = st.wHour * 60 + st.wMinute;
|
||||
|
||||
bool crossedLight = false;
|
||||
bool crossedDark = false;
|
||||
|
||||
if (prevMinutes != -1)
|
||||
{
|
||||
// this means we are in a new day cycle
|
||||
if (nowMinutes < prevMinutes)
|
||||
{
|
||||
crossedLight = (prevMinutes <= lightBoundary || nowMinutes >= lightBoundary);
|
||||
crossedDark = (prevMinutes <= darkBoundary || nowMinutes >= darkBoundary);
|
||||
}
|
||||
else
|
||||
{
|
||||
crossedLight = (prevMinutes < lightBoundary && nowMinutes >= lightBoundary);
|
||||
crossedDark = (prevMinutes < darkBoundary && nowMinutes >= darkBoundary);
|
||||
}
|
||||
}
|
||||
|
||||
if (crossedLight || crossedDark)
|
||||
{
|
||||
ResetEvent(hManualOverride);
|
||||
Logger::info(L"[LightSwitchService] Manual override cleared after crossing schedule boundary.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::debug(L"[LightSwitchService] Skipping schedule due to manual override");
|
||||
skipRest = true;
|
||||
Logger::debug(L"[LightSwitchService] Skipping external-change detection (schedule off, recent reload, or just enabled).");
|
||||
}
|
||||
}
|
||||
|
||||
// Apply theme if nothing has made us skip
|
||||
// ─── Apply Schedule Logic ───────────────────────────────────────────────────
|
||||
if (!skipRest)
|
||||
{
|
||||
// Next two conditionals check for any updates necessary to the sun times.
|
||||
bool modeChangedToSunset = (prevMode != settings.scheduleMode &&
|
||||
settings.scheduleMode == ScheduleMode::SunsetToSunrise);
|
||||
bool coordsChanged = (prevLat != settings.latitude || prevLon != settings.longitude);
|
||||
|
||||
if ((modeChangedToSunset || coordsChanged) && settings.scheduleMode == ScheduleMode::SunsetToSunrise)
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
GetLocalTime(&st);
|
||||
|
||||
Logger::info(L"[LightSwitchService] Mode or coordinates changed, recalculating sun times.");
|
||||
update_sun_times(settings);
|
||||
SYSTEMTIME st;
|
||||
GetLocalTime(&st);
|
||||
g_lastUpdatedDay = st.wDay;
|
||||
prevMode = settings.scheduleMode;
|
||||
prevLat = settings.latitude;
|
||||
@@ -416,23 +383,70 @@ DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
|
||||
Logger::info(L"[LightSwitchService] Recalculated sun times at new day boundary.");
|
||||
}
|
||||
|
||||
// settings after any necessary updates.
|
||||
LightSwitchSettings::instance().LoadSettings();
|
||||
const auto& currentSettings = LightSwitchSettings::instance().settings();
|
||||
|
||||
wchar_t msg[160];
|
||||
swprintf_s(msg,
|
||||
L"[LightSwitchService] now=%02d:%02d | light=%02d:%02d | dark=%02d:%02d | mode=%s",
|
||||
L"[LightSwitchService] now=%02d:%02d | light=%02d:%02d | dark=%02d:%02d | mode=%d",
|
||||
st.wHour,
|
||||
st.wMinute,
|
||||
currentSettings.lightTime / 60,
|
||||
currentSettings.lightTime % 60,
|
||||
currentSettings.darkTime / 60,
|
||||
currentSettings.darkTime % 60,
|
||||
ToString(currentSettings.scheduleMode).c_str());
|
||||
static_cast<int>(currentSettings.scheduleMode));
|
||||
Logger::info(msg);
|
||||
|
||||
LightSwitchSettings::instance().ApplyThemeIfNecessary();
|
||||
bool manualOverrideActive = false;
|
||||
if (hManualOverride)
|
||||
manualOverrideActive = (WaitForSingleObject(hManualOverride, 0) == WAIT_OBJECT_0);
|
||||
|
||||
if (manualOverrideActive)
|
||||
{
|
||||
int lightBoundary = (currentSettings.lightTime + currentSettings.sunrise_offset) % 1440;
|
||||
int darkBoundary = (currentSettings.darkTime + currentSettings.sunset_offset) % 1440;
|
||||
|
||||
bool crossedLight = false;
|
||||
bool crossedDark = false;
|
||||
|
||||
if (prevMinutes != -1)
|
||||
{
|
||||
if (nowMinutes < prevMinutes)
|
||||
{
|
||||
crossedLight = (prevMinutes <= lightBoundary || nowMinutes >= lightBoundary);
|
||||
crossedDark = (prevMinutes <= darkBoundary || nowMinutes >= darkBoundary);
|
||||
}
|
||||
else
|
||||
{
|
||||
crossedLight = (prevMinutes < lightBoundary && nowMinutes >= lightBoundary);
|
||||
crossedDark = (prevMinutes < darkBoundary && nowMinutes >= darkBoundary);
|
||||
}
|
||||
}
|
||||
|
||||
Logger::debug(L"[LightSwitchService] prevMinutes={} nowMinutes={} light={} dark={}",
|
||||
prevMinutes,
|
||||
nowMinutes,
|
||||
lightBoundary,
|
||||
darkBoundary);
|
||||
|
||||
if (crossedLight || crossedDark)
|
||||
{
|
||||
ResetEvent(hManualOverride);
|
||||
Logger::info(L"[LightSwitchService] Manual override cleared after crossing schedule boundary.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::info(L"[LightSwitchService] Skipping schedule due to manual override");
|
||||
skipRest = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!skipRest)
|
||||
applyTheme(nowMinutes,
|
||||
currentSettings.lightTime + currentSettings.sunrise_offset,
|
||||
currentSettings.darkTime + currentSettings.sunset_offset,
|
||||
currentSettings);
|
||||
}
|
||||
|
||||
// ─── Wait For Next Minute Tick Or Stop Event ────────────────────────────────
|
||||
@@ -466,6 +480,54 @@ cleanup:
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ApplyThemeNow()
|
||||
{
|
||||
LightSwitchSettings::instance().LoadSettings();
|
||||
const auto& settings = LightSwitchSettings::instance().settings();
|
||||
|
||||
SYSTEMTIME st;
|
||||
GetLocalTime(&st);
|
||||
int nowMinutes = st.wHour * 60 + st.wMinute;
|
||||
|
||||
bool shouldBeLight = false;
|
||||
if (settings.lightTime < settings.darkTime)
|
||||
shouldBeLight = (nowMinutes >= settings.lightTime && nowMinutes < settings.darkTime);
|
||||
else
|
||||
shouldBeLight = (nowMinutes >= settings.lightTime || nowMinutes < settings.darkTime);
|
||||
|
||||
bool isSystemCurrentlyLight = GetCurrentSystemTheme();
|
||||
bool isAppsCurrentlyLight = GetCurrentAppsTheme();
|
||||
|
||||
Logger::info(L"[LightSwitchService] Applying (if needed) theme immediately due to schedule change.");
|
||||
|
||||
if (shouldBeLight)
|
||||
{
|
||||
if (settings.changeSystem && !isSystemCurrentlyLight)
|
||||
{
|
||||
SetSystemTheme(true);
|
||||
Logger::info(L"[LightSwitchService] Changing system theme to light mode.");
|
||||
}
|
||||
if (settings.changeApps && !isAppsCurrentlyLight)
|
||||
{
|
||||
SetAppsTheme(true);
|
||||
Logger::info(L"[LightSwitchService] Changing apps theme to light mode.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (settings.changeSystem && isSystemCurrentlyLight)
|
||||
{
|
||||
SetSystemTheme(false);
|
||||
Logger::info(L"[LightSwitchService] Changing system theme to dark mode.");
|
||||
}
|
||||
if (settings.changeApps && isAppsCurrentlyLight)
|
||||
{
|
||||
SetAppsTheme(false);
|
||||
Logger::info(L"[LightSwitchService] Changing apps theme to dark mode.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int APIENTRY wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
|
||||
{
|
||||
if (powertoys_gpo::getConfiguredLightSwitchEnabledValue() == powertoys_gpo::gpo_rule_configured_disabled)
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="LightSwitchService.cpp" />
|
||||
<ClCompile Include="LightSwitchServiceObserver.cpp" />
|
||||
<ClCompile Include="LightSwitchSettings.cpp" />
|
||||
<ClCompile Include="SettingsConstants.cpp" />
|
||||
<ClCompile Include="ThemeHelper.cpp" />
|
||||
@@ -84,6 +85,7 @@
|
||||
<ResourceCompile Include="LightSwitchService.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="LightSwitchServiceObserver.h" />
|
||||
<ClInclude Include="LightSwitchSettings.h" />
|
||||
<ClInclude Include="SettingsConstants.h" />
|
||||
<ClInclude Include="SettingsObserver.h" />
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
<ClCompile Include="WinHookEventIDs.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LightSwitchServiceObserver.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ThemeScheduler.h">
|
||||
@@ -53,6 +56,9 @@
|
||||
<ClInclude Include="WinHookEventIDs.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="LightSwitchServiceObserver.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#include "LightSwitchServiceObserver.h"
|
||||
#include <logger.h>
|
||||
#include "LightSwitchSettings.h"
|
||||
|
||||
// These are defined elsewhere in your service module (ServiceWorkerThread.cpp)
|
||||
extern int g_lastUpdatedDay;
|
||||
void ApplyThemeNow();
|
||||
|
||||
void LightSwitchServiceObserver::SettingsUpdate(SettingId id)
|
||||
{
|
||||
Logger::info(L"[LightSwitchService] Setting changed: {}", static_cast<int>(id));
|
||||
g_lastUpdatedDay = -1;
|
||||
ApplyThemeNow();
|
||||
}
|
||||
|
||||
bool LightSwitchServiceObserver::WantsToBeNotified(SettingId id) const noexcept
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case SettingId::LightTime:
|
||||
case SettingId::DarkTime:
|
||||
case SettingId::ScheduleMode:
|
||||
case SettingId::Sunrise_Offset:
|
||||
case SettingId::Sunset_Offset:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "SettingsObserver.h"
|
||||
|
||||
// The LightSwitchServiceObserver reacts when LightSwitchSettings changes.
|
||||
class LightSwitchServiceObserver : public SettingsObserver
|
||||
{
|
||||
public:
|
||||
explicit LightSwitchServiceObserver(std::unordered_set<SettingId> observedSettings) :
|
||||
SettingsObserver(std::move(observedSettings))
|
||||
{
|
||||
}
|
||||
|
||||
void SettingsUpdate(SettingId id) override;
|
||||
bool WantsToBeNotified(SettingId id) const noexcept override;
|
||||
};
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <common/utils/json.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include "SettingsObserver.h"
|
||||
#include "ThemeHelper.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <WinHookEventIDs.h>
|
||||
@@ -38,80 +38,13 @@ void LightSwitchSettings::InitFileWatcher()
|
||||
m_settingsFileWatcher = std::make_unique<FileWatcher>(
|
||||
GetSettingsFileName(),
|
||||
[this]() {
|
||||
using namespace std::chrono;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_debounceMutex);
|
||||
m_lastChangeTime = steady_clock::now();
|
||||
if (m_debouncePending)
|
||||
return;
|
||||
m_debouncePending = true;
|
||||
}
|
||||
|
||||
m_debounceThread = std::jthread([this](std::stop_token stop) {
|
||||
using namespace std::chrono;
|
||||
while (!stop.stop_requested())
|
||||
{
|
||||
std::this_thread::sleep_for(seconds(3));
|
||||
|
||||
auto elapsed = steady_clock::now() - m_lastChangeTime;
|
||||
if (elapsed >= seconds(1))
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_debounceMutex);
|
||||
m_debouncePending = false;
|
||||
}
|
||||
|
||||
Logger::info(L"[LightSwitchSettings] Settings file stabilized, reloading.");
|
||||
|
||||
try
|
||||
{
|
||||
LoadSettings();
|
||||
ApplyThemeIfNecessary();
|
||||
SetEvent(m_settingsChangedEvent);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::wstring wmsg;
|
||||
wmsg.assign(e.what(), e.what() + strlen(e.what()));
|
||||
Logger::error(L"[LightSwitchSettings] Exception during debounced reload: {}", wmsg);
|
||||
}
|
||||
});
|
||||
Logger::info(L"[LightSwitchSettings] Settings file changed, signaling event.");
|
||||
LoadSettings();
|
||||
SetEvent(m_settingsChangedEvent);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
LightSwitchSettings::~LightSwitchSettings()
|
||||
{
|
||||
Logger::info(L"[LightSwitchSettings] Cleaning up settings resources...");
|
||||
|
||||
// Stop and join the debounce thread (std::jthread auto-joins, but we can signal stop too)
|
||||
if (m_debounceThread.joinable())
|
||||
{
|
||||
m_debounceThread.request_stop();
|
||||
}
|
||||
|
||||
// Release the file watcher so it closes file handles and background threads
|
||||
if (m_settingsFileWatcher)
|
||||
{
|
||||
m_settingsFileWatcher.reset();
|
||||
Logger::info(L"[LightSwitchSettings] File watcher stopped.");
|
||||
}
|
||||
|
||||
// Close the Windows event handle
|
||||
if (m_settingsChangedEvent)
|
||||
{
|
||||
CloseHandle(m_settingsChangedEvent);
|
||||
m_settingsChangedEvent = nullptr;
|
||||
Logger::info(L"[LightSwitchSettings] Settings changed event closed.");
|
||||
}
|
||||
|
||||
Logger::info(L"[LightSwitchSettings] Cleanup complete.");
|
||||
}
|
||||
|
||||
|
||||
void LightSwitchSettings::AddObserver(SettingsObserver& observer)
|
||||
{
|
||||
m_observers.insert(&observer);
|
||||
@@ -140,7 +73,6 @@ HANDLE LightSwitchSettings::GetSettingsChangedEvent() const
|
||||
|
||||
void LightSwitchSettings::LoadSettings()
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(m_settingsMutex);
|
||||
try
|
||||
{
|
||||
PowerToysSettings::PowerToyValues values =
|
||||
@@ -249,49 +181,4 @@ void LightSwitchSettings::LoadSettings()
|
||||
{
|
||||
// Keeps defaults if load fails
|
||||
}
|
||||
}
|
||||
|
||||
void LightSwitchSettings::ApplyThemeIfNecessary()
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(m_settingsMutex);
|
||||
|
||||
SYSTEMTIME st;
|
||||
GetLocalTime(&st);
|
||||
int nowMinutes = st.wHour * 60 + st.wMinute;
|
||||
|
||||
bool shouldBeLight = false;
|
||||
if (m_settings.lightTime < m_settings.darkTime)
|
||||
shouldBeLight = (nowMinutes >= m_settings.lightTime && nowMinutes < m_settings.darkTime);
|
||||
else
|
||||
shouldBeLight = (nowMinutes >= m_settings.lightTime || nowMinutes < m_settings.darkTime);
|
||||
|
||||
bool isSystemCurrentlyLight = GetCurrentSystemTheme();
|
||||
bool isAppsCurrentlyLight = GetCurrentAppsTheme();
|
||||
|
||||
if (shouldBeLight)
|
||||
{
|
||||
if (m_settings.changeSystem && !isSystemCurrentlyLight)
|
||||
{
|
||||
SetSystemTheme(true);
|
||||
Logger::info(L"[LightSwitchService] Changing system theme to light mode.");
|
||||
}
|
||||
if (m_settings.changeApps && !isAppsCurrentlyLight)
|
||||
{
|
||||
SetAppsTheme(true);
|
||||
Logger::info(L"[LightSwitchService] Changing apps theme to light mode.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_settings.changeSystem && isSystemCurrentlyLight)
|
||||
{
|
||||
SetSystemTheme(false);
|
||||
Logger::info(L"[LightSwitchService] Changing system theme to dark mode.");
|
||||
}
|
||||
if (m_settings.changeApps && isAppsCurrentlyLight)
|
||||
{
|
||||
SetAppsTheme(false);
|
||||
Logger::info(L"[LightSwitchService] Changing apps theme to dark mode.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,7 @@
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <windows.h>
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
#include <common/SettingsAPI/FileWatcher.h>
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include <SettingsConstants.h>
|
||||
@@ -81,13 +78,12 @@ public:
|
||||
void RemoveObserver(SettingsObserver& observer);
|
||||
|
||||
void LoadSettings();
|
||||
void ApplyThemeIfNecessary();
|
||||
|
||||
HANDLE GetSettingsChangedEvent() const;
|
||||
|
||||
private:
|
||||
LightSwitchSettings();
|
||||
~LightSwitchSettings();
|
||||
~LightSwitchSettings() = default;
|
||||
|
||||
LightSwitchConfig m_settings;
|
||||
std::unique_ptr<FileWatcher> m_settingsFileWatcher;
|
||||
@@ -96,11 +92,4 @@ private:
|
||||
void NotifyObservers(SettingId id) const;
|
||||
|
||||
HANDLE m_settingsChangedEvent = nullptr;
|
||||
mutable std::mutex m_settingsMutex;
|
||||
|
||||
// Debounce state
|
||||
std::atomic_bool m_debouncePending{ false };
|
||||
std::mutex m_debounceMutex;
|
||||
std::chrono::steady_clock::time_point m_lastChangeTime{};
|
||||
std::jthread m_debounceThread;
|
||||
};
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
#include <windows.h>
|
||||
#include "resource.h"
|
||||
#include "../../../../common/version/version.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
#include "winres.h"
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION FILE_VERSION
|
||||
PRODUCTVERSION PRODUCT_VERSION
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", COMPANY_NAME
|
||||
VALUE "FileDescription", "PowerToys CursorWrap"
|
||||
VALUE "FileVersion", FILE_VERSION_STRING
|
||||
VALUE "InternalName", "CursorWrap"
|
||||
VALUE "LegalCopyright", COPYRIGHT_NOTE
|
||||
VALUE "OriginalFilename", "PowerToys.CursorWrap.dll"
|
||||
VALUE "ProductName", PRODUCT_NAME
|
||||
VALUE "ProductVersion", PRODUCT_VERSION_STRING
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_CURSORWRAP_NAME L"CursorWrap"
|
||||
IDS_CURSORWRAP_DISABLE_WRAP_DURING_DRAG L"Disable wrapping during drag"
|
||||
END
|
||||
@@ -1,130 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{48a1db8c-5df8-4fb3-9e14-2b67f3f2d8b5}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>CursorWrap</RootNamespace>
|
||||
<ProjectName>CursorWrap</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\</OutDir>
|
||||
<TargetName>PowerToys.CursorWrap</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="CursorWrapTests.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(UsePrecompiledHeaders)' != 'false'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="CursorWrap.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="COMPLETE_REWRITE_SUMMARY.md" />
|
||||
<None Include="CRITICAL_BUG_ANALYSIS.md" />
|
||||
<None Include="CURSOR_WRAP_FIX_ANALYSIS.md" />
|
||||
<None Include="DEBUG_GUIDE.md" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="VERTICAL_WRAP_BUG_FIX.md" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -1,213 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
// Test case structure for comprehensive monitor layout testing
|
||||
struct MonitorTestCase
|
||||
{
|
||||
std::string name;
|
||||
std::string description;
|
||||
int grid[3][3]; // 3x3 grid representing monitor layout (0 = no monitor, 1-9 = monitor ID)
|
||||
|
||||
// Test scenarios to validate
|
||||
struct TestScenario
|
||||
{
|
||||
int sourceMonitor; // Which monitor to start cursor on (1-based)
|
||||
int edgeDirection; // 0=top, 1=right, 2=bottom, 3=left
|
||||
int expectedTargetMonitor; // Expected destination monitor (1-based, -1 = wrap within same monitor)
|
||||
std::string description;
|
||||
};
|
||||
|
||||
std::vector<TestScenario> scenarios;
|
||||
};
|
||||
|
||||
// Comprehensive test cases for all possible 3x3 monitor grid configurations
|
||||
class CursorWrapTestSuite
|
||||
{
|
||||
public:
|
||||
static std::vector<MonitorTestCase> GetAllTestCases()
|
||||
{
|
||||
std::vector<MonitorTestCase> testCases;
|
||||
|
||||
// Test Case 1: Single monitor (center)
|
||||
testCases.push_back({
|
||||
"Single_Center",
|
||||
"Single monitor in center position",
|
||||
{
|
||||
{0, 0, 0},
|
||||
{0, 1, 0},
|
||||
{0, 0, 0}
|
||||
},
|
||||
{
|
||||
{1, 0, -1, "Top edge wraps to bottom of same monitor"},
|
||||
{1, 1, -1, "Right edge wraps to left of same monitor"},
|
||||
{1, 2, -1, "Bottom edge wraps to top of same monitor"},
|
||||
{1, 3, -1, "Left edge wraps to right of same monitor"}
|
||||
}
|
||||
});
|
||||
|
||||
// Test Case 2: Two monitors horizontal (left + right)
|
||||
testCases.push_back({
|
||||
"Dual_Horizontal_Left_Right",
|
||||
"Two monitors: left + right",
|
||||
{
|
||||
{0, 0, 0},
|
||||
{1, 0, 2},
|
||||
{0, 0, 0}
|
||||
},
|
||||
{
|
||||
{1, 0, -1, "Monitor 1 top wraps to bottom of monitor 1"},
|
||||
{1, 1, 2, "Monitor 1 right edge moves to monitor 2 left"},
|
||||
{1, 2, -1, "Monitor 1 bottom wraps to top of monitor 1"},
|
||||
{1, 3, -1, "Monitor 1 left edge wraps to right of monitor 1"},
|
||||
{2, 0, -1, "Monitor 2 top wraps to bottom of monitor 2"},
|
||||
{2, 1, -1, "Monitor 2 right edge wraps to left of monitor 2"},
|
||||
{2, 2, -1, "Monitor 2 bottom wraps to top of monitor 2"},
|
||||
{2, 3, 1, "Monitor 2 left edge moves to monitor 1 right"}
|
||||
}
|
||||
});
|
||||
|
||||
// Test Case 3: Two monitors vertical (Monitor 2 above Monitor 1) - CORRECTED FOR USER'S SETUP
|
||||
testCases.push_back({
|
||||
"Dual_Vertical_2_Above_1",
|
||||
"Two monitors: Monitor 2 (top) above Monitor 1 (bottom/main)",
|
||||
{
|
||||
{0, 2, 0}, // Row 0: Monitor 2 (physically top monitor)
|
||||
{0, 0, 0}, // Row 1: Empty
|
||||
{0, 1, 0} // Row 2: Monitor 1 (physically bottom/main monitor)
|
||||
},
|
||||
{
|
||||
// Monitor 1 (bottom/main monitor) tests
|
||||
{1, 0, 2, "Monitor 1 (bottom) top edge should move to Monitor 2 (top) bottom"},
|
||||
{1, 1, -1, "Monitor 1 right wraps to left of monitor 1"},
|
||||
{1, 2, -1, "Monitor 1 bottom wraps to top of monitor 1"},
|
||||
{1, 3, -1, "Monitor 1 left wraps to right of monitor 1"},
|
||||
|
||||
// Monitor 2 (top monitor) tests
|
||||
{2, 0, -1, "Monitor 2 (top) top wraps to bottom of monitor 2"},
|
||||
{2, 1, -1, "Monitor 2 right wraps to left of monitor 2"},
|
||||
{2, 2, 1, "Monitor 2 (top) bottom edge should move to Monitor 1 (bottom) top"},
|
||||
{2, 3, -1, "Monitor 2 left wraps to right of monitor 2"}
|
||||
}
|
||||
});
|
||||
|
||||
// Test Case 4: Three monitors L-shape (center + left + top)
|
||||
testCases.push_back({
|
||||
"Triple_L_Shape",
|
||||
"Three monitors in L-shape: center + left + top",
|
||||
{
|
||||
{0, 3, 0},
|
||||
{2, 1, 0},
|
||||
{0, 0, 0}
|
||||
},
|
||||
{
|
||||
{1, 0, 3, "Monitor 1 top moves to monitor 3 bottom"},
|
||||
{1, 1, -1, "Monitor 1 right wraps to left of monitor 1"},
|
||||
{1, 2, -1, "Monitor 1 bottom wraps to top of monitor 1"},
|
||||
{1, 3, 2, "Monitor 1 left moves to monitor 2 right"},
|
||||
{2, 0, -1, "Monitor 2 top wraps to bottom of monitor 2"},
|
||||
{2, 1, 1, "Monitor 2 right moves to monitor 1 left"},
|
||||
{2, 2, -1, "Monitor 2 bottom wraps to top of monitor 2"},
|
||||
{2, 3, -1, "Monitor 2 left wraps to right of monitor 2"},
|
||||
{3, 0, -1, "Monitor 3 top wraps to bottom of monitor 3"},
|
||||
{3, 1, -1, "Monitor 3 right wraps to left of monitor 3"},
|
||||
{3, 2, 1, "Monitor 3 bottom moves to monitor 1 top"},
|
||||
{3, 3, -1, "Monitor 3 left wraps to right of monitor 3"}
|
||||
}
|
||||
});
|
||||
|
||||
// Test Case 5: Three monitors horizontal (left + center + right)
|
||||
testCases.push_back({
|
||||
"Triple_Horizontal",
|
||||
"Three monitors horizontal: left + center + right",
|
||||
{
|
||||
{0, 0, 0},
|
||||
{1, 2, 3},
|
||||
{0, 0, 0}
|
||||
},
|
||||
{
|
||||
{1, 0, -1, "Monitor 1 top wraps to bottom"},
|
||||
{1, 1, 2, "Monitor 1 right moves to monitor 2"},
|
||||
{1, 2, -1, "Monitor 1 bottom wraps to top"},
|
||||
{1, 3, -1, "Monitor 1 left wraps to right"},
|
||||
{2, 0, -1, "Monitor 2 top wraps to bottom"},
|
||||
{2, 1, 3, "Monitor 2 right moves to monitor 3"},
|
||||
{2, 2, -1, "Monitor 2 bottom wraps to top"},
|
||||
{2, 3, 1, "Monitor 2 left moves to monitor 1"},
|
||||
{3, 0, -1, "Monitor 3 top wraps to bottom"},
|
||||
{3, 1, -1, "Monitor 3 right wraps to left"},
|
||||
{3, 2, -1, "Monitor 3 bottom wraps to top"},
|
||||
{3, 3, 2, "Monitor 3 left moves to monitor 2"}
|
||||
}
|
||||
});
|
||||
|
||||
// Test Case 6: Three monitors vertical (top + center + bottom)
|
||||
testCases.push_back({
|
||||
"Triple_Vertical",
|
||||
"Three monitors vertical: top + center + bottom",
|
||||
{
|
||||
{0, 1, 0},
|
||||
{0, 2, 0},
|
||||
{0, 3, 0}
|
||||
},
|
||||
{
|
||||
{1, 0, -1, "Monitor 1 top wraps to bottom"},
|
||||
{1, 1, -1, "Monitor 1 right wraps to left"},
|
||||
{1, 2, 2, "Monitor 1 bottom moves to monitor 2"},
|
||||
{1, 3, -1, "Monitor 1 left wraps to right"},
|
||||
{2, 0, 1, "Monitor 2 top moves to monitor 1"},
|
||||
{2, 1, -1, "Monitor 2 right wraps to left"},
|
||||
{2, 2, 3, "Monitor 2 bottom moves to monitor 3"},
|
||||
{2, 3, -1, "Monitor 2 left wraps to right"},
|
||||
{3, 0, 2, "Monitor 3 top moves to monitor 2"},
|
||||
{3, 1, -1, "Monitor 3 right wraps to left"},
|
||||
{3, 2, -1, "Monitor 3 bottom wraps to top"},
|
||||
{3, 3, -1, "Monitor 3 left wraps to right"}
|
||||
}
|
||||
});
|
||||
|
||||
return testCases;
|
||||
}
|
||||
|
||||
// Helper function to print test case in a readable format
|
||||
static std::string FormatTestCase(const MonitorTestCase& testCase)
|
||||
{
|
||||
std::string result = "Test Case: " + testCase.name + "\n";
|
||||
result += "Description: " + testCase.description + "\n";
|
||||
result += "Layout:\n";
|
||||
|
||||
for (int row = 0; row < 3; row++)
|
||||
{
|
||||
result += " ";
|
||||
for (int col = 0; col < 3; col++)
|
||||
{
|
||||
if (testCase.grid[row][col] == 0)
|
||||
{
|
||||
result += ". ";
|
||||
}
|
||||
else
|
||||
{
|
||||
result += std::to_string(testCase.grid[row][col]) + " ";
|
||||
}
|
||||
}
|
||||
result += "\n";
|
||||
}
|
||||
|
||||
result += "Test Scenarios:\n";
|
||||
for (const auto& scenario : testCase.scenarios)
|
||||
{
|
||||
result += " - " + scenario.description + "\n";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Helper function to validate a specific test case against actual behavior
|
||||
static bool ValidateTestCase(const MonitorTestCase& testCase)
|
||||
{
|
||||
// This would be called with actual CursorWrap instance to validate behavior
|
||||
// For now, just return true - this would need actual implementation
|
||||
return true;
|
||||
}
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
|
||||
</packages>
|
||||
@@ -1 +0,0 @@
|
||||
#include "pch.h"
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#include <windows.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
// Note: Common includes moved to individual source files due to include path issues
|
||||
// #include <common/SettingsAPI/settings_helpers.h>
|
||||
// #include <common/logger/logger.h>
|
||||
// #include <common/utils/logger_helper.h>
|
||||
@@ -1,4 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define IDS_CURSORWRAP_NAME 101
|
||||
#define IDS_CURSORWRAP_DISABLE_WRAP_DURING_DRAG 102
|
||||
@@ -1,31 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "trace.h"
|
||||
|
||||
#include "../../../../common/Telemetry/TraceBase.h"
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
g_hProvider,
|
||||
"Microsoft.PowerToys",
|
||||
// {38e8889b-9731-53f5-e901-e8a7c1753074}
|
||||
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
|
||||
TraceLoggingOptionProjectTelemetry());
|
||||
|
||||
void Trace::RegisterProvider()
|
||||
{
|
||||
TraceLoggingRegister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::UnregisterProvider()
|
||||
{
|
||||
TraceLoggingUnregister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::EnableCursorWrap(const bool enabled) noexcept
|
||||
{
|
||||
TraceLoggingWriteWrapper(
|
||||
g_hProvider,
|
||||
"CursorWrap_EnableCursorWrap",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingBoolean(enabled, "Enabled"));
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/Telemetry/TraceBase.h>
|
||||
|
||||
class Trace : public telemetry::TraceBase
|
||||
{
|
||||
public:
|
||||
static void RegisterProvider();
|
||||
static void UnregisterProvider();
|
||||
static void EnableCursorWrap(const bool enabled) noexcept;
|
||||
};
|
||||
@@ -46,7 +46,7 @@
|
||||
<PreprocessorDefinitions>_DEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories);..\NewShellExtensionContextMenu;$(MSBuildThisFileDirectory)Generated Files</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories);..\NewShellExtensionContextMenu</AdditionalIncludeDirectories>
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
@@ -67,7 +67,7 @@
|
||||
<PreprocessorDefinitions>NDEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories);..\NewShellExtensionContextMenu;$(MSBuildThisFileDirectory)Generated Files</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories);..\NewShellExtensionContextMenu</AdditionalIncludeDirectories>
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
|
||||
@@ -88,6 +88,9 @@ namespace Awake.Core.Native
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool GetCursorPos(out Point lpPoint);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
internal static extern bool ScreenToClient(IntPtr hWnd, ref Point lpPoint);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
internal static extern bool GetMessage(out Msg lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);
|
||||
|
||||
|
||||
@@ -61,8 +61,9 @@ namespace Awake.Core
|
||||
|
||||
Bridge.SetForegroundWindow(hWnd);
|
||||
|
||||
// Get cursor position in screen coordinates
|
||||
// Get cursor position and convert it to client coordinates
|
||||
Bridge.GetCursorPos(out Models.Point cursorPos);
|
||||
Bridge.ScreenToClient(hWnd, ref cursorPos);
|
||||
|
||||
// Set menu information
|
||||
MenuInfo menuInfo = new()
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<clear />
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
||||
</packageSources>
|
||||
<packageSourceMapping>
|
||||
<packageSource key="nuget.org">
|
||||
<package pattern="*" />
|
||||
</packageSource>
|
||||
</packageSourceMapping>
|
||||
</configuration>
|
||||
@@ -11,7 +11,7 @@ namespace Microsoft.CmdPal.UI.ViewModels.BuiltinCommands;
|
||||
/// <summary>
|
||||
/// Built-in Provider for a top-level command which can quit the application. Invokes the <see cref="QuitCommand"/>, which sends a <see cref="QuitMessage"/>.
|
||||
/// </summary>
|
||||
public sealed partial class BuiltInsCommandProvider : CommandProvider
|
||||
public partial class BuiltInsCommandProvider : CommandProvider
|
||||
{
|
||||
private readonly OpenSettingsCommand openSettings = new();
|
||||
private readonly QuitCommand quitCommand = new();
|
||||
@@ -21,7 +21,7 @@ public sealed partial class BuiltInsCommandProvider : CommandProvider
|
||||
|
||||
public override ICommandItem[] TopLevelCommands() =>
|
||||
[
|
||||
new CommandItem(openSettings) { },
|
||||
new CommandItem(openSettings) { Subtitle = Properties.Resources.builtin_open_settings_subtitle },
|
||||
new CommandItem(_newExtension) { Title = _newExtension.Title, Subtitle = Properties.Resources.builtin_new_extension_subtitle },
|
||||
];
|
||||
|
||||
@@ -34,7 +34,7 @@ public sealed partial class BuiltInsCommandProvider : CommandProvider
|
||||
|
||||
public BuiltInsCommandProvider()
|
||||
{
|
||||
Id = "com.microsoft.cmdpal.builtin.core";
|
||||
Id = "Core";
|
||||
DisplayName = Properties.Resources.builtin_display_name;
|
||||
Icon = IconHelpers.FromRelativePath("Assets\\StoreLogo.scale-200.png");
|
||||
}
|
||||
|
||||
@@ -30,12 +30,7 @@ public partial class MainListPage : DynamicListPage,
|
||||
{
|
||||
private readonly string[] _specialFallbacks = [
|
||||
"com.microsoft.cmdpal.builtin.run",
|
||||
"com.microsoft.cmdpal.builtin.calculator",
|
||||
"com.microsoft.cmdpal.builtin.system",
|
||||
"com.microsoft.cmdpal.builtin.core",
|
||||
"com.microsoft.cmdpal.builtin.websearch",
|
||||
"com.microsoft.cmdpal.builtin.windowssettings",
|
||||
"com.microsoft.cmdpal.builtin.datetime",
|
||||
"com.microsoft.cmdpal.builtin.calculator"
|
||||
];
|
||||
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
@@ -117,8 +117,11 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="builtin_open_settings_subtitle" xml:space="preserve">
|
||||
<value>Open Command Palette settings</value>
|
||||
</data>
|
||||
<data name="builtin_new_extension_subtitle" xml:space="preserve">
|
||||
<value>Generate a new Command Palette extension project</value>
|
||||
<value>Creates a project for a new Command Palette extension</value>
|
||||
</data>
|
||||
<data name="builtin_quit_subtitle" xml:space="preserve">
|
||||
<value>Exit Command Palette</value>
|
||||
@@ -154,10 +157,10 @@
|
||||
<value>Open</value>
|
||||
</data>
|
||||
<data name="builtin_create_extension_title" xml:space="preserve">
|
||||
<value>Create extension</value>
|
||||
<value>Create a new extension</value>
|
||||
</data>
|
||||
<data name="builtin_open_settings_name" xml:space="preserve">
|
||||
<value>Open Command Palette settings</value>
|
||||
<value>Open Settings</value>
|
||||
</data>
|
||||
<data name="builtin_create_extension_success" xml:space="preserve">
|
||||
<value>Successfully created your new extension!</value>
|
||||
|
||||
@@ -51,10 +51,10 @@ internal sealed partial class GlobalErrorHandler
|
||||
// without its exception being observed. It is NOT raised immediately
|
||||
// when the Task faults; timing depends on GC finalization.
|
||||
e.SetObserved();
|
||||
HandleException(e.Exception, Context.UnobservedTaskException);
|
||||
HandleException(e.Exception, Context.UnobservedTaskException, isRecoverable: true);
|
||||
}
|
||||
|
||||
private static void HandleException(Exception ex, Context context)
|
||||
private void HandleException(Exception ex, Context context, bool isRecoverable = false)
|
||||
{
|
||||
Logger.LogError($"Unhandled exception detected ({context})", ex);
|
||||
|
||||
@@ -70,25 +70,10 @@ internal sealed partial class GlobalErrorHandler
|
||||
|
||||
StoreReport(report, storeOnDesktop: false);
|
||||
|
||||
string message;
|
||||
string caption;
|
||||
try
|
||||
{
|
||||
message = ResourceLoaderInstance.GetString("GlobalErrorHandler_CrashMessageBox_Message");
|
||||
caption = ResourceLoaderInstance.GetString("GlobalErrorHandler_CrashMessageBox_Caption");
|
||||
}
|
||||
catch
|
||||
{
|
||||
// The resource loader may not be available if the exception occurred during startup.
|
||||
// Fall back to hardcoded strings in that case.
|
||||
message = "Command Palette has encountered a fatal error and must close.";
|
||||
caption = "Command Palette - Fatal error";
|
||||
}
|
||||
|
||||
PInvoke.MessageBox(
|
||||
HWND.Null,
|
||||
message,
|
||||
caption,
|
||||
"Command Palette has encountered a fatal error and must close.\n\nAn error report has been saved to your desktop.",
|
||||
"Unhandled Error",
|
||||
MESSAGEBOX_STYLE.MB_ICONERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,8 +431,8 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
|
||||
<data name="Run_Radio_Position_LastPosition.Content" xml:space="preserve">
|
||||
<value>Last Position</value>
|
||||
<comment>Reopen the window where it was last closed</comment>
|
||||
</data>
|
||||
<data name="TrayMenu_Settings" xml:space="preserve">
|
||||
</data>
|
||||
<data name="TrayMenu_Settings" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
</data>
|
||||
<data name="TrayMenu_Close" xml:space="preserve">
|
||||
@@ -493,34 +493,28 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
|
||||
<data name="Settings_ExtensionsPage_Reloading_Text.Text" xml:space="preserve">
|
||||
<value>Reloading extensions..</value>
|
||||
</data>
|
||||
<data name="Settings_ExtensionsPage_Banner_Header.Text" xml:space="preserve">
|
||||
<data name="Settings_ExtensionsPage_Banner_Header.Text" xml:space="preserve">
|
||||
<value>Discover more extensions</value>
|
||||
</data>
|
||||
<data name="Settings_ExtensionsPage_Banner_Description.Text" xml:space="preserve">
|
||||
<data name="Settings_ExtensionsPage_Banner_Description.Text" xml:space="preserve">
|
||||
<value>Find more extensions on the Microsoft Store or WinGet.</value>
|
||||
</data>
|
||||
<data name="Settings_ExtensionsPage_Banner_Hyperlink.Content" xml:space="preserve">
|
||||
<data name="Settings_ExtensionsPage_Banner_Hyperlink.Content" xml:space="preserve">
|
||||
<value>Learn how to create your own extensions</value>
|
||||
</data>
|
||||
<data name="Settings_ExtensionsPage_FindExtensions_MicrosoftStore.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<data name="Settings_ExtensionsPage_FindExtensions_MicrosoftStore.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Find extensions on the Microsoft Store</value>
|
||||
</data>
|
||||
<data name="Settings_ExtensionsPage_FindExtensions_MicrosoftStore.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<data name="Settings_ExtensionsPage_FindExtensions_MicrosoftStore.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Microsoft Store</value>
|
||||
</data>
|
||||
<data name="Settings_ExtensionsPage_FindExtensions_WinGet.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<data name="Settings_ExtensionsPage_FindExtensions_WinGet.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Find extensions on WinGet</value>
|
||||
</data>
|
||||
<data name="Settings_ExtensionsPage_FindExtensions_WinGet.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<data name="Settings_ExtensionsPage_FindExtensions_WinGet.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Microsoft Store</value>
|
||||
</data>
|
||||
<data name="Settings_ExtensionsPage_SearchBox_Placeholder.PlaceholderText" xml:space="preserve">
|
||||
<data name="Settings_ExtensionsPage_SearchBox_Placeholder.PlaceholderText" xml:space="preserve">
|
||||
<value>Search extensions</value>
|
||||
</data>
|
||||
<data name="GlobalErrorHandler_CrashMessageBox_Message" xml:space="preserve">
|
||||
<value>Command Palette has encountered a fatal error and must close.</value>
|
||||
</data>
|
||||
<data name="GlobalErrorHandler_CrashMessageBox_Caption" xml:space="preserve">
|
||||
<value>Command Palette - Fatal error</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -25,7 +25,7 @@ public class QueryTests : CommandPaletteUnitTestBase
|
||||
[DataRow("hibernate", "Hibernate")]
|
||||
[DataRow("open recycle", "Open Recycle Bin")]
|
||||
[DataRow("empty recycle", "Empty Recycle Bin")]
|
||||
[DataRow("uefi", "UEFI firmware settings")]
|
||||
[DataRow("uefi", "UEFI Firmware Settings")]
|
||||
public void TopLevelPageQueryTest(string input, string matchedTitle)
|
||||
{
|
||||
var settings = new Settings();
|
||||
@@ -143,6 +143,6 @@ public class QueryTests : CommandPaletteUnitTestBase
|
||||
Assert.IsNotNull(result);
|
||||
var firstItem = result.FirstOrDefault();
|
||||
var firstItemIsUefiCommand = firstItem?.Title.Contains("UEFI", StringComparison.OrdinalIgnoreCase) ?? false;
|
||||
Assert.AreEqual(hasCommand, firstItemIsUefiCommand, $"Expected to match (or not match) 'UEFI firmware settings' but got '{firstItem?.Title}'");
|
||||
Assert.AreEqual(hasCommand, firstItemIsUefiCommand, $"Expected to match (or not match) 'UEFI Firmware Settings' but got '{firstItem?.Title}'");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Microsoft.CmdPal.Ext.TimeDate.UnitTests
|
||||
// Assert
|
||||
Assert.IsNotNull(provider);
|
||||
Assert.IsNotNull(provider.DisplayName);
|
||||
Assert.AreEqual("com.microsoft.cmdpal.builtin.datetime", provider.Id);
|
||||
Assert.AreEqual("DateTime", provider.Id);
|
||||
Assert.IsNotNull(provider.Icon);
|
||||
Assert.IsNotNull(provider.Settings);
|
||||
}
|
||||
@@ -103,7 +103,7 @@ namespace Microsoft.CmdPal.Ext.TimeDate.UnitTests
|
||||
|
||||
// Assert
|
||||
Assert.IsFalse(string.IsNullOrEmpty(subtitle));
|
||||
Assert.IsTrue(subtitle.Contains("Show time and date values in different formats"));
|
||||
Assert.IsTrue(subtitle.Contains("Provides time and date values in different formats"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ public class WebSearchCommandProviderTests
|
||||
var provider = new WebSearchCommandsProvider();
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual("com.microsoft.cmdpal.builtin.websearch", provider.Id);
|
||||
Assert.AreEqual("WebSearch", provider.Id);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
||||
@@ -49,8 +49,8 @@ public class BasicTests : CommandPaletteTestBase
|
||||
{
|
||||
SetSearchBox("time and date");
|
||||
|
||||
var searchFileItem = this.Find<NavigationViewItem>("Time and date");
|
||||
Assert.AreEqual(searchFileItem.Name, "Time and date");
|
||||
var searchFileItem = this.Find<NavigationViewItem>("Time and Date");
|
||||
Assert.AreEqual(searchFileItem.Name, "Time and Date");
|
||||
searchFileItem.DoubleClick();
|
||||
|
||||
SetTimeAndDaterExtensionSearchBox("year");
|
||||
@@ -63,8 +63,8 @@ public class BasicTests : CommandPaletteTestBase
|
||||
{
|
||||
SetSearchBox("Windows Terminal");
|
||||
|
||||
var searchFileItem = this.Find<NavigationViewItem>("Open Windows Terminal profiles");
|
||||
Assert.AreEqual(searchFileItem.Name, "Open Windows Terminal profiles");
|
||||
var searchFileItem = this.Find<NavigationViewItem>("Open Windows Terminal Profiles");
|
||||
Assert.AreEqual(searchFileItem.Name, "Open Windows Terminal Profiles");
|
||||
searchFileItem.DoubleClick();
|
||||
|
||||
// SetSearchBox("PowerShell");
|
||||
@@ -74,10 +74,10 @@ public class BasicTests : CommandPaletteTestBase
|
||||
[TestMethod]
|
||||
public void BasicWindowsSettingsTest()
|
||||
{
|
||||
SetSearchBox("Windows settings");
|
||||
SetSearchBox("Windows Settings");
|
||||
|
||||
var searchFileItem = this.Find<NavigationViewItem>("Windows settings");
|
||||
Assert.AreEqual(searchFileItem.Name, "Windows settings");
|
||||
var searchFileItem = this.Find<NavigationViewItem>("Windows Settings");
|
||||
Assert.AreEqual(searchFileItem.Name, "Windows Settings");
|
||||
searchFileItem.DoubleClick();
|
||||
|
||||
SetSearchBox("power");
|
||||
|
||||
@@ -35,6 +35,7 @@ public partial class AllAppsCommandProvider : CommandProvider
|
||||
|
||||
_listItem = new(_page)
|
||||
{
|
||||
Subtitle = Resources.search_installed_apps,
|
||||
MoreCommands = [new CommandContextItem(AllAppsSettings.Instance.Settings.SettingsPage)],
|
||||
};
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Microsoft.CmdPal.Ext.Apps.Properties {
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
@@ -61,7 +61,7 @@ namespace Microsoft.CmdPal.Ext.Apps.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Search apps.
|
||||
/// Looks up a localized string similar to All Apps.
|
||||
/// </summary>
|
||||
internal static string all_apps {
|
||||
get {
|
||||
@@ -313,7 +313,16 @@ namespace Microsoft.CmdPal.Ext.Apps.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Search apps....
|
||||
/// Looks up a localized string similar to Search installed apps.
|
||||
/// </summary>
|
||||
internal static string search_installed_apps {
|
||||
get {
|
||||
return ResourceManager.GetString("search_installed_apps", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Search installed apps....
|
||||
/// </summary>
|
||||
internal static string search_installed_apps_placeholder {
|
||||
get {
|
||||
|
||||
@@ -124,11 +124,14 @@
|
||||
<data name="installed_apps" xml:space="preserve">
|
||||
<value>Installed apps</value>
|
||||
</data>
|
||||
<data name="search_installed_apps" xml:space="preserve">
|
||||
<value>Search installed apps</value>
|
||||
</data>
|
||||
<data name="all_apps" xml:space="preserve">
|
||||
<value>Search apps</value>
|
||||
<value>All Apps</value>
|
||||
</data>
|
||||
<data name="search_installed_apps_placeholder" xml:space="preserve">
|
||||
<value>Search apps...</value>
|
||||
<value>Search installed apps...</value>
|
||||
</data>
|
||||
<data name="open_path_in_console" xml:space="preserve">
|
||||
<value>Open path in console</value>
|
||||
|
||||
@@ -120,6 +120,7 @@ internal sealed partial class FallbackOpenFileItem : FallbackCommandItem, System
|
||||
var indexerPage = new IndexerPage(query, _searchEngine, _queryCookie, results);
|
||||
Title = string.Format(CultureInfo.CurrentCulture, fallbackItemSearchPageTitleCompositeFormat, query);
|
||||
Icon = Icons.FileExplorerIcon;
|
||||
Subtitle = Resources.Indexer_Subtitle;
|
||||
Command = indexerPage;
|
||||
|
||||
return;
|
||||
|
||||
@@ -33,6 +33,7 @@ public partial class IndexerCommandsProvider : CommandProvider
|
||||
new CommandItem(new IndexerPage())
|
||||
{
|
||||
Title = Resources.Indexer_Title,
|
||||
Subtitle = Resources.Indexer_Subtitle,
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ internal sealed partial class IndexerPage : DynamicListPage, IDisposable
|
||||
_noSearchEmptyContent = new CommandItem(new NoOpCommand())
|
||||
{
|
||||
Icon = Icon,
|
||||
Title = Resources.Indexer_Subtitle,
|
||||
Subtitle = Resources.Indexer_NoSearchQueryMessageTip,
|
||||
};
|
||||
|
||||
|
||||
@@ -295,6 +295,15 @@ namespace Microsoft.CmdPal.Ext.Indexer.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Search files on this device.
|
||||
/// </summary>
|
||||
internal static string Indexer_Subtitle {
|
||||
get {
|
||||
return ResourceManager.GetString("Indexer_Subtitle", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Search files.
|
||||
/// </summary>
|
||||
|
||||
@@ -171,6 +171,9 @@
|
||||
<data name="Indexer_Settings_FallbackCommand_FilePathExist" xml:space="preserve">
|
||||
<value>Only when file path exist</value>
|
||||
</data>
|
||||
<data name="Indexer_Subtitle" xml:space="preserve">
|
||||
<value>Search files on this device</value>
|
||||
</data>
|
||||
<data name="Indexer_Title" xml:space="preserve">
|
||||
<value>Search files</value>
|
||||
</data>
|
||||
|
||||
@@ -25,7 +25,8 @@ public partial class RegistryCommandsProvider : CommandProvider
|
||||
return [
|
||||
new CommandItem(new RegistryListPage(_settingsManager))
|
||||
{
|
||||
Title = "Browse the Windows registry",
|
||||
Title = "Registry",
|
||||
Subtitle = "Navigate the Windows registry",
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace Microsoft.CmdPal.Ext.Shell.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Execute system commands like 'ping' and 'cmd'.
|
||||
/// Looks up a localized string similar to Executes commands (e.g. 'ping', 'cmd').
|
||||
/// </summary>
|
||||
public static string cmd_plugin_description {
|
||||
get {
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
<value>Run commands</value>
|
||||
</data>
|
||||
<data name="cmd_plugin_description" xml:space="preserve">
|
||||
<value>Execute system commands like 'ping' and 'cmd'</value>
|
||||
<value>Executes commands (e.g. 'ping', 'cmd')</value>
|
||||
</data>
|
||||
<data name="cmd_has_been_executed_times" xml:space="preserve">
|
||||
<value>this command has been executed {0} times</value>
|
||||
|
||||
@@ -160,7 +160,7 @@ namespace Microsoft.CmdPal.Ext.System {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Adapter details.
|
||||
/// Looks up a localized string similar to Adapter Details.
|
||||
/// </summary>
|
||||
public static string Microsoft_plugin_ext_adapter_details {
|
||||
get {
|
||||
@@ -169,7 +169,7 @@ namespace Microsoft.CmdPal.Ext.System {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Connection details.
|
||||
/// Looks up a localized string similar to Connection Details.
|
||||
/// </summary>
|
||||
public static string Microsoft_plugin_ext_connection_details {
|
||||
get {
|
||||
@@ -187,7 +187,7 @@ namespace Microsoft.CmdPal.Ext.System {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Open system command.
|
||||
/// Looks up a localized string similar to Open System Command.
|
||||
/// </summary>
|
||||
public static string Microsoft_plugin_ext_fallback_display_title {
|
||||
get {
|
||||
@@ -205,7 +205,7 @@ namespace Microsoft.CmdPal.Ext.System {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to System commands.
|
||||
/// Looks up a localized string similar to System Commands.
|
||||
/// </summary>
|
||||
public static string Microsoft_plugin_ext_system_page_name {
|
||||
get {
|
||||
@@ -214,7 +214,7 @@ namespace Microsoft.CmdPal.Ext.System {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Windows system commands.
|
||||
/// Looks up a localized string similar to Windows System Commands.
|
||||
/// </summary>
|
||||
public static string Microsoft_plugin_ext_system_page_title {
|
||||
get {
|
||||
@@ -628,7 +628,7 @@ namespace Microsoft.CmdPal.Ext.System {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You are about to restart this computer. Are you sure?.
|
||||
/// Looks up a localized string similar to You are about to restart this computer, are you sure?.
|
||||
/// </summary>
|
||||
public static string Microsoft_plugin_sys_restart_computer_confirmation {
|
||||
get {
|
||||
@@ -790,7 +790,7 @@ namespace Microsoft.CmdPal.Ext.System {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to DNS suffix.
|
||||
/// Looks up a localized string similar to DNS Suffix.
|
||||
/// </summary>
|
||||
public static string Microsoft_plugin_sys_Suffix {
|
||||
get {
|
||||
@@ -817,7 +817,7 @@ namespace Microsoft.CmdPal.Ext.System {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to UEFI firmware settings.
|
||||
/// Looks up a localized string similar to UEFI Firmware Settings.
|
||||
/// </summary>
|
||||
public static string Microsoft_plugin_sys_uefi {
|
||||
get {
|
||||
@@ -826,7 +826,7 @@ namespace Microsoft.CmdPal.Ext.System {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You are about to reboot this computer into UEFI firmware settings menu, are you sure?.
|
||||
/// Looks up a localized string similar to You are about to reboot this computer into UEFI Firmware Settings menu, are you sure?.
|
||||
/// </summary>
|
||||
public static string Microsoft_plugin_sys_uefi_confirmation {
|
||||
get {
|
||||
@@ -835,7 +835,7 @@ namespace Microsoft.CmdPal.Ext.System {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Reboot computer into UEFI firmware Settings (requires administrative permissions.).
|
||||
/// Looks up a localized string similar to Reboot computer into UEFI Firmware Settings (Requires administrative permissions.).
|
||||
/// </summary>
|
||||
public static string Microsoft_plugin_sys_uefi_description {
|
||||
get {
|
||||
|
||||
@@ -149,10 +149,10 @@
|
||||
<value>Shutdown</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_ext_connection_details" xml:space="preserve">
|
||||
<value>Connection details</value>
|
||||
<value>Connection Details</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_ext_adapter_details" xml:space="preserve">
|
||||
<value>Adapter details</value>
|
||||
<value>Adapter Details</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_ext_copy" xml:space="preserve">
|
||||
<value>Copy to clipboard</value>
|
||||
@@ -161,10 +161,10 @@
|
||||
<value>Hide disconnected network info</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_ext_system_page_title" xml:space="preserve">
|
||||
<value>Windows system commands</value>
|
||||
<value>Windows System Commands</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_ext_system_page_name" xml:space="preserve">
|
||||
<value>System commands</value>
|
||||
<value>System Commands</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_sys_AdapterName" xml:space="preserve">
|
||||
<value>Adapter name</value>
|
||||
@@ -327,7 +327,7 @@
|
||||
<comment>This should align to the action in Windows of a restarting your computer.</comment>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_sys_restart_computer_confirmation" xml:space="preserve">
|
||||
<value>You are about to restart this computer. Are you sure?</value>
|
||||
<value>You are about to restart this computer, are you sure?</value>
|
||||
<comment>This should align to the action in Windows of a restarting your computer.</comment>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_sys_restart_computer_description" xml:space="preserve">
|
||||
@@ -381,7 +381,7 @@
|
||||
<value>State</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_sys_Suffix" xml:space="preserve">
|
||||
<value>DNS suffix</value>
|
||||
<value>DNS Suffix</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_sys_TunnelConnection" xml:space="preserve">
|
||||
<value>Tunnel</value>
|
||||
@@ -391,15 +391,15 @@
|
||||
<comment>Means type like category. Here it means network interface type (ethernet, wifi, ...).</comment>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_sys_uefi" xml:space="preserve">
|
||||
<value>UEFI firmware settings</value>
|
||||
<value>UEFI Firmware Settings</value>
|
||||
<comment>This should align to the action in Windows Recovery Environment that restart into uefi settings.</comment>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_sys_uefi_confirmation" xml:space="preserve">
|
||||
<value>You are about to reboot this computer into UEFI firmware settings menu, are you sure?</value>
|
||||
<value>You are about to reboot this computer into UEFI Firmware Settings menu, are you sure?</value>
|
||||
<comment>This should align to the action in Windows Recovery Environment that restart into uefi settings.</comment>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_sys_uefi_description" xml:space="preserve">
|
||||
<value>Reboot computer into UEFI firmware Settings (requires administrative permissions.)</value>
|
||||
<value>Reboot computer into UEFI Firmware Settings (Requires administrative permissions.)</value>
|
||||
<comment>This should align to the action in Windows Recovery Environment that restart into uefi settings.</comment>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_sys_Unknown" xml:space="preserve">
|
||||
@@ -415,7 +415,7 @@
|
||||
<value>Sleep</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_ext_fallback_display_title" xml:space="preserve">
|
||||
<value>Execute system commands</value>
|
||||
<value>Open System Command</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_sys_RestartShell" xml:space="preserve">
|
||||
<value>Restart Windows Explorer</value>
|
||||
|
||||
@@ -9,7 +9,7 @@ using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.System;
|
||||
|
||||
public sealed partial class SystemCommandExtensionProvider : CommandProvider
|
||||
public partial class SystemCommandExtensionProvider : CommandProvider
|
||||
{
|
||||
private readonly ICommandItem[] _commands;
|
||||
private static readonly SettingsManager _settingsManager = new();
|
||||
@@ -19,7 +19,7 @@ public sealed partial class SystemCommandExtensionProvider : CommandProvider
|
||||
public SystemCommandExtensionProvider()
|
||||
{
|
||||
DisplayName = Resources.Microsoft_plugin_ext_system_page_name;
|
||||
Id = "com.microsoft.cmdpal.builtin.system";
|
||||
Id = "System";
|
||||
_commands = [
|
||||
new CommandItem(Page)
|
||||
{
|
||||
|
||||
@@ -17,6 +17,11 @@ public sealed partial class TimeDateCalculator
|
||||
/// </summary>
|
||||
private const string InputDelimiter = "::";
|
||||
|
||||
/// <summary>
|
||||
/// A list of conjunctions that we ignore on search
|
||||
/// </summary>
|
||||
private static readonly string[] _conjunctionList = Resources.Microsoft_plugin_timedate_Search_ConjunctionList.Split("; ");
|
||||
|
||||
/// <summary>
|
||||
/// Searches for results
|
||||
/// </summary>
|
||||
|
||||
@@ -349,7 +349,7 @@ namespace Microsoft.CmdPal.Ext.TimeDate {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Time and date.
|
||||
/// Looks up a localized string similar to Time and Date.
|
||||
/// </summary>
|
||||
public static string Microsoft_plugin_timedate_main_page_title {
|
||||
get {
|
||||
@@ -448,7 +448,7 @@ namespace Microsoft.CmdPal.Ext.TimeDate {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Show time and date values in different formats.
|
||||
/// Looks up a localized string similar to Provides time and date values in different formats.
|
||||
/// </summary>
|
||||
public static string Microsoft_plugin_timedate_plugin_description {
|
||||
get {
|
||||
@@ -484,7 +484,7 @@ namespace Microsoft.CmdPal.Ext.TimeDate {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Time and date.
|
||||
/// Looks up a localized string similar to Time and Date.
|
||||
/// </summary>
|
||||
public static string Microsoft_plugin_timedate_plugin_name {
|
||||
get {
|
||||
@@ -501,6 +501,15 @@ namespace Microsoft.CmdPal.Ext.TimeDate {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to "for; and; nor; but; or; so".
|
||||
/// </summary>
|
||||
public static string Microsoft_plugin_timedate_Search_ConjunctionList {
|
||||
get {
|
||||
return ResourceManager.GetString("Microsoft_plugin_timedate_Search_ConjunctionList", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Date and time; Time and Date; Custom format.
|
||||
/// </summary>
|
||||
|
||||
@@ -202,7 +202,7 @@
|
||||
<comment>'UTC' means here 'Universal Time Convention'</comment>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_timedate_plugin_description" xml:space="preserve">
|
||||
<value>Show time and date values in different formats</value>
|
||||
<value>Provides time and date values in different formats</value>
|
||||
<comment>Do not translate the placeholders like '{0}' because it will be replaced in code.</comment>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_timedate_plugin_description_example_calendarWeek" xml:space="preserve">
|
||||
@@ -215,7 +215,7 @@
|
||||
<value>Time</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_timedate_plugin_name" xml:space="preserve">
|
||||
<value>Time and date</value>
|
||||
<value>Time and Date</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_timedate_Rfc1123" xml:space="preserve">
|
||||
<value>RFC1123</value>
|
||||
@@ -252,6 +252,10 @@
|
||||
<value>Current Time; Now</value>
|
||||
<comment>Don't change order</comment>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_timedate_Search_ConjunctionList" xml:space="preserve">
|
||||
<value>for; and; nor; but; or; so</value>
|
||||
<comment>List of conjunctions. We don't add 'yet' because this can be a synonym of 'now' which might be problematic on localized searches.</comment>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_timedate_Second" xml:space="preserve">
|
||||
<value>Second</value>
|
||||
</data>
|
||||
@@ -354,7 +358,7 @@
|
||||
<value>Error: Invalid input</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_timedate_main_page_title" xml:space="preserve">
|
||||
<value>Time and date</value>
|
||||
<value>Time and Date</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_timedate_InvalidInput_SupportedInput" xml:space="preserve">
|
||||
<value>A {0}format name{0}, a {0}valid date or time value{0}, or a {0}prefixed number{0}. To search for a format in a specific date/time please use the syntax {0}format::date/time/number{0}.{1}Supported prefixes:{2}'{0}u{0}' for Unix Timestamp{2}'{0}ums{0}' for Unix Timestamp in milliseconds{2}'{0}ft{0}' for Windows file time{2}'{0}oa{0}' for OLE Automation Date{2}'{0}exc{0}' for Excel's 1900 date value{2}'{0}exf{0}' for Excel's 1904 date value</value>
|
||||
|
||||
@@ -12,7 +12,7 @@ using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.TimeDate;
|
||||
|
||||
public sealed partial class TimeDateCommandsProvider : CommandProvider
|
||||
public partial class TimeDateCommandsProvider : CommandProvider
|
||||
{
|
||||
private readonly CommandItem _command;
|
||||
private static readonly SettingsManager _settingsManager = new SettingsManager();
|
||||
@@ -23,7 +23,7 @@ public sealed partial class TimeDateCommandsProvider : CommandProvider
|
||||
public TimeDateCommandsProvider()
|
||||
{
|
||||
DisplayName = Resources.Microsoft_plugin_timedate_plugin_name;
|
||||
Id = "com.microsoft.cmdpal.builtin.datetime";
|
||||
Id = "DateTime";
|
||||
_command = new CommandItem(_timeDateExtensionPage)
|
||||
{
|
||||
Icon = _timeDateExtensionPage.Icon,
|
||||
|
||||
@@ -11,7 +11,7 @@ using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.WebSearch;
|
||||
|
||||
public sealed partial class WebSearchCommandsProvider : CommandProvider
|
||||
public partial class WebSearchCommandsProvider : CommandProvider
|
||||
{
|
||||
private readonly SettingsManager _settingsManager = new();
|
||||
private readonly FallbackExecuteSearchItem _fallbackItem;
|
||||
@@ -22,7 +22,7 @@ public sealed partial class WebSearchCommandsProvider : CommandProvider
|
||||
|
||||
public WebSearchCommandsProvider()
|
||||
{
|
||||
Id = "com.microsoft.cmdpal.builtin.websearch";
|
||||
Id = "WebSearch";
|
||||
DisplayName = Resources.extension_name;
|
||||
Icon = Icons.WebSearch;
|
||||
Settings = _settingsManager.Settings;
|
||||
|
||||
@@ -124,7 +124,16 @@ namespace Microsoft.CmdPal.Ext.WinGet.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Add Command Palette extensions from WinGet.
|
||||
/// Looks up a localized string similar to Search for extensions on WinGet.
|
||||
/// </summary>
|
||||
public static string winget_install_extensions_subtitle {
|
||||
get {
|
||||
return ResourceManager.GetString("winget_install_extensions_subtitle", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Install Command Palette extensions.
|
||||
/// </summary>
|
||||
public static string winget_install_extensions_title {
|
||||
get {
|
||||
@@ -196,7 +205,7 @@ namespace Microsoft.CmdPal.Ext.WinGet.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Find apps on WinGet.
|
||||
/// Looks up a localized string similar to Search WinGet.
|
||||
/// </summary>
|
||||
public static string winget_page_name {
|
||||
get {
|
||||
@@ -259,7 +268,7 @@ namespace Microsoft.CmdPal.Ext.WinGet.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Add Command Palette extensions from the Microsoft Store.
|
||||
/// Looks up a localized string similar to Search for extensions in the Store.
|
||||
/// </summary>
|
||||
public static string winget_search_store_title {
|
||||
get {
|
||||
|
||||
@@ -127,15 +127,19 @@
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="winget_install_extensions_title" xml:space="preserve">
|
||||
<value>Add Command Palette extensions from WinGet</value>
|
||||
<value>Install Command Palette extensions</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="winget_install_extensions_subtitle" xml:space="preserve">
|
||||
<value>Search for extensions on WinGet</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="winget_search_store_title" xml:space="preserve">
|
||||
<value>Add Command Palette extensions from the Microsoft Store</value>
|
||||
<value>Search for extensions in the Store</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="winget_page_name" xml:space="preserve">
|
||||
<value>Find apps on WinGet</value>
|
||||
<value>Search WinGet</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="winget_create_catalog_error" xml:space="preserve">
|
||||
|
||||
@@ -27,6 +27,7 @@ public partial class WinGetExtensionCommandsProvider : CommandProvider
|
||||
new WinGetExtensionPage(WinGetExtensionPage.ExtensionsTag) { Title = Properties.Resources.winget_install_extensions_title })
|
||||
{
|
||||
Title = Properties.Resources.winget_install_extensions_title,
|
||||
Subtitle = Properties.Resources.winget_install_extensions_subtitle,
|
||||
},
|
||||
|
||||
new ListItem(
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace Microsoft.CmdPal.Ext.WindowWalker.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to On all desktops.
|
||||
/// Looks up a localized string similar to On all Desktops.
|
||||
/// </summary>
|
||||
public static string VirtualDesktopHelper_AllDesktops {
|
||||
get {
|
||||
@@ -196,7 +196,7 @@ namespace Microsoft.CmdPal.Ext.WindowWalker.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Not responding.
|
||||
/// Looks up a localized string similar to Not Responding.
|
||||
/// </summary>
|
||||
public static string windowwalker_NotResponding {
|
||||
get {
|
||||
|
||||
@@ -209,7 +209,7 @@
|
||||
<value>When disabled, windows will be sorted by title</value>
|
||||
</data>
|
||||
<data name="windowwalker_NotResponding" xml:space="preserve">
|
||||
<value>Not responding</value>
|
||||
<value>Not Responding</value>
|
||||
</data>
|
||||
<data name="window_walker_top_level_command_title" xml:space="preserve">
|
||||
<value>Switch between open windows</value>
|
||||
@@ -218,7 +218,7 @@
|
||||
<value>Switch to</value>
|
||||
</data>
|
||||
<data name="VirtualDesktopHelper_AllDesktops" xml:space="preserve">
|
||||
<value>On all desktops</value>
|
||||
<value>On all Desktops</value>
|
||||
</data>
|
||||
<data name="VirtualDesktopHelper_Desktop" xml:space="preserve">
|
||||
<value>Desktop {0}</value>
|
||||
|
||||
@@ -23,7 +23,8 @@ public partial class WindowsServicesCommandsProvider : CommandProvider
|
||||
return [
|
||||
new CommandItem(new ServicesListPage())
|
||||
{
|
||||
Title = "Manage Windows services",
|
||||
Title = "Windows Services",
|
||||
Subtitle = "Manage Windows Services",
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.WindowsSettings;
|
||||
|
||||
public sealed partial class WindowsSettingsCommandsProvider : CommandProvider
|
||||
public partial class WindowsSettingsCommandsProvider : CommandProvider
|
||||
{
|
||||
private readonly CommandItem _searchSettingsListItem;
|
||||
|
||||
@@ -22,7 +22,7 @@ public sealed partial class WindowsSettingsCommandsProvider : CommandProvider
|
||||
|
||||
public WindowsSettingsCommandsProvider()
|
||||
{
|
||||
Id = "com.microsoft.cmdpal.builtin.windowssettings";
|
||||
Id = "Windows.Settings";
|
||||
DisplayName = Resources.WindowsSettingsProvider_DisplayName;
|
||||
Icon = Icons.WindowsSettingsIcon;
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace Microsoft.CmdPal.Ext.WindowsTerminal.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Open Windows Terminal profiles.
|
||||
/// Looks up a localized string similar to Open Windows Terminal Profiles.
|
||||
/// </summary>
|
||||
internal static string list_item_title {
|
||||
get {
|
||||
|
||||
@@ -156,7 +156,7 @@
|
||||
<value>Settings</value>
|
||||
</data>
|
||||
<data name="list_item_title" xml:space="preserve">
|
||||
<value>Open Windows Terminal profiles</value>
|
||||
<value>Open Windows Terminal Profiles</value>
|
||||
</data>
|
||||
<data name="preferred_channel" xml:space="preserve">
|
||||
<value>Preferred channel</value>
|
||||
|
||||
@@ -63,7 +63,7 @@ internal sealed partial class SampleListPageWithDetails : ListPage
|
||||
Details = new Details()
|
||||
{
|
||||
Title = "Hero Image Example",
|
||||
HeroImage = new IconInfo("https://m.media-amazon.com/images/M/MV5BNDBkMzVmNGQtYTM2OC00OWRjLTk5OWMtNzNkMDI4NjFjNTZmXkEyXkFqcGdeQXZ3ZXNsZXk@._V1_QL75_UX500_CR0,0,500,281_.jpg"), /* #no-spell-check-line */
|
||||
HeroImage = new IconInfo("https://m.media-amazon.com/images/M/MV5BNDBkMzVmNGQtYTM2OC00OWRjLTk5OWMtNzNkMDI4NjFjNTZmXkEyXkFqcGdeQXZ3ZXNsZXk@._V1_QL75_UX500_CR0,0,500,281_.jpg"),
|
||||
Body = "It is literally an image of a hero",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -62,18 +62,10 @@
|
||||
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Only enable Native AOT for Release builds to avoid System.Private.CoreLib.dll version conflicts during development -->
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||
<PropertyGroup>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<PublishAot>true</PublishAot>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- For Debug builds, use standard JIT compilation -->
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
|
||||
<PublishTrimmed>false</PublishTrimmed>
|
||||
<PublishSingleFile>false</PublishSingleFile>
|
||||
<PublishAot>false</PublishAot>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -10,7 +10,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using ImageResizer.Properties;
|
||||
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using Moq.Protected;
|
||||
@@ -101,9 +101,7 @@ namespace ImageResizer.Models
|
||||
private static ResizeBatch CreateBatch(Action<string> executeAction)
|
||||
{
|
||||
var mock = new Mock<ResizeBatch> { CallBase = true };
|
||||
mock.Protected()
|
||||
.Setup("Execute", ItExpr.IsAny<string>(), ItExpr.IsAny<Settings>())
|
||||
.Callback((string file, Settings settings) => executeAction(file));
|
||||
mock.Protected().Setup("Execute", ItExpr.IsAny<string>()).Callback(executeAction);
|
||||
|
||||
return mock.Object;
|
||||
}
|
||||
|
||||
@@ -87,14 +87,9 @@ namespace ImageResizer.Models
|
||||
public IEnumerable<ResizeError> Process(Action<int, double> reportProgress, CancellationToken cancellationToken)
|
||||
{
|
||||
double total = Files.Count;
|
||||
int completed = 0;
|
||||
var completed = 0;
|
||||
var errors = new ConcurrentBag<ResizeError>();
|
||||
|
||||
// NOTE: Settings.Default is captured once before parallel processing.
|
||||
// Any changes to settings on disk during this batch will NOT be reflected until the next batch.
|
||||
// This improves performance and predictability by avoiding repeated mutex acquisition and behaviour change results in a batch.
|
||||
var settings = Settings.Default;
|
||||
|
||||
// TODO: If we ever switch to Windows.Graphics.Imaging, we can get a lot more throughput by using the async
|
||||
// APIs and a custom SynchronizationContext
|
||||
Parallel.ForEach(
|
||||
@@ -102,12 +97,13 @@ namespace ImageResizer.Models
|
||||
new ParallelOptions
|
||||
{
|
||||
CancellationToken = cancellationToken,
|
||||
MaxDegreeOfParallelism = Environment.ProcessorCount,
|
||||
},
|
||||
(file, state, i) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Execute(file, settings);
|
||||
Execute(file);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -115,13 +111,14 @@ namespace ImageResizer.Models
|
||||
}
|
||||
|
||||
Interlocked.Increment(ref completed);
|
||||
|
||||
reportProgress(completed, total);
|
||||
});
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
protected virtual void Execute(string file, Settings settings)
|
||||
=> new ResizeOperation(file, DestinationDirectory, settings).Execute();
|
||||
protected virtual void Execute(string file)
|
||||
=> new ResizeOperation(file, DestinationDirectory, Settings.Default).Execute();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,42 +461,33 @@ namespace ImageResizer.Properties
|
||||
{
|
||||
}
|
||||
|
||||
if (App.Current?.Dispatcher != null)
|
||||
// Needs to be called on the App UI thread as the properties are bound to the UI.
|
||||
App.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
// Needs to be called on the App UI thread as the properties are bound to the UI.
|
||||
App.Current.Dispatcher.Invoke(() => ReloadCore(jsonSettings));
|
||||
}
|
||||
else
|
||||
{
|
||||
ReloadCore(jsonSettings);
|
||||
}
|
||||
ShrinkOnly = jsonSettings.ShrinkOnly;
|
||||
Replace = jsonSettings.Replace;
|
||||
IgnoreOrientation = jsonSettings.IgnoreOrientation;
|
||||
RemoveMetadata = jsonSettings.RemoveMetadata;
|
||||
JpegQualityLevel = jsonSettings.JpegQualityLevel;
|
||||
PngInterlaceOption = jsonSettings.PngInterlaceOption;
|
||||
TiffCompressOption = jsonSettings.TiffCompressOption;
|
||||
FileName = jsonSettings.FileName;
|
||||
KeepDateModified = jsonSettings.KeepDateModified;
|
||||
FallbackEncoder = jsonSettings.FallbackEncoder;
|
||||
CustomSize = jsonSettings.CustomSize;
|
||||
SelectedSizeIndex = jsonSettings.SelectedSizeIndex;
|
||||
|
||||
if (jsonSettings.Sizes.Count > 0)
|
||||
{
|
||||
Sizes.Clear();
|
||||
Sizes.AddRange(jsonSettings.Sizes);
|
||||
|
||||
// Ensure Ids are unique and handle missing Ids
|
||||
IdRecoveryHelper.RecoverInvalidIds(Sizes);
|
||||
}
|
||||
});
|
||||
|
||||
_jsonMutex.ReleaseMutex();
|
||||
}
|
||||
|
||||
private void ReloadCore(Settings jsonSettings)
|
||||
{
|
||||
ShrinkOnly = jsonSettings.ShrinkOnly;
|
||||
Replace = jsonSettings.Replace;
|
||||
IgnoreOrientation = jsonSettings.IgnoreOrientation;
|
||||
RemoveMetadata = jsonSettings.RemoveMetadata;
|
||||
JpegQualityLevel = jsonSettings.JpegQualityLevel;
|
||||
PngInterlaceOption = jsonSettings.PngInterlaceOption;
|
||||
TiffCompressOption = jsonSettings.TiffCompressOption;
|
||||
FileName = jsonSettings.FileName;
|
||||
KeepDateModified = jsonSettings.KeepDateModified;
|
||||
FallbackEncoder = jsonSettings.FallbackEncoder;
|
||||
CustomSize = jsonSettings.CustomSize;
|
||||
SelectedSizeIndex = jsonSettings.SelectedSizeIndex;
|
||||
|
||||
if (jsonSettings.Sizes.Count > 0)
|
||||
{
|
||||
Sizes.Clear();
|
||||
Sizes.AddRange(jsonSettings.Sizes);
|
||||
|
||||
// Ensure Ids are unique and handle missing Ids
|
||||
IdRecoveryHelper.RecoverInvalidIds(Sizes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace Microsoft.PowerToys.Run.Plugin.System.UnitTests
|
||||
var result = main.Object.Query(expectedQuery).FirstOrDefault().SubTitle;
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual("Reboot computer into UEFI firmware settings (Requires administrative permissions.)", result);
|
||||
Assert.AreEqual("Reboot computer into UEFI Firmware Settings (Requires administrative permissions.)", result);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Microsoft.PowerToys.Run.Plugin.System.Properties {
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
@@ -682,7 +682,7 @@ namespace Microsoft.PowerToys.Run.Plugin.System.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You are about to reboot this computer into UEFI firmware settings menu, are you sure?.
|
||||
/// Looks up a localized string similar to You are about to reboot this computer into UEFI Firmware Settings menu, are you sure?.
|
||||
/// </summary>
|
||||
internal static string Microsoft_plugin_sys_uefi_confirmation {
|
||||
get {
|
||||
@@ -691,7 +691,7 @@ namespace Microsoft.PowerToys.Run.Plugin.System.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Reboot computer into UEFI firmware settings (Requires administrative permissions.).
|
||||
/// Looks up a localized string similar to Reboot computer into UEFI Firmware Settings (Requires administrative permissions.).
|
||||
/// </summary>
|
||||
internal static string Microsoft_plugin_sys_uefi_description {
|
||||
get {
|
||||
|
||||
@@ -362,15 +362,15 @@
|
||||
<comment>Means type like category. Here it means network interface type (ethernet, wifi, ...).</comment>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_sys_uefi" xml:space="preserve">
|
||||
<value>UEFI firmware settings</value>
|
||||
<value>UEFI Firmware Settings</value>
|
||||
<comment>This should align to the action in Windows Recovery Environment that restart into uefi settings.</comment>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_sys_uefi_confirmation" xml:space="preserve">
|
||||
<value>You are about to reboot this computer into UEFI firmware settings menu, are you sure?</value>
|
||||
<value>You are about to reboot this computer into UEFI Firmware Settings menu, are you sure?</value>
|
||||
<comment>This should align to the action in Windows Recovery Environment that restart into uefi settings.</comment>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_sys_uefi_description" xml:space="preserve">
|
||||
<value>Reboot computer into UEFI firmware settings (Requires administrative permissions.)</value>
|
||||
<value>Reboot computer into UEFI Firmware Settings (Requires administrative permissions.)</value>
|
||||
<comment>This should align to the action in Windows Recovery Environment that restart into uefi settings.</comment>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_sys_Unknown" xml:space="preserve">
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
<comment>'UTC' means here 'Universal Time Convention'</comment>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_timedate_plugin_description" xml:space="preserve">
|
||||
<value>Shows time and date values for the system time or a custom time stamp (e.g.'{0}', '{1}', '{2}', '{3}')</value>
|
||||
<value>Provides time and date values for the system time or a custom time stamp (e.g.'{0}', '{1}', '{2}', '{3}')</value>
|
||||
<comment>Do not translate the placeholders like '{0}' because it will be replaced in code.</comment>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_timedate_plugin_description_example_calendarWeek" xml:space="preserve">
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace PowerLauncher.Helper
|
||||
// Many bug reports because users see the "Report problem UI" after "the" crash with System.Runtime.InteropServices.COMException 0xD0000701 or 0x80263001.
|
||||
// However, displaying this "Report problem UI" during WPF crashes, especially when DWM composition is changing, is not ideal; some users reported it hangs for up to a minute before the "Report problem UI" appears.
|
||||
// This change modifies the behavior to log the exception instead of showing the "Report problem UI".
|
||||
if (ExceptionHelper.IsRecoverableDwmCompositionException(e as System.Runtime.InteropServices.COMException))
|
||||
if (IsDwmCompositionException(e as System.Runtime.InteropServices.COMException))
|
||||
{
|
||||
var logger = LogManager.GetLogger(LoggerName);
|
||||
logger.Error($"From {(isNotUIThread ? "non" : string.Empty)} UI thread's exception: {ExceptionFormatter.FormatException(e)}");
|
||||
@@ -91,5 +91,22 @@ namespace PowerLauncher.Helper
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsDwmCompositionException(System.Runtime.InteropServices.COMException comException)
|
||||
{
|
||||
if (comException == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var stackTrace = comException.StackTrace;
|
||||
if (string.IsNullOrEmpty(stackTrace))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for common DWM composition changed patterns in the stack trace
|
||||
return stackTrace.Contains("DwmCompositionChanged");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,46 +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.Runtime.InteropServices;
|
||||
|
||||
namespace PowerLauncher.Helper
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore", Justification = "Win32 naming conventions")]
|
||||
internal static class ExceptionHelper
|
||||
{
|
||||
private const string PresentationFrameworkExceptionSource = "PresentationFramework";
|
||||
|
||||
private const int DWM_E_COMPOSITIONDISABLED = unchecked((int)0x80263001);
|
||||
|
||||
// HRESULT for NT STATUS STATUS_MESSAGE_LOST (0xC0000701 | 0x10000000 == 0xD0000701)
|
||||
private const int STATUS_MESSAGE_LOST_HR = unchecked((int)0xD0000701);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the exception is a recoverable DWM composition exception.
|
||||
/// </summary>
|
||||
internal static bool IsRecoverableDwmCompositionException(Exception exception)
|
||||
{
|
||||
if (exception is not COMException comException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (comException.HResult is DWM_E_COMPOSITIONDISABLED)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (comException.HResult is STATUS_MESSAGE_LOST_HR && comException.Source == PresentationFrameworkExceptionSource)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for common DWM composition changed patterns in the stack trace
|
||||
var stackTrace = comException.StackTrace;
|
||||
return !string.IsNullOrEmpty(stackTrace) &&
|
||||
stackTrace.Contains("DwmCompositionChanged");
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user