Compare commits

...

18 Commits

Author SHA1 Message Date
Leilei Zhang
7f2e454c48 update pipeline for testing 2024-12-11 12:31:33 +08:00
Leilei Zhang
13a49ad5a8 add helper to fuzz test 2024-12-10 21:28:29 +08:00
Leilei Zhang
05e54e64c8 add fuzz 2024-12-10 08:38:15 +08:00
Jeremy Sinclair
eadcf4b120 [Analyzers] Update .editorconfig with rules to relax IDE errors (#36095)
* [Analyzers] Remove duplicate pascal case style from .editorconfig

* [Analyzers] Configured severity for individual IDE and CA rules showing as errors in VS

Set severity for IDE0005, IDE0008, IDE0016, IDE0018, IDE0019, IDE0021, IDE0022, IDE0023, IDE0025, IDE0027, IDE0028, IDE0029, IDE0031, IDE0032, IDE0034, IDE0036, IDE0039, IDE0042, IDE0044, IDE0045, IDE0046, IDE0047, IDE0057, IDE0051, IDE0052, IDE0054, IDE0055, IDE0056, IDE0057, IDE0059, IDE0060, IDE0061, IDE0063, IDE0071, IDE0073, IDE0074, IDE0075, IDE0077, IDE0078, IDE0083, IDE0090, IDE0100, IDE0130, IDE160, IDE180, IDE0200, IDE0240, IDE0250, IDE0251, IDE0260, IDE0270, IDE0290, IDE0300, IDE0301, IDE0305, IDE1005, IDE1006, CA1859, CA2022, CA2263

* [Analyzers] Fix mismatched analyzer descriptions

* [Analyzers] Fix misspelling

* Update .editorconfig

Made the following style rules `silent` instead of `suggestion`: 
- Use explicit type instead of 'var'
- Use expression body for ...
- Use block-scoped namespace

* [Analyzers] Set IDE0290 to silent

* [Analyzers] Remove IDE1006 configuration from .editorconfig in favor of making exclusions for the few entries

* [Analyzers][Indexer] Add IDE1006 suppressions

* [Analyzers][Peek] Add IDE1006 suppression

* [Analyzers][MWB] Add IDE1006 suppression.

* [Analyzers][Plugins] Add IDE1006 suppression

* [Analyzers][ImageResizer] Suppress IDE0073 to retain original copyright

* [Analyzers] Remove IDE0073 severity change in .editorconfig

---------

Co-authored-by: Ani <115020168+drawbyperpetual@users.noreply.github.com>
2024-12-04 12:58:36 -05:00
Ionuț Manța
e7f17495bb [KeyboardManager]Fix mapping shift to numpad (#35890)
* Keyboard Manger fix numpad as shift

Fixed shift not being released if a numpad key as shift.

* Added comments

* Fix typo

* Fix the numpad unlocked key not working if the locked version is overridden by shift

* Fix spelling check.

* Revert the VK_CLEAR change.

---------

Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
2024-12-04 17:41:12 +00:00
Laszlo Nemeth
89be43e15d [Workspaces] implement the move feature (#35480)
* [Workspaces] Add move functionality

* spell checker

* [Workspaces] Modify Arranger to move apps without launch

* moved ipc helper

* removed callback

* use LauncherStatus in WindowArranger

* wait for launching next app

* launch in a separate thread and protect by mutexes

* update app version in advance

* changed canceling launch

* increased waiting time

* Fix optional parameter load from json

* changed arranger waiting time

* additional waiting time for Outlook

* added app id

* ensure ids before launch

* set id in editor

* minor updates

* [Workspaces] Move: Get the nearest window when moving a window

* [Workspaces] convert optional boolean to enum to avoid json problems

* Handle case when the new Application Property "moveIfExists" does not exist

* Re-implementing app-window pairing for moving feature.

* spell checker

* XAML formatting

* Fixing bug: IPC message not arriving

* spell checker

* Removing app-level-setting for move app. Also fixed compiler errors due styling.

* Updating editor window layout

* Re-implementing window positioning UI elements

* XAML formatting

* Code review findings

* Code cleanup

* Code cleanup

* Code cleanup

* code cleanup

* Code cleanup

* Code cleanup

* fix Move attribute after launch and snapshot

* Extend WindowArranger with PWA functionality to detect different PWA apps. PwaHelper moved to the common library

* fix repeat counter in the editor

* Code optimization

* code cleanup, optimization

* fix double-processing window

---------

Co-authored-by: Seraphima <zykovas91@gmail.com>
Co-authored-by: donlaci <donlaci@yahoo.com>
2024-12-04 18:17:54 +01:00
Clint Rutkas
e0949cb4ea adding in new friends and amazing community members (#36204)
* adding in new friends and amazing community members

* updating names

* Update names.txt

* Update COMMUNITY.md

* Update COMMUNITY.md

* Update names.txt

* Westernized Ionut name

---------

Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
2024-12-04 07:29:57 -08:00
PesBandi
35b9bcacdb [Monaco] Use syntax highlighting for .srt (#35651)
* [FilePreview] Use syntax highlighting for .srt

* Change customTokenColors to customTokenThemeRules

* Ignore text on the same line as a timestamp

* Update tokenization rules
2024-12-03 17:25:35 +00:00
Davide Giacometti
50b1342234 [PreviewPane]Use PerMonitorV2 DPI mode (#36174)
use PerMonitorV2 DPI mode
2024-12-03 17:24:43 +00:00
KITAGAWA Yasutaka
866518e119 [KeyboardManager]Add IME On, IME Off (#34697) 2024-12-03 16:06:43 +00:00
leileizhang
fe610d4d0e [AOT compatible] Add Common MSBuild Props for AOT Compatibility Validation to Be Imported by Projects for Future AOT Support (#36176)
[AOT compatible] Add Common MSBuild Props for AOT compatibility validation to be imported by projects for future support
2024-12-03 09:00:28 +08:00
Sergey Chernyaev
54aab5d109 [QuickAccent]Multi-language selection (#35539)
* PowerAccent with multi-language selection

- Updated Language enum, method signatures, and settings to support multiple language selections.
- Remove ALL language and added special characters language instead.
- Modified UI to use ListView with checkboxes for language selection, including a "Select All" option.
- Adjusted ViewModel and code-behind to handle multi-selection logic.
- Updated Resources.resw and PowerAccentViewModel.cs to reflect these changes.

* Changes Language selection UI

- Groups languages into two groups
- Sort them by localized language name
- Remove unneeded looping when no languages selected
2024-12-02 15:21:56 +00:00
Christian Gaarden Gaardmark
db23992aac [New+]Fix for renaming when creating file (#36143) 2024-12-02 15:13:54 +00:00
Kayla Cinnamon
0ee1befe7b Update README with advent calendar (#36172)
* update readme

* fix spellcheck
2024-12-01 16:26:33 -05:00
moooyo
f565874fc8 [AOT Compatible] Add word "AOT" to spelling check allow list. (#36138)
* init

* Add new empty line in the end

* Add Aot to allow list

---------

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
2024-11-28 20:07:13 -08:00
Dave Rayment
438ee39252 [Peek]UserSettings load logging fix and refactor (#36111)
* UserSettings refactor to fix logging bug, properly initialise defaults etc.

* Apply lock only to code which changes shared data.
2024-11-28 17:36:32 +00:00
octastylos-pseudodipteros
28304838af [FilePreview]Add support for descript.ion files (#35599)
[FilePreview] Add support for descript.ion file
2024-11-28 17:11:28 +00:00
Frederik Höft
fc29fc7426 [PTRun][ValueGenerator]Add support for UUIDv7 (#35757)
* add Run support for UUIDv7 generation

* simplify comments and maybe satisfy spell check

* fix endianess

* prefer stack allocation for temporary fixed-size buffer

* perhaps the async test caused the pipeline to hang

* switch to .NET 9 BCL implementation of UUIDv7

* add UUIDv7 to input query suggestions + update exception messages to include v7

* simplify Guid description switch + update devdocs
2024-11-28 15:52:16 +00:00
151 changed files with 1982 additions and 984 deletions

View File

@@ -226,3 +226,8 @@ arcosh
dbus
anypass
gpg
# .NET
AOT
Aot

View File

@@ -44,6 +44,7 @@ Bartosz
betadele
betsegaw
bricelam
bsky
CCcat
Chinh
chrdavis
@@ -53,6 +54,7 @@ Coplen
craigloewen
crutkas
damienleroy
daverayment
davidegiacometti
debian
Deibisu
@@ -64,6 +66,7 @@ Essey
ethanfangg
ferraridavide
frankychen
Gaarden
gaardmark
gabime
Galaxi
@@ -71,6 +74,7 @@ Garside
Gershaft
Giordani
Gokce
gordon
grzhan
Guo
hanselman
@@ -82,6 +86,7 @@ Horvalds
Howett
htcfreek
Huynh
Ionut
Jaswal
jefflord
Jordi
@@ -90,11 +95,13 @@ Kairu
Kamra
Kantarci
Karthick
kaylacinnamon
kevinguo
Krigun
Lambson
Laute
laviusmotileng
Leilei
Luecking
Mahalingam
Markovic
@@ -110,6 +117,7 @@ nathancartlidge
Nemeth
nielslaute
oldnewthing
onegreatworld
palenshus
pedrolamas
peteblois
@@ -120,6 +128,7 @@ Pylyp
quachpas
Quriz
randyrants
rayment
ricardosantos
riri
ritchielawrence
@@ -148,6 +157,7 @@ waaverecords
Whuihuan
Xpg
ycv
yeelam
Yuniardi
yuyoyuppe
Zeol

View File

@@ -667,6 +667,7 @@ Iindex
IJson
Ijwhost
IKs
iljxck
ILogon
IMAGEHLP
IMAGERESIZERCONTEXTMENU
@@ -770,6 +771,7 @@ lastcodeanalysissucceeded
Lastdevice
LASTEXITCODE
LAYOUTRTL
lcb
LCIDTo
lcl
Lclean

View File

@@ -28,7 +28,6 @@ parameters:
type: object
default:
- x64
- arm64
- name: enableMsBuildCaching
type: boolean
displayName: "Enable MSBuild Caching"

View File

@@ -0,0 +1,39 @@
parameters:
- name: configuration
type: string
default: "Release"
- name: platform
type: string
default: ""
- name: inputArtifactStem
type: string
default: ""
jobs:
- job: OneFuzz
pool:
vmImage: windows-2022
steps:
- checkout: self
submodules: false
clean: true
fetchDepth: 1
fetchTags: false
- download: current
displayName: Download artifacts
artifact: build-${{ parameters.platform }}-${{ parameters.configuration }}${{ parameters.inputArtifactStem }}
patterns: |-
**/tests/*.FuzzTests/**
- script: |
echo "Printing files in target directory..."
dir "$(Pipeline.Workspace)\build-${{ parameters.platform }}-${{ parameters.configuration }}${{ parameters.inputArtifactStem }}\x64\Release\tests\AdvancedPaste.FuzzTests\net8.0-windows10.0.19041.0"
displayName: "Print files in target directory"
- task: onefuzz-task@0
inputs:
onefuzzOSes: Windows
env:
onefuzzDropDirectory: $(Pipeline.Workspace)\build-${{ parameters.platform }}-${{ parameters.configuration }}${{ parameters.inputArtifactStem }}\x64\Release\tests\AdvancedPaste.FuzzTests\net8.0-windows10.0.19041.0
SYSTEM_ACCESSTOKEN: $(System.AccessToken)

View File

@@ -4,8 +4,8 @@ variables:
- name: EnablePipelineCache
value: true
- ${{ if eq(parameters.enableMsBuildCaching, true) }}:
- name: EnablePipelineCache
value: true
- name: EnablePipelineCache
value: true
parameters:
- name: buildPlatforms
@@ -26,43 +26,54 @@ parameters:
stages:
# Allow manual builds to skip pre-check
- ${{ if ne(variables['Build.Reason'], 'Manual') }}:
- stage: Precheck
jobs:
- template: job-ci-precheck.yml
- stage: Precheck
jobs:
- template: job-ci-precheck.yml
- ${{ each platform in parameters.buildPlatforms }}:
- stage: Build_${{ platform }}
displayName: Build ${{ platform }}
${{ if ne(variables['Build.Reason'], 'Manual') }}:
dependsOn: [Precheck]
condition: and(succeeded(), ne(dependencies.Precheck.outputs['Precheck.verifyBuildRequest.skipBuild'], 'Yes'))
${{ else }}:
dependsOn: []
jobs:
- template: job-build-project.yml
parameters:
pool:
${{ if eq(variables['System.CollectionId'], 'cb55739e-4afe-46a3-970f-1b49d8ee7564') }}:
name: SHINE-INT-L
${{ else }}:
name: SHINE-OSS-L
${{ if eq(parameters.useVSPreview, true) }}:
demands: ImageOverride -equals SHINE-VS17-Preview
buildPlatforms:
- ${{ platform }}
buildConfigurations: [Release]
enablePackageCaching: true
enableMsBuildCaching: ${{ parameters.enableMsBuildCaching }}
runTests: ${{ parameters.runTests }}
useVSPreview: ${{ parameters.useVSPreview }}
- ${{ if eq(parameters.runTests, true) }}:
- stage: Test_${{ platform }}
displayName: Test ${{ platform }}
dependsOn:
- Build_${{platform}}
- stage: Build_${{ platform }}
displayName: Build ${{ platform }}
${{ if ne(variables['Build.Reason'], 'Manual') }}:
dependsOn: [Precheck]
condition: and(succeeded(), ne(dependencies.Precheck.outputs['Precheck.verifyBuildRequest.skipBuild'], 'Yes'))
${{ else }}:
dependsOn: []
jobs:
- template: job-test-project.yml
- template: job-build-project.yml
parameters:
pool:
${{ if eq(variables['System.CollectionId'], 'cb55739e-4afe-46a3-970f-1b49d8ee7564') }}:
name: SHINE-INT-L
${{ else }}:
name: SHINE-OSS-L
${{ if eq(parameters.useVSPreview, true) }}:
demands: ImageOverride -equals SHINE-VS17-Preview
buildPlatforms:
- ${{ platform }}
buildConfigurations: [Release]
enablePackageCaching: true
enableMsBuildCaching: ${{ parameters.enableMsBuildCaching }}
runTests: ${{ parameters.runTests }}
useVSPreview: ${{ parameters.useVSPreview }}
# - ${{ if eq(parameters.runTests, true) }}:
# - stage: Test_${{ platform }}
# displayName: Test ${{ platform }}
# dependsOn:
# - Build_${{platform}}
# jobs:
# - template: job-test-project.yml
# parameters:
# platform: ${{ platform }}
# configuration: Release
- stage: Fuzz ${platform}
displayName: Fuzz ${{ platform }}
dependsOn:
- Build_${platform}
jobs:
- template: job-fuzz.yml
parameters:
platform: ${{ platform }}
configuration: Release
inputArtifactStem: ""

View File

@@ -9,12 +9,18 @@ Names are in alphabetical order based on first name.
### [@Aaron-Junker](https://github.com/Aaron-Junker) - [Aaron Junker](https://aaron-junker.github.io)
Aaron has helped triaging, discussing, and creating a substantial number of issues and contributed features/fixes. Aaron was the primary person for helping build the File Explorer preview pane handler for developer files.
### [@cgaarden](https://github.com/cgaarden) - [Christian Gaarden Gaardmark](https://www.onegreatworld.com)
Christian contributed New+ utility
### [@CleanCodeDeveloper](https://github.com/CleanCodeDeveloper)
CleanCodeDeveloper helped do massive amounts of code stability and image resizer work.
### [@damienleroy](https://github.com/damienleroy) - [Damien Leroy](https://www.linkedin.com/in/Damien-Leroy-b2734416a/)
Damien has helped out by developing and contributing the Quick Accent utility.
### [@daverayment ](https://github.com/daverayment ) - [David Rayment](https://www.linkedin.com/in/david-rayment-168b5251/)
Dave has helped improve the experience inside of Peek by adding in new features and fixing bugs.
### [@davidegiacometti](https://github.com/davidegiacometti) - [Davide Giacometti](https://www.linkedin.com/in/davidegiacometti/)
Davide has helped fix multiple bugs, added new utilities, features, as well as help us with the ARM64 effort by porting applications to .NET Core.
@@ -42,6 +48,9 @@ Color Picker is from Martin.
### [@mikeclayton](https://github.com/mikeclayton) - [Michael Clayton](https://michael-clayton.com)
Michael contributed the [initial version](https://github.com/microsoft/PowerToys/issues/23216) of the Mouse Jump tool and [a number of updates](https://github.com/microsoft/PowerToys/pulls?q=is%3Apr+author%3Amikeclayton) based on his FancyMouse utility.
### [@PesBandi](https://github.com/PesBandi/) - PesBandi
PesBandi has helped do massive amounts of Quick Accent and bug fixes.
### [@riverar](https://github.com/riverar) - [Rafael Rivera](https://withinrafael.com/)
Rafael has helped do the [upgrade from CppWinRT 1.x to 2.0](https://github.com/microsoft/PowerToys/issues/1907). He directly provided feedback to the CppWinRT team for bugs from this migration as well.
@@ -154,18 +163,23 @@ Other contributors:
## PowerToys core team
- [@crutkas](https://github.com/crutkas/) - Clint Rutkas - Lead
- [@ethanfangg](https://github.com/ethanfangg) - Ethan Fang - Lead
- [@cinnamon-msft](https://github.com/cinnamon-msft) - Kayla Cinnamon - Product Manager
- [@cinnamon-msft](https://github.com/cinnamon-msft) - Kayla Cinnamon - Lead
- [@ethanfangg](https://github.com/ethanfangg) - Ethan Fang - Product Manager
- [@plante-msft](https://github.com/plante-msft) - Connor Plante - Product Manager
- [@nguyen-dows](https://github.com/nguyen-dows) - Christopher Nguyen - Product Manager
- [@joadoumie](https://github.com/joadoumie) - Jordi Adoumie - Product Manager
- [@jaimecbernardo](https://github.com/jaimecbernardo) - Jaime Bernardo - Dev lead
- [@dhowett](https://github.com/dhowett) - Dustin Howett - Dev lead
- [@yeelam-gordon](https://github.com/yeelam-gordon) - Gordon Lam - Dev lead
- [@drawbyperpetual](https://github.com/drawbyperpetual) - Anirudha Shankar - Dev
- [@mantaionut](https://github.com/mantaionut) - Ionut Manta - Dev
- [@donlaci](https://github.com/donlaci) - Laszlo Nemeth - Dev
- [@gokcekantarci](https://github.com/gokcekantarci) - Gokce Kantarci - Dev
- [@SeraphimaZykova](https://github.com/SeraphimaZykova) - Seraphima Zykova - Dev
- [@stefansjfw](https://github.com/stefansjfw) - Stefan Markovic - Dev
- [@lei9444](https://github.com/lei9444) - Leilei Zhang - Dev
- [@shuaiyuanxx](https://github.com/shuaiyuanxx) - Shawn Yuan - Dev
- [@moooyo](https://github.com/moooyo) - Yu Leng - Dev
- [@haoliuu](https://github.com/haoliuu) - Hao Liu - Dev
# Former PowerToys core team members
@@ -176,3 +190,4 @@ Other contributors:
- [@mykhailopylyp](https://github.com/mykhailopylyp) - Mykhailo Pylyp - Dev
- [@taras-janea](https://github.com/taras-janea) - Taras Sich - Dev
- [@yuyoyuppe](https://github.com/yuyoyuppe) - Andrey Nekrasov - Dev
- [@gokcekantarci](https://github.com/gokcekantarci) - Gokce Kantarci - Dev

View File

@@ -34,6 +34,7 @@
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageVersion Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
<PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.2739.15" />
<!-- Package Microsoft.Win32.SystemEvents added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Drawing.Common but the 8.0.1 version wasn't published to nuget. -->

View File

@@ -171,6 +171,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject
src\.editorconfig = src\.editorconfig
.vsconfig = .vsconfig
src\Common.Dotnet.AotCompatibility.props = src\Common.Dotnet.AotCompatibility.props
src\Common.Dotnet.CsWinRT.props = src\Common.Dotnet.CsWinRT.props
src\Common.SelfContained.props = src\Common.SelfContained.props
Cpp.Build.props = Cpp.Build.props
@@ -634,6 +635,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkspacesCsharpLibrary", "
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NewPlus.ShellExtension.win10", "src\modules\NewPlus\NewShellExtensionContextMenu.win10\NewPlus.ShellExtension.win10.vcxproj", "{0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdvancedPaste.FuzzTests", "src\modules\AdvancedPaste\AdvancedPaste.FuzzTests\AdvancedPaste.FuzzTests.csproj", "{4D079CB1-E2FE-417D-9DB4-9D0B03BC80C6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
@@ -2806,6 +2809,18 @@ Global
{0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Release|x64.Build.0 = Release|x64
{0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Release|x86.ActiveCfg = Release|x64
{0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Release|x86.Build.0 = Release|x64
{4D079CB1-E2FE-417D-9DB4-9D0B03BC80C6}.Debug|ARM64.ActiveCfg = Debug|ARM64
{4D079CB1-E2FE-417D-9DB4-9D0B03BC80C6}.Debug|ARM64.Build.0 = Debug|ARM64
{4D079CB1-E2FE-417D-9DB4-9D0B03BC80C6}.Debug|x64.ActiveCfg = Debug|x64
{4D079CB1-E2FE-417D-9DB4-9D0B03BC80C6}.Debug|x64.Build.0 = Debug|x64
{4D079CB1-E2FE-417D-9DB4-9D0B03BC80C6}.Debug|x86.ActiveCfg = Debug|x64
{4D079CB1-E2FE-417D-9DB4-9D0B03BC80C6}.Debug|x86.Build.0 = Debug|x64
{4D079CB1-E2FE-417D-9DB4-9D0B03BC80C6}.Release|ARM64.ActiveCfg = Release|ARM64
{4D079CB1-E2FE-417D-9DB4-9D0B03BC80C6}.Release|ARM64.Build.0 = Release|ARM64
{4D079CB1-E2FE-417D-9DB4-9D0B03BC80C6}.Release|x64.ActiveCfg = Release|x64
{4D079CB1-E2FE-417D-9DB4-9D0B03BC80C6}.Release|x64.Build.0 = Release|x64
{4D079CB1-E2FE-417D-9DB4-9D0B03BC80C6}.Release|x86.ActiveCfg = Release|x64
{4D079CB1-E2FE-417D-9DB4-9D0B03BC80C6}.Release|x86.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -3039,6 +3054,7 @@ Global
{66614C26-314C-4B91-9071-76133422CFEF} = {B6C42F16-73EB-477E-8B0D-4E6CF6C20AAC}
{89D0E199-B17A-418C-B2F8-7375B6708357} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF}
{0DB0F63A-D2F8-4DA3-A650-2D0B8724218E} = {CA716AE6-FE5C-40AC-BB8F-2C87912687AC}
{4D079CB1-E2FE-417D-9DB4-9D0B03BC80C6} = {9873BA05-4C41-4819-9283-CF45D795431B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}

View File

@@ -1,6 +1,6 @@
# Microsoft PowerToys
![Hero image for Microsoft PowerToys](doc/images/overview/PT_hero_image.png)
![Hero image for Microsoft PowerToys](doc/images/overview/PT_holiday_hero_image.png)
[How to use PowerToys][usingPowerToys-docs-link] | [Downloads & Release notes][github-release-link] | [Contributing to PowerToys](#contributing) | [What's Happening](#whats-happening) | [Roadmap](#powertoys-roadmap)
@@ -20,6 +20,12 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
| [Registry Preview](https://aka.ms/PowerToysOverview_RegistryPreview) | [Screen Ruler](https://aka.ms/PowerToysOverview_ScreenRuler) | [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) |
| [Text Extractor](https://aka.ms/PowerToysOverview_TextExtractor) | [Video Conference Mute](https://aka.ms/PowerToysOverview_VideoConference) | [Workspaces](https://aka.ms/PowerToysOverview_Workspaces) |
## 🎁⭐ PowerToys Advent calendar ⭐🎁
We will be highlighting a cool utility each day for 24 days in December! To follow along, check out these threads:
- https://bsky.app/profile/kaylacinnamon.bsky.social/post/3lcb7iljxck2o
- https://x.com/cinnamon_msft/status/1863284610773246257
## Installing and running Microsoft PowerToys
### Requirements

View File

@@ -47,7 +47,7 @@ registerAdditionalNewLanguage("id", [".fileExtension"], idDefinition(), monaco)
* The id can be anything. Recommended is one of the file extensions. For example "php" or "reg".
4. In case you wish to add a custom color for a token, you can do so by adding the following line to [`customTokenColors.js`](/src/Monaco/customTokenColors.js):
4. In case you wish to add a custom color for a token, you can do so by adding the following line to [`customTokenThemeRules.js`](/src/Monaco/customTokenThemeRules.js):
```javascript
{token: 'token-name', foreground: 'ff0000'}
```

View File

@@ -1,6 +1,6 @@
# Value Generator Plugin
The Value Generator plugin is used to generate hashes for strings, to calculate base64 encodings, escape and encode URLs/URIs and to generate GUIDs versions 1, 3, 4 and 5.
The Value Generator plugin is used to generate hashes for strings, to calculate base64 encodings, escape and encode URLs/URIs and to generate GUIDs of version 1, 3, 4, 5, and 7.
![Image of Value Generator plugin](/doc/images/launcher/plugin/community.valuegenerator.png)
@@ -34,7 +34,10 @@ The Value Generator plugin is used to generate hashes for strings, to calculate
### [`GUIDGenerator`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/GUID/GUIDGenerator.cs)
- Utility class for generating or calculating GUIDs
- Generating GUID versions 1 and 4 is done using builtin APIs. [`UuidCreateSequential`](https://learn.microsoft.com/en-us/windows/win32/api/rpcdce/nf-rpcdce-uuidcreatesequential) for version 1 and `System.Guid.NewGuid()` for version 4
- Generating GUID versions 1, 4, and 7 is done using builtin APIs:
- [`UuidCreateSequential`](https://learn.microsoft.com/en-us/windows/win32/api/rpcdce/nf-rpcdce-uuidcreatesequential) for version 1
- `System.Guid.NewGuid()` for version 4
- `System.Guid.CreateVersion7()` for version 7
- Versions 3 and 5 take two parameters, a namespace and a name
- The namespace must be a valid GUID or one of the [predefined ones](https://datatracker.ietf.org/doc/html/rfc4122#appendix-C)
- The `PredefinedNamespaces` dictionary contains aliases for the predefined namespaces

Binary file not shown.

After

Width:  |  Height:  |  Size: 503 KiB

View File

@@ -30,7 +30,7 @@ Function Generate-FileList() {
$fileExclusionList = @("*.pdb", "*.lastcodeanalysissucceeded", "createdump.exe", "powertoys.exe")
$fileInclusionList = @("*.dll", "*.exe", "*.json", "*.msix", "*.png", "*.gif", "*.ico", "*.cur", "*.svg", "index.html", "reg.js", "gitignore.js", "monacoSpecialLanguages.js", "customTokenColors.js", "*.pri")
$fileInclusionList = @("*.dll", "*.exe", "*.json", "*.msix", "*.png", "*.gif", "*.ico", "*.cur", "*.svg", "index.html", "reg.js", "gitignore.js", "srt.js", "monacoSpecialLanguages.js", "customTokenThemeRules.js", "*.pri")
$dllsToIgnore = @("System.CodeDom.dll", "WindowsBase.dll")

View File

@@ -46,32 +46,28 @@ dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
dotnet_naming_symbols.interface.applicable_kinds = interface
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.interface.required_modifiers =
dotnet_naming_symbols.interface.required_modifiers =
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.types.required_modifiers =
dotnet_naming_symbols.types.required_modifiers =
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.non_field_members.required_modifiers =
dotnet_naming_symbols.non_field_members.required_modifiers =
# Naming styles
dotnet_naming_style.begins_with_i.required_prefix = I
dotnet_naming_style.begins_with_i.required_suffix =
dotnet_naming_style.begins_with_i.word_separator =
dotnet_naming_style.begins_with_i.required_suffix =
dotnet_naming_style.begins_with_i.word_separator =
dotnet_naming_style.begins_with_i.capitalization = pascal_case
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
@@ -96,4 +92,176 @@ end_of_line = crlf
dotnet_diagnostic.IDE0065.severity = none
# IDE0009: Add this or Me qualification
dotnet_diagnostic.IDE0009.severity = none
dotnet_diagnostic.IDE0009.severity = none
# IDE-based code analysis rules
# IDE0005: Remove unnecessary import
dotnet_diagnostic.IDE0005.severity = suggestion
# IDE0008: Use explicit type instead of 'var'
dotnet_diagnostic.IDE0008.severity = silent
# IDE0016: Use throw expression
dotnet_diagnostic.IDE0016.severity = suggestion
# IDE0018: Inline variable declaration
dotnet_diagnostic.IDE0018.severity = suggestion
# IDE0019: Use pattern matching
dotnet_diagnostic.IDE0019.severity = suggestion
# IDE0021: Use expression body for constructors
dotnet_diagnostic.IDE0021.severity = silent
# IDE0022: Use expression body for methods
dotnet_diagnostic.IDE0022.severity = silent
# IDE0023: Use expression body for conversion operators
dotnet_diagnostic.IDE0023.severity = silent
# IDE0025: Use expression body for properties
dotnet_diagnostic.IDE0025.severity = silent
# IDE0027: Use expression body for accessors
dotnet_diagnostic.IDE0027.severity = silent
# IDE0028: Use collection initializers
dotnet_diagnostic.IDE0028.severity = suggestion
# IDE0029: Null check can be simplified
dotnet_diagnostic.IDE0029.severity = suggestion
# IDE0031: Use null propagation
dotnet_diagnostic.IDE0031.severity = suggestion
# IDE0032: Use auto property
dotnet_diagnostic.IDE0032.severity = suggestion
# IDE0034: Simplify default expression
dotnet_diagnostic.IDE0034.severity = suggestion
# IDE0036: Order modifiers
dotnet_diagnostic.IDE0036.severity = suggestion
# IDE0039: Use local function instead of lambda
dotnet_diagnostic.IDE0039.severity = suggestion
# IDE0042: Deconstruct variable declaration
dotnet_diagnostic.IDE0042.severity = suggestion
# IDE0044: Add readonly modifier
dotnet_diagnostic.IDE0044.severity = suggestion
# IDE0045: Use conditional expression for assignment
dotnet_diagnostic.IDE0045.severity = suggestion
# IDE0046: Use conditional expression for return
dotnet_diagnostic.IDE0046.severity = suggestion
# IDE0047: Remove unnecessary parentheses
dotnet_diagnostic.IDE0047.severity = suggestion
# IDE0051: Remove unused private member
dotnet_diagnostic.IDE0051.severity = suggestion
# IDE0052: Remove unread private member
dotnet_diagnostic.IDE0052.severity = suggestion
# IDE0054: Use compound assignment
dotnet_diagnostic.IDE0054.severity = suggestion
# IDE0055: Fix formatting
dotnet_diagnostic.IDE0055.severity = suggestion
# IDE0056: Use index operator
dotnet_diagnostic.IDE0056.severity = suggestion
# IDE0057: Use range operator
dotnet_diagnostic.IDE0057.severity = suggestion
# IDE0059: Remove unnecessary value assignment
dotnet_diagnostic.IDE0059.severity = suggestion
# IDE0060: Remove unused parameter
dotnet_diagnostic.IDE0060.severity = suggestion
# IDE0061: Use expression body for local functions
dotnet_diagnostic.IDE0061.severity = silent
# IDE0063: Use simple 'using' statement
dotnet_diagnostic.IDE0063.severity = suggestion
# IDE0071: Simplify interpolation
dotnet_diagnostic.IDE0071.severity = suggestion
# IDE0074: Use coalesce compound assignment
dotnet_diagnostic.IDE0074.severity = suggestion
# IDE0075: Simplify conditional expression
dotnet_diagnostic.IDE0075.severity = suggestion
# IDE0077: Avoid legacy format target in global 'SuppressMessageAttribute'
dotnet_diagnostic.IDE0077.severity = suggestion
# IDE0078: Use pattern matching
dotnet_diagnostic.IDE0078.severity = suggestion
# IDE0083: Use pattern matching ('not' operator)
dotnet_diagnostic.IDE0083.severity = suggestion
# IDE0090: Simplify 'new' expression
dotnet_diagnostic.IDE0090.severity = suggestion
# IDE0100: Remove unnecessary equality operator
dotnet_diagnostic.IDE0100.severity = suggestion
# IDE0130: Namespace does not match folder structure
dotnet_diagnostic.IDE0130.severity = suggestion
# IDE0160: Use block-scoped namespace
dotnet_diagnostic.IDE0160.severity = silent
# IDE0180: Use tuple to swap values
dotnet_diagnostic.IDE0180.severity = suggestion
# IDE0200: Remove unnecessary lambda expression
dotnet_diagnostic.IDE0200.severity = suggestion
# IDE0240: Nullable directive is redundant
dotnet_diagnostic.IDE0240.severity = suggestion
# IDE0250: Struct can be made 'readonly'
dotnet_diagnostic.IDE0250.severity = suggestion
# IDE0251: Member can be made 'readonly''
dotnet_diagnostic.IDE0251.severity = suggestion
# IDE0260: Use pattern matching
dotnet_diagnostic.IDE0260.severity = suggestion
# IDE0270: Null check can be simplified
dotnet_diagnostic.IDE0270.severity = suggestion
# IDE0290: Use primary constructor
dotnet_diagnostic.IDE0290.severity = silent
# IDE0300: Use collection expression for array
dotnet_diagnostic.IDE0300.severity = suggestion
# IDE0301: Use collection expression for empty
dotnet_diagnostic.IDE0301.severity = suggestion
# IDE0305: Use collection expression for fluent
dotnet_diagnostic.IDE0305.severity = suggestion
# IDE1005: Use conditional delegate call
dotnet_diagnostic.IDE1005.severity = suggestion
# CA1859: Use concrete types when possible for improved performance
dotnet_diagnostic.CA1859.severity = suggestion
# CA2202: Avoid inexact read with Stream.Read
dotnet_diagnostic.CA2022.severity = suggestion
# CA2263: Prefer generic overload when type is known
dotnet_diagnostic.CA2263.severity = suggestion

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Some items may be set in Directory.Build.props in root -->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<IsAotCompatible>true</IsAotCompatible>
<CsWinRTAotOptimizerEnabled>true</CsWinRTAotOptimizerEnabled>
<CsWinRTAotWarningLevel>2</CsWinRTAotWarningLevel>
</PropertyGroup>
</Project>

View File

@@ -2,8 +2,8 @@
<!-- Include Monaco Editor source code -->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)\Monaco\customTokenColors.js">
<Link>Assets\Monaco\customTokenColors.js</Link>
<None Include="$(MSBuildThisFileDirectory)\Monaco\customTokenThemeRules.js">
<Link>Assets\Monaco\customTokenThemeRules.js</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)\Monaco\monacoSpecialLanguages.js">

View File

@@ -6,7 +6,7 @@
root: [
[/^#.*$/, 'comment'],
[/.*((?<!(^|\/))\*\*.*|\*\*(?!(\/|$))).*/, 'invalid'],
[/((?:^!\s*(?:\\\s|\S)+)?)((?:^\s*(?:\\\s|\S)+)?)((?:\s+(?:\\\s|\S)+)*)/, ['custom-gitignore.negation', 'tag', 'invalid']]
[/((?:^!\s*(?:\\\s|\S)+)?)((?:^\s*(?:\\\s|\S)+)?)((?:\s+(?:\\\s|\S)+)*)/, ['custom-negation', 'tag', 'invalid']]
]
}
};

View File

@@ -0,0 +1,29 @@
export function srtDefinition() {
return {
tokenizer: {
root: [
[/\s*\d+/, 'number', '@block']
],
block: [
[/^\d{2}:\d{2}:\d{2},\d{3} --> \d{2}:\d{2}:\d{2},\d{3}/, {
cases: {
'@eos': {token: 'type.identifier', next: '@subtitle'},
'@default': {token: 'type.identifier', next: '@ignore'}
}
}],
[/^$/, 'string', '@pop']
],
ignore: [
[/.+$/, '', '@subtitle']
],
subtitle: [
[/^$/, 'string', '@popall'],
[/<\/?(?:[ibu]|font(?:\s+color="[^"]+"\s*)?)>/, 'tag'],
[/./, 'string']
]
}
};
}

View File

@@ -1,3 +0,0 @@
export const customTokenColors = [
{token: 'custom-gitignore.negation', foreground: 'c00ce0'}
];

View File

@@ -0,0 +1,3 @@
export const customTokenThemeRules = [
{token: 'custom-negation.gitignore', foreground: 'c00ce0'}
];

View File

@@ -79,7 +79,7 @@
<script src="http://[[PT_URL]]/monacoSpecialLanguages.js" type="module"></script>
<script type="module">
import { registerAdditionalLanguages } from 'http://[[PT_URL]]/monacoSpecialLanguages.js';
import { customTokenColors } from 'http://[[PT_URL]]/customTokenColors.js';
import { customTokenThemeRules } from 'http://[[PT_URL]]/customTokenThemeRules.js';
require.config({ paths: { vs: 'http://[[PT_URL]]/monacoSRC/min/vs' } });
require(['vs/editor/editor.main'], async function () {
await registerAdditionalLanguages(monaco)
@@ -88,7 +88,7 @@
monaco.editor.defineTheme('theme', {
base: theme, // Sets the base theme to "vs" or "vs-dark" depending on the user's preference
inherit: true,
rules: customTokenColors,
rules: customTokenThemeRules,
colors: {} // `colors` is a required attribute
});

View File

@@ -2,18 +2,20 @@
import { regDefinition } from './customLanguages/reg.js';
import { gitignoreDefinition } from './customLanguages/gitignore.js';
import { srtDefinition } from './customLanguages/srt.js';
export async function registerAdditionalLanguages(monaco){
await languageDefinitions();
registerAdditionalLanguage("cppExt", [".ino", ".pde"], "cpp", monaco)
registerAdditionalLanguage("xmlExt", [".wsdl", ".csproj", ".vcxproj", ".vbproj", ".fsproj"], "xml", monaco)
registerAdditionalLanguage("txtExt", [".sln", ".log", ".vsconfig", ".env", ".srt", ".ahk"], "txt", monaco)
registerAdditionalLanguage("razorExt", [".razor"], "razor", monaco)
registerAdditionalLanguage("vbExt", [".vbs"], "vb", monaco)
registerAdditionalLanguage("iniExt", [".inf", ".gitconfig", ".gitattributes", ".editorconfig"], "ini", monaco)
registerAdditionalLanguage("shellExt", [".ksh", ".zsh", ".bsh"], "shell", monaco)
registerAdditionalNewLanguage("reg", [".reg"], regDefinition(), monaco)
registerAdditionalNewLanguage("gitignore", [".gitignore"], gitignoreDefinition(), monaco)
registerAdditionalLanguage("cppExt", [".ino", ".pde"], "cpp", monaco);
registerAdditionalLanguage("xmlExt", [".wsdl", ".csproj", ".vcxproj", ".vbproj", ".fsproj"], "xml", monaco);
registerAdditionalLanguage("txtExt", [".sln", ".log", ".vsconfig", ".env", ".ahk", ".ion"], "txt", monaco);
registerAdditionalLanguage("razorExt", [".razor"], "razor", monaco);
registerAdditionalLanguage("vbExt", [".vbs"], "vb", monaco);
registerAdditionalLanguage("iniExt", [".inf", ".gitconfig", ".gitattributes", ".editorconfig"], "ini", monaco);
registerAdditionalLanguage("shellExt", [".ksh", ".zsh", ".bsh"], "shell", monaco);
registerAdditionalNewLanguage("reg", [".reg"], regDefinition(), monaco);
registerAdditionalNewLanguage("gitignore", [".gitignore"], gitignoreDefinition(), monaco);
registerAdditionalNewLanguage("srt", [".srt"], srtDefinition(), monaco);
}
// Language definitions taken from Monaco source code

File diff suppressed because one or more lines are too long

View File

@@ -109,6 +109,24 @@ namespace DPIAware
}
}
void InverseConvert(HMONITOR monitor_handle, RECT& rect)
{
if (monitor_handle == NULL)
{
const POINT ptZero = { 0, 0 };
monitor_handle = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY);
}
UINT dpi_x, dpi_y;
if (GetDpiForMonitor(monitor_handle, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y) == S_OK)
{
rect.left = static_cast<long>(std::round(rect.left * static_cast<float>(DEFAULT_DPI) / dpi_x));
rect.right = static_cast<long>(std::round(rect.right * static_cast<float>(DEFAULT_DPI) / dpi_x));
rect.top = static_cast<long>(std::round(rect.top * static_cast<float>(DEFAULT_DPI) / dpi_y));
rect.bottom = static_cast<long>(std::round(rect.bottom * static_cast<float>(DEFAULT_DPI) / dpi_y));
}
}
void EnableDPIAwarenessForThisProcess()
{
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);

View File

@@ -15,6 +15,7 @@ namespace DPIAware
void Convert(HMONITOR monitor_handle, RECT& rect);
void ConvertByCursorPosition(float& width, float& height);
void InverseConvert(HMONITOR monitor_handle, float& width, float& height);
void InverseConvert(HMONITOR monitor_handle, RECT& rect);
void EnableDPIAwarenessForThisProcess();
enum AwarenessLevel

View File

@@ -241,10 +241,12 @@ void LayoutMap::LayoutMapImpl::UpdateLayout()
keyboardLayoutMap[VK_KANA] = L"IME Kana";
keyboardLayoutMap[VK_HANGEUL] = L"IME Hangeul";
keyboardLayoutMap[VK_HANGUL] = L"IME Hangul";
keyboardLayoutMap[VK_IME_ON] = L"IME On";
keyboardLayoutMap[VK_JUNJA] = L"IME Junja";
keyboardLayoutMap[VK_FINAL] = L"IME Final";
keyboardLayoutMap[VK_HANJA] = L"IME Hanja";
keyboardLayoutMap[VK_KANJI] = L"IME Kanji";
keyboardLayoutMap[VK_IME_OFF] = L"IME Off";
keyboardLayoutMap[VK_CONVERT] = L"IME Convert";
keyboardLayoutMap[VK_NONCONVERT] = L"IME Non-Convert";
keyboardLayoutMap[VK_ACCEPT] = L"IME Kana";

View File

@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\tests\AdvancedPaste.FuzzTests\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\AdvancedPaste\Helpers\JsonHelper.cs" Link="JsonHelper.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="MSTest" />
</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,19 @@
// 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 AdvancedPaste.Helpers;
using Windows.ApplicationModel.DataTransfer;
namespace AdvancedPaste.FuzzTests
{
public class FuzzTests
{
public static void FuzzToJsonFromXmlOrCsv(ReadOnlySpan<byte> input)
{
var dataPackage = new DataPackage();
dataPackage.SetText(input.ToString());
JsonHelper.ToJsonFromXmlOrCsv(dataPackage.GetView());
}
}
}

View File

@@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ManagedCommon
{
public static class Logger
{
// An empty method to simulate logging information
public static void LogTrace()
{
// Do nothing
}
// An empty method to simulate logging information
public static void LogInfo(string message)
{
// Do nothing
}
// An empty method to simulate logging warnings
public static void LogWarning(string message)
{
// Do nothing
}
// An empty method to simulate logging errors
public static void LogError(string message, Exception? ex = null)
{
// Do nothing
}
public static void LogDebug(string message, Exception? ex = null)
{
// Do nothing
}
}
}

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,40 @@
{
"configVersion": 3,
"entries": [
{
"fuzzer": {
"$type": "libfuzzerDotNet",
"dll": "AdvancedPaste.FuzzTests.dll",
"class": "AdvancedPaste.FuzzTests.FuzzTests",
"method": "FuzzPhoneNumber"
},
"adoTemplate": {
// supply the values appropriate to your
// project, where bugs will be filed
"org": "microsoft",
"project": "OS",
"AssignedTo": "leilzh@microsoft.com",
"AreaPath": "OS\\Windows Client and Services\\WinPD\\DEEP-Developer Experience, Ecosystem and Partnerships\\SHINE\\PowerToys",
"IterationPath": "OS\\Future"
},
"jobNotificationEmail": "leilzh@microsoft.com",
"skip": false,
"rebootAfterSetup": false,
"oneFuzzJobs": [
// at least one job is required
{
"projectName": "AdvancedPaste",
"targetName": "AdvancedPaste-dotnet-fuzzer"
}
],
"jobDependencies": [
// this should contain, at minimum,
// the DLL and PDB files
// you will need to add any other files required
// (globs are supported)
"AdvancedPaste.FuzzTests.dll",
"AdvancedPaste.FuzzTests.pdb"
]
}
]
}

View File

@@ -33,6 +33,7 @@ using Timer = System.Windows.Forms.Timer;
[module: SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", Scope = "member", Target = "MouseWithoutBorders.frmMatrix.#Dispose(System.Boolean)", MessageId = "logoBitmap", Justification = "Dotnet port with style preservation")]
[module: SuppressMessage("Microsoft.Mobility", "CA1601:DoNotUseTimersThatPreventPowerStateChanges", Scope = "member", Target = "MouseWithoutBorders.frmMatrix.#frmMatrix_Shown(System.Object,System.EventArgs)", Justification = "Dotnet port with style preservation")]
[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.frmMatrix.#PaintMyLogo()", Justification = "Dotnet port with style preservation")]
[module: SuppressMessage("Style", "IDE1006:Naming Styles", Scope = "member", Target = "~M:MouseWithoutBorders.FrmMatrix.M_EnabledChanged(System.Object,System.EventArgs)", Justification = "Dotnet port with style preservation")]
namespace MouseWithoutBorders
{

View File

@@ -215,10 +215,10 @@ namespace newplus::utilities
inline bool is_desktop_folder(const std::filesystem::path target_fullpath)
{
TCHAR desktopPath[MAX_PATH];
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, 0, desktopPath)))
TCHAR desktop_path[MAX_PATH];
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, 0, desktop_path)))
{
return StrCmpIW(target_fullpath.c_str(), desktopPath) == 0;
return StrCmpIW(target_fullpath.c_str(), desktop_path) == 0;
}
return false;
}
@@ -376,8 +376,10 @@ namespace newplus::utilities
// Copy file and determine final filename
std::filesystem::path target_final_fullpath = template_entry->copy_object_to(GetActiveWindow(), target_fullpath);
// Consider copy completed. If we do tracing after enter_rename_mode, then rename mode won't consistently work
trace.UpdateState(true);
Trace::EventCopyTemplate(target_final_fullpath.extension().c_str());
Trace::EventCopyTemplateResult(hr);
trace.Flush();
trace.UpdateState(false);
@@ -392,13 +394,12 @@ namespace newplus::utilities
Logger::error(ex.what());
hr = S_FALSE;
trace.UpdateState(true);
Trace::EventCopyTemplateResult(hr);
trace.Flush();
trace.UpdateState(false);
}
trace.UpdateState(true);
Trace::EventCopyTemplateResult(hr);
trace.Flush();
trace.UpdateState(false);
return hr;
}

View File

@@ -3,9 +3,6 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using Workspaces.Data;
using static WorkspacesEditor.Data.ProjectData;
namespace WorkspacesEditor.Data

View File

@@ -8,13 +8,7 @@ namespace WorkspacesEditor.Data
{
public class TempProjectData : ProjectData
{
public static string File
{
get
{
return FolderUtils.DataFolder() + "\\temp-workspaces.json";
}
}
public static string File => FolderUtils.DataFolder() + "\\temp-workspaces.json";
public static void DeleteTempFile()
{

View File

@@ -3,8 +3,6 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using Workspaces.Data;
using WorkspacesEditor.Utils;
using static WorkspacesEditor.Data.ProjectData;
@@ -14,13 +12,7 @@ namespace WorkspacesEditor.Data
{
public class WorkspacesData : WorkspacesEditorData<WorkspacesListWrapper>
{
public string File
{
get
{
return FolderUtils.DataFolder() + "\\workspaces.json";
}
}
public string File => FolderUtils.DataFolder() + "\\workspaces.json";
public struct WorkspacesListWrapper
{

View File

@@ -3,28 +3,24 @@
// See the LICENSE file in the project root for more information.
using System.Text.Json;
using WorkspacesEditor.Utils;
namespace Workspaces.Data
namespace WorkspacesEditor.Data
{
public class WorkspacesEditorData<T>
{
protected JsonSerializerOptions JsonOptions
{
get
get => new()
{
return new JsonSerializerOptions
{
PropertyNamingPolicy = new DashCaseNamingPolicy(),
WriteIndented = true,
};
}
PropertyNamingPolicy = new DashCaseNamingPolicy(),
WriteIndented = true,
};
}
public T Read(string file)
{
IOUtils ioUtils = new IOUtils();
IOUtils ioUtils = new();
string data = ioUtils.ReadFile(file);
return JsonSerializer.Deserialize<T>(data, JsonOptions);
}

View File

@@ -8,7 +8,7 @@
xmlns:ui="http://schemas.modernwpf.com/2019"
x:Name="WorkspacesMainWindow"
Title="{x:Static props:Resources.MainTitle}"
MinWidth="700"
MinWidth="750"
MinHeight="680"
ui:TitleBar.Background="{DynamicResource PrimaryBackgroundBrush}"
ui:TitleBar.InactiveBackground="{DynamicResource TertiaryBackgroundBrush}"

View File

@@ -18,14 +18,7 @@ namespace WorkspacesEditor.Models
public override System.Windows.DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)
{
if (item is MonitorHeaderRow)
{
return HeaderTemplate;
}
else
{
return AppTemplate;
}
return item is MonitorHeaderRow ? HeaderTemplate : AppTemplate;
}
}
}

View File

@@ -1,25 +1,22 @@
// Copyright (c) Microsoft Corporation
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Windows.Media.Imaging;
using ManagedCommon;
using Windows.Management.Deployment;
using WorkspacesCsharpLibrary;
using WorkspacesCsharpLibrary.Models;
namespace WorkspacesEditor.Models
{
public enum WindowPositionKind
{
Custom = 0,
Maximized = 1,
Minimized = 2,
}
public class Application : BaseApplication, IDisposable
{
private bool _isInitialized;
@@ -79,7 +76,7 @@ namespace WorkspacesEditor.Models
return left.X != right.X || left.Y != right.Y || left.Width != right.Width || left.Height != right.Height;
}
public override bool Equals(object obj)
public override readonly bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
{
@@ -90,7 +87,7 @@ namespace WorkspacesEditor.Models
return X == pos.X && Y == pos.Y && Width == pos.Width && Height == pos.Height;
}
public override int GetHashCode()
public override readonly int GetHashCode()
{
return base.GetHashCode();
}
@@ -136,36 +133,24 @@ namespace WorkspacesEditor.Models
}
}
private bool _minimized;
public bool Minimized { get; set; }
public bool Minimized
public bool Maximized { get; set; }
public bool EditPositionEnabled => !Minimized && !Maximized;
public int PositionComboboxIndex
{
get => _minimized;
get => Maximized ? (int)WindowPositionKind.Maximized : Minimized ? (int)WindowPositionKind.Minimized : (int)WindowPositionKind.Custom;
set
{
_minimized = value;
OnPropertyChanged(new PropertyChangedEventArgs(nameof(Minimized)));
Maximized = value == (int)WindowPositionKind.Maximized;
Minimized = value == (int)WindowPositionKind.Minimized;
OnPropertyChanged(new PropertyChangedEventArgs(nameof(EditPositionEnabled)));
RedrawPreviewImage();
}
}
private bool _maximized;
public bool Maximized
{
get => _maximized;
set
{
_maximized = value;
OnPropertyChanged(new PropertyChangedEventArgs(nameof(Maximized)));
OnPropertyChanged(new PropertyChangedEventArgs(nameof(EditPositionEnabled)));
RedrawPreviewImage();
}
}
public bool EditPositionEnabled { get => !Minimized && !Maximized; }
private string _appMainParams;
public string AppMainParams
@@ -183,7 +168,7 @@ namespace WorkspacesEditor.Models
}
}
public bool IsAppMainParamVisible { get => !string.IsNullOrWhiteSpace(_appMainParams); }
public bool IsAppMainParamVisible => !string.IsNullOrWhiteSpace(_appMainParams);
[JsonIgnore]
public bool IsHighlighted { get; set; }
@@ -192,13 +177,7 @@ namespace WorkspacesEditor.Models
public int RepeatIndex { get; set; }
[JsonIgnore]
public string RepeatIndexString
{
get
{
return RepeatIndex <= 1 ? string.Empty : RepeatIndex.ToString(CultureInfo.InvariantCulture);
}
}
public string RepeatIndexString => RepeatIndex <= 1 ? string.Empty : RepeatIndex.ToString(CultureInfo.InvariantCulture);
private WindowPosition _position;
@@ -242,10 +221,7 @@ namespace WorkspacesEditor.Models
{
get
{
if (_monitorSetup == null)
{
_monitorSetup = Parent.GetMonitorForApp(this);
}
_monitorSetup ??= Parent.GetMonitorForApp(this);
return _monitorSetup;
}
@@ -271,7 +247,7 @@ namespace WorkspacesEditor.Models
}
}
public string DeleteButtonContent { get => _isIncluded ? Properties.Resources.Delete : Properties.Resources.AddBack; }
public string DeleteButtonContent => _isIncluded ? Properties.Resources.Delete : Properties.Resources.AddBack;
private bool _isIncluded = true;
@@ -298,15 +274,5 @@ namespace WorkspacesEditor.Models
CommandLineArguments = newCommandLineValue;
OnPropertyChanged(new PropertyChangedEventArgs(nameof(AppMainParams)));
}
internal void MaximizedChecked()
{
Minimized = false;
}
internal void MinimizedChecked()
{
Maximized = false;
}
}
}

View File

@@ -6,28 +6,18 @@ using System.Windows;
namespace WorkspacesEditor.Models
{
public class Monitor
public class Monitor(string monitorName, string monitorInstanceId, int number, int dpi, Rect dpiAwareBounds, Rect dpiUnawareBounds)
{
public string MonitorName { get; private set; }
public string MonitorName { get; private set; } = monitorName;
public string MonitorInstanceId { get; private set; }
public string MonitorInstanceId { get; private set; } = monitorInstanceId;
public int MonitorNumber { get; private set; }
public int MonitorNumber { get; private set; } = number;
public int Dpi { get; private set; }
public int Dpi { get; private set; } = dpi;
public Rect MonitorDpiUnawareBounds { get; private set; }
public Rect MonitorDpiUnawareBounds { get; private set; } = dpiUnawareBounds;
public Rect MonitorDpiAwareBounds { get; private set; }
public Monitor(string monitorName, string monitorInstanceId, int number, int dpi, Rect dpiAwareBounds, Rect dpiUnawareBounds)
{
MonitorName = monitorName;
MonitorInstanceId = monitorInstanceId;
MonitorNumber = number;
Dpi = dpi;
MonitorDpiAwareBounds = dpiAwareBounds;
MonitorDpiUnawareBounds = dpiUnawareBounds;
}
public Rect MonitorDpiAwareBounds { get; private set; } = dpiAwareBounds;
}
}

View File

@@ -16,9 +16,9 @@ namespace WorkspacesEditor.Models
PropertyChanged?.Invoke(this, e);
}
public string MonitorInfo { get => MonitorName; }
public string MonitorInfo => MonitorName;
public string MonitorInfoWithResolution { get => $"{MonitorName} {MonitorDpiAwareBounds.Width}x{MonitorDpiAwareBounds.Height}"; }
public string MonitorInfoWithResolution => $"{MonitorName} {MonitorDpiAwareBounds.Width}x{MonitorDpiAwareBounds.Height}";
public MonitorSetup(string monitorName, string monitorInstanceId, int number, int dpi, Rect dpiAwareBounds, Rect dpiUnawareBounds)
: base(monitorName, monitorInstanceId, number, dpi, dpiAwareBounds, dpiUnawareBounds)

View File

@@ -29,10 +29,7 @@ namespace WorkspacesEditor.Models
public string Name
{
get
{
return _name;
}
get => _name;
set
{
@@ -68,8 +65,7 @@ namespace WorkspacesEditor.Models
DateTime lastLaunchDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(LastLaunchedTime);
var now = DateTime.UtcNow.Ticks;
var ts = DateTime.UtcNow - lastLaunchDateTime;
TimeSpan ts = DateTime.UtcNow - lastLaunchDateTime;
double delta = Math.Abs(ts.TotalSeconds);
if (delta < 1 * MINUTE)
@@ -120,10 +116,7 @@ namespace WorkspacesEditor.Models
}
}
public bool CanBeSaved
{
get => Name.Length > 0 && Applications.Count > 0;
}
public bool CanBeSaved => Name.Length > 0 && Applications.Count > 0;
private bool _isRevertEnabled;
@@ -145,10 +138,7 @@ namespace WorkspacesEditor.Models
[JsonIgnore]
public bool IsPopupVisible
{
get
{
return _isPopupVisible;
}
get => _isPopupVisible;
set
{
@@ -163,11 +153,11 @@ namespace WorkspacesEditor.Models
{
get
{
List<object> applicationsListed = new List<object>();
List<object> applicationsListed = [];
ILookup<MonitorSetup, Application> apps = Applications.Where(x => !x.Minimized).ToLookup(x => x.MonitorSetup);
foreach (var appItem in apps.OrderBy(x => x.Key.MonitorDpiUnawareBounds.Left).ThenBy(x => x.Key.MonitorDpiUnawareBounds.Top))
foreach (IGrouping<MonitorSetup, Application> appItem in apps.OrderBy(x => x.Key.MonitorDpiUnawareBounds.Left).ThenBy(x => x.Key.MonitorDpiUnawareBounds.Top))
{
MonitorHeaderRow headerRow = new MonitorHeaderRow { MonitorName = "Screen " + appItem.Key.MonitorNumber, SelectString = Properties.Resources.SelectAllAppsOnMonitor + " " + appItem.Key.MonitorInfo };
MonitorHeaderRow headerRow = new() { MonitorName = "Screen " + appItem.Key.MonitorNumber, SelectString = Properties.Resources.SelectAllAppsOnMonitor + " " + appItem.Key.MonitorInfo };
applicationsListed.Add(headerRow);
foreach (Application app in appItem)
{
@@ -175,10 +165,10 @@ namespace WorkspacesEditor.Models
}
}
var minimizedApps = Applications.Where(x => x.Minimized);
IEnumerable<Application> minimizedApps = Applications.Where(x => x.Minimized);
if (minimizedApps.Any())
{
MonitorHeaderRow headerRow = new MonitorHeaderRow { MonitorName = Properties.Resources.Minimized_Apps, SelectString = Properties.Resources.SelectAllMinimizedApps };
MonitorHeaderRow headerRow = new() { MonitorName = Properties.Resources.Minimized_Apps, SelectString = Properties.Resources.SelectAllMinimizedApps };
applicationsListed.Add(headerRow);
foreach (Application app in minimizedApps)
{
@@ -219,17 +209,17 @@ namespace WorkspacesEditor.Models
int screenIndex = 1;
Monitors = new List<MonitorSetup>();
foreach (var item in selectedProject.Monitors.OrderBy(x => x.MonitorDpiAwareBounds.Left).ThenBy(x => x.MonitorDpiAwareBounds.Top))
Monitors = [];
foreach (MonitorSetup item in selectedProject.Monitors.OrderBy(x => x.MonitorDpiAwareBounds.Left).ThenBy(x => x.MonitorDpiAwareBounds.Top))
{
Monitors.Add(item);
screenIndex++;
}
Applications = new List<Application>();
foreach (var item in selectedProject.Applications)
Applications = [];
foreach (Application item in selectedProject.Applications)
{
Application newApp = new Application(item);
Application newApp = new(item);
newApp.Parent = this;
newApp.InitializationFinished();
Applications.Add(newApp);
@@ -244,14 +234,14 @@ namespace WorkspacesEditor.Models
LastLaunchedTime = project.LastLaunchedTime;
IsShortcutNeeded = project.IsShortcutNeeded;
MoveExistingWindows = project.MoveExistingWindows;
Monitors = new List<MonitorSetup>() { };
Applications = new List<Models.Application> { };
Monitors = [];
Applications = [];
foreach (var app in project.Applications)
foreach (ProjectData.ApplicationWrapper app in project.Applications)
{
Models.Application newApp = new Models.Application()
Models.Application newApp = new()
{
Id = string.IsNullOrEmpty(app.Id) ? $"{{{Guid.NewGuid().ToString()}}}" : app.Id,
Id = string.IsNullOrEmpty(app.Id) ? $"{{{Guid.NewGuid()}}}" : app.Id,
AppName = app.Application,
AppPath = app.ApplicationPath,
AppTitle = app.Title,
@@ -278,20 +268,17 @@ namespace WorkspacesEditor.Models
Applications.Add(newApp);
}
foreach (var monitor in project.MonitorConfiguration)
foreach (ProjectData.MonitorConfigurationWrapper monitor in project.MonitorConfiguration)
{
System.Windows.Rect dpiAware = new System.Windows.Rect(monitor.MonitorRectDpiAware.Left, monitor.MonitorRectDpiAware.Top, monitor.MonitorRectDpiAware.Width, monitor.MonitorRectDpiAware.Height);
System.Windows.Rect dpiUnaware = new System.Windows.Rect(monitor.MonitorRectDpiUnaware.Left, monitor.MonitorRectDpiUnaware.Top, monitor.MonitorRectDpiUnaware.Width, monitor.MonitorRectDpiUnaware.Height);
System.Windows.Rect dpiAware = new(monitor.MonitorRectDpiAware.Left, monitor.MonitorRectDpiAware.Top, monitor.MonitorRectDpiAware.Width, monitor.MonitorRectDpiAware.Height);
System.Windows.Rect dpiUnaware = new(monitor.MonitorRectDpiUnaware.Left, monitor.MonitorRectDpiUnaware.Top, monitor.MonitorRectDpiUnaware.Width, monitor.MonitorRectDpiUnaware.Height);
Monitors.Add(new MonitorSetup(monitor.Id, monitor.InstanceId, monitor.MonitorNumber, monitor.Dpi, dpiAware, dpiUnaware));
}
}
public BitmapImage PreviewIcons
{
get
{
return _previewIcons;
}
get => _previewIcons;
set
{
@@ -302,10 +289,7 @@ namespace WorkspacesEditor.Models
public BitmapImage PreviewImage
{
get
{
return _previewImage;
}
get => _previewImage;
set
{
@@ -316,10 +300,7 @@ namespace WorkspacesEditor.Models
public double PreviewImageWidth
{
get
{
return _previewImageWidth;
}
get => _previewImageWidth;
set
{
@@ -366,6 +347,7 @@ namespace WorkspacesEditor.Models
Id = other.Id;
Name = other.Name;
IsRevertEnabled = true;
MoveExistingWindows = other.MoveExistingWindows;
}
internal void CloseExpanders()
@@ -378,13 +360,13 @@ namespace WorkspacesEditor.Models
internal MonitorSetup GetMonitorForApp(Application app)
{
var monitorSetup = Monitors.Where(x => x.MonitorNumber == app.MonitorNumber).FirstOrDefault();
MonitorSetup monitorSetup = Monitors.Where(x => x.MonitorNumber == app.MonitorNumber).FirstOrDefault();
if (monitorSetup == null)
{
// monitors changed: try to determine monitor id based on middle point
int middleX = app.Position.X + (app.Position.Width / 2);
int middleY = app.Position.Y + (app.Position.Height / 2);
var monitorCandidate = Monitors.Where(x =>
MonitorSetup monitorCandidate = Monitors.Where(x =>
(x.MonitorDpiUnawareBounds.Left < middleX) &&
(x.MonitorDpiUnawareBounds.Right > middleX) &&
(x.MonitorDpiUnawareBounds.Top < middleY) &&

View File

@@ -61,7 +61,7 @@ namespace WorkspacesEditor.Properties {
}
/// <summary>
/// Looks up a localized string similar to Add Back.
/// Looks up a localized string similar to Add back.
/// </summary>
public static string AddBack {
get {
@@ -78,15 +78,6 @@ namespace WorkspacesEditor.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Launch new app instances.
/// </summary>
public static string AlwaysLaunch {
get {
return ResourceManager.GetString("AlwaysLaunch", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to app.
/// </summary>
@@ -169,7 +160,7 @@ namespace WorkspacesEditor.Properties {
}
/// <summary>
/// Looks up a localized string similar to Create Desktop Shortcut.
/// Looks up a localized string similar to Create desktop shortcut.
/// </summary>
public static string CreateShortcut {
get {
@@ -186,6 +177,15 @@ namespace WorkspacesEditor.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Custom.
/// </summary>
public static string Custom {
get {
return ResourceManager.GetString("Custom", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to days ago.
/// </summary>
@@ -223,7 +223,7 @@ namespace WorkspacesEditor.Properties {
}
/// <summary>
/// Looks up a localized string similar to Remove Selected Apps.
/// Looks up a localized string similar to Remove selected apps.
/// </summary>
public static string DeleteSelected {
get {
@@ -322,7 +322,7 @@ namespace WorkspacesEditor.Properties {
}
/// <summary>
/// Looks up a localized string similar to Launch &amp; Edit.
/// Looks up a localized string similar to Launch &amp; edit.
/// </summary>
public static string LaunchEdit {
get {
@@ -367,7 +367,7 @@ namespace WorkspacesEditor.Properties {
}
/// <summary>
/// Looks up a localized string similar to Minimized Apps.
/// Looks up a localized string similar to Minimized apps.
/// </summary>
public static string Minimized_Apps {
get {
@@ -394,7 +394,7 @@ namespace WorkspacesEditor.Properties {
}
/// <summary>
/// Looks up a localized string similar to Move apps if present.
/// Looks up a localized string similar to Move existing windows.
/// </summary>
public static string MoveIfExist {
get {
@@ -502,7 +502,7 @@ namespace WorkspacesEditor.Properties {
}
/// <summary>
/// Looks up a localized string similar to Pin Workspaces to Taskbar.
/// Looks up a localized string similar to Pin Workspaces to taskbar.
/// </summary>
public static string PinToTaskbar {
get {
@@ -565,7 +565,7 @@ namespace WorkspacesEditor.Properties {
}
/// <summary>
/// Looks up a localized string similar to Select All Apps on.
/// Looks up a localized string similar to Select all apps on.
/// </summary>
public static string SelectAllAppsOnMonitor {
get {
@@ -574,7 +574,7 @@ namespace WorkspacesEditor.Properties {
}
/// <summary>
/// Looks up a localized string similar to Select All Minimized Apps.
/// Looks up a localized string similar to Select all minimized apps.
/// </summary>
public static string SelectAllMinimizedApps {
get {
@@ -583,7 +583,7 @@ namespace WorkspacesEditor.Properties {
}
/// <summary>
/// Looks up a localized string similar to Select All Apps in Workspace.
/// Looks up a localized string similar to Select all apps in Workspace.
/// </summary>
public static string SelectedAllInWorkspace {
get {
@@ -645,6 +645,15 @@ namespace WorkspacesEditor.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Window position.
/// </summary>
public static string WindowPosition {
get {
return ResourceManager.GetString("WindowPosition", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Workspace name.
/// </summary>

View File

@@ -123,9 +123,6 @@
<data name="Admin" xml:space="preserve">
<value>Admin</value>
</data>
<data name="AlwaysLaunch" xml:space="preserve">
<value>Launch new app instances</value>
</data>
<data name="App" xml:space="preserve">
<value>app</value>
</data>
@@ -160,6 +157,9 @@
<data name="CreateShortcut" xml:space="preserve">
<value>Create desktop shortcut</value>
</data>
<data name="Custom" xml:space="preserve">
<value>Custom</value>
</data>
<data name="DaysAgo" xml:space="preserve">
<value>days ago</value>
</data>
@@ -231,7 +231,7 @@
<value>months ago</value>
</data>
<data name="MoveIfExist" xml:space="preserve">
<value>Move apps if present</value>
<value>Move existing windows</value>
</data>
<data name="Name" xml:space="preserve">
<value>Name</value>
@@ -321,6 +321,9 @@
<data name="Width" xml:space="preserve">
<value>Width</value>
</data>
<data name="WindowPosition" xml:space="preserve">
<value>Window position</value>
</data>
<data name="WriteArgs" xml:space="preserve">
<value>Write arguments here</value>
</data>

View File

@@ -20,21 +20,21 @@ namespace WorkspacesEditor.Utils
{
public class DrawHelper
{
private static Font font = new("Tahoma", 24);
private static double scale = 0.1;
private static readonly Font Font = new("Tahoma", 24);
private static readonly double Scale = 0.1;
private static double gapWidth;
private static double gapHeight;
public static BitmapImage DrawPreview(Project project, Rectangle bounds, Theme currentTheme)
{
List<double> horizontalGaps = new List<double>();
List<double> verticalGaps = new List<double>();
List<double> horizontalGaps = [];
List<double> verticalGaps = [];
gapWidth = bounds.Width * 0.01;
gapHeight = bounds.Height * 0.01;
int Scaled(double value)
{
return (int)(value * scale);
return (int)(value * Scale);
}
int TransformX(double posX)
@@ -54,7 +54,7 @@ namespace WorkspacesEditor.Utils
if (app.Maximized)
{
Project project = app.Parent;
var monitor = project.GetMonitorForApp(app);
MonitorSetup monitor = project.GetMonitorForApp(app);
if (monitor == null)
{
// unrealistic case, there are no monitors at all in the workspace, use original rect
@@ -69,22 +69,23 @@ namespace WorkspacesEditor.Utils
}
}
Dictionary<string, int> repeatCounter = new Dictionary<string, int>();
Dictionary<string, int> repeatCounter = [];
var appsIncluded = project.Applications.Where(x => x.IsIncluded);
IEnumerable<Application> appsIncluded = project.Applications.Where(x => x.IsIncluded);
foreach (Application app in appsIncluded)
{
if (repeatCounter.TryGetValue(app.AppPath + app.AppTitle, out int value))
string appIdentifier = app.AppPath + app.PwaAppId;
if (repeatCounter.TryGetValue(appIdentifier, out int value))
{
repeatCounter[app.AppPath + app.AppTitle] = ++value;
repeatCounter[appIdentifier] = ++value;
}
else
{
repeatCounter.Add(app.AppPath + app.AppTitle, 1);
repeatCounter.Add(appIdentifier, 1);
}
app.RepeatIndex = repeatCounter[app.AppPath + app.AppTitle];
app.RepeatIndex = repeatCounter[appIdentifier];
}
foreach (Application app in project.Applications.Where(x => !x.IsIncluded))
@@ -113,7 +114,7 @@ namespace WorkspacesEditor.Utils
}
}
Bitmap previewBitmap = new Bitmap(Scaled(bounds.Width + (verticalGaps.Count * gapWidth)), Scaled((bounds.Height * 1.2) + (horizontalGaps.Count * gapHeight)));
Bitmap previewBitmap = new(Scaled(bounds.Width + (verticalGaps.Count * gapWidth)), Scaled((bounds.Height * 1.2) + (horizontalGaps.Count * gapHeight)));
double desiredIconSize = Scaled(Math.Min(bounds.Width, bounds.Height)) * 0.25;
using (Graphics g = Graphics.FromImage(previewBitmap))
{
@@ -131,7 +132,7 @@ namespace WorkspacesEditor.Utils
g.FillRectangle(monitorBrush, new Rectangle(TransformX(monitor.MonitorDpiAwareBounds.Left), TransformY(monitor.MonitorDpiAwareBounds.Top), Scaled(monitor.MonitorDpiAwareBounds.Width), Scaled(monitor.MonitorDpiAwareBounds.Height)));
}
var appsToDraw = appsIncluded.Where(x => !x.Minimized);
IEnumerable<Application> appsToDraw = appsIncluded.Where(x => !x.Minimized);
// draw the highlighted app at the end to have its icon in the foreground for the case there are overlapping icons
foreach (Application app in appsToDraw.Where(x => !x.IsHighlighted))
@@ -147,24 +148,22 @@ namespace WorkspacesEditor.Utils
}
// draw the minimized windows
Rectangle rectMinimized = new Rectangle(0, Scaled((bounds.Height * 1.02) + (horizontalGaps.Count * gapHeight)), Scaled(bounds.Width + (verticalGaps.Count * gapWidth)), Scaled(bounds.Height * 0.18));
Rectangle rectMinimized = new(0, Scaled((bounds.Height * 1.02) + (horizontalGaps.Count * gapHeight)), Scaled(bounds.Width + (verticalGaps.Count * gapWidth)), Scaled(bounds.Height * 0.18));
DrawWindow(g, brush, brushForHighlight, rectMinimized, appsIncluded.Where(x => x.Minimized), currentTheme);
}
using (var memory = new MemoryStream())
{
previewBitmap.Save(memory, ImageFormat.Png);
memory.Position = 0;
using MemoryStream memory = new();
previewBitmap.Save(memory, ImageFormat.Png);
memory.Position = 0;
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
bitmapImage.Freeze();
BitmapImage bitmapImage = new();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
bitmapImage.Freeze();
return bitmapImage;
}
return bitmapImage;
}
public static void DrawWindow(Graphics graphics, Brush brush, Rectangle bounds, Application app, double desiredIconSize, Theme currentTheme)
@@ -194,7 +193,7 @@ namespace WorkspacesEditor.Utils
}
double iconSize = Math.Min(Math.Min(bounds.Width - 4, bounds.Height - 4), desiredIconSize);
Rectangle iconBounds = new Rectangle((int)(bounds.Left + (bounds.Width / 2) - (iconSize / 2)), (int)(bounds.Top + (bounds.Height / 2) - (iconSize / 2)), (int)iconSize, (int)iconSize);
Rectangle iconBounds = new((int)(bounds.Left + (bounds.Width / 2) - (iconSize / 2)), (int)(bounds.Top + (bounds.Height / 2) - (iconSize / 2)), (int)iconSize, (int)iconSize);
try
{
@@ -203,13 +202,13 @@ namespace WorkspacesEditor.Utils
{
string indexString = app.RepeatIndex.ToString(CultureInfo.InvariantCulture);
int indexSize = (int)(iconBounds.Width * 0.5);
Rectangle indexBounds = new Rectangle(iconBounds.Right - indexSize, iconBounds.Bottom - indexSize, indexSize, indexSize);
Rectangle indexBounds = new(iconBounds.Right - indexSize, iconBounds.Bottom - indexSize, indexSize, indexSize);
var textSize = graphics.MeasureString(indexString, font);
var state = graphics.Save();
SizeF textSize = graphics.MeasureString(indexString, Font);
GraphicsState state = graphics.Save();
graphics.TranslateTransform(indexBounds.Left, indexBounds.Top);
graphics.ScaleTransform(indexBounds.Width / textSize.Width, indexBounds.Height / textSize.Height);
graphics.DrawString(indexString, font, Brushes.Black, PointF.Empty);
graphics.DrawString(indexString, Font, Brushes.Black, PointF.Empty);
graphics.Restore(state);
}
}
@@ -255,7 +254,7 @@ namespace WorkspacesEditor.Utils
for (int iconCounter = 0; iconCounter < appsCount; iconCounter++)
{
Application app = apps.ElementAt(iconCounter);
Rectangle iconBounds = new Rectangle((int)(bounds.Left + (bounds.Width / 2) - (iconSize * ((appsCount / 2) - iconCounter))), (int)(bounds.Top + (bounds.Height / 2) - (iconSize / 2)), (int)iconSize, (int)iconSize);
Rectangle iconBounds = new((int)(bounds.Left + (bounds.Width / 2) - (iconSize * ((appsCount / 2) - iconCounter))), (int)(bounds.Top + (bounds.Height / 2) - (iconSize / 2)), (int)iconSize, (int)iconSize);
try
{
@@ -264,13 +263,13 @@ namespace WorkspacesEditor.Utils
{
string indexString = app.RepeatIndex.ToString(CultureInfo.InvariantCulture);
int indexSize = (int)(iconBounds.Width * 0.5);
Rectangle indexBounds = new Rectangle(iconBounds.Right - indexSize, iconBounds.Bottom - indexSize, indexSize, indexSize);
Rectangle indexBounds = new(iconBounds.Right - indexSize, iconBounds.Bottom - indexSize, indexSize, indexSize);
var textSize = graphics.MeasureString(indexString, font);
var state = graphics.Save();
SizeF textSize = graphics.MeasureString(indexString, Font);
GraphicsState state = graphics.Save();
graphics.TranslateTransform(indexBounds.Left, indexBounds.Top);
graphics.ScaleTransform(indexBounds.Width / textSize.Width, indexBounds.Height / textSize.Height);
graphics.DrawString(indexString, font, Brushes.Black, PointF.Empty);
graphics.DrawString(indexString, Font, Brushes.Black, PointF.Empty);
graphics.Restore(state);
}
}
@@ -289,14 +288,14 @@ namespace WorkspacesEditor.Utils
return null;
}
Bitmap previewBitmap = new Bitmap(32 * appsCount, 24);
Bitmap previewBitmap = new(32 * appsCount, 24);
using (Graphics graphics = Graphics.FromImage(previewBitmap))
{
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
int appIndex = 0;
foreach (var app in project.Applications)
foreach (Application app in project.Applications)
{
try
{
@@ -311,20 +310,18 @@ namespace WorkspacesEditor.Utils
}
}
using (var memory = new MemoryStream())
{
previewBitmap.Save(memory, ImageFormat.Png);
memory.Position = 0;
using MemoryStream memory = new();
previewBitmap.Save(memory, ImageFormat.Png);
memory.Position = 0;
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
bitmapImage.Freeze();
BitmapImage bitmapImage = new();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
bitmapImage.Freeze();
return bitmapImage;
}
return bitmapImage;
}
private static GraphicsPath RoundedRect(Rectangle bounds)
@@ -333,9 +330,9 @@ namespace WorkspacesEditor.Utils
int radius = (int)(minorSize / 8);
int diameter = radius * 2;
Size size = new Size(diameter, diameter);
Rectangle arc = new Rectangle(bounds.Location, size);
GraphicsPath path = new GraphicsPath();
Size size = new(diameter, diameter);
Rectangle arc = new(bounds.Location, size);
GraphicsPath path = new();
if (radius == 0)
{

View File

@@ -26,18 +26,16 @@ namespace WorkspacesEditor.Utils
{
if (_fileSystem.File.Exists(fileName))
{
var attempts = 0;
int attempts = 0;
while (attempts < 10)
{
try
{
using (FileSystemStream inputStream = _fileSystem.File.Open(fileName, FileMode.Open))
using (StreamReader reader = new StreamReader(inputStream))
{
string data = reader.ReadToEnd();
inputStream.Close();
return data;
}
using FileSystemStream inputStream = _fileSystem.File.Open(fileName, FileMode.Open);
using StreamReader reader = new(inputStream);
string data = reader.ReadToEnd();
inputStream.Close();
return data;
}
catch (Exception)
{

View File

@@ -26,7 +26,7 @@ namespace WorkspacesEditor.Utils
private Screen[] GetDpiUnawareScreenBounds()
{
Thread dpiUnawareThread = new Thread(new ThreadStart(SaveDpiUnawareScreens));
Thread dpiUnawareThread = new(new ThreadStart(SaveDpiUnawareScreens));
dpiUnawareThread.Start();
dpiUnawareThread.Join();
@@ -35,15 +35,15 @@ namespace WorkspacesEditor.Utils
public static Screen[] GetDpiUnawareScreens()
{
MonitorHelper monitorHelper = new MonitorHelper();
MonitorHelper monitorHelper = new();
return monitorHelper.GetDpiUnawareScreenBounds();
}
internal static double GetScreenDpiFromScreen(Screen screen)
{
var point = new System.Drawing.Point(screen.Bounds.Left + 1, screen.Bounds.Top + 1);
var monitor = NativeMethods.MonitorFromPoint(point, NativeMethods._MONITOR_DEFAULTTONEAREST);
NativeMethods.GetDpiForMonitor(monitor, NativeMethods.DpiType.EFFECTIVE, out uint dpiX, out uint dpiY);
System.Drawing.Point point = new(screen.Bounds.Left + 1, screen.Bounds.Top + 1);
nint monitor = NativeMethods.MonitorFromPoint(point, NativeMethods._MONITOR_DEFAULTTONEAREST);
_ = NativeMethods.GetDpiForMonitor(monitor, NativeMethods.DpiType.EFFECTIVE, out uint dpiX, out _);
return dpiX / 96.0;
}
}

View File

@@ -4,19 +4,12 @@
namespace WorkspacesEditor.Utils
{
public struct ParsingResult
public readonly struct ParsingResult(bool result, string message = "", string data = "")
{
public bool Result { get; }
public bool Result { get; } = result;
public string Message { get; }
public string Message { get; } = message;
public string MalformedData { get; }
public ParsingResult(bool result, string message = "", string data = "")
{
Result = result;
Message = message;
MalformedData = data;
}
public string MalformedData { get; } = data;
}
}

View File

@@ -9,13 +9,13 @@ namespace WorkspacesEditor.Utils
public class Settings
{
private const string WorkspacesModuleName = "Workspaces";
private static SettingsUtils _settingsUtils = new SettingsUtils();
private static readonly SettingsUtils _settingsUtils = new();
public static WorkspacesSettings ReadSettings()
{
if (!_settingsUtils.SettingsExists(WorkspacesModuleName))
{
var defaultWorkspacesSettings = new WorkspacesSettings();
WorkspacesSettings defaultWorkspacesSettings = new();
defaultWorkspacesSettings.Save(_settingsUtils);
return defaultWorkspacesSettings;
}

View File

@@ -11,12 +11,9 @@ namespace WorkspacesEditor.Utils
public static string UpperCamelCaseToDashCase(this string str)
{
// If it's single letter variable, leave it as it is
if (str.Length == 1)
{
return str;
}
return string.Concat(str.Select((x, i) => i > 0 && char.IsUpper(x) ? "-" + x.ToString() : x.ToString())).ToLowerInvariant();
return str.Length == 1
? str
: string.Concat(str.Select((x, i) => i > 0 && char.IsUpper(x) ? "-" + x.ToString() : x.ToString())).ToLowerInvariant();
}
}
}

View File

@@ -24,7 +24,7 @@ namespace WorkspacesEditor.Utils
{
try
{
WorkspacesData parser = new WorkspacesData();
WorkspacesData parser = new();
if (!File.Exists(parser.File))
{
Logger.LogWarning($"Workspaces storage file not found: {parser.File}");
@@ -56,14 +56,14 @@ namespace WorkspacesEditor.Utils
{
try
{
ProjectData parser = new ProjectData();
ProjectData parser = new();
if (!File.Exists(TempProjectData.File))
{
Logger.LogWarning($"ParseProject method. Workspaces storage file not found: {TempProjectData.File}");
return null;
}
Project project = new Project(parser.Read(TempProjectData.File));
Project project = new(parser.Read(TempProjectData.File));
return project;
}
catch (Exception e)
@@ -75,13 +75,13 @@ namespace WorkspacesEditor.Utils
public void SerializeWorkspaces(List<Project> workspaces, bool useTempFile = false)
{
WorkspacesData serializer = new WorkspacesData();
WorkspacesData.WorkspacesListWrapper workspacesWrapper = new WorkspacesData.WorkspacesListWrapper { };
workspacesWrapper.Workspaces = new List<ProjectData.ProjectWrapper>();
WorkspacesData serializer = new();
WorkspacesData.WorkspacesListWrapper workspacesWrapper = new() { };
workspacesWrapper.Workspaces = [];
foreach (Project project in workspaces)
{
ProjectData.ProjectWrapper wrapper = new ProjectData.ProjectWrapper
ProjectData.ProjectWrapper wrapper = new()
{
Id = project.Id,
Name = project.Name,
@@ -89,11 +89,11 @@ namespace WorkspacesEditor.Utils
IsShortcutNeeded = project.IsShortcutNeeded,
MoveExistingWindows = project.MoveExistingWindows,
LastLaunchedTime = project.LastLaunchedTime,
Applications = new List<ProjectData.ApplicationWrapper> { },
MonitorConfiguration = new List<ProjectData.MonitorConfigurationWrapper> { },
Applications = [],
MonitorConfiguration = [],
};
foreach (var app in project.Applications.Where(x => x.IsIncluded))
foreach (Application app in project.Applications.Where(x => x.IsIncluded))
{
wrapper.Applications.Add(new ProjectData.ApplicationWrapper
{
@@ -120,7 +120,7 @@ namespace WorkspacesEditor.Utils
});
}
foreach (var monitor in project.Monitors)
foreach (MonitorSetup monitor in project.Monitors)
{
wrapper.MonitorConfiguration.Add(new ProjectData.MonitorConfigurationWrapper
{
@@ -150,7 +150,7 @@ namespace WorkspacesEditor.Utils
try
{
IOUtils ioUtils = new IOUtils();
IOUtils ioUtils = new();
ioUtils.WriteFile(useTempFile ? TempProjectData.File : serializer.File, serializer.Serialize(workspacesWrapper));
}
catch (Exception e)
@@ -162,7 +162,7 @@ namespace WorkspacesEditor.Utils
private bool AddWorkspaces(MainViewModel mainViewModel, WorkspacesData.WorkspacesListWrapper workspaces)
{
foreach (var project in workspaces.Workspaces)
foreach (ProjectData.ProjectWrapper project in workspaces.Workspaces)
{
mainViewModel.Workspaces.Add(new Project(project));
}
@@ -173,13 +173,13 @@ namespace WorkspacesEditor.Utils
private bool SetWorkspaces(MainViewModel mainViewModel, WorkspacesData.WorkspacesListWrapper workspaces)
{
mainViewModel.Workspaces = new System.Collections.ObjectModel.ObservableCollection<Project> { };
mainViewModel.Workspaces = [];
return AddWorkspaces(mainViewModel, workspaces);
}
internal void SerializeTempProject(Project project)
{
SerializeWorkspaces(new List<Project>() { project }, true);
SerializeWorkspaces([project], true);
}
}
}

View File

@@ -156,24 +156,33 @@
Content="{x:Static props:Resources.LaunchAsAdmin}"
IsChecked="{Binding IsElevated, Mode=TwoWay}"
IsEnabled="{Binding CanLaunchElevated, Mode=OneWay}" />
<CheckBox
MinWidth="10"
Margin="15,0,0,0"
Checked="MaximizedChecked"
Content="{x:Static props:Resources.Maximized}"
IsChecked="{Binding Maximized, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<CheckBox
MinWidth="10"
Margin="15,0,0,0"
Checked="MinimizedChecked"
Content="{x:Static props:Resources.Minimized}"
IsChecked="{Binding Minimized, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
<StackPanel
Grid.Row="2"
Margin="100,5,0,0"
Orientation="Horizontal">
<TextBlock
VerticalAlignment="Center"
FontSize="14"
FontWeight="Normal"
IsEnabled="{Binding EditPositionEnabled, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource TextBlockEnabledStyle}"
Text="{x:Static props:Resources.WindowPosition}" />
<ComboBox
Margin="15,0,0,0"
VerticalAlignment="Center"
Background="{DynamicResource SecondaryBackgroundBrush}"
BorderBrush="{DynamicResource PrimaryBorderBrush}"
BorderThickness="2"
FontSize="14"
FontWeight="Normal"
SelectedIndex="{Binding PositionComboboxIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ComboBoxItem Content="{x:Static props:Resources.Custom}" />
<ComboBoxItem Content="{x:Static props:Resources.Maximized}" />
<ComboBoxItem Content="{x:Static props:Resources.Minimized}" />
</ComboBox>
<TextBlock
Margin="15,0,0,0"
VerticalAlignment="Center"
FontSize="14"
FontWeight="Normal"
@@ -267,14 +276,12 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<Button
Margin="0,20,0,20"
Margin="0,10,0,20"
VerticalAlignment="Center"
Background="Transparent"
Click="CancelButtonClicked">
@@ -300,27 +307,8 @@
Foreground="{DynamicResource PrimaryForegroundBrush}"
Text="{Binding EditorWindowTitle}" />
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Vertical">
<TextBlock
FontSize="14"
FontWeight="Normal"
Foreground="{DynamicResource PrimaryForegroundBrush}"
Text="{x:Static props:Resources.WorkspaceName}" />
<TextBox
x:Name="EditNameTextBox"
Width="320"
Margin="0,6,0,6"
HorizontalAlignment="Left"
Background="{DynamicResource SecondaryBackgroundBrush}"
BorderBrush="{DynamicResource PrimaryBorderBrush}"
BorderThickness="2"
GotFocus="EditNameTextBox_GotFocus"
KeyDown="EditNameTextBoxKeyDown"
Text="{Binding Name, Mode=TwoWay}"
TextChanged="EditNameTextBox_TextChanged" />
</StackPanel>
<Border
Grid.Row="2"
Grid.Row="1"
HorizontalAlignment="Stretch"
Background="{DynamicResource MonitorViewBackgroundBrush}"
CornerRadius="5">
@@ -361,8 +349,47 @@
DockPanel.Dock="Right" />
</DockPanel>
</Border>
<DockPanel Grid.Row="2" HorizontalAlignment="Stretch">
<StackPanel Orientation="Vertical">
<TextBlock
Margin="0,10,0,0"
FontSize="14"
FontWeight="Normal"
Foreground="{DynamicResource PrimaryForegroundBrush}"
Text="{x:Static props:Resources.WorkspaceName}" />
<TextBox
x:Name="EditNameTextBox"
Width="300"
Margin="0,6,0,6"
HorizontalAlignment="Left"
Background="{DynamicResource SecondaryBackgroundBrush}"
BorderBrush="{DynamicResource PrimaryBorderBrush}"
BorderThickness="2"
GotFocus="EditNameTextBox_GotFocus"
KeyDown="EditNameTextBoxKeyDown"
Text="{Binding Name, Mode=TwoWay}"
TextChanged="EditNameTextBox_TextChanged" />
</StackPanel>
<StackPanel
HorizontalAlignment="Right"
DockPanel.Dock="Right"
Orientation="Horizontal">
<CheckBox
Margin="20,0,0,0"
VerticalAlignment="Bottom"
Content="{x:Static props:Resources.CreateShortcut}"
FontSize="14"
IsChecked="{Binding IsShortcutNeeded, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<CheckBox
Margin="20,0,0,0"
VerticalAlignment="Bottom"
Content="{x:Static props:Resources.MoveIfExist}"
FontSize="14"
IsChecked="{Binding MoveExistingWindows, Mode=TwoWay}" />
</StackPanel>
</DockPanel>
<ScrollViewer
Grid.Row="4"
Grid.Row="3"
Margin="0,10,0,0"
PreviewMouseWheel="ScrollViewer_PreviewMouseWheel"
VerticalScrollBarVisibility="Auto">
@@ -377,52 +404,31 @@
</StackPanel>
</ScrollViewer>
<StackPanel
Grid.Row="5"
Margin="0,5,0,0"
Orientation="Horizontal"
Visibility="Collapsed">
<CheckBox
Margin="0,0,0,0"
VerticalAlignment="Center"
Content="{x:Static props:Resources.MoveIfExist}"
FontSize="14"
FontWeight="Normal"
Foreground="{DynamicResource PrimaryForegroundBrush}"
IsChecked="{Binding MoveExistingWindows, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
Grid.Row="4"
Margin="40,20,0,0"
HorizontalAlignment="Right"
Orientation="Horizontal">
<Button
x:Name="CancelButton"
Height="36"
Margin="20,0,0,0"
Padding="24,0,24,0"
AutomationProperties.Name="{x:Static props:Resources.Cancel}"
Background="{DynamicResource SecondaryBackgroundBrush}"
BorderBrush="{DynamicResource PrimaryBorderBrush}"
BorderThickness="2"
Click="CancelButtonClicked"
Content="{x:Static props:Resources.Cancel}" />
<Button
x:Name="SaveButton"
Height="36"
Margin="20,0,0,0"
Padding="24,0,24,0"
AutomationProperties.Name="{x:Static props:Resources.Save_Workspace}"
Click="SaveButtonClicked"
Content="{x:Static props:Resources.Save_Workspace}"
IsEnabled="{Binding CanBeSaved, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource AccentButtonStyle}" />
</StackPanel>
<DockPanel Grid.Row="6" Margin="0,20,0,20">
<CheckBox
Content="{x:Static props:Resources.CreateShortcut}"
DockPanel.Dock="Left"
FontSize="14"
IsChecked="{Binding IsShortcutNeeded, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<StackPanel
Margin="40,0,0,0"
HorizontalAlignment="Right"
DockPanel.Dock="Right"
Orientation="Horizontal">
<Button
x:Name="CancelButton"
Height="36"
Margin="20,0,0,0"
Padding="24,0,24,0"
AutomationProperties.Name="{x:Static props:Resources.Cancel}"
Background="{DynamicResource SecondaryBackgroundBrush}"
BorderBrush="{DynamicResource PrimaryBorderBrush}"
BorderThickness="2"
Click="CancelButtonClicked"
Content="{x:Static props:Resources.Cancel}" />
<Button
x:Name="SaveButton"
Height="36"
Margin="20,0,0,0"
Padding="24,0,24,0"
AutomationProperties.Name="{x:Static props:Resources.Save_Workspace}"
Click="SaveButtonClicked"
Content="{x:Static props:Resources.Save_Workspace}"
IsEnabled="{Binding CanBeSaved, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource AccentButtonStyle}" />
</StackPanel>
</DockPanel>
</Grid>
</Page>

View File

@@ -185,20 +185,6 @@ namespace WorkspacesEditor
application.CommandLineTextChanged(textBox.Text);
}
private void MaximizedChecked(object sender, RoutedEventArgs e)
{
CheckBox checkBox = sender as CheckBox;
Models.Application application = checkBox.DataContext as Models.Application;
application.MaximizedChecked();
}
private void MinimizedChecked(object sender, RoutedEventArgs e)
{
CheckBox checkBox = sender as CheckBox;
Models.Application application = checkBox.DataContext as Models.Application;
application.MinimizedChecked();
}
private void LaunchEditButtonClicked(object sender, RoutedEventArgs e)
{
Button button = sender as Button;

View File

@@ -101,7 +101,7 @@ void Launcher::Launch() // Launching thread
const long ms = 100;
// Launch apps
for (auto appState = m_launchingStatus.GetNext(LaunchingState::Waiting); appState.has_value(); appState = m_launchingStatus.GetNext(LaunchingState::Waiting))
for (auto appState = m_launchingStatus.GetNext(LaunchingState::Waiting);appState.has_value();appState = m_launchingStatus.GetNext(LaunchingState::Waiting))
{
auto app = appState.value().application;
@@ -157,7 +157,7 @@ void Launcher::Launch() // Launching thread
{
std::lock_guard lock(m_uiHelperMutex);
m_uiHelper->UpdateLaunchStatus(m_launchingStatus.Get());
}
};
}
}

View File

@@ -31,6 +31,9 @@ namespace Utils
constexpr const wchar_t* PowerToysSettings = L"PowerToys.Settings.exe";
constexpr const wchar_t* ApplicationFrameHost = L"APPLICATIONFRAMEHOST.EXE";
constexpr const wchar_t* Exe = L".EXE";
constexpr const wchar_t* EdgeFilename = L"msedge.exe";
constexpr const wchar_t* ChromeFilename = L"chrome.exe";
}
AppList IterateAppsFolder()
@@ -214,7 +217,7 @@ namespace Utils
std::wstring appPathUpper(appPath);
std::transform(appPathUpper.begin(), appPathUpper.end(), appPathUpper.begin(), towupper);
// filter out ApplicationFrameHost.exe
// filter out ApplicationFrameHost.exe
if (appPathUpper.ends_with(NonLocalizable::ApplicationFrameHost))
{
return std::nullopt;
@@ -325,7 +328,7 @@ namespace Utils
}
}
}
return AppData{
.name = std::filesystem::path(appPath).stem(),
.installPath = appPath
@@ -335,7 +338,7 @@ namespace Utils
std::optional<AppData> GetApp(HWND window, const AppList& apps)
{
std::wstring processPath = get_process_path(window);
DWORD pid{};
GetWindowThreadProcessId(window, &pid);
@@ -378,5 +381,15 @@ namespace Utils
return updated;
}
bool AppData::IsEdge() const
{
return installPath.ends_with(NonLocalizable::EdgeFilename);
}
bool AppData::IsChrome() const
{
return installPath.ends_with(NonLocalizable::ChromeFilename);
}
}
}

View File

@@ -12,7 +12,11 @@ namespace Utils
std::wstring installPath;
std::wstring packageFullName;
std::wstring appUserModelId;
std::wstring pwaAppId;
bool canLaunchElevated = false;
bool IsEdge() const;
bool IsChrome() const;
};
using AppList = std::vector<AppData>;

View File

@@ -1,5 +1,6 @@
#include "pch.h"
#include "PwaHelper.h"
#include "AppUtils.h"
#include <ShlObj.h>
#include <tlhelp32.h>
#include <winternl.h>
@@ -11,7 +12,7 @@
#include <wil\com.h>
#pragma comment(lib, "ntdll.lib")
namespace SnapshotUtils
namespace Utils
{
namespace NonLocalizable
{
@@ -22,6 +23,7 @@ namespace SnapshotUtils
const std::wstring ChromeDirPrefix = L"_crx_";
const std::wstring EdgeDirPrefix = L"_crx__";
}
// {c8900b66-a973-584b-8cae-355b7f55341b}
DEFINE_GUID(CLSID_StartMenuCacheAndAppResolver, 0x660b90c8, 0x73a9, 0x4b58, 0x8c, 0xae, 0x35, 0x5b, 0x7f, 0x55, 0x34, 0x1b);
@@ -48,9 +50,10 @@ namespace SnapshotUtils
virtual HRESULT STDMETHODCALLTYPE GetAppIDForProcess(DWORD dwProcessId, WCHAR** pszAppId, void* pUnknown1, void* pUnknown2, void* pUnknown3) = 0;
};
BOOL GetAppId_7(HWND hWnd, std::wstring* result)
std::optional<std::wstring> PwaHelper::GetAppId_7(HWND hWnd) const
{
HRESULT hr;
std::optional<std::wstring> result = std::nullopt;
wil::com_ptr<IAppResolver_7> appResolver;
hr = CoCreateInstance(CLSID_StartMenuCacheAndAppResolver, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, IID_IAppResolver_7, reinterpret_cast<void**>(appResolver.put()));
@@ -60,19 +63,19 @@ namespace SnapshotUtils
hr = appResolver->GetAppIDForWindow(hWnd, &pszAppId, NULL, NULL, NULL);
if (SUCCEEDED(hr))
{
*result = std::wstring(pszAppId.get());
result = std::wstring(pszAppId.get());
}
appResolver->Release();
}
return SUCCEEDED(hr);
return result;
}
BOOL GetAppId_8(HWND hWnd, std::wstring* result)
std::optional<std::wstring> PwaHelper::GetAppId_8(HWND hWnd) const
{
HRESULT hr;
*result = L"";
std::optional<std::wstring> result = std::nullopt;
wil::com_ptr<IAppResolver_8> appResolver;
hr = CoCreateInstance(CLSID_StartMenuCacheAndAppResolver, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, IID_IAppResolver_8, reinterpret_cast<void**>(appResolver.put()));
@@ -82,29 +85,29 @@ namespace SnapshotUtils
hr = appResolver->GetAppIDForWindow(hWnd, &pszAppId, NULL, NULL, NULL);
if (SUCCEEDED(hr))
{
*result = std::wstring(pszAppId.get());
result = std::wstring(pszAppId.get());
}
appResolver->Release();
}
return SUCCEEDED(hr);
return result;
}
BOOL PwaHelper::GetAppId(HWND hWnd, std::wstring* result)
std::wstring PwaHelper::GetAppId(HWND hWnd) const
{
HRESULT hr = GetAppId_8(hWnd, result);
if (!SUCCEEDED(hr))
std::optional<std::wstring> result = GetAppId_8(hWnd);
if (result == std::nullopt)
{
hr = GetAppId_7(hWnd, result);
result = GetAppId_7(hWnd);
}
return SUCCEEDED(hr);
return result.has_value() ? result.value() : L"";
}
BOOL GetProcessId_7(DWORD dwProcessId, std::wstring* result)
std::optional<std::wstring> PwaHelper::GetProcessId_7(DWORD dwProcessId) const
{
HRESULT hr;
*result = L"";
std::optional<std::wstring> result = std::nullopt;
wil::com_ptr<IAppResolver_7> appResolver;
hr = CoCreateInstance(CLSID_StartMenuCacheAndAppResolver, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, IID_IAppResolver_7, reinterpret_cast<void**>(appResolver.put()));
@@ -114,19 +117,19 @@ namespace SnapshotUtils
hr = appResolver->GetAppIDForProcess(dwProcessId, &pszAppId, NULL, NULL, NULL);
if (SUCCEEDED(hr))
{
*result = std::wstring(pszAppId.get());
result = std::wstring(pszAppId.get());
}
appResolver->Release();
}
return SUCCEEDED(hr);
return result;
}
BOOL GetProcessId_8(DWORD dwProcessId, std::wstring* result)
std::optional<std::wstring> PwaHelper::GetProcessId_8(DWORD dwProcessId) const
{
HRESULT hr;
*result = L"";
std::optional<std::wstring> result = std::nullopt;
wil::com_ptr<IAppResolver_8> appResolver;
hr = CoCreateInstance(CLSID_StartMenuCacheAndAppResolver, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, IID_IAppResolver_8, reinterpret_cast<void**>(appResolver.put()));
@@ -136,23 +139,23 @@ namespace SnapshotUtils
hr = appResolver->GetAppIDForProcess(dwProcessId, &pszAppId, NULL, NULL, NULL);
if (SUCCEEDED(hr))
{
*result = std::wstring(pszAppId.get());
result = std::wstring(pszAppId.get());
}
appResolver->Release();
}
return SUCCEEDED(hr);
return result;
}
BOOL GetProcessId(DWORD dwProcessId, std::wstring* result)
std::wstring PwaHelper::GetProcessId(DWORD dwProcessId) const
{
HRESULT hr = GetProcessId_8(dwProcessId, result);
if (!SUCCEEDED(hr))
std::optional<std::wstring> result = GetProcessId_8(dwProcessId);
if (result == std::nullopt)
{
hr = GetProcessId_7(dwProcessId, result);
result = GetProcessId_7(dwProcessId);
}
return SUCCEEDED(hr);
return result.has_value() ? result.value() : L"";
}
std::wstring GetProcCommandLine(DWORD pid)
@@ -244,7 +247,7 @@ namespace SnapshotUtils
void PwaHelper::InitAumidToAppId()
{
if (pwaAumidToAppId.size() > 0)
if (m_pwaAumidToAppId.size() > 0)
{
return;
}
@@ -254,7 +257,7 @@ namespace SnapshotUtils
for (const auto subProcessID : pwaHelperProcessIds)
{
std::wstring aumidID;
GetProcessId(subProcessID, &aumidID);
aumidID = GetProcessId(subProcessID);
std::wstring commandLineArg = GetProcCommandLine(subProcessID);
auto appIdIndexStart = commandLineArg.find(NonLocalizable::EdgeAppIdIdentifier);
if (appIdIndexStart != std::wstring::npos)
@@ -267,7 +270,7 @@ namespace SnapshotUtils
}
}
std::wstring appId{ commandLineArg };
pwaAumidToAppId.insert(std::map<std::wstring, std::wstring>::value_type(aumidID, appId));
m_pwaAumidToAppId.insert(std::map<std::wstring, std::wstring>::value_type(aumidID, appId));
Logger::info(L"Found an edge Pwa helper process with AumidID {} and PwaAppId {}", aumidID, appId);
PWSTR path = NULL;
@@ -293,7 +296,7 @@ namespace SnapshotUtils
const std::filesystem::path filenameString = filename.path().filename();
if (filenameString.extension().wstring() == L".ico")
{
pwaAppIdsToAppNames.insert(std::map<std::wstring, std::wstring>::value_type(appId, filenameString.stem().wstring()));
m_pwaAppIdsToAppNames.insert(std::map<std::wstring, std::wstring>::value_type(appId, filenameString.stem().wstring()));
Logger::info(L"Storing an edge Pwa app name {} for PwaAppId {}", filenameString.stem().wstring(), appId);
}
}
@@ -307,41 +310,39 @@ namespace SnapshotUtils
}
}
BOOL PwaHelper::GetPwaAppId(std::wstring windowAumid, std::wstring* result)
std::optional<std::wstring> PwaHelper::GetPwaAppId(const std::wstring& windowAumid) const
{
const auto pwaIndex = pwaAumidToAppId.find(windowAumid);
if (pwaIndex != pwaAumidToAppId.end())
const auto pwaIndex = m_pwaAumidToAppId.find(windowAumid);
if (pwaIndex != m_pwaAumidToAppId.end())
{
*result = pwaIndex->second;
return true;
return pwaIndex->second;
}
return false;
return std::nullopt;
;
}
BOOL PwaHelper::SearchPwaName(std::wstring pwaAppId, std::wstring windowAumid, std::wstring* pwaName)
std::wstring PwaHelper::SearchPwaName(const std::wstring& pwaAppId, const std::wstring& windowAumid) const
{
const auto index = pwaAppIdsToAppNames.find(pwaAppId);
if (index != pwaAppIdsToAppNames.end())
const auto index = m_pwaAppIdsToAppNames.find(pwaAppId);
if (index != m_pwaAppIdsToAppNames.end())
{
*pwaName = index->second;
return true;
return index->second;
}
std::wstring nameFromAumid{ windowAumid };
const std::size_t delimiterPos = nameFromAumid.find(L"-");
if (delimiterPos != std::string::npos)
{
nameFromAumid = nameFromAumid.substr(0, delimiterPos);
return nameFromAumid.substr(0, delimiterPos);
}
*pwaName = nameFromAumid;
return false;
return nameFromAumid;
}
void PwaHelper::InitChromeAppIds()
{
if (chromeAppIds.size() > 0)
if (m_chromeAppIds.size() > 0)
{
return;
}
@@ -360,7 +361,7 @@ namespace SnapshotUtils
if (directoryName.wstring().find(NonLocalizable::ChromeDirPrefix) == 0)
{
const std::wstring appId = directoryName.wstring().substr(NonLocalizable::ChromeDirPrefix.size());
chromeAppIds.push_back(appId);
m_chromeAppIds.push_back(appId);
for (const auto& filename : std::filesystem::directory_iterator(directory))
{
if (!filename.is_directory())
@@ -368,7 +369,7 @@ namespace SnapshotUtils
const std::filesystem::path filenameString = filename.path().filename();
if (filenameString.extension().wstring() == L".ico")
{
pwaAppIdsToAppNames.insert(std::map<std::wstring, std::wstring>::value_type(appId, filenameString.stem().wstring()));
m_pwaAppIdsToAppNames.insert(std::map<std::wstring, std::wstring>::value_type(appId, filenameString.stem().wstring()));
Logger::info(L"Found an installed chrome Pwa app {} with PwaAppId {}", filenameString.stem().wstring(), appId);
}
}
@@ -380,30 +381,73 @@ namespace SnapshotUtils
}
}
BOOL PwaHelper::SearchPwaAppId(std::wstring windowAumid, std::wstring* pwaAppId)
std::optional<std::wstring> PwaHelper::SearchPwaAppId(const std::wstring& windowAumid) const
{
const auto appIdIndexStart = windowAumid.find(NonLocalizable::ChromeAppIdIdentifier);
if (appIdIndexStart != std::wstring::npos)
{
windowAumid = windowAumid.substr(appIdIndexStart + NonLocalizable::ChromeAppIdIdentifier.size());
const auto appIdIndexEnd = windowAumid.find(L" ");
std::wstring windowAumidSub = windowAumid.substr(appIdIndexStart + NonLocalizable::ChromeAppIdIdentifier.size());
const auto appIdIndexEnd = windowAumidSub.find(L" ");
if (appIdIndexEnd != std::wstring::npos)
{
windowAumid = windowAumid.substr(0, appIdIndexEnd);
windowAumidSub = windowAumidSub.substr(0, appIdIndexEnd);
}
const std::wstring windowAumidBegin = windowAumid.substr(0, 10);
for (const auto chromeAppId : chromeAppIds)
const std::wstring windowAumidBegin = windowAumidSub.substr(0, 10);
for (const auto chromeAppId : m_chromeAppIds)
{
if (chromeAppId.find(windowAumidBegin) == 0)
{
*pwaAppId = chromeAppId;
return true;
return chromeAppId;
}
}
}
*pwaAppId = L"";
return false;
return std::nullopt;
}
void PwaHelper::UpdatePwaApp(Utils::Apps::AppData* appData, HWND window)
{
std::optional<std::wstring> pwaAppId = std::nullopt;
std::wstring finalName = appData->name;
std::wstring pwaName = L"";
if (appData->IsEdge())
{
InitAumidToAppId();
std::wstring windowAumid = GetAppId(window);
Logger::info(L"Found an edge window with aumid {}", windowAumid);
pwaAppId = GetPwaAppId(windowAumid);
if (pwaAppId.has_value())
{
Logger::info(L"The found edge window is a PWA app with appId {}", pwaAppId.value());
pwaName = SearchPwaName(pwaAppId.value(), windowAumid);
Logger::info(L"The found edge window is a PWA app with name {}", pwaName);
finalName = pwaName + L" (" + finalName + L")";
}
else
{
Logger::info(L"The found edge window does not contain a PWA app");
}
}
else if (appData->IsChrome())
{
InitChromeAppIds();
std::wstring windowAumid = GetAppId(window);
Logger::info(L"Found a chrome window with aumid {}", windowAumid);
pwaAppId = SearchPwaAppId(windowAumid);
if (pwaAppId.has_value())
{
pwaName = SearchPwaName(pwaAppId.value(), windowAumid);
finalName = pwaName + L" (" + finalName + L")";
}
}
appData->name = finalName;
appData->pwaAppId = pwaAppId.has_value() ? pwaAppId.value() : L"";
}
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include <WorkspacesLib/AppUtils.h>
namespace Utils
{
class PwaHelper
{
public:
void UpdatePwaApp(Apps::AppData* appData, HWND window);
private:
std::map<std::wstring, std::wstring> m_pwaAumidToAppId;
std::vector<std::wstring> m_chromeAppIds;
std::map<std::wstring, std::wstring> m_pwaAppIdsToAppNames;
void InitAumidToAppId();
void InitChromeAppIds();
std::optional<std::wstring> GetAppId_7(HWND hWnd) const;
std::optional<std::wstring> GetAppId_8(HWND hWnd) const;
std::wstring GetAppId(HWND hWnd) const;
std::optional<std::wstring> GetProcessId_7(DWORD dwProcessId) const;
std::optional<std::wstring> GetProcessId_8(DWORD dwProcessId) const;
std::wstring GetProcessId(DWORD dwProcessId) const;
std::optional<std::wstring> GetPwaAppId(const std::wstring& windowAumid) const;
std::wstring SearchPwaName(const std::wstring& pwaAppId, const std::wstring& windowAumid) const;
std::optional<std::wstring> SearchPwaAppId(const std::wstring& windowAumid) const;
};
}

View File

@@ -1,6 +1,5 @@
#include "pch.h"
#include "WorkspacesData.h"
#include <common/SettingsAPI/settings_helpers.h>
#include <workspaces-common/GuidUtils.h>
@@ -157,6 +156,7 @@ namespace WorkspacesData
result.isMaximized = json.GetNamedBoolean(NonLocalizable::MaximizedID);
result.isMinimized = json.GetNamedBoolean(NonLocalizable::MinimizedID);
result.monitor = static_cast<int>(json.GetNamedNumber(NonLocalizable::MonitorID));
if (json.HasKey(NonLocalizable::PositionID))
{

View File

@@ -38,6 +38,7 @@
<ClInclude Include="LaunchingStateEnum.h" />
<ClInclude Include="LaunchingStatus.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="PwaHelper.h" />
<ClInclude Include="Result.h" />
<ClInclude Include="utils.h" />
<ClInclude Include="WorkspacesData.h" />
@@ -51,6 +52,7 @@
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(UsePrecompiledHeaders)' != 'false'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="PwaHelper.cpp" />
<ClCompile Include="two_way_pipe_message_ipc.cpp" />
<ClCompile Include="WorkspacesData.cpp" />
<ClCompile Include="trace.cpp" />
@@ -70,6 +72,7 @@
<Import Project="..\..\..\..\deps\spdlog.props" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
<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')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
@@ -77,5 +80,6 @@
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

View File

@@ -41,6 +41,9 @@
<ClInclude Include="LaunchingStatus.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="PwaHelper.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
@@ -67,6 +70,9 @@
<ClCompile Include="LaunchingStatus.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="PwaHelper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.231216.1" targetFramework="native" />
</packages>

View File

@@ -1,20 +0,0 @@
#pragma once
namespace SnapshotUtils
{
class PwaHelper
{
public:
void InitAumidToAppId();
BOOL GetAppId(HWND hWnd, std::wstring* result);
BOOL GetPwaAppId(std::wstring windowAumid, std::wstring* result);
BOOL SearchPwaName(std::wstring pwaAppId, std::wstring windowAumid, std::wstring* pwaName);
void InitChromeAppIds();
BOOL SearchPwaAppId(std::wstring windowAumid, std::wstring* pwaAppId);
private:
std::map<std::wstring, std::wstring> pwaAumidToAppId;
std::vector<std::wstring> chromeAppIds;
std::map<std::wstring, std::wstring> pwaAppIdsToAppNames;
};
}

View File

@@ -9,7 +9,7 @@
#include <workspaces-common/WindowFilter.h>
#include <WorkspacesLib/AppUtils.h>
#include <PwaHelper.h>
#include <WorkspacesLib/PwaHelper.h>
#pragma comment(lib, "ntdll.lib")
@@ -18,8 +18,6 @@ namespace SnapshotUtils
namespace NonLocalizable
{
const std::wstring ApplicationFrameHost = L"ApplicationFrameHost.exe";
const std::wstring EdgeFilename = L"msedge.exe";
const std::wstring ChromeFilename = L"chrome.exe";
}
bool IsProcessElevated(DWORD processID)
@@ -40,19 +38,9 @@ namespace SnapshotUtils
return false;
}
bool IsEdge(Utils::Apps::AppData appData)
{
return appData.installPath.ends_with(NonLocalizable::EdgeFilename);
}
bool IsChrome(Utils::Apps::AppData appData)
{
return appData.installPath.ends_with(NonLocalizable::ChromeFilename);
}
std::vector<WorkspacesData::WorkspacesProject::Application> GetApps(const std::function<unsigned int(HWND)> getMonitorNumberFromWindowHandle, const std::function<WorkspacesData::WorkspacesProject::Monitor::MonitorRect(unsigned int)> getMonitorRect)
{
PwaHelper pwaHelper{};
Utils::PwaHelper pwaHelper{};
std::vector<WorkspacesData::WorkspacesProject::Application> apps{};
auto installedApps = Utils::Apps::GetAppsList();
@@ -128,47 +116,7 @@ namespace SnapshotUtils
continue;
}
std::wstring pwaAppId = L"";
std::wstring finalName = data.value().name;
std::wstring pwaName = L"";
if (IsEdge(data.value()))
{
pwaHelper.InitAumidToAppId();
std::wstring windowAumid;
pwaHelper.GetAppId(window, &windowAumid);
Logger::info(L"Found an edge window with aumid {}", windowAumid);
if (pwaHelper.GetPwaAppId(windowAumid, &pwaAppId))
{
Logger::info(L"The found edge window is a PWA app with appId {}", pwaAppId);
if (pwaHelper.SearchPwaName(pwaAppId, windowAumid ,& pwaName))
{
Logger::info(L"The found edge window is a PWA app with name {}", finalName);
}
finalName = pwaName + L" (" + finalName + L")";
}
else
{
Logger::info(L"The found edge window does not contain a PWA app", pwaAppId);
}
}
else if (IsChrome(data.value()))
{
pwaHelper.InitChromeAppIds();
std::wstring windowAumid;
pwaHelper.GetAppId(window, &windowAumid);
Logger::info(L"Found a chrome window with aumid {}", windowAumid);
if (pwaHelper.SearchPwaAppId(windowAumid, &pwaAppId))
{
if (pwaHelper.SearchPwaName(pwaAppId, windowAumid, &pwaName))
{
finalName = pwaName + L" (" + finalName + L")";
}
}
}
pwaHelper.UpdatePwaApp(&data.value(), window);
bool isMinimized = WindowUtils::IsMinimized(window);
unsigned int monitorNumber = getMonitorNumberFromWindowHandle(window);
@@ -184,12 +132,12 @@ namespace SnapshotUtils
}
WorkspacesData::WorkspacesProject::Application app{
.name = finalName,
.name = data.value().name,
.title = title,
.path = data.value().installPath,
.packageFullName = data.value().packageFullName,
.appUserModelId = data.value().appUserModelId,
.pwaAppId = pwaAppId,
.pwaAppId = data.value().pwaAppId,
.commandLineArgs = L"",
.isElevated = IsProcessElevated(pid),
.canLaunchElevated = data.value().canLaunchElevated,

View File

@@ -130,12 +130,10 @@
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(UsePrecompiledHeaders)' != 'false'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="PwaHelper.cpp" />
<ClCompile Include="SnapshotUtils.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="PwaHelper.h" />
<ClInclude Include="resource.base.h" />
<ClInclude Include="SnapshotUtils.h" />
</ItemGroup>

View File

@@ -24,9 +24,6 @@
<ClInclude Include="resource.base.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="PwaHelper.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
@@ -38,9 +35,6 @@
<ClCompile Include="SnapshotUtils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="PwaHelper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@@ -12,9 +12,18 @@
#include <workspaces-common/WindowUtils.h>
#include <WindowProperties/WorkspacesWindowPropertyUtils.h>
#include <WorkspacesLib/PwaHelper.h>
namespace FancyZones
namespace PlacementHelper
{
// When calculating the coordinates difference (== 'distance') between 2 windows, there are additional values added to the real distance
// if both windows are minimized, the 'distance' is 0, the minimal value, this is the best match, we prefer this 'pairing'
// if both are in normal state (non-minimized), we add 1 to the calculated 'distance', this is the 2nd best match
// if one window is minimized and the other is maximized, we add a high value (10.000) to the result as
// this case is the least desired match, we want this pairing (matching) only if there is no other possibility left
const int PlacementDistanceAdditionBothNormal = 1;
const int PlacementDistanceAdditionNormalAndMinimized = 10000;
inline void ScreenToWorkAreaCoords(HWND window, HMONITOR monitor, RECT& rect)
{
MONITORINFOEXW monitorInfo{ sizeof(MONITORINFOEXW) };
@@ -52,14 +61,7 @@ namespace FancyZones
}
else
{
if ((placement.showCmd != SW_SHOWMINIMIZED) &&
(placement.showCmd != SW_MINIMIZE))
{
if (placement.showCmd == SW_SHOWMAXIMIZED)
placement.flags &= ~WPF_RESTORETOMAXIMIZED;
placement.showCmd = SW_RESTORE;
}
placement.showCmd = SW_RESTORE;
ScreenToWorkAreaCoords(window, monitor, rect);
placement.rcNormalPosition = rect;
@@ -91,18 +93,191 @@ namespace FancyZones
return true;
}
int CalculateDistance(const WorkspacesData::WorkspacesProject::Application& app, HWND window)
{
WINDOWPLACEMENT placement{};
::GetWindowPlacement(window, &placement);
if (app.isMinimized && (placement.showCmd == SW_SHOWMINIMIZED))
{
// The most preferred case: both windows are minimized. The 'distance' between these 2 windows is 0, the lowest value
return 0;
}
int placementDiffPenalty = PlacementDistanceAdditionBothNormal;
if (app.isMinimized || (placement.showCmd == SW_SHOWMINIMIZED))
{
// The least preferred case: one window is minimized the other one isn't.
// We add a high number to the real distance, as we want this 2 windows be matched only if there is no other match
placementDiffPenalty = PlacementDistanceAdditionNormalAndMinimized;
}
RECT windowPosition;
GetWindowRect(window, &windowPosition);
DPIAware::InverseConvert(MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY), windowPosition);
return placementDiffPenalty + abs(app.position.x - windowPosition.left) + abs(app.position.y - windowPosition.top) + abs(app.position.x + app.position.width - windowPosition.right) + abs(app.position.y + app.position.height - windowPosition.bottom);
}
}
bool WindowArranger::TryMoveWindow(const WorkspacesData::WorkspacesProject::Application& app, HWND windowToMove)
{
Logger::info(L"The app {} is found at launch, moving it", app.name);
auto appState = m_launchingStatus.Get(app);
if (!appState.has_value())
{
Logger::info(L"The app {} is not found in the map of apps", app.name);
return false;
}
bool success = moveWindow(windowToMove, app);
if (success)
{
m_launchingStatus.Update(appState.value().application, windowToMove, LaunchingState::LaunchedAndMoved);
}
else
{
Logger::info(L"Failed to move the existing app {} ", app.name);
m_launchingStatus.Update(appState.value().application, windowToMove, LaunchingState::Failed);
}
auto updatedState = m_launchingStatus.Get(app);
if (updatedState.has_value())
{
m_ipcHelper.send(WorkspacesData::AppLaunchInfoJSON::ToJson(updatedState.value()).ToString().c_str());
}
return success;
}
std::optional<WindowWithDistance> WindowArranger::GetNearestWindow(const WorkspacesData::WorkspacesProject::Application& app, const std::vector<HWND>& movedWindows, Utils::PwaHelper& pwaHelper)
{
std::optional<Utils::Apps::AppData> appDataNearest = std::nullopt;
WindowWithDistance nearestWindowWithDistance{};
for (HWND window : m_windowsBefore)
{
if (std::find(movedWindows.begin(), movedWindows.end(), window) != movedWindows.end())
{
continue;
}
std::wstring processPath = get_process_path(window);
if (processPath.empty())
{
continue;
}
DWORD pid{};
GetWindowThreadProcessId(window, &pid);
auto data = Utils::Apps::GetApp(processPath, pid, m_installedApps);
if (!data.has_value())
{
continue;
}
pwaHelper.UpdatePwaApp(&data.value(), window);
if ((app.name == data.value().name || app.path == data.value().installPath) && (app.pwaAppId == data.value().pwaAppId))
{
if (!appDataNearest.has_value())
{
appDataNearest = data;
nearestWindowWithDistance.distance = PlacementHelper::CalculateDistance(app, window);
nearestWindowWithDistance.window = window;
}
else
{
int currentDistance = PlacementHelper::CalculateDistance(app, window);
if (currentDistance < nearestWindowWithDistance.distance)
{
appDataNearest = data;
nearestWindowWithDistance.distance = currentDistance;
nearestWindowWithDistance.window = window;
}
}
}
}
if (appDataNearest.has_value())
{
return nearestWindowWithDistance;
}
return std::nullopt;
}
WindowArranger::WindowArranger(WorkspacesData::WorkspacesProject project) :
m_project(project),
m_windowsBefore(WindowEnumerator::Enumerate(WindowFilter::Filter)),
m_monitors(MonitorUtils::IdentifyMonitors()),
m_installedApps(Utils::Apps::GetAppsList()),
//m_windowCreationHandler(std::bind(&WindowArranger::onWindowCreated, this, std::placeholders::_1)),
m_ipcHelper(IPCHelperStrings::WindowArrangerPipeName, IPCHelperStrings::LauncherArrangerPipeName, std::bind(&WindowArranger::receiveIpcMessage, this, std::placeholders::_1)),
m_launchingStatus(m_project)
{
if (project.moveExistingWindows)
{
Logger::info(L"Moving existing windows");
bool isMovePhase = true;
bool movedAny = false;
std::vector<HWND> movedWindows;
std::vector<WorkspacesData::WorkspacesProject::Application> movedApps;
Utils::PwaHelper pwaHelper{};
while (isMovePhase)
{
isMovePhase = false;
int minDistance = INT_MAX;
WorkspacesData::WorkspacesProject::Application appToMove;
HWND windowToMove = NULL;
for (auto& app : project.apps)
{
// move the apps which are set to "Move-If-Exists" and are already present (launched, running)
if (std::find(movedApps.begin(), movedApps.end(), app) != movedApps.end())
{
continue;
}
std::optional<WindowWithDistance> nearestWindowWithDistance;
nearestWindowWithDistance = GetNearestWindow(app, movedWindows, pwaHelper);
if (nearestWindowWithDistance.has_value())
{
if (nearestWindowWithDistance.value().distance < minDistance)
{
minDistance = nearestWindowWithDistance.value().distance;
appToMove = app;
windowToMove = nearestWindowWithDistance.value().window;
}
}
else
{
Logger::info(L"The app {} is not found at launch, cannot be moved, has to be started", app.name);
movedApps.push_back(app);
}
}
if (minDistance < INT_MAX)
{
isMovePhase = true;
movedAny = true;
bool success = TryMoveWindow(appToMove, windowToMove);
movedApps.push_back(appToMove);
if (success)
{
movedWindows.push_back(windowToMove);
}
}
}
if (movedAny)
{
// Wait if there were moved windows. This message might not arrive if sending immediately after the last "moved" message (status update)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
Logger::info(L"Finished moving existing windows");
}
m_ipcHelper.send(L"ready");
const long maxLaunchingWaitingTime = 10000, maxRepositionWaitingTime = 3000, ms = 300;
@@ -138,27 +313,17 @@ WindowArranger::WindowArranger(WorkspacesData::WorkspacesProject project) :
}
}
//void WindowArranger::onWindowCreated(HWND window)
//{
// if (!WindowFilter::Filter(window))
// {
// return;
// }
//
// processWindow(window);
//}
void WindowArranger::processWindows(bool processAll)
{
std::vector<HWND> windows = WindowEnumerator::Enumerate(WindowFilter::Filter);
if (!processAll)
{
std::vector<HWND> windowsDiff{};
std::copy_if(windows.begin(), windows.end(), std::back_inserter(windowsDiff), [&](HWND window) { return std::find(m_windowsBefore.begin(), m_windowsBefore.end(), window) == m_windowsBefore.end(); });
windows = windowsDiff;
}
for (HWND window : windows)
{
processWindow(window);
@@ -194,12 +359,11 @@ void WindowArranger::processWindow(HWND window)
}
const auto& apps = m_launchingStatus.Get();
auto iter = std::find_if(apps.begin(), apps.end(), [&](const auto& val)
{
return val.second.state == LaunchingState::Launched &&
!val.second.window &&
(val.first.name == data.value().name || val.first.path == data.value().installPath);
});
auto iter = std::find_if(apps.begin(), apps.end(), [&](const auto& val) {
return val.second.state == LaunchingState::Launched &&
!val.second.window &&
(val.first.name == data.value().name || val.first.path == data.value().installPath);
});
if (iter == apps.end())
{
@@ -258,7 +422,7 @@ bool WindowArranger::moveWindow(HWND window, const WorkspacesData::WorkspacesPro
rect.top = static_cast<long>(std::round(rect.top * mult));
rect.bottom = static_cast<long>(std::round(rect.bottom * mult));
if (FancyZones::SizeWindowToRect(window, currentMonitor, launchMinimized, launchMaximized, rect))
if (PlacementHelper::SizeWindowToRect(window, currentMonitor, launchMinimized, launchMaximized, rect))
{
WorkspacesWindowProperties::StampWorkspacesLaunchedProperty(window);
Logger::trace(L"Placed {} to ({},{}) [{}x{}]", app.name, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);

View File

@@ -5,8 +5,15 @@
#include <WorkspacesLib/AppUtils.h>
#include <WorkspacesLib/IPCHelper.h>
#include <WorkspacesLib/LaunchingStatus.h>
#include <WorkspacesLib/PwaHelper.h>
#include <WorkspacesLib/WorkspacesData.h>
struct WindowWithDistance
{
int distance;
HWND window;
};
class WindowArranger
{
public:
@@ -21,7 +28,9 @@ private:
//const WindowCreationHandler m_windowCreationHandler;
IPCHelper m_ipcHelper;
LaunchingStatus m_launchingStatus;
std::optional<WindowWithDistance> GetNearestWindow(const WorkspacesData::WorkspacesProject::Application& app, const std::vector<HWND>& movedWindows, Utils::PwaHelper& pwaHelper);
bool TryMoveWindow(const WorkspacesData::WorkspacesProject::Application& app, HWND windowToMove);
//void onWindowCreated(HWND window);
void processWindows(bool processAll);
void processWindow(HWND window);

View File

@@ -1,6 +1,8 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.

View File

@@ -1,6 +1,8 @@
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using ImageResizer.Properties;
using Microsoft.VisualStudio.TestTools.UnitTesting;

View File

@@ -1,6 +1,8 @@
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System;
using System.Collections.Concurrent;

View File

@@ -1,6 +1,8 @@
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System;
using System.IO;

View File

@@ -1,6 +1,8 @@
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System;
using System.Collections.Generic;

View File

@@ -1,6 +1,8 @@
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System.Collections.Specialized;
using System.ComponentModel;

View File

@@ -1,6 +1,8 @@
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System;
using System.Collections.Generic;

View File

@@ -1,6 +1,8 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System.Windows;
using System.Windows.Media;

View File

@@ -1,6 +1,8 @@
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System;
using System.Collections.Generic;

View File

@@ -1,6 +1,8 @@
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System;
using System.Globalization;

View File

@@ -1,6 +1,8 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System;
using System.Globalization;

View File

@@ -1,6 +1,8 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
namespace System.Windows.Media.Imaging
{

View File

@@ -1,6 +1,8 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
namespace System.Collections.Generic
{

View File

@@ -1,6 +1,8 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
namespace System
{

View File

@@ -1,6 +1,8 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System.Text.Json.Serialization;

View File

@@ -1,6 +1,8 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System;
using System.Collections.Concurrent;

View File

@@ -1,6 +1,8 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
namespace ImageResizer.Models
{

View File

@@ -1,7 +1,9 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
namespace ImageResizer.Models
{

View File

@@ -1,6 +1,8 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System;
using System.Diagnostics;

View File

@@ -1,7 +1,9 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System.Collections.Generic;
using System.Diagnostics;

View File

@@ -1,7 +1,9 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
namespace ImageResizer.Models
{

View File

@@ -1,6 +1,8 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System.Runtime.CompilerServices;

View File

@@ -1,6 +1,8 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System;
using System.Collections;

View File

@@ -1,6 +1,8 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System.Text.Json.Serialization;

View File

@@ -1,6 +1,8 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System;
using System.Text.Json;

View File

@@ -1,6 +1,8 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System;
using System.Text.Json;

View File

@@ -1,6 +1,8 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System;

View File

@@ -1,6 +1,8 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System;
using System.Collections.Generic;

View File

@@ -1,6 +1,8 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
namespace ImageResizer.ViewModels
{

View File

@@ -1,6 +1,8 @@
// Copyright (c) Brice Lambson
#pragma warning disable IDE0073
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
#pragma warning restore IDE0073
using System;
using System.Collections.Generic;

Some files were not shown because too many files have changed in this diff Show More