Compare commits

...

17 Commits

Author SHA1 Message Date
Shawn Yuan
12534a986f update
Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
2025-06-03 12:40:10 +08:00
Shawn Yuan
8916442406 update
Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
2025-06-03 11:57:51 +08:00
Shawn Yuan
2ef0262897 update
Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
2025-06-03 11:53:51 +08:00
Shawn Yuan
7a0ebbd21e allow pipeline to use unstable winappsdk.
Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
2025-06-03 10:57:42 +08:00
Dustin L. Howett
c6a4ee1441 build: try even harder to find a working VC tools version (#39862)
I can't explain this, but VS 17.14 ships with VisualCpp.Tools.Core
version 14.44.35208 but the files say 14.44.35207.

See https://github.com/microsoft/terminal/pull/18996 for more info.
2025-06-02 15:47:56 -05:00
mbartlett21
89c33fae68 [peek, explorer] Update QOI reader for 3-channel images (#39304)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Make sure we account for Bitmap row length being a multiple of 4 when
reading Qoi files.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] **Closes:** #31948
- [ ] **Communication:** Not discussed, but a bug fix
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end user facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments



<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Built and run and restarted file explorer.
Sample files from my comment on the issue (after rewriting each one to
force the thumbnail to regenrate):

![image](https://github.com/user-attachments/assets/5874f958-0f03-4683-abe3-d54c979ad2a1)
2025-05-30 18:32:40 +08:00
Yu Leng
c9922302e5 [PowerRename] Add ModificationTime and AccessTime support when renaming with $YY-$MM-$DD patterns (#39653)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
1. Add new configuration to control this behaviour. By default, set to
creation time to align with previous version
2. Add UI in PowerRename's MainWindow
3. Implement the logic


![image](https://github.com/user-attachments/assets/fde6731b-73f9-453f-8b68-6ce66589f44a)


Original discussion here:
https://github.com/microsoft/PowerToys/pull/38186

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] **Closes:** #36040
- [x] **Communication:** I've discussed this with core contributors
already. If work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** All end user facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Heiko <61519853+htcfreek@users.noreply.github.com>
2025-05-30 13:07:20 +08:00
Kai Tao
498ef676f4 Runner: Add log when error happen in setting startup (#39801)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Add log when error happen in setting startup 

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [X] **Closes:** #39798
- [ ] **Communication:** I've discussed this with core contributors
already. If work hasn't been agreed, this work might be rejected
- [X] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end user facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed


![image](https://github.com/user-attachments/assets/2208c65f-4d42-4612-a77e-d92a748fd723)

Set error in code deliberately, and verify that the error appears in the
log.
2025-05-30 10:03:36 +08:00
zhw
3821e8427c [Localization] Add comments in Resources.resw (#39778)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This PR mainly add comments in
src/modules/AdvancedPaste/AdvancedPaste/Strings/en-us/Resources.resw to
solve issues raised by localization team.

---------

Co-authored-by: ArleneYu <yuzw@pku.edu.cn>
2025-05-29 18:09:05 +08:00
Royce Williams
964e5c9d5e cmdpal README: minor typo (#39764)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Minor typo it's -> its

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

<!-- Provide a more detailed description of the PR, other things fixed
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
README-only change

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
n/a
2025-05-28 20:13:05 +00:00
Michael Jolley
48d9d19df1 CmdPal: Styling critical context items using the SystemFillColorCriticalBrush (#39645)
Styles context items based on the IsCritical property.


![image](https://github.com/user-attachments/assets/aa1ee0b0-de09-45af-8f5e-74dff666fbb4)


![image](https://github.com/user-attachments/assets/90a7f750-c949-4f76-b699-db2e29251414)

Closes #38307
2025-05-28 14:35:26 -05:00
Kai Tao
d21b7fac7b Log: Clear mwb module interface old version log and clear dotnet old version log (#39652)
* Initial plan for issue

* Add cleanup of old version log folders for Mouse Without Borders

Co-authored-by: vanzue <69313318+vanzue@users.noreply.github.com>

* Add try-catch block to cleanup_old_logs function

Co-authored-by: vanzue <69313318+vanzue@users.noreply.github.com>

* Refactor Mouse Without Borders log cleanup to use common mechanism

Co-authored-by: vanzue <69313318+vanzue@users.noreply.github.com>

* Investigate .NET logger cleanup mechanism for old version logs

Co-authored-by: vanzue <69313318+vanzue@users.noreply.github.com>

* delete in other thread

* clear mwb previous folder

* slow down the deletion

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2025-05-28 18:53:35 +08:00
Mengyuan
02a9269435 [Fuzz] Add Fuzz testing for FancyZones (#38165)
* Add FancyZones.FuzzTests Module for fuzzing grid from json element

* remove unuse test cs

* fix spell error

* remove specific modify in job-fuzz.yml

* add Testably.Abstractions.FileSystem.Interface.dll

* fix spell error

* add dependency dll

* add annotations

* fix pipeline error  need to import 'Common.Dotnet.CsWinRT.props'
2025-05-28 14:56:37 +08:00
PesBandi
f642720087 [CmdPal][Calc]Trim leading = to support pasting formulas (#39743)
* [CmdPal][Calc]Trim leading `=` to support pasting formulas

* Update README.md

* Update README.md
2025-05-28 14:25:07 +08:00
Bradley Myers
53b989857b Option to toggle the system tray icon (#23220)
* Added option to toggle the system tray icon

At the moment, this hides the icon making the settings window inaccessible without first modifying the general `settings.json` file.

* Use IPC messages to manage the tray icon settings

* Fix launching second window binds to active settings process

* Added context menu option to hide tray icon

* Added Exit PT button to settings ui NavigationView.PaneFooter

* Moved DllImports to NativeMethods.cs

* Sentence case titles

* Fix whitespace

* Re-add exit icon to NavView

* Re-added toggle switch to new UI

* Fix build

* Fix build after merge main

* Fix the string to display

* add shut down buttons

* finish polish

* fix string

* Styling tweaks to titlebar and settingscards

* fix comment

* fix unit test

* fix ut

---------

Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
Co-authored-by: vanzue <vanzue@outlook.com>
Co-authored-by: Kayla Cinnamon <cinnamon@microsoft.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
2025-05-26 17:03:35 +08:00
Yu Leng
718e725571 [cmdpal] Fix calculator error when pressing Space (#39679)
Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
2025-05-26 11:37:38 +08:00
Gordon Lam
a804bf86a4 Update to WinAppSDK 1.7.2 (#39592)
Update to WinAppSDK 1.7.2
2025-05-23 11:19:24 +08:00
67 changed files with 870 additions and 100 deletions

View File

@@ -126,16 +126,15 @@ Get-ChildItem -Path $rootPath -Recurse packages.config | ForEach-Object {
}
# Update Directory.Packages.props file
$propsFile = [System.IO.Path]::Combine($rootPath,"Directory.Packages.props")
if (Test-Path $propsFile) {
$file = Read-FileWithEncoding -Path $propsFile
Get-ChildItem -Path $rootPath -Recurse "Directory.Packages.props" | ForEach-Object {
$file = Read-FileWithEncoding -Path $_.FullName
$content = $file.Content
if ($content -match '<PackageVersion Include="Microsoft.WindowsAppSDK"') {
$newVersionString = '<PackageVersion Include="Microsoft.WindowsAppSDK" Version="' + $WinAppSDKVersion + '" />'
$oldVersionString = '<PackageVersion Include="Microsoft.WindowsAppSDK" Version="[-.0-9a-zA-Z]*" />'
$content = $content -replace $oldVersionString, $newVersionString
Write-FileWithEncoding -Path $propsFile -Content $content -Encoding $file.encoding
Write-Host "Modified " $propsFile
Write-FileWithEncoding -Path $_.FullName -Content $content -Encoding $file.encoding
Write-Host "Modified " $_.FullName
}
}
@@ -144,8 +143,8 @@ Get-ChildItem -Path $rootPath -Recurse *.vcxproj | ForEach-Object {
$file = Read-FileWithEncoding -Path $_.FullName
$content = $file.Content
if ($content -match '\\Microsoft.WindowsAppSDK.') {
$newVersionString = '\Microsoft.WindowsAppSDK.' + $WinAppSDKVersion + '\'
$oldVersionString = '\\Microsoft.WindowsAppSDK.[-.0-9a-zA-Z]*\\'
$newVersionString = '\Microsoft.WindowsAppSDK.' + $WinAppSDKVersion
$oldVersionString = '\\Microsoft.WindowsAppSDK.(?=[-.0-9a-zA-Z]*\d)[-.0-9a-zA-Z]*' #positive lookahead for at least a digit
$content = $content -replace $oldVersionString, $newVersionString
Write-FileWithEncoding -Path $_.FullName -Content $content -Encoding $file.encoding
Write-Host "Modified " $_.FullName

View File

@@ -37,6 +37,10 @@ parameters:
- name: useExperimentalVersion
type: boolean
default: false
- name: useUnstableWinAppSDK
type: boolean
displayName: "Allow using unstable WinAppSDK package (even if build failed)"
default: false
extends:
template: templates/pipeline-ci-build.yml
@@ -48,3 +52,4 @@ extends:
useLatestWinAppSDK: ${{ parameters.useLatestWinAppSDK }}
winAppSDKVersionNumber: ${{ parameters.winAppSDKVersionNumber }}
useExperimentalVersion: ${{ parameters.useExperimentalVersion }}
useUnstableWinAppSDK: ${{ parameters.useUnstableWinAppSDK }}

View File

@@ -68,6 +68,9 @@ parameters:
- name: useExperimentalVersion
type: boolean
default: false
- name: useUnstableWinAppSDK
type: boolean
default: false
- name: csProjectsToPublish
type: object
default:
@@ -204,6 +207,7 @@ jobs:
parameters:
versionNumber: ${{ parameters.winAppSDKVersionNumber }}
useExperimentalVersion: ${{ parameters.useExperimentalVersion }}
useUnstableWinAppSDK: ${{ parameters.useUnstableWinAppSDK }}
- ${{ if eq(parameters.useLatestWinAppSDK, false)}}:
- template: .\steps-restore-nuget.yml

View File

@@ -34,6 +34,9 @@ parameters:
- name: useExperimentalVersion
type: boolean
default: false
- name: useUnstableWinAppSDK
type: boolean
default: false
stages:
- ${{ each platform in parameters.buildPlatforms }}:
@@ -58,6 +61,7 @@ stages:
runTests: ${{ parameters.runTests }}
useVSPreview: ${{ parameters.useVSPreview }}
useLatestWinAppSDK: ${{ parameters.useLatestWinAppSDK }}
useUnstableWinAppSDK: ${{ parameters.useUnstableWinAppSDK }}
${{ if eq(parameters.useLatestWinAppSDK, true) }}:
winAppSDKVersionNumber: ${{ parameters.winAppSDKVersionNumber }}
useExperimentalVersion: ${{ parameters.useExperimentalVersion }}

View File

@@ -5,6 +5,9 @@ parameters:
- name: useExperimentalVersion
type: boolean
default: false
- name: useUnstableWinAppSDK
type: boolean
default: false
steps:
- task: NuGetAuthenticate@1
@@ -28,6 +31,8 @@ steps:
buildType: 'specific'
project: '55e8140e-57ac-4e5f-8f9c-c7c15b51929d'
definition: '104083'
allowPartiallySucceededBuilds: ${{ parameters.useUnstableWinAppSDK }}
allowFailedBuilds: ${{ parameters.useUnstableWinAppSDK }}
buildVersionToDownload: 'latestFromBranch'
branchName: 'refs/heads/release/${{ parameters.versionNumber }}-stable'
artifactName: 'WindowsAppSDK_Nuget_And_MSIX'

View File

@@ -1,7 +1,28 @@
$VSInstances = ([xml](& 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -include packages -format xml))
$VSPackages = $VSInstances.instances.instance.packages.package
$LatestVCPackage = ($VSInstances.instances.instance.packages.package | ? { $_.id -eq "Microsoft.VisualCpp.Tools.Core" })
$LatestVCPackage = ($VSPackages | ? { $_.id -eq "Microsoft.VisualCpp.Tools.Core" })
$LatestVCToolsVersion = $LatestVCPackage.version;
$VSRoot = (& 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property 'resolvedInstallationPath')
$VCToolsRoot = Join-Path $VSRoot "VC\Tools\MSVC"
# We have observed a few instances where the VC tools package version actually
# differs from the version on the files themselves. We might as well check
# whether the version we just found _actually exists_ before we use it.
# We'll use whichever highest version exists.
$PackageVCToolPath = Join-Path $VCToolsRoot $LatestVCToolsVersion
If ($Null -Eq (Get-Item $PackageVCToolPath -ErrorAction:Ignore)) {
$VCToolsVersions = Get-ChildItem $VCToolsRoot | ForEach-Object {
[Version]$_.Name
} | Sort -Descending
$LatestActualVCToolsVersion = $VCToolsVersions | Select -First 1
If ([Version]$LatestVCToolsVersion -Ne $LatestActualVCToolsVersion) {
Write-Output "VC Tools Mismatch: Directory = $LatestActualVCToolsVersion, Package = $LatestVCToolsVersion"
$LatestVCToolsVersion = $LatestActualVCToolsVersion.ToString(3)
}
}
Write-Output "Latest VCToolsVersion: $LatestVCToolsVersion"
Write-Output "Updating VCToolsVersion environment variable for job"
Write-Output "##vso[task.setvariable variable=VCToolsVersion]$LatestVCToolsVersion"

View File

@@ -55,7 +55,7 @@
-->
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.7.250401001" />
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.7.250513003" />
<PackageVersion Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" />
<PackageVersion Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
<PackageVersion Include="ModernWpfUI" Version="0.9.4" />

View File

@@ -1472,7 +1472,7 @@ SOFTWARE.
- Microsoft.Windows.CsWin32 0.2.46-beta
- Microsoft.Windows.CsWinRT 2.2.0
- Microsoft.Windows.SDK.BuildTools 10.0.22621.2428
- Microsoft.WindowsAppSDK 1.7.250401001
- Microsoft.WindowsAppSDK 1.7.250513003
- Microsoft.WindowsPackageManager.ComInterop 1.10.340
- Microsoft.Xaml.Behaviors.WinUI.Managed 2.0.9
- Microsoft.Xaml.Behaviors.Wpf 1.1.39

View File

@@ -706,6 +706,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RegistryPreview.FuzzTests",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.System", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.System\Microsoft.CmdPal.Ext.System.csproj", "{64B88F02-CD88-4ED8-9624-989A800230F9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FancyZones.FuzzTests", "src\modules\fancyzones\FancyZones.FuzzTests\FancyZones.FuzzTests.csproj", "{0217E86E-3476-9946-DE8E-9D200CEBD47A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmdPalKeyboardService", "src\modules\cmdpal\CmdPalKeyboardService\CmdPalKeyboardService.vcxproj", "{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRename.FuzzingTest", "src\modules\powerrename\PowerRename.FuzzingTest\PowerRename.FuzzingTest.vcxproj", "{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E}"
@@ -2596,6 +2598,14 @@ Global
{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E}.Release|ARM64.ActiveCfg = Release|ARM64
{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E}.Release|x64.ActiveCfg = Release|x64
{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E}.Release|x64.Build.0 = Release|x64
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|ARM64.ActiveCfg = Debug|ARM64
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|ARM64.Build.0 = Debug|ARM64
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|x64.ActiveCfg = Debug|x64
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|x64.Build.0 = Debug|x64
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|ARM64.ActiveCfg = Release|ARM64
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|ARM64.Build.0 = Release|ARM64
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|x64.ActiveCfg = Release|x64
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2866,6 +2876,7 @@ Global
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A0} = {F05E590D-AD46-42BE-9C25-6A63ADD2E3EA}
{5702B3CC-8575-48D5-83D8-15BB42269CD3} = {929C1324-22E8-4412-A9A8-80E85F3985A5}
{64B88F02-CD88-4ED8-9624-989A800230F9} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{0217E86E-3476-9946-DE8E-9D200CEBD47A} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2} = {3846508C-77EB-4034-A702-F8BB263C4F79}
{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
EndGlobalSection

View File

@@ -92,6 +92,9 @@ namespace Microsoft.PowerToys.FilePreviewCommon
var run = 0;
var chunksLen = fileSize - QOI_PADDING_LENGTH;
var x = 0;
var rowAdd = bitmapData.Stride - (channels * bitmapData.Width);
for (var dataIndex = 0; dataIndex < dataLength; dataIndex += channels)
{
if (run > 0)
@@ -153,6 +156,14 @@ namespace Microsoft.PowerToys.FilePreviewCommon
bitmapPixel[3] = pixel.A;
}
}
x++;
if (x == bitmapData.Width)
{
// We align dataIndex with the stride
dataIndex += rowAdd;
x = 0;
}
}
bitmap.UnlockBits(bitmapData);

View File

@@ -6,9 +6,10 @@ using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using PowerToys.Interop;
namespace ManagedCommon
@@ -40,25 +41,72 @@ namespace ManagedCommon
/// <param name="isLocalLow">If the process using Logger is a low-privilege process.</param>
public static void InitializeLogger(string applicationLogPath, bool isLocalLow = false)
{
string basePath;
if (isLocalLow)
{
applicationLogPath = Environment.GetEnvironmentVariable("userprofile") + "\\appdata\\LocalLow\\Microsoft\\PowerToys" + applicationLogPath + "\\" + Version;
basePath = Environment.GetEnvironmentVariable("userprofile") + "\\appdata\\LocalLow\\Microsoft\\PowerToys" + applicationLogPath;
}
else
{
applicationLogPath = Constants.AppDataPath() + applicationLogPath + "\\" + Version;
basePath = Constants.AppDataPath() + applicationLogPath;
}
if (!Directory.Exists(applicationLogPath))
string versionedPath = Path.Combine(basePath, Version);
if (!Directory.Exists(versionedPath))
{
Directory.CreateDirectory(applicationLogPath);
Directory.CreateDirectory(versionedPath);
}
var logFilePath = Path.Combine(applicationLogPath, "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.InvariantCulture) + ".log");
var logFilePath = Path.Combine(versionedPath, "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.InvariantCulture) + ".log");
Trace.Listeners.Add(new TextWriterTraceListener(logFilePath));
Trace.AutoFlush = true;
// Clean up old version log folders
Task.Run(() => DeleteOldVersionLogFolders(basePath, versionedPath));
}
/// <summary>
/// Deletes old version log folders, keeping only the current version's folder.
/// </summary>
/// <param name="basePath">The base path to the log files folder.</param>
/// <param name="currentVersionPath">The path to the current version's log folder.</param>
private static void DeleteOldVersionLogFolders(string basePath, string currentVersionPath)
{
try
{
if (!Directory.Exists(basePath))
{
return;
}
var dirs = Directory.GetDirectories(basePath)
.Select(d => new DirectoryInfo(d))
.OrderBy(d => d.CreationTime)
.Where(d => !string.Equals(d.FullName, currentVersionPath, StringComparison.OrdinalIgnoreCase))
.Take(3)
.ToList();
foreach (var directory in dirs)
{
try
{
Directory.Delete(directory.FullName, true);
LogInfo($"Deleted old log directory: {directory.FullName}");
Task.Delay(500).Wait();
}
catch (Exception ex)
{
LogError($"Failed to delete old log directory: {directory.FullName}", ex);
}
}
}
catch (Exception ex)
{
LogError("Error cleaning up old log folders", ex);
}
}
public static void LogError(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)

View File

@@ -152,6 +152,7 @@
</data>
<data name="ClipboardHistoryImage" xml:space="preserve">
<value>Image data</value>
<comment>Label used to represent an image in the clipboard history</comment>
</data>
<data name="ClipboardHistoryItemMoreOptionsButton.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>More options</value>
@@ -194,15 +195,19 @@
</data>
<data name="TranscodeToMp3" xml:space="preserve">
<value>Transcode to .mp3</value>
<comment>Option to transcode audio files to MP3 format</comment>
</data>
<data name="TranscodeToMp4" xml:space="preserve">
<value>Transcode to .mp4 (H.264/AAC)</value>
<comment>Option to transcode video files to MP4 format with H.264 video codec and AAC audio codec</comment>
</data>
<data name="TranscodeErrorGeneral" xml:space="preserve">
<value>An error occurred while transcoding media file</value>
<comment>Error message displayed when media conversion fails for an unknown or general reason</comment>
</data>
<data name="TranscodeErrorUnsupportedCodec" xml:space="preserve">
<value>The media file contains an unsupported codec</value>
<comment>Error message displayed when media conversion fails due to an unsupported codec in the source file</comment>
</data>
<data name="PasteButtonAutomation.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Paste</value>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.props')" />
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.props')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props')" />
<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">
@@ -141,7 +141,7 @@
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
@@ -153,7 +153,7 @@
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.targets'))" />
</Target>
</Project>

View File

@@ -4,5 +4,5 @@
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.231216.1" targetFramework="native" />
<package id="Microsoft.Windows.SDK.BuildTools" version="10.0.22621.2428" targetFramework="native" />
<package id="Microsoft.WindowsAppSDK" version="1.7.250401001" targetFramework="native" />
<package id="Microsoft.WindowsAppSDK" version="1.7.250513003" targetFramework="native" />
</packages>

View File

@@ -13,6 +13,7 @@
#include <common/utils/winapi_error.h>
#include <common/utils/processApi.h>
#include <common/utils/elevation.h>
#include <common/utils/logger_helper.h>
HINSTANCE g_hInst_MouseWithoutBorders = 0;
@@ -409,9 +410,12 @@ public:
{
app_name = L"MouseWithoutBorders";
app_key = app_name;
std::filesystem::path logFilePath(PTSettingsHelper::get_module_save_folder_location(app_key));
logFilePath.append(LogSettings::mouseWithoutBordersLogPath);
Logger::init(LogSettings::mouseWithoutBordersLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
LoggerHelpers::init_logger(app_key, L"ModuleInterface", LogSettings::mouseWithoutBordersLoggerName);
std::filesystem::path oldLogPath(PTSettingsHelper::get_module_save_folder_location(app_key));
oldLogPath.append("LogsModuleInterface");
LoggerHelpers::delete_old_log_folder(oldLogPath);
try
{

View File

@@ -1,4 +1,4 @@
<Project>
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
@@ -9,7 +9,7 @@
<PackageVersion Include="Microsoft.Windows.CsWin32" Version="0.2.46-beta" />
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.7.250401001" />
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.7.250513003" />
<PackageVersion Include="Shmuelie.WinRTServer" Version="2.1.1" />
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
<PackageVersion Include="System.Text.Json" Version="9.0.5" />

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<RootNamespace>TemplateCmdPalExtension</RootNamespace>

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.Dotnet.AotCompatibility.props" />
<PropertyGroup>

View File

@@ -11,6 +11,7 @@
<!-- Other merged dictionaries here -->
<ResourceDictionary Source="Styles/Button.xaml" />
<ResourceDictionary Source="Styles/Colors.xaml" />
<ResourceDictionary Source="Styles/TextBlock.xaml" />
<ResourceDictionary Source="Styles/TextBox.xaml" />
<ResourceDictionary Source="Styles/Settings.xaml" />
<ResourceDictionary Source="Controls/Tag.xaml" />

View File

@@ -34,8 +34,13 @@
Orientation="Vertical"
Spacing="4" />
<!-- Template for actions in the mode actions dropdown button -->
<DataTemplate x:Key="ContextMenuViewModelTemplate" x:DataType="viewmodels:CommandContextItemViewModel">
<cmdpalUI:ContextItemTemplateSelector
x:Key="ContextItemTemplateSelector"
Critical="{StaticResource CriticalContextMenuViewModelTemplate}"
Default="{StaticResource DefaultContextMenuViewModelTemplate}" />
<!-- Template for context items in the context item menu -->
<DataTemplate x:Key="DefaultContextMenuViewModelTemplate" x:DataType="viewmodels:CommandContextItemViewModel">
<Grid AutomationProperties.Name="{x:Bind Title, Mode=OneWay}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="32" />
@@ -63,6 +68,38 @@
Text="{x:Bind RequestedShortcut, Mode=OneWay, Converter={StaticResource KeyChordToStringConverter}}" />
</Grid>
</DataTemplate>
<!-- Template for context items flagged as critical -->
<DataTemplate x:Key="CriticalContextMenuViewModelTemplate" x:DataType="viewmodels:CommandContextItemViewModel">
<Grid AutomationProperties.Name="{x:Bind Title, Mode=OneWay}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="32" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<cpcontrols:IconBox
Width="16"
Height="16"
Margin="4,0,0,0"
HorizontalAlignment="Left"
Foreground="{ThemeResource SystemFillColorCriticalBrush}"
SourceKey="{x:Bind Icon, Mode=OneWay}"
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested}" />
<TextBlock
Grid.Column="1"
VerticalAlignment="Center"
Style="{StaticResource ContextItemTitleTextBlockCriticalStyle}"
Text="{x:Bind Title, Mode=OneWay}" />
<TextBlock
Grid.Column="2"
Margin="16,0,0,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Style="{StaticResource ContextItemCaptionTextBlockCriticalStyle}"
Text="{x:Bind RequestedShortcut, Mode=OneWay, Converter={StaticResource KeyChordToStringConverter}}" />
</Grid>
</DataTemplate>
</ResourceDictionary>
</UserControl.Resources>
@@ -237,7 +274,7 @@
Margin="-16,-12,-16,-12"
IsItemClickEnabled="True"
ItemClick="CommandsDropdown_ItemClick"
ItemTemplate="{StaticResource ContextMenuViewModelTemplate}"
ItemTemplateSelector="{StaticResource ContextItemTemplateSelector}"
ItemsSource="{x:Bind ViewModel.ContextMenu.FilteredItems, Mode=OneWay}"
KeyDown="CommandsDropdown_KeyDown"
SelectionMode="Single">

View File

@@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.CmdPal.UI.ViewModels;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
namespace Microsoft.CmdPal.UI;
internal sealed partial class ContextItemTemplateSelector : DataTemplateSelector
{
public DataTemplate? Default { get; set; }
public DataTemplate? Critical { get; set; }
protected override DataTemplate? SelectTemplateCore(object item)
{
return ((CommandContextItemViewModel)item).IsCritical ? Critical : Default;
}
}

View File

@@ -39,9 +39,7 @@
</PropertyGroup>
<!-- BODGY: XES Versioning and WinAppSDK get into a fight about the app manifest, which breaks WinAppSDK. -->
<Target Name="RearrangeXefVersioningAndWinAppSDKResourceGeneration"
DependsOnTargets="GetNewAppManifestValues;CreateWinRTRegistration"
BeforeTargets="XesWriteVersionInfoResourceFile">
<Target Name="RearrangeXefVersioningAndWinAppSDKResourceGeneration" DependsOnTargets="GetNewAppManifestValues;CreateWinRTRegistration" BeforeTargets="XesWriteVersionInfoResourceFile">
<PropertyGroup>
<!-- XES uses this property to store the "final" location of the app manifest, before it erases it.
We have to update it to the value WinAppSDK set it to. -->

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:CommunityToolkit.WinUI.Converters">
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<!-- Other merged dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<Style
x:Key="ContextItemTitleTextBlockCriticalStyle"
BasedOn="{StaticResource BaseTextBlockStyle}"
TargetType="TextBlock">
<Setter Property="Foreground" Value="{ThemeResource SystemFillColorCriticalBrush}" />
<Setter Property="FontWeight" Value="Normal" />
</Style>
<Style
x:Key="ContextItemCaptionTextBlockCriticalStyle"
BasedOn="{StaticResource CaptionTextBlockStyle}"
TargetType="TextBlock">
<Setter Property="Foreground" Value="{ThemeResource SystemFillColorCriticalBrush}" />
</Style>
</ResourceDictionary>

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<?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>
<PathToRoot>..\..\..\..\</PathToRoot>
<WasdkNuget>$(PathToRoot)packages\Microsoft.WindowsAppSDK.1.7.250401001</WasdkNuget>
<WasdkNuget>$(PathToRoot)packages\Microsoft.WindowsAppSDK.1.7.250513003</WasdkNuget>
</PropertyGroup>
<Import Project="$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.props')" />
<PropertyGroup Label="Globals">

View File

@@ -1,6 +1,6 @@
# ![cmdpal logo](./Microsoft.CmdPal.UI/Assets/Stable/StoreLogo.scale-100.png) Command Palette
Windows Command Palette ("CmdPal") is the next iteration of PowerToys Run. With extensibility at it's core, the Command Palette is your one-stop launcher to start _anything_.
Windows Command Palette ("CmdPal") is the next iteration of PowerToys Run. With extensibility at its core, the Command Palette is your one-stop launcher to start _anything_.
By default, CmdPal is bound to <kbd>Win+Alt+Space</kbd>.

View File

@@ -35,7 +35,7 @@ public static class CalculateHelper
{
if (string.IsNullOrWhiteSpace(input))
{
throw new ArgumentNullException(paramName: nameof(input));
return false;
}
if (!RegValidExpressChar.IsMatch(input))

View File

@@ -23,6 +23,9 @@ public static partial class QueryHelper
CultureInfo inputCulture = settings.InputUseEnglishFormat ? new CultureInfo("en-us") : CultureInfo.CurrentCulture;
CultureInfo outputCulture = settings.OutputUseEnglishFormat ? new CultureInfo("en-us") : CultureInfo.CurrentCulture;
// In case the user pastes a query with a leading =
query = query.TrimStart('=');
// Happens if the user has only typed the action key so far
if (string.IsNullOrEmpty(query))
{
@@ -32,6 +35,11 @@ public static partial class QueryHelper
NumberTranslator translator = NumberTranslator.Create(inputCulture, new CultureInfo("en-US"));
var input = translator.Translate(query.Normalize(NormalizationForm.FormKC));
if (string.IsNullOrWhiteSpace(input))
{
return ErrorHandler.OnError(isFallbackSearch, query, Properties.Resources.calculator_expression_empty);
}
if (!CalculateHelper.InputValid(input))
{
return null;

View File

@@ -132,6 +132,15 @@ namespace Microsoft.CmdPal.Ext.Calc.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Please enter an expression.
/// </summary>
public static string calculator_expression_empty {
get {
return ResourceManager.GetString("calculator_expression_empty", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Expression wrong or incomplete.
/// </summary>

View File

@@ -199,4 +199,7 @@
<data name="calculator_copy_binary" xml:space="preserve">
<value>Copy binary</value>
</data>
<data name="calculator_expression_empty" xml:space="preserve">
<value>Please enter an expression</value>
</data>
</root>

View File

@@ -36,6 +36,7 @@ internal sealed class ContextMenuHelper
contextMenu.Add(new CommandContextItem(new KillProcessCommand(windowData))
{
RequestedShortcut = KeyChordHelpers.FromModifiers(true, false, false, false, (int)VirtualKey.Delete, 0),
IsCritical = true,
});
}

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PathToRoot>..\..\..\..\..\</PathToRoot>
<WasdkNuget>$(PathToRoot)packages\Microsoft.WindowsAppSDK.1.7.250401001</WasdkNuget>
<WasdkNuget>$(PathToRoot)packages\Microsoft.WindowsAppSDK.1.7.250513003</WasdkNuget>
<CppWinRTNuget>$(PathToRoot)packages\Microsoft.Windows.CppWinRT.2.0.240111.5</CppWinRTNuget>
<WindowsSdkBuildToolsNuget>$(PathToRoot)packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428</WindowsSdkBuildToolsNuget>
<WebView2Nuget>$(PathToRoot)packages\Microsoft.Web.WebView2.1.0.2903.40</WebView2Nuget>

View File

@@ -3,5 +3,5 @@
<package id="Microsoft.Web.WebView2" version="1.0.2903.40" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
<package id="Microsoft.Windows.SDK.BuildTools" version="10.0.22621.2428" targetFramework="native" />
<package id="Microsoft.WindowsAppSDK" version="1.7.250401001" targetFramework="native" />
<package id="Microsoft.WindowsAppSDK" version="1.7.250513003" targetFramework="native" />
</packages>

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.Dotnet.FuzzTest.props" />
<PropertyGroup>
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\tests\FancyZones.FuzzTests\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\editor\FancyZonesEditor\Utils\ParsingResult.cs" Link="ParsingResult.cs" />
<Compile Include="..\FancyZonesEditorCommon\Data\CustomLayouts.cs" Link="CustomLayouts.cs" />
<Compile Include="..\FancyZonesEditorCommon\Data\EditorData`1.cs" Link="EditorData`1.cs" />
<Compile Include="..\FancyZonesEditorCommon\Data\LayoutDefaultSettings.cs" Link="LayoutDefaultSettings.cs" />
<Compile Include="..\FancyZonesEditorCommon\Utils\DashCaseNamingPolicy.cs" Link="DashCaseNamingPolicy.cs" />
<Compile Include="..\FancyZonesEditorCommon\Utils\IOUtils.cs" Link="IOUtils.cs" />
<Compile Include="..\FancyZonesEditorCommon\Utils\StringUtils.cs" Link="StringUtils.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MSTest" />
<PackageReference Include="System.IO.Abstractions" />
</ItemGroup>
<ItemGroup>
<Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" />
</ItemGroup>
<ItemGroup>
<Content Include="OneFuzzConfig.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,86 @@
// 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.Text.Json;
using FancyZonesEditorCommon.Data;
using FancyZonesEditorCommon.Utils;
using static FancyZonesEditorCommon.Data.CustomLayouts;
namespace FancyZones.FuzzTests
{
public class FuzzTests
{
public static void FuzzGridFromJsonElement(ReadOnlySpan<byte> input)
{
if (input.Length < 4)
{
return;
}
int inputData = BitConverter.ToInt32(input.Slice(0, 4));
// mock user input for custom-layouts.json
string mockCustomLayouts = $@"{{""custom-layouts"": [{{
""uuid"": ""{{B8C275E-A7BC-485F-A35C-67B69164F51F}}"",
""name"": ""Custom layout 1"",
""type"": ""grid"",
""info"": {{
""rows"": {inputData},
""columns"": {inputData},
""rows-percentage"": [ {inputData} ],
""columns-percentage"": [ {inputData}, {inputData}, {inputData} ],
""cell-child-map"": [ [{inputData}, {inputData}, {inputData}] ],
""show-spacing"": true,
""spacing"": {inputData},
""sensitivity-radius"": {inputData}
}}
}}]}}";
CustomLayoutListWrapper wrapper;
try
{
wrapper = JsonSerializer.Deserialize<CustomLayoutListWrapper>(mockCustomLayouts, JsonOptions);
}
catch (JsonException)
{
return;
}
List<CustomLayouts.CustomLayoutWrapper> customLayouts = wrapper.CustomLayouts;
if (customLayouts == null)
{
return;
}
// Get Layout Info from mockCustomLayouts
foreach (var zoneSet in customLayouts)
{
if (zoneSet.Uuid == null || zoneSet.Uuid.Length == 0)
{
return;
}
CustomLayouts deserializer = new CustomLayouts();
// Fuzzing the deserializer
_ = deserializer.GridFromJsonElement(zoneSet.Info.GetRawText());
}
}
private static JsonSerializerOptions JsonOptions
{
get
{
return new JsonSerializerOptions
{
PropertyNamingPolicy = new DashCaseNamingPolicy(),
WriteIndented = true,
};
}
}
}
}

View File

@@ -0,0 +1,5 @@
// 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.
[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)]

View File

@@ -0,0 +1,51 @@
{
"configVersion": 3,
"entries": [
{
"fuzzer": {
"$type": "libfuzzerDotNet",
"dll": "FancyZones.FuzzTests.dll",
"class": "FancyZones.FuzzTests.FuzzTests",
"method": "FuzzGridFromJsonElement",
"FuzzingTargetBinaries": [
"PowerToys.FancyZones.dll"
]
},
"adoTemplate": {
// supply the values appropriate to your
// project, where bugs will be filed
"org": "microsoft",
"project": "OS",
"AssignedTo": "mengyuanchen@microsoft.com",
"AreaPath": "OS\\Windows Client and Services\\WinPD\\DEEP-Developer Experience, Ecosystem and Partnerships\\SHINE\\PowerToys",
"IterationPath": "OS\\Future"
},
"jobNotificationEmail": "mengyuanchen@microsoft.com",
"skip": false,
"rebootAfterSetup": false,
"oneFuzzJobs": [
// at least one job is required
{
"projectName": "FancyZones",
"targetName": "FancyZones-dotnet-fuzzer-FuzzGridFromJsonElement"
}
],
"jobDependencies": [
// this should contain, at minimum,
// the DLL and PDB files
// you will need to add any other files required
// (globs are supported)
"FancyZones.FuzzTests.dll",
"FancyZones.FuzzTests.pdb",
"Microsoft.Windows.SDK.NET.dll",
"Newtonsoft.Json.dll",
"System.IO.Abstractions.dll",
"Testably.Abstractions.FileSystem.Interface.dll",
"TestableIO.System.IO.Abstractions.dll",
"TestableIO.System.IO.Abstractions.Wrappers.dll",
"WinRT.Runtime.dll"
],
"SdlWorkItemId": 49911822
}
]
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.props')" />
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.props')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props')" />
<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">
@@ -207,7 +207,7 @@
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.targets')" />
<Import Project="..\..\..\..\packages\boost.1.87.0\build\boost.targets" Condition="Exists('..\..\..\..\packages\boost.1.87.0\build\boost.targets')" />
<Import Project="..\..\..\..\packages\boost_regex-vc143.1.87.0\build\boost_regex-vc143.targets" Condition="Exists('..\..\..\..\packages\boost_regex-vc143.1.87.0\build\boost_regex-vc143.targets')" />
</ImportGroup>
@@ -221,8 +221,8 @@
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\boost.1.87.0\build\boost.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\boost.1.87.0\build\boost.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\boost_regex-vc143.1.87.0\build\boost_regex-vc143.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\boost_regex-vc143.1.87.0\build\boost_regex-vc143.targets'))" />
</Target>

View File

@@ -184,6 +184,7 @@
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="48" />
<RowDefinition Height="48" />
</Grid.RowDefinitions>
<StackPanel
@@ -558,6 +559,33 @@
Content="&#xE8B1;"
FontFamily="{ThemeResource SymbolThemeFontFamily}" />
</StackPanel>
<TextBlock
x:Name="FileTimeLabel"
x:Uid="TextBlock_FileTime"
Margin="0,16,0,8"
FontSize="12"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
<StackPanel
Grid.Row="2"
Grid.Column="1"
Orientation="Horizontal"
Spacing="4">
<ComboBox
x:Name="comboBox_fileTimeParts"
Grid.Row="1"
Grid.Column="0"
Width="200"
HorizontalAlignment="Stretch"
AutomationProperties.LabeledBy="{Binding ElementName=FileDateLabel}"
SelectedIndex="0">
<ComboBoxItem x:Uid="FileTimeParts_CreationTime" />
<ComboBoxItem x:Uid="FileTimeParts_ModificationTime" />
<ComboBoxItem x:Uid="FileTimeParts_AccessTime" />
</ComboBox>
</StackPanel>
</StackPanel>
<Rectangle

View File

@@ -792,6 +792,32 @@ namespace winrt::PowerRenameUI::implementation
button_settings().Click([&](auto const&, auto const&) {
OpenSettingsApp();
});
// ComboBox RenameParts
comboBox_fileTimeParts().SelectionChanged([&](auto const&, auto const&) {
int selectedIndex = comboBox_fileTimeParts().SelectedIndex();
if (selectedIndex == 0)
{
// default behaviour. Date Created
UpdateFlag(CreationTime, UpdateFlagCommand::Set);
UpdateFlag(ModificationTime, UpdateFlagCommand::Reset);
UpdateFlag(AccessTime, UpdateFlagCommand::Reset);
}
else if (selectedIndex == 1)
{
// Date Modified
UpdateFlag(ModificationTime, UpdateFlagCommand::Set);
UpdateFlag(CreationTime, UpdateFlagCommand::Reset);
UpdateFlag(AccessTime, UpdateFlagCommand::Reset);
}
else if (selectedIndex == 2)
{
// Accessed
UpdateFlag(AccessTime, UpdateFlagCommand::Set);
UpdateFlag(CreationTime, UpdateFlagCommand::Reset);
UpdateFlag(ModificationTime, UpdateFlagCommand::Reset);
}
});
}
void MainWindow::ToggleItem(int32_t id, bool checked)

View File

@@ -411,4 +411,16 @@
<data name="ToggleButton_RandItems.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
<value>Random string features</value>
</data>
<data name="TextBlock_FileTime.Text" xml:space="preserve">
<value>Time used for replacement</value>
</data>
<data name="FileTimeParts_CreationTime.Content" xml:space="preserve">
<value>Creation Time</value>
</data>
<data name="FileTimeParts_ModificationTime.Content" xml:space="preserve">
<value>Modification Time</value>
</data>
<data name="FileTimeParts_AccessTime.Content" xml:space="preserve">
<value>Access Time</value>
</data>
</root>

View File

@@ -6,5 +6,5 @@
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.231216.1" targetFramework="native" />
<package id="Microsoft.Windows.SDK.BuildTools" version="10.0.22621.2428" targetFramework="native" />
<package id="Microsoft.WindowsAppSDK" version="1.7.250401001" targetFramework="native" />
<package id="Microsoft.WindowsAppSDK" version="1.7.250513003" targetFramework="native" />
</packages>

View File

@@ -18,7 +18,10 @@ enum PowerRenameFlags
Lowercase = 0x400,
Titlecase = 0x800,
Capitalized = 0x1000,
RandomizeItems = 0x2000
RandomizeItems = 0x2000,
CreationTime = 0x4000,
ModificationTime = 0x8000,
AccessTime = 0x10000,
};
enum PowerRenameFilters
@@ -67,7 +70,7 @@ interface __declspec(uuid("C7F59201-4DE1-4855-A3A2-26FC3279C8A5")) IPowerRenameI
public:
IFACEMETHOD(PutPath)(_In_opt_ PCWSTR newPath) = 0;
IFACEMETHOD(GetPath)(_Outptr_ PWSTR * path) = 0;
IFACEMETHOD(GetTime)(_Outptr_ SYSTEMTIME* time) = 0;
IFACEMETHOD(GetTime)(_In_ DWORD flags, _Outptr_ SYSTEMTIME * time) = 0;
IFACEMETHOD(GetShellItem)(_Outptr_ IShellItem** ppsi) = 0;
IFACEMETHOD(GetOriginalName)(_Outptr_ PWSTR * originalName) = 0;
IFACEMETHOD(PutOriginalName)(_In_opt_ PCWSTR originalName) = 0;

View File

@@ -56,12 +56,28 @@ IFACEMETHODIMP CPowerRenameItem::GetPath(_Outptr_ PWSTR* path)
return hr;
}
IFACEMETHODIMP CPowerRenameItem::GetTime(_Outptr_ SYSTEMTIME* time)
IFACEMETHODIMP CPowerRenameItem::GetTime(_In_ DWORD flags, _Outptr_ SYSTEMTIME* time)
{
CSRWSharedAutoLock lock(&m_lock);
HRESULT hr = E_FAIL;
PowerRenameFlags parsedTimeType;
if (m_isTimeParsed)
// Get Time by PowerRenameFlags
if (flags & PowerRenameFlags::ModificationTime)
{
parsedTimeType = PowerRenameFlags::ModificationTime;
}
else if (flags & PowerRenameFlags::AccessTime)
{
parsedTimeType = PowerRenameFlags::AccessTime;
}
else
{
// Default to modification time if no specific flag is set
parsedTimeType = PowerRenameFlags::CreationTime;
}
if (m_isTimeParsed && parsedTimeType == m_parsedTimeType)
{
hr = S_OK;
}
@@ -70,21 +86,43 @@ IFACEMETHODIMP CPowerRenameItem::GetTime(_Outptr_ SYSTEMTIME* time)
HANDLE hFile = CreateFileW(m_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
FILETIME CreationTime;
if (GetFileTime(hFile, &CreationTime, NULL, NULL))
FILETIME FileTime;
bool success = false;
// Get Time by PowerRenameFlags
switch (parsedTimeType)
{
case PowerRenameFlags::CreationTime:
success = GetFileTime(hFile, &FileTime, NULL, NULL);
break;
case PowerRenameFlags::ModificationTime:
success = GetFileTime(hFile, NULL, NULL, &FileTime);
break;
case PowerRenameFlags::AccessTime:
success = GetFileTime(hFile, NULL, &FileTime, NULL);
break;
default:
// Default to modification time if no specific flag is set
success = GetFileTime(hFile, NULL, NULL, &FileTime);
break;
}
if (success)
{
SYSTEMTIME SystemTime, LocalTime;
if (FileTimeToSystemTime(&CreationTime, &SystemTime))
if (FileTimeToSystemTime(&FileTime, &SystemTime))
{
if (SystemTimeToTzSpecificLocalTime(NULL, &SystemTime, &LocalTime))
{
m_time = LocalTime;
m_isTimeParsed = true;
m_parsedTimeType = parsedTimeType;
hr = S_OK;
}
}
}
}
CloseHandle(hFile);
}
*time = m_time;

View File

@@ -16,7 +16,7 @@ public:
// IPowerRenameItem
IFACEMETHODIMP PutPath(_In_opt_ PCWSTR newPath);
IFACEMETHODIMP GetPath(_Outptr_ PWSTR* path);
IFACEMETHODIMP GetTime(_Outptr_ SYSTEMTIME* time);
IFACEMETHODIMP GetTime(_In_ DWORD flags, _Outptr_ SYSTEMTIME* time);
IFACEMETHODIMP GetShellItem(_Outptr_ IShellItem** ppsi);
IFACEMETHODIMP PutOriginalName(_In_opt_ PCWSTR originalName);
IFACEMETHODIMP GetOriginalName(_Outptr_ PWSTR* originalName);
@@ -54,6 +54,7 @@ protected:
bool m_selected = true;
bool m_isFolder = false;
bool m_isTimeParsed = false;
PowerRenameFlags m_parsedTimeType = PowerRenameFlags::CreationTime;
bool m_canRename = true;
int m_id = -1;
int m_iconIndex = -1;

View File

@@ -78,7 +78,7 @@ bool DoRename(CComPtr<IPowerRenameRegEx>& spRenameRegEx, unsigned long& itemEnum
if (useFileTime)
{
winrt::check_hresult(spItem->GetTime(&fileTime));
winrt::check_hresult(spItem->GetTime(flags, &fileTime));
winrt::check_hresult(spRenameRegEx->PutFileTime(fileTime));
}

View File

@@ -1,5 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
@@ -89,7 +148,7 @@
<value>This setting has been disabled by your administrator.</value>
</data>
<data name="STARTUP_DISABLED_BY_USER" xml:space="preserve">
<value>This setting has been disabled manually via &lt;a href=&quot;https://ms_settings_startupapps&quot; target=&quot;_blank&quot;&gt;Startup Settings&lt;/a&gt;.</value>
<value>This setting has been disabled manually via &lt;a href="https://ms_settings_startupapps" target="_blank"&gt;Startup Settings&lt;/a&gt;.</value>
</data>
<data name="GITHUB_NEW_VERSION_AVAILABLE" xml:space="preserve">
<value>An update to PowerToys is available.</value>
@@ -121,6 +180,9 @@
<value>Exit</value>
<comment>Exit as a verb, as in Exit the application</comment>
</data>
<data name="SHOW_TRAY_ICON_MENU_TEXT" xml:space="preserve">
<value>Show icon</value>
</data>
<data name="SUBMIT_BUG_TEXT" xml:space="preserve">
<value>Report bug</value>
</data>
@@ -134,4 +196,4 @@
<data name="TRAY_ICON_ADMIN_TOOLTIP" xml:space="preserve">
<value>Administrator</value>
</data>
</root>
</root>

View File

@@ -5,12 +5,13 @@
#include <comdef.h>
#include <taskschd.h>
#include <common/logger/logger.h>
// Helper macros from wix.
// TODO: use "s" and "..." parameters to report errors from these functions.
#define ExitOnFailure(x, s, ...) \
if (FAILED(x)) \
{ \
Logger::error(s, ##__VA_ARGS__); \
goto LExit; \
}
#define ExitWithLastError(x, s, ...) \
@@ -21,6 +22,7 @@
{ \
x = E_FAIL; \
} \
Logger::error(s, ##__VA_ARGS__); \
goto LExit; \
}
#define ExitFunction() \
@@ -52,11 +54,11 @@ bool create_auto_start_task_for_this_user(bool runElevated)
// Get the Domain/Username for the trigger.
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN))
{
ExitWithLastError(hr, "Getting username failed: %x", hr);
ExitWithLastError(hr, "Getting username failed: {:x}", hr);
}
if (!GetEnvironmentVariable(L"USERDOMAIN", username_domain, USERNAME_DOMAIN_LEN))
{
ExitWithLastError(hr, "Getting the user's domain failed: %x", hr);
ExitWithLastError(hr, "Getting the user's domain failed: {:x}", hr);
}
wcscat_s(username_domain, L"\\");
wcscat_s(username_domain, username);
@@ -76,11 +78,11 @@ bool create_auto_start_task_for_this_user(bool runElevated)
CLSCTX_INPROC_SERVER,
IID_ITaskService,
reinterpret_cast<void**>(&pService));
ExitOnFailure(hr, "Failed to create an instance of ITaskService: %x", hr);
ExitOnFailure(hr, "Failed to create an instance of ITaskService: {:x}", hr);
// Connect to the task service.
hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr);
ExitOnFailure(hr, "ITaskService::Connect failed: {:x}", hr);
// ------------------------------------------------------
// Get the PowerToys task folder. Creates it if it doesn't exist.
@@ -90,12 +92,12 @@ bool create_auto_start_task_for_this_user(bool runElevated)
// Folder doesn't exist. Get the Root folder and create the PowerToys subfolder.
ITaskFolder* pRootFolder = NULL;
hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder);
ExitOnFailure(hr, "Cannot get Root Folder pointer: %x", hr);
ExitOnFailure(hr, "Cannot get Root Folder pointer: {:x}", hr);
hr = pRootFolder->CreateFolder(_bstr_t(L"\\PowerToys"), _variant_t(L""), &pTaskFolder);
if (FAILED(hr))
{
pRootFolder->Release();
ExitOnFailure(hr, "Cannot create PowerToys task folder: %x", hr);
ExitOnFailure(hr, "Cannot create PowerToys task folder: {:x}", hr);
}
}
@@ -118,47 +120,47 @@ bool create_auto_start_task_for_this_user(bool runElevated)
// Create the task builder object to create the task.
hr = pService->NewTask(0, &pTask);
ExitOnFailure(hr, "Failed to create a task definition: %x", hr);
ExitOnFailure(hr, "Failed to create a task definition: {:x}", hr);
// ------------------------------------------------------
// Get the registration info for setting the identification.
hr = pTask->get_RegistrationInfo(&pRegInfo);
ExitOnFailure(hr, "Cannot get identification pointer: %x", hr);
ExitOnFailure(hr, "Cannot get identification pointer: {:x}", hr);
hr = pRegInfo->put_Author(_bstr_t(username_domain));
ExitOnFailure(hr, "Cannot put identification info: %x", hr);
ExitOnFailure(hr, "Cannot put identification info: {:x}", hr);
// ------------------------------------------------------
// Create the settings for the task
hr = pTask->get_Settings(&pSettings);
ExitOnFailure(hr, "Cannot get settings pointer: %x", hr);
ExitOnFailure(hr, "Cannot get settings pointer: {:x}", hr);
hr = pSettings->put_StartWhenAvailable(VARIANT_FALSE);
ExitOnFailure(hr, "Cannot put_StartWhenAvailable setting info: %x", hr);
ExitOnFailure(hr, "Cannot put_StartWhenAvailable setting info: {:x}", hr);
hr = pSettings->put_StopIfGoingOnBatteries(VARIANT_FALSE);
ExitOnFailure(hr, "Cannot put_StopIfGoingOnBatteries setting info: %x", hr);
ExitOnFailure(hr, "Cannot put_StopIfGoingOnBatteries setting info: {:x}", hr);
hr = pSettings->put_ExecutionTimeLimit(_bstr_t(L"PT0S")); //Unlimited
ExitOnFailure(hr, "Cannot put_ExecutionTimeLimit setting info: %x", hr);
ExitOnFailure(hr, "Cannot put_ExecutionTimeLimit setting info: {:x}", hr);
hr = pSettings->put_DisallowStartIfOnBatteries(VARIANT_FALSE);
ExitOnFailure(hr, "Cannot put_DisallowStartIfOnBatteries setting info: %x", hr);
ExitOnFailure(hr, "Cannot put_DisallowStartIfOnBatteries setting info: {:x}", hr);
hr = pSettings->put_Priority(4);
ExitOnFailure(hr, "Cannot put_Priority setting info : %x", hr);
ExitOnFailure(hr, "Cannot put_Priority setting info : {:x}", hr);
// ------------------------------------------------------
// Get the trigger collection to insert the logon trigger.
hr = pTask->get_Triggers(&pTriggerCollection);
ExitOnFailure(hr, "Cannot get trigger collection: %x", hr);
ExitOnFailure(hr, "Cannot get trigger collection: {:x}", hr);
// Add the logon trigger to the task.
{
ITrigger* pTrigger = NULL;
ILogonTrigger* pLogonTrigger = NULL;
hr = pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger);
ExitOnFailure(hr, "Cannot create the trigger: %x", hr);
ExitOnFailure(hr, "Cannot create the trigger: {:x}", hr);
hr = pTrigger->QueryInterface(
IID_ILogonTrigger, reinterpret_cast<void**>(&pLogonTrigger));
pTrigger->Release();
ExitOnFailure(hr, "QueryInterface call failed for ILogonTrigger: %x", hr);
ExitOnFailure(hr, "QueryInterface call failed for ILogonTrigger: {:x}", hr);
hr = pLogonTrigger->put_Id(_bstr_t(L"Trigger1"));
@@ -170,7 +172,7 @@ bool create_auto_start_task_for_this_user(bool runElevated)
// The specified user must be a user on this computer.
hr = pLogonTrigger->put_UserId(_bstr_t(username_domain));
pLogonTrigger->Release();
ExitOnFailure(hr, "Cannot add user ID to logon trigger: %x", hr);
ExitOnFailure(hr, "Cannot add user ID to logon trigger: {:x}", hr);
}
// ------------------------------------------------------
@@ -182,23 +184,23 @@ bool create_auto_start_task_for_this_user(bool runElevated)
// Get the task action collection pointer.
hr = pTask->get_Actions(&pActionCollection);
ExitOnFailure(hr, "Cannot get Task collection pointer: %x", hr);
ExitOnFailure(hr, "Cannot get Task collection pointer: {:x}", hr);
// Create the action, specifying that it is an executable action.
hr = pActionCollection->Create(TASK_ACTION_EXEC, &pAction);
pActionCollection->Release();
ExitOnFailure(hr, "Cannot create the action: %x", hr);
ExitOnFailure(hr, "Cannot create the action: {:x}", hr);
// QI for the executable task pointer.
hr = pAction->QueryInterface(
IID_IExecAction, reinterpret_cast<void**>(&pExecAction));
pAction->Release();
ExitOnFailure(hr, "QueryInterface call failed for IExecAction: %x", hr);
ExitOnFailure(hr, "QueryInterface call failed for IExecAction: {:x}", hr);
// Set the path of the executable to PowerToys (passed as CustomActionData).
hr = pExecAction->put_Path(_bstr_t(wszExecutablePath));
pExecAction->Release();
ExitOnFailure(hr, "Cannot set path of executable: %x", hr);
ExitOnFailure(hr, "Cannot set path of executable: {:x}", hr);
}
// ------------------------------------------------------
@@ -206,7 +208,7 @@ bool create_auto_start_task_for_this_user(bool runElevated)
{
IPrincipal* pPrincipal = NULL;
hr = pTask->get_Principal(&pPrincipal);
ExitOnFailure(hr, "Cannot get principal pointer: %x", hr);
ExitOnFailure(hr, "Cannot get principal pointer: {:x}", hr);
// Set up principal information:
hr = pPrincipal->put_Id(_bstr_t(L"Principal1"));
@@ -224,7 +226,7 @@ bool create_auto_start_task_for_this_user(bool runElevated)
hr = pPrincipal->put_RunLevel(_TASK_RUNLEVEL::TASK_RUNLEVEL_LUA);
}
pPrincipal->Release();
ExitOnFailure(hr, "Cannot put principal run level: %x", hr);
ExitOnFailure(hr, "Cannot put principal run level: {:x}", hr);
}
// ------------------------------------------------------
// Save the task in the PowerToys folder.
@@ -239,7 +241,7 @@ bool create_auto_start_task_for_this_user(bool runElevated)
TASK_LOGON_INTERACTIVE_TOKEN,
SDDL_FULL_ACCESS_FOR_EVERYONE,
&pRegisteredTask);
ExitOnFailure(hr, "Error saving the Task : %x", hr);
ExitOnFailure(hr, "Error saving the Task : {:x}", hr);
}
LExit:
@@ -275,7 +277,7 @@ bool delete_auto_start_task_for_this_user()
// Get the Username for the task.
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN))
{
ExitWithLastError(hr, "Getting username failed: %x", hr);
ExitWithLastError(hr, "Getting username failed: {:x}", hr);
}
// Task Name.
@@ -289,11 +291,11 @@ bool delete_auto_start_task_for_this_user()
CLSCTX_INPROC_SERVER,
IID_ITaskService,
reinterpret_cast<void**>(&pService));
ExitOnFailure(hr, "Failed to create an instance of ITaskService: %x", hr);
ExitOnFailure(hr, "Failed to create an instance of ITaskService: {:x}", hr);
// Connect to the task service.
hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr);
ExitOnFailure(hr, "ITaskService::Connect failed: {:x}", hr);
// ------------------------------------------------------
// Get the PowerToys task folder.
@@ -340,7 +342,7 @@ bool is_auto_start_task_active_for_this_user()
// Get the Username for the task.
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN))
{
ExitWithLastError(hr, "Getting username failed: %x", hr);
ExitWithLastError(hr, "Getting username failed: {:x}", hr);
}
// Task Name.
@@ -354,16 +356,16 @@ bool is_auto_start_task_active_for_this_user()
CLSCTX_INPROC_SERVER,
IID_ITaskService,
reinterpret_cast<void**>(&pService));
ExitOnFailure(hr, "Failed to create an instance of ITaskService: %x", hr);
ExitOnFailure(hr, "Failed to create an instance of ITaskService: {:x}", hr);
// Connect to the task service.
hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr);
ExitOnFailure(hr, "ITaskService::Connect failed: {:x}", hr);
// ------------------------------------------------------
// Get the PowerToys task folder.
hr = pService->GetFolder(_bstr_t(L"\\PowerToys"), &pTaskFolder);
ExitOnFailure(hr, "ITaskFolder doesn't exist: %x", hr);
ExitOnFailure(hr, "ITaskFolder doesn't exist: {:x}", hr);
// ------------------------------------------------------
// If the task exists, disable.

View File

@@ -1,6 +1,7 @@
#include "pch.h"
#include "general_settings.h"
#include "auto_start_helper.h"
#include "tray_icon.h"
#include "Generated files/resource.h"
#include <common/SettingsAPI/settings_helpers.h>
@@ -14,6 +15,7 @@
// TODO: would be nice to get rid of these globals, since they're basically cached json settings
static std::wstring settings_theme = L"system";
static bool show_tray_icon = true;
static bool run_as_elevated = false;
static bool show_new_updates_toast_notification = true;
static bool download_updates_automatically = true;
@@ -38,6 +40,7 @@ json::JsonObject GeneralSettings::to_json()
}
result.SetNamedValue(L"enabled", std::move(enabled));
result.SetNamedValue(L"show_tray_icon", json::value(showSystemTrayIcon));
result.SetNamedValue(L"is_elevated", json::value(isElevated));
result.SetNamedValue(L"run_elevated", json::value(isRunElevated));
result.SetNamedValue(L"show_new_updates_toast_notification", json::value(showNewUpdatesToastNotification));
@@ -74,7 +77,9 @@ json::JsonObject load_general_settings()
GeneralSettings get_general_settings()
{
const bool is_user_admin = check_user_is_admin();
GeneralSettings settings{
GeneralSettings settings
{
.showSystemTrayIcon = show_tray_icon,
.isElevated = is_process_elevated(),
.isRunElevated = run_as_elevated,
.isAdmin = is_user_admin,
@@ -214,6 +219,13 @@ void apply_general_settings(const json::JsonObject& general_configs, bool save)
settings_theme = general_configs.GetNamedString(L"theme");
}
if (json::has(general_configs, L"show_tray_icon", json::JsonValueType::Boolean))
{
show_tray_icon = general_configs.GetNamedBoolean(L"show_tray_icon");
// Update tray icon visibility when setting is toggled
set_tray_icon_visible(show_tray_icon);
}
if (save)
{
GeneralSettings save_settings = get_general_settings();

View File

@@ -5,6 +5,7 @@
struct GeneralSettings
{
bool isStartupEnabled;
bool showSystemTrayIcon;
std::wstring startupDisabledReason;
std::map<std::wstring, bool> isModulesEnabledMap;
bool isElevated;

View File

@@ -90,6 +90,7 @@ void open_menu_from_another_instance(std::optional<std::string> settings_window)
msg = static_cast<LPARAM>(ESettingsWindowNames_from_string(settings_window.value()));
}
PostMessageW(hwnd_main, WM_COMMAND, ID_SETTINGS_MENU_COMMAND, msg);
SetForegroundWindow(hwnd_main); // Bring the settings window to the front
}
int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow, bool openOobe, bool openScoobe, bool showRestartNotificationAfterUpdate)
@@ -104,6 +105,7 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow
#endif
Trace::RegisterProvider();
start_tray_icon(isProcessElevated);
set_tray_icon_visible(get_general_settings().showSystemTrayIcon);
CentralizedKeyboardHook::Start();
int result = -1;

View File

@@ -20,4 +20,5 @@
#define ID_ABOUT_MENU_COMMAND 40003
#define ID_REPORT_BUG_COMMAND 40004
#define ID_DOCUMENTATION_MENU_COMMAND 40005
#define ID_QUICK_ACCESS_MENU_COMMAND 40006
#define ID_QUICK_ACCESS_MENU_COMMAND 40006
#define ID_SHOW_TRAY_ICON_MENU_COMMAND 40007

Binary file not shown.

View File

@@ -2,6 +2,7 @@
#include "Generated files/resource.h"
#include "settings_window.h"
#include "tray_icon.h"
#include "general_settings.h"
#include "centralized_hotkeys.h"
#include "centralized_kb_hook.h"
#include <Windows.h>
@@ -90,6 +91,13 @@ void handle_tray_command(HWND window, const WPARAM command_id, LPARAM lparam)
}
DestroyWindow(window);
break;
case ID_SHOW_TRAY_ICON_MENU_COMMAND:
{
GeneralSettings settings = get_general_settings();
settings.showSystemTrayIcon = true;
apply_general_settings(settings.to_json(), true);
break;
}
case ID_ABOUT_MENU_COMMAND:
if (!about_box_shown)
{
@@ -191,11 +199,13 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam
{
static std::wstring settings_menuitem_label = GET_RESOURCE_STRING(IDS_SETTINGS_MENU_TEXT);
static std::wstring exit_menuitem_label = GET_RESOURCE_STRING(IDS_EXIT_MENU_TEXT);
static std::wstring show_tray_icon_menuitem_label = GET_RESOURCE_STRING(IDS_SHOW_TRAY_ICON_MENU_TEXT);
static std::wstring submit_bug_menuitem_label = GET_RESOURCE_STRING(IDS_SUBMIT_BUG_TEXT);
static std::wstring documentation_menuitem_label = GET_RESOURCE_STRING(IDS_DOCUMENTATION_MENU_TEXT);
static std::wstring quick_access_menuitem_label = GET_RESOURCE_STRING(IDS_QUICK_ACCESS_MENU_TEXT);
change_menu_item_text(ID_SETTINGS_MENU_COMMAND, settings_menuitem_label.data());
change_menu_item_text(ID_EXIT_MENU_COMMAND, exit_menuitem_label.data());
change_menu_item_text(ID_SHOW_TRAY_ICON_MENU_COMMAND, show_tray_icon_menuitem_label.data());
change_menu_item_text(ID_REPORT_BUG_COMMAND, submit_bug_menuitem_label.data());
change_menu_item_text(ID_DOCUMENTATION_MENU_COMMAND, documentation_menuitem_label.data());
change_menu_item_text(ID_QUICK_ACCESS_MENU_COMMAND, quick_access_menuitem_label.data());
@@ -312,6 +322,14 @@ void start_tray_icon(bool isProcessElevated)
}
}
void set_tray_icon_visible(bool shouldIconBeVisible)
{
tray_icon_data.uFlags |= NIF_STATE;
tray_icon_data.dwStateMask = NIS_HIDDEN;
tray_icon_data.dwState = shouldIconBeVisible ? 0 : NIS_HIDDEN;
Shell_NotifyIcon(NIM_MODIFY, &tray_icon_data);
}
void stop_tray_icon()
{
if (tray_icon_created)

View File

@@ -4,6 +4,8 @@
// Start the Tray Icon
void start_tray_icon(bool isProcessElevated);
// Change the Tray Icon visibility
void set_tray_icon_visible(bool shouldIconBeVisible);
// Stop the Tray Icon
void stop_tray_icon();
// Open the Settings Window
@@ -13,4 +15,5 @@ typedef void (*main_loop_callback_function)(PVOID);
// Calls a callback in _callback
bool dispatch_run_on_main_ui_thread(main_loop_callback_function _callback, PVOID data);
// Must be the same as: settings-ui/Settings.UI/Views/ShellPage.xaml.cs -> ExitPTItem_Tapped() -> const string ptTrayIconWindowClass
const inline wchar_t* pt_tray_icon_window_class = L"PToyTrayIconWindow";

View File

@@ -19,6 +19,10 @@ namespace Microsoft.PowerToys.Settings.UI.Library
[JsonPropertyName("startup")]
public bool Startup { get; set; }
// Gets or sets a value indicating whether the powertoys system tray icon should be hidden.
[JsonPropertyName("show_tray_icon")]
public bool ShowSysTrayIcon { get; set; }
// Gets or sets a value indicating whether the powertoy elevated.
[CmdConfigureIgnoreAttribute]
[JsonPropertyName("is_elevated")]
@@ -75,6 +79,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public GeneralSettings()
{
Startup = false;
ShowSysTrayIcon = true;
IsAdmin = false;
EnableWarningsElevatedApps = true;
IsElevated = false;

View File

@@ -224,6 +224,36 @@ namespace ViewModelTests
viewModel.ThemeIndex = 0;
}
[TestMethod]
public void IsShowSysTrayIconEnabledByDefaultShouldDisableWhenSuccessful()
{
// Arrange
// Assert
Func<string, int> sendMockIPCConfigMSG = msg =>
{
OutGoingGeneralSettings snd = JsonSerializer.Deserialize<OutGoingGeneralSettings>(msg);
Assert.IsFalse(snd.GeneralSettings.ShowSysTrayIcon);
return 0;
};
Func<string, int> sendRestartAdminIPCMessage = msg => { return 0; };
Func<string, int> sendCheckForUpdatesIPCMessage = msg => { return 0; };
GeneralViewModel viewModel = new(
settingsRepository: SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object),
"GeneralSettings_RunningAsAdminText",
"GeneralSettings_RunningAsUserText",
false,
false,
sendMockIPCConfigMSG,
sendRestartAdminIPCMessage,
sendCheckForUpdatesIPCMessage,
GeneralSettingsFileName);
Assert.IsTrue(viewModel.ShowSysTrayIcon);
// Act
viewModel.ShowSysTrayIcon = false;
}
[TestMethod]
public void AllModulesAreEnabledByDefault()
{

View File

@@ -17,6 +17,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
internal const int SW_SHOWNORMAL = 1;
internal const int SW_SHOWMAXIMIZED = 3;
internal const int SW_HIDE = 0;
internal const int WM_COMMAND = 0x0111; // https://learn.microsoft.com/en-us/windows/win32/menurc/wm-command
[DllImport("user32.dll")]
internal static extern IntPtr GetActiveWindow();
@@ -48,6 +49,12 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
[DllImport("Comdlg32.dll", CharSet = CharSet.Unicode)]
internal static extern bool GetOpenFileName([In, Out] OpenFileName openFileName);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
internal static extern IntPtr SendMessage(IntPtr hWnd, IntPtr msg, UIntPtr wParam, UIntPtr lParam);
[DllImport("comdlg32.dll", CharSet = CharSet.Auto, EntryPoint = "ChooseFont", SetLastError = true)]
internal static extern bool ChooseFont(IntPtr lpChooseFont);

View File

@@ -39,6 +39,7 @@
<tkconverters:StringFormatConverter x:Key="StringFormatConverter" />
<tkconverters:BoolNegationConverter x:Key="BoolNegationConverter" />
<x:Double x:Key="SettingsCardSpacing">2</x:Double>
<!-- Overrides -->
<Thickness x:Key="InfoBarIconMargin">6,16,16,16</Thickness>

View File

@@ -10,7 +10,7 @@
<StackPanel
ChildrenTransitions="{StaticResource SettingsCardsAnimations}"
Orientation="Vertical"
Spacing="2" />
Spacing="{StaticResource SettingsCardSpacing}" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>

View File

@@ -176,7 +176,7 @@ namespace Microsoft.PowerToys.Settings.UI.Flyout
});
}
private void ReportBugBtn_Click(object sender, RoutedEventArgs e)
internal void ReportBugBtn_Click(object sender, RoutedEventArgs e)
{
ViewModel.StartBugReport();

View File

@@ -266,6 +266,10 @@
<tkcontrols:SettingsCard x:Uid="GeneralPage_RunAtStartUp" IsEnabled="{x:Bind ViewModel.IsRunAtStartupGPOManaged, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.Startup, Mode=TwoWay}" />
</tkcontrols:SettingsCard>
<tkcontrols:SettingsCard x:Uid="ShowSystemTrayIcon">
<ToggleSwitch x:Uid="ShowSystemTrayIcon_ToggleSwitch" IsOn="{x:Bind ViewModel.ShowSysTrayIcon, Mode=TwoWay}" />
</tkcontrols:SettingsCard>
<InfoBar
x:Uid="GPO_SettingIsManaged"
BorderThickness="0"
@@ -402,10 +406,11 @@
</InfoBar>
</controls:SettingsGroup>
<controls:SettingsGroup x:Uid="General_DiagnosticsAndFeedback" Visibility="Visible">
<StackPanel>
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<HyperlinkButton
x:Uid="GeneralPage_DiagnosticsAndFeedback_Link"
Margin="-8,0,0,0"
Margin="0,0,0,8"
Padding="0"
NavigateUri="https://aka.ms/powertoys-data-and-privacy-documentation" />
<tkcontrols:SettingsCard
x:Uid="GeneralPage_EnableDataDiagnostics"
@@ -449,7 +454,12 @@
<Button x:Uid="GeneralPage_ViewDiagnosticDataViewerInfoButton" Click="Click_ViewDiagnosticDataViewerRestart" />
</InfoBar.ActionButton>
</InfoBar>
<tkcontrols:SettingsCard x:Uid="GeneralPage_ReportBugPackage" HeaderIcon="{ui:FontIcon Glyph=&#xEBE8;}">
<Button
x:Uid="GeneralPageReportBugPackage"
HorizontalAlignment="Right"
Click="BugReportToolClicked" />
</tkcontrols:SettingsCard>
</StackPanel>
</controls:SettingsGroup>
</StackPanel>

View File

@@ -7,6 +7,7 @@ using System.Threading;
using System.Threading.Tasks;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Flyout;
using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.ViewModels;
@@ -165,5 +166,24 @@ namespace Microsoft.PowerToys.Settings.UI.Views
{
await Task.Run(ViewModel.ViewDiagnosticData);
}
private void ExitPTItem_Tapped(object sender, RoutedEventArgs e)
{
const string ptTrayIconWindowClass = "PToyTrayIconWindow"; // Defined in runner/tray_icon.h
const nuint ID_EXIT_MENU_COMMAND = 40001; // Generated resource from runner/runner.base.rc
// Exit the XAML application
Application.Current.Exit();
// Invoke the exit command from the tray icon
IntPtr hWnd = NativeMethods.FindWindow(ptTrayIconWindowClass, ptTrayIconWindowClass);
NativeMethods.SendMessage(hWnd, NativeMethods.WM_COMMAND, ID_EXIT_MENU_COMMAND, 0);
}
private void BugReportToolClicked(object sender, RoutedEventArgs e)
{
var launchPage = new LaunchPage();
launchPage.ReportBugBtn_Click(sender, e);
}
}
}

View File

@@ -39,10 +39,17 @@
Margin="48,0,0,0"
VerticalAlignment="Top"
IsHitTestVisible="True">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="LeftTitleBarColumn" Width="*" />
<ColumnDefinition x:Name="RightTitleBarColumn" Width="Auto" />
</Grid.ColumnDefinitions>
<animations:Implicit.Animations>
<animations:OffsetAnimation Duration="0:0:0.3" />
</animations:Implicit.Animations>
<StackPanel Orientation="Horizontal">
<StackPanel
Grid.Column="0"
HorizontalAlignment="Left"
Orientation="Horizontal">
<Image
Width="16"
Height="16"
@@ -64,6 +71,24 @@
TextWrapping="NoWrap"
Visibility="Collapsed" />
</StackPanel>
<StackPanel
Grid.Column="1"
Margin="0,0,148,0"
HorizontalAlignment="Right"
Orientation="Horizontal">
<Button
x:Name="ShutDownBtn"
Height="48"
Click="ExitPTItem_Tapped"
Style="{StaticResource SubtleButtonStyle}">
<FontIcon FontSize="16" Glyph="&#xE7E8;" />
<ToolTipService.ToolTip>
<ToolTip>
<TextBlock x:Uid="AppTitleBarShutDown_Tooltip" />
</ToolTip>
</ToolTipService.ToolTip>
</Button>
</StackPanel>
</Grid>
<NavigationView
x:Name="navigationView"

View File

@@ -9,6 +9,7 @@ using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.PowerToys.Settings.UI.Services;
using Microsoft.PowerToys.Settings.UI.ViewModels;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Automation.Peers;
using Microsoft.UI.Xaml.Controls;
@@ -422,6 +423,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
// A custom title bar is required for full window theme and Mica support.
// https://docs.microsoft.com/windows/apps/develop/title-bar?tabs=winui3#full-customization
u.ExtendsContentIntoTitleBar = true;
u.AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Tall;
WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(WindowNative.GetWindowHandle(u));
u.SetTitleBar(AppTitleBar);
var loader = ResourceLoaderInstance.ResourceLoader;
@@ -457,5 +459,18 @@ namespace Microsoft.PowerToys.Settings.UI.Views
{
navigationView.IsPaneOpen = !navigationView.IsPaneOpen;
}
private void ExitPTItem_Tapped(object sender, RoutedEventArgs e)
{
const string ptTrayIconWindowClass = "PToyTrayIconWindow"; // Defined in runner/tray_icon.h
const nuint ID_EXIT_MENU_COMMAND = 40001; // Generated resource from runner/runner.base.rc
// Exit the XAML application
Application.Current.Exit();
// Invoke the exit command from the tray icon
IntPtr hWnd = NativeMethods.FindWindow(ptTrayIconWindowClass, ptTrayIconWindowClass);
NativeMethods.SendMessage(hWnd, NativeMethods.WM_COMMAND, ID_EXIT_MENU_COMMAND, 0);
}
}
}

View File

@@ -4299,6 +4299,12 @@ Activate by holding the key for the character you want to add an accent to, then
<data name="GeneralPage_ShowWhatsNewAfterUpdates.Content" xml:space="preserve">
<value>Show the release notes after an update</value>
</data>
<data name="ShowSystemTrayIcon.Description" xml:space="preserve">
<value>This settings page is accessible by running the PowerToys executable again</value>
</data>
<data name="ShowSystemTrayIcon.Header" xml:space="preserve">
<value>Show system tray icon</value>
</data>
<data name="QuickAccent_Prevent_Activation_On_Game_Mode.Content" xml:space="preserve">
<value>Do not activate when Game Mode is on</value>
<comment>"Game mode" is the Windows feature to prevent notification when playing a game.</comment>
@@ -5020,4 +5026,25 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
<data name="Help_hueOklch" xml:space="preserve">
<value>hue (Oklch)</value>
</data>
<data name="ExitPT_NavViewItem.Content" xml:space="preserve">
<value>Exit PowerToys</value>
</data>
<data name="General_System.Header" xml:space="preserve">
<value>System</value>
</data>
<data name="GeneralPage_ReportBugPackage.Header" xml:space="preserve">
<value>Generate bug report package</value>
</data>
<data name="GeneralPage_ReportBugPackage.Description" xml:space="preserve">
<value>Create zip folder with logs on the Desktop</value>
</data>
<data name="GeneralPageReportBugPackage.Content" xml:space="preserve">
<value>Generate package</value>
</data>
<data name="AppTitleBarShutDown_Tooltip.Text" xml:space="preserve">
<value>Shut down</value>
</data>
<data name="BugReportUnderConstruction" xml:space="preserve">
<value>Bug report package is being created</value>
</data>
</root>

View File

@@ -146,6 +146,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
_startup = GeneralSettingsConfig.Startup;
}
_showSysTrayIcon = GeneralSettingsConfig.ShowSysTrayIcon;
_showNewUpdatesToastNotification = GeneralSettingsConfig.ShowNewUpdatesToastNotification;
_autoDownloadUpdates = GeneralSettingsConfig.AutoDownloadUpdates;
_showWhatsNewAfterUpdates = GeneralSettingsConfig.ShowWhatsNewAfterUpdates;
@@ -228,6 +229,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
private static bool _isDevBuild;
private bool _startup;
private bool _showSysTrayIcon;
private GpoRuleConfigured _runAtStartupGpoRuleConfiguration;
private bool _runAtStartupIsGPOConfigured;
private bool _isElevated;
@@ -359,6 +361,25 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
}
}
// Gets or sets a value indicating whether the PowerToys icon should be shown in the system tray.
public bool ShowSysTrayIcon
{
get
{
return _showSysTrayIcon;
}
set
{
if (_showSysTrayIcon != value)
{
_showSysTrayIcon = value;
GeneralSettingsConfig.ShowSysTrayIcon = value;
NotifyPropertyChanged();
}
}
}
public string RunningAsText
{
get