mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-01-30 16:07:29 +01:00
Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a97db8992 | ||
|
|
04636339ce | ||
|
|
9731cdee67 | ||
|
|
0c02a9acd7 | ||
|
|
6077fa3530 | ||
|
|
1a4d97ef28 | ||
|
|
88513cf38a | ||
|
|
7c0cc145eb | ||
|
|
398dcc4a44 | ||
|
|
823d641087 | ||
|
|
65618ffa9c | ||
|
|
5e4f50fa45 | ||
|
|
b2a86db6de | ||
|
|
d2e04d46f4 | ||
|
|
6dfaf6a21c | ||
|
|
9af08d9842 | ||
|
|
d57773e8ef | ||
|
|
24a80de2ec | ||
|
|
ec544b0907 | ||
|
|
d87a325529 | ||
|
|
c651a4b36e | ||
|
|
37132c91e6 | ||
|
|
9727d56864 | ||
|
|
03b5a0f283 | ||
|
|
91797669ee | ||
|
|
e6ffbcf315 | ||
|
|
e12e707704 | ||
|
|
f4a54b667e | ||
|
|
a084ea24b3 | ||
|
|
c05e33cae3 | ||
|
|
55923f2790 | ||
|
|
cdfb566137 | ||
|
|
39f0db8cb4 | ||
|
|
1bd702340b | ||
|
|
3c04111483 | ||
|
|
e965fcb690 | ||
|
|
d583b083d1 | ||
|
|
25a7bf9ab0 | ||
|
|
4d8c18a557 | ||
|
|
579881002e | ||
|
|
5027a55e7f | ||
|
|
d3cd7bec5f | ||
|
|
323a12a44a | ||
|
|
8c955ce9d6 | ||
|
|
9d597faabc | ||
|
|
d85c3f8cc9 | ||
|
|
3f70c8c889 | ||
|
|
370e8c8574 | ||
|
|
25ab4afe78 | ||
|
|
6ad6ff7fb6 | ||
|
|
0d5f97d8bf | ||
|
|
71f2561eb1 | ||
|
|
b42eb08ec6 | ||
|
|
086394d455 | ||
|
|
03eb9c3f5c | ||
|
|
9c248cdcd2 | ||
|
|
2ddab2549e | ||
|
|
4c323ab71a | ||
|
|
a90c738c10 | ||
|
|
4e23832d52 | ||
|
|
e450669663 | ||
|
|
d8f0f7aca4 | ||
|
|
e5cb07729f |
1
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
1
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -32,6 +32,7 @@ body:
|
||||
multiple: true
|
||||
options:
|
||||
- General
|
||||
- Awake
|
||||
- ColorPicker
|
||||
- FancyZones
|
||||
- FancyZones Editor
|
||||
|
||||
378
.github/actions/spell-check/expect.txt
vendored
378
.github/actions/spell-check/expect.txt
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,21 +1,22 @@
|
||||
# spelling.yml is blocked per https://github.com/check-spelling/check-spelling/security/advisories/GHSA-g86g-chm8-7r2p
|
||||
name: Spell checking
|
||||
on:
|
||||
pull_request_target:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
spelling:
|
||||
name: Spell checking
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout-merge
|
||||
if: "contains(github.event_name, 'pull_request')"
|
||||
uses: actions/checkout@v2.0.0
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: refs/pull/${{github.event.pull_request.number}}/merge
|
||||
- name: checkout
|
||||
if: "!contains(github.event_name, 'pull_request')"
|
||||
uses: actions/checkout@v2.0.0
|
||||
- uses: check-spelling/check-spelling@v0.0.18
|
||||
uses: actions/checkout@v2
|
||||
- uses: check-spelling/check-spelling@v0.0.19
|
||||
with:
|
||||
config: .github/actions/spell-check
|
||||
@@ -7,3 +7,5 @@ set SolutionDir=%cd%
|
||||
popd
|
||||
SET IsPipeline=1
|
||||
call msbuild ../tools/BugReportTool/BugReportTool.sln /p:Configuration=Release /p:Platform=x64 /p:CIBuild=true || exit /b 1
|
||||
call msbuild ../tools/WebcamReportTool/WebcamReportTool.sln /p:Configuration=Release /p:Platform=x64 /p:CIBuild=true || exit /b 1
|
||||
|
||||
|
||||
@@ -61,6 +61,11 @@ build:
|
||||
- 'x64/**/*.pdb'
|
||||
exclude:
|
||||
- 'x64/Release/obj/**/*.pdb'
|
||||
# TODO(yuyoyuppe): uncomment when VCM should be enabled
|
||||
#- from: 'x86/Release'
|
||||
# to: 'Build_Output'
|
||||
# include:
|
||||
# - 'modules\VideoConference\VideoConferenceProxyFilter_x86.dll'
|
||||
- from: 'x64/Release'
|
||||
to: 'Build_Output'
|
||||
include:
|
||||
@@ -93,8 +98,11 @@ build:
|
||||
- 'modules\FancyZones\fancyzones.dll'
|
||||
- 'modules\FancyZones\FancyZonesEditor.exe'
|
||||
- 'modules\FancyZones\FancyZonesEditor.dll'
|
||||
- 'modules\FancyZones\FancyZonesModuleInterface.dll'
|
||||
- 'modules\FancyZones\ManagedCommon.dll'
|
||||
- 'modules\FancyZones\ManagedTelemetry.dll'
|
||||
- 'modules\FancyZones\PowerToys.FancyZones.exe'
|
||||
- 'modules\FancyZones\PowerToysInterop.dll'
|
||||
- 'modules\FancyZones\Telemetry.dll'
|
||||
- 'modules\FancyZones\Microsoft.PowerToys.Common.UI.dll'
|
||||
- 'modules\FileExplorerPreview\ManagedTelemetry.dll'
|
||||
@@ -157,6 +165,9 @@ build:
|
||||
- 'modules\PowerRename\PowerRenameExt.dll'
|
||||
- 'modules\ShortcutGuide\ShortcutGuide\PowerToys.ShortcutGuide.exe'
|
||||
- 'modules\ShortcutGuide\ShortcutGuideModuleInterface\ShortcutGuideModuleInterface.dll'
|
||||
# TODO(yuyoyuppe): uncomment when VCM should be enabled
|
||||
#- 'modules\VideoConference\VideoConferenceModule.dll'
|
||||
#- 'modules\VideoConference\VideoConferenceProxyFilter_x64.dll'
|
||||
- 'Settings\ManagedTelemetry.dll'
|
||||
- 'Settings\Microsoft.PowerToys.Settings.UI.exe'
|
||||
- 'Settings\Microsoft.PowerToys.Settings.UI.Lib.dll'
|
||||
@@ -175,6 +186,7 @@ build:
|
||||
to: 'Build_Output'
|
||||
include:
|
||||
- 'BugReportTool\BugReportTool.exe'
|
||||
- 'WebcamReportTool\WebcamReportTool.exe'
|
||||
signing_options:
|
||||
sign_inline: true # This does signing a soon as this command completes
|
||||
- !!buildcommand
|
||||
@@ -235,4 +247,3 @@ static_analysis_options:
|
||||
files_to_scan:
|
||||
- exclude:
|
||||
- '**/*.lcl'
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
cd /D "%~dp0"
|
||||
|
||||
nuget restore ../tools/BugReportTool/BugReportTool.sln || exit /b 1
|
||||
nuget restore ../tools/WebcamReportTool/WebcamReportTool.sln || exit /b 1
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
cd /D "%~dp0"
|
||||
|
||||
nuget restore ../PowerToys.sln || exit /b 1
|
||||
|
||||
powershell.exe -Command "Invoke-WebRequest -OutFile %tmp%\wdksetup.exe https://go.microsoft.com/fwlink/p/?linkid=2085767"
|
||||
%tmp%\wdksetup.exe /q
|
||||
|
||||
copy "C:\Program Files (x86)\Windows Kits\10\Vsix\VS2019\WDK.vsix" %tmp%\wdkvsix.zip
|
||||
powershell Expand-Archive %tmp%\wdkvsix.zip -DestinationPath %tmp%\wdkvsix -Force
|
||||
|
||||
robocopy /e %tmp%\wdkvsix\$MSBuild\Microsoft\VC\v160 "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VC\v160" || IF %ERRORLEVEL% LEQ 7 EXIT 0
|
||||
robocopy /e %tmp%\wdkvsix\$VCTargets "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\VC\VCTargets" || IF %ERRORLEVEL% LEQ 7 EXIT 0
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project ToolsVersion="4.0"
|
||||
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<!-- Project configurations -->
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
@@ -12,7 +13,7 @@
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<!-- Props that should be disabled while building on CI server -->
|
||||
<ItemDefinitionGroup Condition="'$(CIBuild)'!='true'">
|
||||
<ClCompile>
|
||||
@@ -22,10 +23,15 @@
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<!-- C++ source compile-specific things for all configurations -->
|
||||
<PropertyGroup>
|
||||
<ExternalIncludePath>$(MSBuildThisFileFullPath)\..\deps\;$(ExternalIncludePath)</ExternalIncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DisableAnalyzeExternal >true</DisableAnalyzeExternal>
|
||||
<ExternalWarningLevel>TurnOffAllWarnings</ExternalWarningLevel>
|
||||
<ConformanceMode>false</ConformanceMode>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
@@ -34,10 +40,10 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
</Link>
|
||||
<Lib>
|
||||
<TreatLibWarningAsErrors>true</TreatLibWarningAsErrors>
|
||||
</Lib>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<!-- C++ source compile-specific things for Debug/Release configurations -->
|
||||
@@ -50,7 +56,7 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
@@ -60,12 +66,12 @@
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<!-- Global props -->
|
||||
@@ -75,7 +81,7 @@
|
||||
|
||||
<!-- Props that are constant for both Debug and Release configurations -->
|
||||
<PropertyGroup Label="Configuration">
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(OverridePlatformToolset)'!='True'">v142</PlatformToolset>
|
||||
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<SpectreMitigation>Spectre</SpectreMitigation>
|
||||
@@ -83,13 +89,13 @@
|
||||
|
||||
<!-- Debug/Release props -->
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
258
PowerToys.sln
258
PowerToys.sln
@@ -333,7 +333,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Community.PowerToys.Run.Plu
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Community.PowerToys.Run.Plugin.UnitConverter.UnitTest", "src\modules\launcher\Plugins\Community.PowerToys.Run.Plugin.UnitConverter.UnitTest\Community.PowerToys.Run.Plugin.UnitConverter.UnitTest.csproj", "{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}"
|
||||
EndProject
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shortcutguide", "shortcutguide", "{106CBECA-0701-4FC3-838C-9DF816A19AE2}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShortcutGuideModuleInterface", "src\modules\ShortcutGuide\ShortcutGuideModuleInterface\ShortcutGuideModuleInterface.vcxproj", "{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}"
|
||||
@@ -342,376 +341,597 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShortcutGuide", "src\module
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FancyZonesModuleInterface", "src\modules\fancyzones\FancyZonesModuleInterface\FancyZonesModuleInterface.vcxproj", "{48804216-2A0E-4168-A6D8-9CD068D14227}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FancyZones", "src\modules\fancyzones\FancyZones\FancyZones.vcxproj", "{390AE700-B55F-4202-91EA-A822EB75B9BD}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FancyZones", "src\modules\fancyzones\FancyZones\FancyZones.vcxproj", "{FF1D7936-842A-4BBB-8BEA-E9FE796DE700}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerToys.Update", "src\Update\PowerToys.Update.vcxproj", "{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.WindowsSettings", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\Microsoft.PowerToys.Run.Plugin.WindowsSettings.csproj", "{5043CECE-E6A7-4867-9CBE-02D27D83747A}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoConferenceShared", "src\modules\videoconference\VideoConferenceShared\VideoConferenceShared.vcxproj", "{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoConferenceModule", "src\modules\videoconference\VideoConferenceModule\Video Conference.vcxproj", "{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoConferenceProxyFilter", "src\modules\videoconference\VideoConferenceProxyFilter\VideoConferenceProxyFilter.vcxproj", "{AC2857B4-103D-4D6D-9740-926EBF785042}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A} = {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VideoConference", "VideoConference", "{470FBAF9-E1F8-4F3E-8786-198A1C81C8A8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Debug|x64.Build.0 = Debug|x64
|
||||
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Release|x64.ActiveCfg = Release|x64
|
||||
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Release|x64.Build.0 = Release|x64
|
||||
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Release|x86.ActiveCfg = Release|x64
|
||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Debug|x64.Build.0 = Debug|x64
|
||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Release|x64.ActiveCfg = Release|x64
|
||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Release|x64.Build.0 = Release|x64
|
||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Release|x86.ActiveCfg = Release|x64
|
||||
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Debug|x64.Build.0 = Debug|x64
|
||||
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Release|x64.ActiveCfg = Release|x64
|
||||
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Release|x64.Build.0 = Release|x64
|
||||
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Release|x86.ActiveCfg = Release|x64
|
||||
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Debug|x64.Build.0 = Debug|x64
|
||||
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Release|x64.ActiveCfg = Release|x64
|
||||
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Release|x64.Build.0 = Release|x64
|
||||
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Release|x86.ActiveCfg = Release|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|x64.Build.0 = Debug|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|x64.ActiveCfg = Release|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|x64.Build.0 = Release|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|x86.ActiveCfg = Release|x64
|
||||
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Debug|x64.Build.0 = Debug|x64
|
||||
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Release|x64.ActiveCfg = Release|x64
|
||||
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Release|x64.Build.0 = Release|x64
|
||||
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Release|x86.ActiveCfg = Release|x64
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2}.Debug|x64.Build.0 = Debug|x64
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2}.Release|x64.ActiveCfg = Release|x64
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2}.Release|x64.Build.0 = Release|x64
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2}.Release|x86.ActiveCfg = Release|x64
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798}.Debug|x64.Build.0 = Debug|x64
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798}.Release|x64.ActiveCfg = Release|x64
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798}.Release|x64.Build.0 = Release|x64
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798}.Release|x86.ActiveCfg = Release|x64
|
||||
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Debug|x64.Build.0 = Debug|x64
|
||||
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Release|x64.ActiveCfg = Release|x64
|
||||
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Release|x64.Build.0 = Release|x64
|
||||
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Release|x86.ActiveCfg = Release|x64
|
||||
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Debug|x64.Build.0 = Debug|x64
|
||||
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Release|x64.ActiveCfg = Release|x64
|
||||
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Release|x64.Build.0 = Release|x64
|
||||
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Release|x86.ActiveCfg = Release|x64
|
||||
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Debug|x64.Build.0 = Debug|x64
|
||||
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Release|x64.ActiveCfg = Release|x64
|
||||
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Release|x64.Build.0 = Release|x64
|
||||
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Release|x86.ActiveCfg = Release|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Debug|x64.Build.0 = Debug|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Release|x64.ActiveCfg = Release|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Release|x64.Build.0 = Release|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Release|x86.ActiveCfg = Release|x64
|
||||
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Debug|x64.Build.0 = Debug|x64
|
||||
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Release|x64.ActiveCfg = Release|x64
|
||||
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Release|x64.Build.0 = Release|x64
|
||||
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Release|x86.ActiveCfg = Release|x64
|
||||
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Debug|x64.Build.0 = Debug|x64
|
||||
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Release|x64.ActiveCfg = Release|x64
|
||||
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Release|x64.Build.0 = Release|x64
|
||||
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Release|x86.ActiveCfg = Release|x64
|
||||
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Debug|x64.Build.0 = Debug|x64
|
||||
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Release|x64.ActiveCfg = Release|x64
|
||||
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Release|x64.Build.0 = Release|x64
|
||||
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Release|x86.ActiveCfg = Release|x64
|
||||
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Debug|x64.Build.0 = Debug|x64
|
||||
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Release|x64.ActiveCfg = Release|x64
|
||||
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Release|x64.Build.0 = Release|x64
|
||||
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Release|x86.ActiveCfg = Release|x64
|
||||
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Debug|x64.Build.0 = Debug|x64
|
||||
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Release|x64.ActiveCfg = Release|x64
|
||||
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Release|x64.Build.0 = Release|x64
|
||||
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Release|x86.ActiveCfg = Release|x64
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Debug|x64.Build.0 = Debug|x64
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Release|x64.ActiveCfg = Release|x64
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Release|x64.Build.0 = Release|x64
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Release|x86.ActiveCfg = Release|x64
|
||||
{8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Debug|x64.Build.0 = Debug|x64
|
||||
{8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Release|x64.ActiveCfg = Release|x64
|
||||
{8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Release|x64.Build.0 = Release|x64
|
||||
{8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Release|x86.ActiveCfg = Release|x64
|
||||
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Debug|x64.Build.0 = Debug|x64
|
||||
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Release|x64.ActiveCfg = Release|x64
|
||||
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Release|x64.Build.0 = Release|x64
|
||||
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Release|x86.ActiveCfg = Release|x64
|
||||
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Debug|x64.Build.0 = Debug|x64
|
||||
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|x64.ActiveCfg = Release|x64
|
||||
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|x64.Build.0 = Release|x64
|
||||
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|x86.ActiveCfg = Release|x64
|
||||
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|x64.Build.0 = Debug|x64
|
||||
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Release|x64.ActiveCfg = Release|x64
|
||||
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Release|x64.Build.0 = Release|x64
|
||||
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Release|x86.ActiveCfg = Release|x64
|
||||
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|x64.Build.0 = Debug|x64
|
||||
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x64.ActiveCfg = Release|x64
|
||||
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x64.Build.0 = Release|x64
|
||||
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x86.ActiveCfg = Release|x64
|
||||
{4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Debug|x64.Build.0 = Debug|x64
|
||||
{4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Release|x64.ActiveCfg = Release|x64
|
||||
{4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Release|x64.Build.0 = Release|x64
|
||||
{4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Release|x86.ActiveCfg = Release|x64
|
||||
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Debug|x64.Build.0 = Debug|x64
|
||||
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Release|x64.ActiveCfg = Release|x64
|
||||
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Release|x64.Build.0 = Release|x64
|
||||
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Release|x86.ActiveCfg = Release|x64
|
||||
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Debug|x64.Build.0 = Debug|x64
|
||||
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Release|x64.ActiveCfg = Release|x64
|
||||
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Release|x64.Build.0 = Release|x64
|
||||
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Release|x86.ActiveCfg = Release|x64
|
||||
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Debug|x64.Build.0 = Debug|x64
|
||||
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Release|x64.ActiveCfg = Release|x64
|
||||
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Release|x64.Build.0 = Release|x64
|
||||
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Release|x86.ActiveCfg = Release|x64
|
||||
{F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Debug|x64.Build.0 = Debug|x64
|
||||
{F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Release|x64.ActiveCfg = Release|x64
|
||||
{F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Release|x64.Build.0 = Release|x64
|
||||
{F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Release|x86.ActiveCfg = Release|x64
|
||||
{E364F67B-BB12-4E91-B639-355866EBCD8B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E364F67B-BB12-4E91-B639-355866EBCD8B}.Debug|x64.Build.0 = Debug|x64
|
||||
{E364F67B-BB12-4E91-B639-355866EBCD8B}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{E364F67B-BB12-4E91-B639-355866EBCD8B}.Release|x64.ActiveCfg = Release|x64
|
||||
{E364F67B-BB12-4E91-B639-355866EBCD8B}.Release|x64.Build.0 = Release|x64
|
||||
{E364F67B-BB12-4E91-B639-355866EBCD8B}.Release|x86.ActiveCfg = Release|x64
|
||||
{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Debug|x64.Build.0 = Debug|x64
|
||||
{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Release|x64.ActiveCfg = Release|x64
|
||||
{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Release|x64.Build.0 = Release|x64
|
||||
{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Release|x86.ActiveCfg = Release|x64
|
||||
{AF2349B8-E5B6-4004-9502-687C1C7730B1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{AF2349B8-E5B6-4004-9502-687C1C7730B1}.Debug|x64.Build.0 = Debug|x64
|
||||
{AF2349B8-E5B6-4004-9502-687C1C7730B1}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{AF2349B8-E5B6-4004-9502-687C1C7730B1}.Release|x64.ActiveCfg = Release|x64
|
||||
{AF2349B8-E5B6-4004-9502-687C1C7730B1}.Release|x64.Build.0 = Release|x64
|
||||
{AF2349B8-E5B6-4004-9502-687C1C7730B1}.Release|x86.ActiveCfg = Release|x64
|
||||
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Debug|x64.Build.0 = Debug|x64
|
||||
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Release|x64.ActiveCfg = Release|x64
|
||||
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Release|x64.Build.0 = Release|x64
|
||||
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Release|x86.ActiveCfg = Release|x64
|
||||
{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Debug|x64.Build.0 = Debug|x64
|
||||
{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Release|x64.ActiveCfg = Release|x64
|
||||
{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Release|x64.Build.0 = Release|x64
|
||||
{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Release|x86.ActiveCfg = Release|x64
|
||||
{DA425894-6E13-404F-8DCB-78584EC0557A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DA425894-6E13-404F-8DCB-78584EC0557A}.Debug|x64.Build.0 = Debug|x64
|
||||
{DA425894-6E13-404F-8DCB-78584EC0557A}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{DA425894-6E13-404F-8DCB-78584EC0557A}.Release|x64.ActiveCfg = Release|x64
|
||||
{DA425894-6E13-404F-8DCB-78584EC0557A}.Release|x64.Build.0 = Release|x64
|
||||
{DA425894-6E13-404F-8DCB-78584EC0557A}.Release|x86.ActiveCfg = Release|x64
|
||||
{060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Debug|x64.Build.0 = Debug|x64
|
||||
{060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Release|x64.ActiveCfg = Release|x64
|
||||
{060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Release|x64.Build.0 = Release|x64
|
||||
{060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Release|x86.ActiveCfg = Release|x64
|
||||
{748417CA-F17E-487F-9411-CAFB6D3F4877}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{748417CA-F17E-487F-9411-CAFB6D3F4877}.Debug|x64.Build.0 = Debug|x64
|
||||
{748417CA-F17E-487F-9411-CAFB6D3F4877}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{748417CA-F17E-487F-9411-CAFB6D3F4877}.Release|x64.ActiveCfg = Release|x64
|
||||
{748417CA-F17E-487F-9411-CAFB6D3F4877}.Release|x64.Build.0 = Release|x64
|
||||
{748417CA-F17E-487F-9411-CAFB6D3F4877}.Release|x86.ActiveCfg = Release|x64
|
||||
{217DF501-135C-4E38-BFC8-99D4821032EA}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{217DF501-135C-4E38-BFC8-99D4821032EA}.Debug|x64.Build.0 = Debug|x64
|
||||
{217DF501-135C-4E38-BFC8-99D4821032EA}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{217DF501-135C-4E38-BFC8-99D4821032EA}.Release|x64.ActiveCfg = Release|x64
|
||||
{217DF501-135C-4E38-BFC8-99D4821032EA}.Release|x64.Build.0 = Release|x64
|
||||
{217DF501-135C-4E38-BFC8-99D4821032EA}.Release|x86.ActiveCfg = Release|x64
|
||||
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Debug|x64.Build.0 = Debug|x64
|
||||
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Release|x64.ActiveCfg = Release|x64
|
||||
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Release|x64.Build.0 = Release|x64
|
||||
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Release|x86.ActiveCfg = Release|x64
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x64.Build.0 = Debug|x64
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x86.Build.0 = Debug|Win32
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x86.Deploy.0 = Debug|Win32
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x64.ActiveCfg = Release|x64
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x64.Build.0 = Release|x64
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x86.ActiveCfg = Release|Win32
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x86.Build.0 = Release|Win32
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x86.Deploy.0 = Release|Win32
|
||||
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Debug|x64.Build.0 = Debug|x64
|
||||
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Release|x64.ActiveCfg = Release|x64
|
||||
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Release|x64.Build.0 = Release|x64
|
||||
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Release|x86.ActiveCfg = Release|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Debug|x64.Build.0 = Debug|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Release|x64.ActiveCfg = Release|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Release|x64.Build.0 = Release|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Release|x86.ActiveCfg = Release|x64
|
||||
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Debug|x64.Build.0 = Debug|x64
|
||||
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Release|x64.ActiveCfg = Release|x64
|
||||
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Release|x64.Build.0 = Release|x64
|
||||
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Release|x86.ActiveCfg = Release|x64
|
||||
{08C8C05F-0362-41BC-818C-724572DF8B06}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{08C8C05F-0362-41BC-818C-724572DF8B06}.Debug|x64.Build.0 = Debug|x64
|
||||
{08C8C05F-0362-41BC-818C-724572DF8B06}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{08C8C05F-0362-41BC-818C-724572DF8B06}.Release|x64.ActiveCfg = Release|x64
|
||||
{08C8C05F-0362-41BC-818C-724572DF8B06}.Release|x64.Build.0 = Release|x64
|
||||
{08C8C05F-0362-41BC-818C-724572DF8B06}.Release|x86.ActiveCfg = Release|x64
|
||||
{5D00D290-4016-4CFE-9E41-1E7C724509BA}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5D00D290-4016-4CFE-9E41-1E7C724509BA}.Debug|x64.Build.0 = Debug|x64
|
||||
{5D00D290-4016-4CFE-9E41-1E7C724509BA}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{5D00D290-4016-4CFE-9E41-1E7C724509BA}.Release|x64.ActiveCfg = Release|x64
|
||||
{5D00D290-4016-4CFE-9E41-1E7C724509BA}.Release|x64.Build.0 = Release|x64
|
||||
{5D00D290-4016-4CFE-9E41-1E7C724509BA}.Release|x86.ActiveCfg = Release|x64
|
||||
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Debug|x64.Build.0 = Debug|x64
|
||||
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Release|x64.ActiveCfg = Release|x64
|
||||
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Release|x64.Build.0 = Release|x64
|
||||
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Release|x86.ActiveCfg = Release|x64
|
||||
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Debug|x64.Build.0 = Debug|x64
|
||||
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Release|x64.ActiveCfg = Release|x64
|
||||
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Release|x64.Build.0 = Release|x64
|
||||
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Release|x86.ActiveCfg = Release|x64
|
||||
{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Debug|x64.Build.0 = Debug|x64
|
||||
{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Release|x64.ActiveCfg = Release|x64
|
||||
{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Release|x64.Build.0 = Release|x64
|
||||
{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Release|x86.ActiveCfg = Release|x64
|
||||
{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Debug|x64.Build.0 = Debug|x64
|
||||
{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Release|x64.ActiveCfg = Release|x64
|
||||
{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Release|x64.Build.0 = Release|x64
|
||||
{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Release|x86.ActiveCfg = Release|x64
|
||||
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Debug|x64.Build.0 = Debug|x64
|
||||
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Release|x64.ActiveCfg = Release|x64
|
||||
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Release|x64.Build.0 = Release|x64
|
||||
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Release|x86.ActiveCfg = Release|x64
|
||||
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Debug|x64.Build.0 = Debug|x64
|
||||
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Release|x64.ActiveCfg = Release|x64
|
||||
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Release|x64.Build.0 = Release|x64
|
||||
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Release|x86.ActiveCfg = Release|x64
|
||||
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Debug|x64.Build.0 = Debug|x64
|
||||
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Release|x64.ActiveCfg = Release|x64
|
||||
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Release|x64.Build.0 = Release|x64
|
||||
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Release|x86.ActiveCfg = Release|x64
|
||||
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Debug|x64.Build.0 = Debug|x64
|
||||
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Release|x64.ActiveCfg = Release|x64
|
||||
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Release|x64.Build.0 = Release|x64
|
||||
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Release|x86.ActiveCfg = Release|x64
|
||||
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Debug|x64.Build.0 = Debug|x64
|
||||
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Release|x64.ActiveCfg = Release|x64
|
||||
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Release|x64.Build.0 = Release|x64
|
||||
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Release|x86.ActiveCfg = Release|x64
|
||||
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Debug|x64.Build.0 = Debug|x64
|
||||
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Release|x64.ActiveCfg = Release|x64
|
||||
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Release|x64.Build.0 = Release|x64
|
||||
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Release|x86.ActiveCfg = Release|x64
|
||||
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Debug|x64.Build.0 = Debug|x64
|
||||
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Release|x64.ActiveCfg = Release|x64
|
||||
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Release|x64.Build.0 = Release|x64
|
||||
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Release|x86.ActiveCfg = Release|x64
|
||||
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Debug|x64.Build.0 = Debug|x64
|
||||
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Release|x64.ActiveCfg = Release|x64
|
||||
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Release|x64.Build.0 = Release|x64
|
||||
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Release|x86.ActiveCfg = Release|x64
|
||||
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|x64.Build.0 = Debug|x64
|
||||
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Release|x64.ActiveCfg = Release|x64
|
||||
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Release|x64.Build.0 = Release|x64
|
||||
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Release|x86.ActiveCfg = Release|x64
|
||||
{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Debug|x64.Build.0 = Debug|x64
|
||||
{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Release|x64.ActiveCfg = Release|x64
|
||||
{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Release|x64.Build.0 = Release|x64
|
||||
{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Release|x86.ActiveCfg = Release|x64
|
||||
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Debug|x64.Build.0 = Debug|x64
|
||||
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Release|x64.ActiveCfg = Release|x64
|
||||
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Release|x64.Build.0 = Release|x64
|
||||
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Release|x86.ActiveCfg = Release|x64
|
||||
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Debug|x64.Build.0 = Debug|x64
|
||||
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Release|x64.ActiveCfg = Release|x64
|
||||
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Release|x64.Build.0 = Release|x64
|
||||
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Release|x86.ActiveCfg = Release|x64
|
||||
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Debug|x64.Build.0 = Debug|x64
|
||||
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Release|x64.ActiveCfg = Release|x64
|
||||
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Release|x64.Build.0 = Release|x64
|
||||
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Release|x86.ActiveCfg = Release|x64
|
||||
{6955446D-23F7-4023-9BB3-8657F904AF99}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6955446D-23F7-4023-9BB3-8657F904AF99}.Debug|x64.Build.0 = Debug|x64
|
||||
{6955446D-23F7-4023-9BB3-8657F904AF99}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{6955446D-23F7-4023-9BB3-8657F904AF99}.Release|x64.ActiveCfg = Release|x64
|
||||
{6955446D-23F7-4023-9BB3-8657F904AF99}.Release|x64.Build.0 = Release|x64
|
||||
{6955446D-23F7-4023-9BB3-8657F904AF99}.Release|x86.ActiveCfg = Release|x64
|
||||
{58736667-1027-4AD7-BFDF-7A3A6474103A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{58736667-1027-4AD7-BFDF-7A3A6474103A}.Debug|x64.Build.0 = Debug|x64
|
||||
{58736667-1027-4AD7-BFDF-7A3A6474103A}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{58736667-1027-4AD7-BFDF-7A3A6474103A}.Release|x64.ActiveCfg = Release|x64
|
||||
{58736667-1027-4AD7-BFDF-7A3A6474103A}.Release|x64.Build.0 = Release|x64
|
||||
{58736667-1027-4AD7-BFDF-7A3A6474103A}.Release|x86.ActiveCfg = Release|x64
|
||||
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Debug|x64.Build.0 = Debug|x64
|
||||
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Release|x64.ActiveCfg = Release|x64
|
||||
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Release|x64.Build.0 = Release|x64
|
||||
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Release|x86.ActiveCfg = Release|x64
|
||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Debug|x64.Build.0 = Debug|x64
|
||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Release|x64.ActiveCfg = Release|x64
|
||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Release|x64.Build.0 = Release|x64
|
||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Release|x86.ActiveCfg = Release|x64
|
||||
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Debug|x64.Build.0 = Debug|x64
|
||||
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Release|x64.ActiveCfg = Release|x64
|
||||
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Release|x64.Build.0 = Release|x64
|
||||
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Release|x86.ActiveCfg = Release|x64
|
||||
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Debug|x64.Build.0 = Debug|x64
|
||||
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Release|x64.ActiveCfg = Release|x64
|
||||
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Release|x64.Build.0 = Release|x64
|
||||
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Release|x86.ActiveCfg = Release|x64
|
||||
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Debug|x64.Build.0 = Debug|x64
|
||||
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Release|x64.ActiveCfg = Release|x64
|
||||
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Release|x64.Build.0 = Release|x64
|
||||
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Release|x86.ActiveCfg = Release|x64
|
||||
{CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Debug|x64.Build.0 = Debug|x64
|
||||
{CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Release|x64.ActiveCfg = Release|x64
|
||||
{CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Release|x64.Build.0 = Release|x64
|
||||
{CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Release|x86.ActiveCfg = Release|x64
|
||||
{98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Debug|x64.Build.0 = Debug|x64
|
||||
{98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Release|x64.ActiveCfg = Release|x64
|
||||
{98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Release|x64.Build.0 = Release|x64
|
||||
{98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Release|x86.ActiveCfg = Release|x64
|
||||
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Debug|x64.Build.0 = Debug|x64
|
||||
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Release|x64.ActiveCfg = Release|x64
|
||||
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Release|x64.Build.0 = Release|x64
|
||||
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Release|x86.ActiveCfg = Release|x64
|
||||
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Debug|x64.Build.0 = Debug|x64
|
||||
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Release|x64.ActiveCfg = Release|x64
|
||||
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Release|x64.Build.0 = Release|x64
|
||||
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Release|x86.ActiveCfg = Release|x64
|
||||
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Debug|x64.Build.0 = Debug|x64
|
||||
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Release|x64.ActiveCfg = Release|x64
|
||||
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Release|x64.Build.0 = Release|x64
|
||||
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Release|x86.ActiveCfg = Release|x64
|
||||
{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Debug|x64.Build.0 = Debug|x64
|
||||
{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Release|x64.ActiveCfg = Release|x64
|
||||
{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Release|x64.Build.0 = Release|x64
|
||||
{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Release|x86.ActiveCfg = Release|x64
|
||||
{BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Debug|x64.Build.0 = Debug|x64
|
||||
{BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Release|x64.ActiveCfg = Release|x64
|
||||
{BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Release|x64.Build.0 = Release|x64
|
||||
{BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Release|x86.ActiveCfg = Release|x64
|
||||
{E496B7FC-1E99-4BAB-849B-0E8367040B02}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E496B7FC-1E99-4BAB-849B-0E8367040B02}.Debug|x64.Build.0 = Debug|x64
|
||||
{E496B7FC-1E99-4BAB-849B-0E8367040B02}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{E496B7FC-1E99-4BAB-849B-0E8367040B02}.Release|x64.ActiveCfg = Release|x64
|
||||
{E496B7FC-1E99-4BAB-849B-0E8367040B02}.Release|x64.Build.0 = Release|x64
|
||||
{E496B7FC-1E99-4BAB-849B-0E8367040B02}.Release|x86.ActiveCfg = Release|x64
|
||||
{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Debug|x64.Build.0 = Debug|x64
|
||||
{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Release|x64.ActiveCfg = Release|x64
|
||||
{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Release|x64.Build.0 = Release|x64
|
||||
{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Release|x86.ActiveCfg = Release|x64
|
||||
{8DF78B53-200E-451F-9328-01EB907193AE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8DF78B53-200E-451F-9328-01EB907193AE}.Debug|x64.Build.0 = Debug|x64
|
||||
{8DF78B53-200E-451F-9328-01EB907193AE}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{8DF78B53-200E-451F-9328-01EB907193AE}.Release|x64.ActiveCfg = Release|x64
|
||||
{8DF78B53-200E-451F-9328-01EB907193AE}.Release|x64.Build.0 = Release|x64
|
||||
{8DF78B53-200E-451F-9328-01EB907193AE}.Release|x86.ActiveCfg = Release|x64
|
||||
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Debug|x64.Build.0 = Debug|x64
|
||||
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Release|x64.ActiveCfg = Release|x64
|
||||
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Release|x64.Build.0 = Release|x64
|
||||
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Release|x86.ActiveCfg = Release|x64
|
||||
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Debug|x64.Build.0 = Debug|x64
|
||||
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Release|x64.ActiveCfg = Release|x64
|
||||
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Release|x64.Build.0 = Release|x64
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Debug|x64.Build.0 = Debug|x64
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Release|x64.ActiveCfg = Release|x64
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Release|x64.Build.0 = Release|x64
|
||||
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Release|x86.ActiveCfg = Release|x64
|
||||
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Debug|x64.Build.0 = Debug|x64
|
||||
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Release|x64.ActiveCfg = Release|x64
|
||||
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Release|x64.Build.0 = Release|x64
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Debug|x64.Build.0 = Debug|x64
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Release|x64.ActiveCfg = Release|x64
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Release|x64.Build.0 = Release|x64
|
||||
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Release|x86.ActiveCfg = Release|x64
|
||||
{D940E07F-532C-4FF3-883F-790DA014F19A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D940E07F-532C-4FF3-883F-790DA014F19A}.Debug|x64.Build.0 = Debug|x64
|
||||
{D940E07F-532C-4FF3-883F-790DA014F19A}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x64.ActiveCfg = Release|x64
|
||||
{D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x64.Build.0 = Release|x64
|
||||
{D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x86.ActiveCfg = Release|x64
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Debug|x64.Build.0 = Debug|x64
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Release|x64.ActiveCfg = Release|x64
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Release|x64.Build.0 = Release|x64
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Release|x86.ActiveCfg = Release|x64
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Debug|x64.Build.0 = Debug|x64
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Release|x64.ActiveCfg = Release|x64
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Release|x64.Build.0 = Release|x64
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Release|x86.ActiveCfg = Release|x64
|
||||
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Debug|x64.Build.0 = Debug|x64
|
||||
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Release|x64.ActiveCfg = Release|x64
|
||||
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Release|x64.Build.0 = Release|x64
|
||||
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Release|x86.ActiveCfg = Release|x64
|
||||
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Debug|x64.Build.0 = Debug|x64
|
||||
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Release|x64.ActiveCfg = Release|x64
|
||||
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Release|x64.Build.0 = Release|x64
|
||||
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Release|x86.ActiveCfg = Release|x64
|
||||
{48804216-2A0E-4168-A6D8-9CD068D14227}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{48804216-2A0E-4168-A6D8-9CD068D14227}.Debug|x64.Build.0 = Debug|x64
|
||||
{48804216-2A0E-4168-A6D8-9CD068D14227}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{48804216-2A0E-4168-A6D8-9CD068D14227}.Release|x64.ActiveCfg = Release|x64
|
||||
{48804216-2A0E-4168-A6D8-9CD068D14227}.Release|x64.Build.0 = Release|x64
|
||||
{390AE700-B55F-4202-91EA-A822EB75B9BD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{390AE700-B55F-4202-91EA-A822EB75B9BD}.Debug|x64.Build.0 = Debug|x64
|
||||
{390AE700-B55F-4202-91EA-A822EB75B9BD}.Release|x64.ActiveCfg = Release|x64
|
||||
{390AE700-B55F-4202-91EA-A822EB75B9BD}.Release|x64.Build.0 = Release|x64
|
||||
{48804216-2A0E-4168-A6D8-9CD068D14227}.Release|x86.ActiveCfg = Release|x64
|
||||
{FF1D7936-842A-4BBB-8BEA-E9FE796DE700}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{FF1D7936-842A-4BBB-8BEA-E9FE796DE700}.Debug|x64.Build.0 = Debug|x64
|
||||
{FF1D7936-842A-4BBB-8BEA-E9FE796DE700}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{FF1D7936-842A-4BBB-8BEA-E9FE796DE700}.Release|x64.ActiveCfg = Release|x64
|
||||
{FF1D7936-842A-4BBB-8BEA-E9FE796DE700}.Release|x64.Build.0 = Release|x64
|
||||
{FF1D7936-842A-4BBB-8BEA-E9FE796DE700}.Release|x86.ActiveCfg = Release|x64
|
||||
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Debug|x64.Build.0 = Debug|x64
|
||||
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Release|x64.ActiveCfg = Release|x64
|
||||
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Release|x64.Build.0 = Release|x64
|
||||
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Release|x86.ActiveCfg = Release|x64
|
||||
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Debug|x64.Build.0 = Debug|x64
|
||||
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x64.ActiveCfg = Release|x64
|
||||
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x64.Build.0 = Release|x64
|
||||
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x86.ActiveCfg = Release|x64
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|x64.Build.0 = Debug|x64
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|x86.Build.0 = Debug|Win32
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x64.ActiveCfg = Release|x64
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x64.Build.0 = Release|x64
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x86.ActiveCfg = Release|Win32
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x86.Build.0 = Release|Win32
|
||||
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Debug|x64.Build.0 = Debug|x64
|
||||
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Release|x64.ActiveCfg = Release|x64
|
||||
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Release|x64.Build.0 = Release|x64
|
||||
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Release|x86.ActiveCfg = Release|x64
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|x64.Build.0 = Debug|x64
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|x86.Build.0 = Debug|Win32
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x64.ActiveCfg = Release|x64
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x64.Build.0 = Release|x64
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x86.ActiveCfg = Release|Win32
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -809,16 +1029,20 @@ Global
|
||||
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
|
||||
{62173D9A-6724-4C00-A1C8-FB646480A9EC} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
|
||||
{127F38E0-40AA-4594-B955-5616BF206882} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A} = {127F38E0-40AA-4594-B955-5616BF206882}
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{D940E07F-532C-4FF3-883F-790DA014F19A} = {127F38E0-40AA-4594-B955-5616BF206882}
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{106CBECA-0701-4FC3-838C-9DF816A19AE2} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81} = {106CBECA-0701-4FC3-838C-9DF816A19AE2}
|
||||
{2EDB3EB4-FA92-4BFF-B2D8-566584837231} = {106CBECA-0701-4FC3-838C-9DF816A19AE2}
|
||||
{48804216-2A0E-4168-A6D8-9CD068D14227} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{390AE700-B55F-4202-91EA-A822EB75B9BD} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{FF1D7936-842A-4BBB-8BEA-E9FE796DE700} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{5043CECE-E6A7-4867-9CBE-02D27D83747A} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A} = {470FBAF9-E1F8-4F3E-8786-198A1C81C8A8}
|
||||
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB} = {470FBAF9-E1F8-4F3E-8786-198A1C81C8A8}
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042} = {470FBAF9-E1F8-4F3E-8786-198A1C81C8A8}
|
||||
{470FBAF9-E1F8-4F3E-8786-198A1C81C8A8} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
||||
102
README.md
102
README.md
@@ -16,23 +16,24 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
|
||||
|
||||
| | Current utilities: | |
|
||||
|--------------|--------------------|--------------|
|
||||
| [Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) | [FancyZones](https://aka.ms/PowerToysOverview_FancyZones) | [File Explorer Add-ons](https://aka.ms/PowerToysOverview_FileExplorerAddOns) |
|
||||
| [Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) | [Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) | [PowerRename](https://aka.ms/PowerToysOverview_PowerRename) |
|
||||
| [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) | [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) | [Video Conference Mute (Experimental)](https://aka.ms/PowerToysOverview_VideoConference) |
|
||||
| Awake (Coming soon in 0.39) | | |
|
||||
| [Awake](https://aka.ms/PowerToysOverview_Awake) | [Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) | [FancyZones](https://aka.ms/PowerToysOverview_FancyZones) |
|
||||
| [File Explorer Add-ons](https://aka.ms/PowerToysOverview_FileExplorerAddOns) | [Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) | [Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) |
|
||||
| [PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) | [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) |
|
||||
| [Video Conference Mute (Experimental)](https://aka.ms/PowerToysOverview_VideoConference) | | |
|
||||
|
||||
## Installing and running Microsoft PowerToys
|
||||
|
||||
### Requirements
|
||||
|
||||
- Windows 10 v1903 (build 18362) or newer.
|
||||
- ⚠️ PowerToys minimum version of Windows 10 is v1903 starting with the 0.37 release
|
||||
- Have [.NET Core 3.1.14 Desktop Runtime](https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-desktop-3.1.14-windows-x64-installer). The installer should handle this but we want to directly make people aware.
|
||||
- ⚠️ PowerToys (v0.37.0 and newer) requires Windows 10 v1903 (18362) or newer.
|
||||
- Have [.NET Core 3.1.15 Desktop Runtime](https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-desktop-3.1.15-windows-x64-installer). The installer should handle this but we want to directly make people aware.
|
||||
|
||||
### Via GitHub with EXE [Recommended]
|
||||
|
||||
#### Stable version
|
||||
|
||||
Install from the [Microsoft PowerToys GitHub releases page][github-release-link]. Click on `Assets` to show the files available in the release and then click on `PowerToysSetup-0.37.2-x64.exe` to download the PowerToys installer.
|
||||
Install from the [Microsoft PowerToys GitHub releases page][github-release-link]. Click on `Assets` to show the files available in the release and then click on `PowerToysSetup-0.41.2-x64.exe` to download the PowerToys installer.
|
||||
|
||||
This is our preferred method.
|
||||
|
||||
@@ -74,78 +75,71 @@ For guidance on developing for PowerToys, please read the [developer docs](/doc/
|
||||
|
||||
Our [prioritized roadmap][roadmap] of features and utilities that the core team is focusing on.
|
||||
|
||||
### 0.39 - May 2021 Update
|
||||
### 0.41 - June 2021 Update
|
||||
|
||||
The PowerToys team is delaying our 0.39 release. We learned a lot but items took longer than expected. We have more we want done before the next release. This longer time will allow us to get in more amazing pull requests by you, the community, to add / improve functionality
|
||||
Our goals for [v0.39 release cycle](https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F20) and [v0.41 release cycle](https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F21) cycle included stability updates and optimizations, general bug fixes, accessibility improvements, and supporting the integration of the new community led project, Awake, which allows Power-Users to now keep their computer awake on demand!
|
||||
|
||||
### 0.37 - April 2021 Update
|
||||
#### Highlights from v0.39 / v0.41
|
||||
|
||||
Our goals for [v0.37 release cycle](https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F19) Video Conference Mute work so we can bring it into the stable branch, general bug fixes, moving Keyboard manager out, and removing the legacy settings app.
|
||||
|
||||
The 0.36 experimental release was released this month as well which includes Video Conference Mute which is based off the 0.35 code base.
|
||||
|
||||
Our [prioritized roadmap][roadmap] of features and utilities will dictate what the core team is focusing on for the near future.
|
||||
|
||||
#### Highlights from v0.37
|
||||
The PowerToys team delayed our 0.39 release. We decided that we wanted to do more for the next release of PowerToys, so this longer time allowed us to get in more amazing pull requests by you, the community, to add / improve functionality which we merged into 0.41.
|
||||
|
||||
**General**
|
||||
|
||||
- PowerToys now requires Windows 10, version 1903 or higher
|
||||
- FancyZones editor default launching key is <kbd>Win</kbd>+<kbd>Shift</kbd>+<kbd>`</kbd>
|
||||
- Windows Terminal's new Quake mode will use <kbd>Win</kbd>+<kbd>`</kbd>. We feel this is a far better use of the keystroke.
|
||||
- Current PowerToys users can update this in our settings in the FancyZone section.
|
||||
- Removed our v1 HTML based settings system
|
||||
- New Awake utility added! Power-Users can now keep their computer awake on-demand without having to manage its power settings. A huge thank you to [@dend](https://github.com/dend) for driving the development of this feature. Check out complete guidance and getting started info on [Microsoft Docs](https://aka.ms/PowerToysOverview_Awake)
|
||||
- Improved auto-update experience in PowerToys Settings
|
||||
- Improved settings layout for radio button groups. Updated images and menu for OOBE. Thanks [@niels9001](https://github.com/niels9001)!
|
||||
- Updated general bug report information.
|
||||
|
||||
## New Spec - Feedback please!
|
||||
### Color Picker
|
||||
|
||||
- What is new in PowerToys (SCOOBE) - [Pull Request](https://github.com/microsoft/PowerToys/pull/10978)
|
||||
- New fix to prevent the creation of duplicate colors in the selection history. Thanks [@DoctorNefario](https://github.com/DoctorNefario)!
|
||||
- Fixed OOBE hotkey description. Thanks [@coc0a](https://github.com/coc0a)!
|
||||
- Improved editor UX to better support keyboard navigation. Thanks [@niels9001](https://github.com/niels9001)!
|
||||
- Updated Color Picker GIF for OOBE. Thanks [@niels9001](https://github.com/niels9001)!
|
||||
|
||||
### FancyZones
|
||||
- Editor UX bug fixes. Thanks [@niels9001](https://github.com/niels9001)
|
||||
- Monitor resolution is added to the top to directly infer the boxes on top are your monitors
|
||||
- Fix for editor crash when editing a custom layout
|
||||
|
||||
### PowerRename
|
||||
- Option added for capitalization.
|
||||
- Improved loading responsiveness with large sums of files.
|
||||
- Full keyboard support added for the canvas editor’s main window and context. Thanks [@niels9001](https://github.com/niels9001)!
|
||||
- Use `Arrows` to move a zone by 10 pixels or `Ctrl + Arrows` to move the zone by 1 pixel
|
||||
- `Shift + Arrows` to resize a zone by 10 pixels (5 per edge), `Ctrl + Shift + Arrows` to resize a zone by 2 pixels (1 per edge)
|
||||
- `Ctrl + Tab` to switch between the editor and dialog
|
||||
- New support for faster layout selection by double clicking a desired layout from the editor to automatically apply it and dismiss the editor.
|
||||
- New zone activation behavior allows users to snap a window to the zone who's center is closest to the cursor. Thanks [@ulazy1](https://github.com/ulazy1)!
|
||||
- Added process icon for FancyZones.
|
||||
- Fixed issue with zoning minimized windows.
|
||||
- Fixed a bunch of accessibility bugs
|
||||
- Now an independent exe, detached from the runner process.
|
||||
|
||||
### Image Resizer
|
||||
|
||||
- Fixed bug where specifying a width but no height generated a 1x1 px image instead of auto-adjusting the height. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
|
||||
### PowerToys Run
|
||||
- Changed XAML to improve rendering. Thanks [@niels9001](https://github.com/niels9001)
|
||||
- Disabled plugins are no longer loaded
|
||||
- VS Code plugin workspaces showing up now. Thanks [@ricardosantos9521](https://github.com/ricardosantos9521)
|
||||
|
||||
### Keyboard manager
|
||||
- Now an independent exe. This now runs high priority in its own process. When your CPU is under load, this should allow the process to continue to be prioritized
|
||||
- Multiple crashing bugs resolved.
|
||||
- New Unit Converter plugin! Activate in the query prompt with the default activation phrase `%%`. Ex: `%% 10 ft in m`. Thanks [@jsoref](https://github.com/jsoref) and [@ThiefZero](https://github.com/ThiefZero)!
|
||||
- New Windows Settings plugin! Search for specific Windows settings from PowerToys Run by utilizing the default activation phrase `$` followed by the desired setting. Ex: `$ Add/Remove Programs` To list all settings of an area category, type `:` after the category name. Ex: `$ Device:`. Thanks [@TobiasSekan](https://github.com/TobiasSekan) and [@htcfreek](https://github.com/htcfreek).
|
||||
- Updated the URL plugin to enable quickly launching the default browser with the action keyword, which defaults to `//`.
|
||||
- Added remainder/modulo support for Calculator plugin via `%` operator.
|
||||
- Faster launching from improved Win32 program indexing. Thanks [@royvou](https://github.com/royvou)!
|
||||
- Search text results now highlight matched characters from input. Thanks [@niels9001](https://github.com/niels9001)!
|
||||
|
||||
### Color Picker
|
||||
- uses a centralized keyhook. This should improve activation
|
||||
- Esc for closing will no longer bubble through. Thanks [@DoctorNefario](https://github.com/DoctorNefario)
|
||||
### Shortcut Guide
|
||||
|
||||
### Settings / Welcome to PowerToys
|
||||
- Shortcuts will stand out more
|
||||
- Few accessability bugs fixed. Thanks [@niels9001](https://github.com/niels9001)
|
||||
|
||||
### Shortcut Guide
|
||||
- Excluded apps for Shortcut Guide. Thanks [@davidegiacometti ](https://github.com/davidegiacometti)
|
||||
|
||||
### Installer
|
||||
- new arg for starting PT after silent install
|
||||
|
||||
### Developer quality of life
|
||||
- Ability to directly debug against Settings
|
||||
- Now an independent exe, detached from the runner process.
|
||||
- Removed support for long `Win` press to activate Shortcut Guide. Users can now `Win + ?` to launch and new customization settings added for users to define their own shortcut.
|
||||
|
||||
## Community contributions
|
||||
|
||||
We'd like to directly mention (in alphabetical order) for their continued community support this month and helping directly make PowerToys a better piece of software.
|
||||
|
||||
[@Aaron-Junker](https://github.com/Aaron-Junker), [@addrum](https://github.com/addrum), [@davidegiacometti ](https://github.com/davidegiacometti), [@DoctorNefario](https://github.com/DoctorNefario), [@htcfreek](https://github.com/htcfreek), [@Jay-o-Way](https://github.com/Jay-o-Way), [@niels9001](https://github.com/niels9001), and [@ricardosantos9521](https://github.com/ricardosantos9521)
|
||||
[@Aaron-Junker](https://github.com/Aaron-Junker), [@coc0a](https://github.com/coc0a), [@davidegiacometti](https://github.com/davidegiacometti), [@dend](https://github.com/dend), [@DoctorNefario](https://github.com/DoctorNefario), [@dogancelik](https://github.com/dogancelik), [@htcfreek](https://github.com/htcfreek), [@itsme-alan](https://github.com/itsme-alan), [@Jay-o-Way](https://github.com/Jay-o-Way), [@djsoref](https://github.com/jsoref), [@niels9001](https://github.com/niels9001), [@nitroin](https://github.com/nitroin), [@ricardosantos9521](https://github.com/ricardosantos9521), [@ThiefZero](https://github.com/ThiefZero), [@TobiasSekan](https://github.com/TobiasSekan), and [@ulazy1](https://github.com/ulazy1)
|
||||
|
||||
#### What is being planned for v0.39 / 0.41
|
||||
#### What is being planned for v0.43
|
||||
|
||||
For [v0.39 / 0.41][github-next-release-work], we are planning to work on:
|
||||
For [v0.43][github-next-release-work], we are planning to work on:
|
||||
|
||||
- Stability and bug fixes
|
||||
- Moving FancyZones & Shortcutguide out of the main exe
|
||||
- Installer improvements
|
||||
|
||||
## PowerToys Community
|
||||
|
||||
@@ -66,7 +66,12 @@ Various tools used by PowerToys. Includes the Visual Studio 2019 project templat
|
||||
2. Visual Studio Community/Professional/Enterprise 2019
|
||||
3. Once you've cloned and started the `PowerToys.sln`, in the solution explorer, if you see a dialog that says `install extra components`, click `install`
|
||||
|
||||
### Compile source code
|
||||
**Optional step:**<br/>
|
||||
4. to build the Video Conference module, install the [WDK version 1903](https://docs.microsoft.com/en-us/windows-hardware/drivers/other-wdk-downloads) ([direct download link](https://go.microsoft.com/fwlink/?linkid=2085767))<br />
|
||||
During the installation, make sure that, when prompted, the `Install Windows Driver Kit Visual Studio extension` option is checked.
|
||||
|
||||
|
||||
### Compiling Source Code
|
||||
|
||||
- Open `PowerToys.sln` in Visual Studio, in the `Solutions Configuration` drop-down menu select `Release` or `Debug`, from the `Build` menu choose `Build Solution`.
|
||||
- The PowerToys binaries will be in your repo under `x64\Release\`.
|
||||
@@ -82,8 +87,9 @@ The installer can only be compiled in `Release` mode, step 1 and 2 must be done
|
||||
|
||||
1. Compile `PowerToys.sln`. Instructions are listed above.
|
||||
2. Compile `BugReportTool.sln` tool. Path from root: `tools\BugReportTool\BugReportTool.sln` (details listed below)
|
||||
3. Compile `PowerToysSetup.sln` Path from root: `installer\PowerToysSetup.sln` (details listed below)
|
||||
4. Compile `PowerToysBootstrapper.sln` Path from root: `installer\PowerToysBootstrapper\PowerToysBootstrapper.sln` (details listed below)
|
||||
3. Compile `WebcamReportTool.sln` tool. Path from root: `tools\WebcamReportTool\WebcamReportTool.sln` (details listed below)
|
||||
4. Compile `PowerToysSetup.sln` Path from root: `installer\PowerToysSetup.sln` (details listed below)
|
||||
5. Compile `PowerToysBootstrapper.sln` Path from root: `installer\PowerToysBootstrapper\PowerToysBootstrapper.sln` (details listed below)
|
||||
|
||||
### Prerequisites for building the MSI installer
|
||||
|
||||
@@ -93,8 +99,14 @@ The installer can only be compiled in `Release` mode, step 1 and 2 must be done
|
||||
### Locally compiling the Bug reporting tool
|
||||
|
||||
1. Open `tools\BugReportTool\BugReportTool.sln`
|
||||
1. In Visual Studio, in the `Solutions Configuration` drop-down menu select `Release`
|
||||
2. From the `Build` menu, choose `Build Solution`.
|
||||
2. In Visual Studio, in the `Solutions Configuration` drop-down menu select `Release`
|
||||
3. From the `Build` menu, choose `Build Solution`.
|
||||
|
||||
### Locally compiling the Webcam reporting tool
|
||||
|
||||
1. Open `tools\WebcamReportTool\WebcamReportTool.sln`
|
||||
2. In Visual Studio, in the `Solutions Configuration` drop-down menu select `Release`
|
||||
3. From the `Build` menu, choose `Build Solution`.
|
||||
|
||||
### Locally compiling the .MSI installer
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<Import Project="..\packages\WiX.3.11.2\build\wix.props" Condition="Exists('..\packages\WiX.3.11.2\build\wix.props')" />
|
||||
<Import Project="..\..\src\Version.props" />
|
||||
<PropertyGroup>
|
||||
<DefineConstants>Version=$(Version);</DefineConstants>
|
||||
<DefineConstants>Version=$(Version)</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
|
||||
@@ -74,7 +74,6 @@
|
||||
</Target>
|
||||
<PropertyGroup>
|
||||
<PreBuildEvent>IF NOT DEFINED IsPipeline (
|
||||
|
||||
call "$([MSBuild]::GetVsInstallRoot())\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 -winsdk=10.0.18362.0
|
||||
SET PTRoot=..\..\..\..
|
||||
call "..\..\publish.cmd"
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
<?define KeyboardManagerProjectName="KeyboardManager"?>
|
||||
<?define PowerRenameProjectName="PowerRename"?>
|
||||
<?define ColorPickerProjectName="ColorPicker"?>
|
||||
<?define VideoConferenceProjectName="VideoConference"?>
|
||||
<?define AwakeProjectName="Awake"?>
|
||||
|
||||
<?define RepoDir="$(var.ProjectDir)..\..\" ?>
|
||||
<?define BinX32Dir="$(var.RepoDir)x86\$(var.Configuration)\" ?>
|
||||
<?define BinX64Dir="$(var.RepoDir)x64\$(var.Configuration)\" ?>
|
||||
<?define ShortcutGuideExecutable=$(var.BinX64Dir)\modules\ShortcutGuide\ShortcutGuide?>
|
||||
<?define ShortcutGuideModuleInterface=$(var.BinX64Dir)\modules\ShortcutGuide\ShortcutGuideModuleInterface?>
|
||||
@@ -195,7 +197,8 @@
|
||||
/>
|
||||
|
||||
<!-- Close 'PowerToys.exe' before uninstall-->
|
||||
<Property Id="MSIRESTARTMANAGERCONTROL" Value="Disable" />
|
||||
<Property Id="MSIRESTARTMANAGERCONTROL" Value="DisableShutdown" />
|
||||
<Property Id="MSIFASTINSTALL" Value="DisableShutdown" />
|
||||
<util:CloseApplication CloseMessage="yes" Target="PowerToys.exe" ElevatedCloseMessage="yes" RebootPrompt="no" TerminateProcess="0" />
|
||||
</Product>
|
||||
|
||||
@@ -218,6 +221,10 @@
|
||||
</Directory>
|
||||
<Directory Id="ShortcutGuideModuleInterfaceInstallFolder" Name="ShortcutGuideModuleInterface"/>
|
||||
</Directory>
|
||||
<!-- TODO(yuyoyuppe): uncomment when VCM should be enabled -->
|
||||
<!-- <Directory Id="VideoConferenceInstallFolder" Name="$(var.VideoConferenceProjectName)">
|
||||
<Directory Id="VideoConferenceIconsFolder" Name="Icons" />
|
||||
</Directory> -->
|
||||
<Directory Id="FileExplorerPreviewInstallFolder" Name="FileExplorerPreview" />
|
||||
<Directory Id="FancyZonesInstallFolder" Name="$(var.FancyZonesProjectName)" />
|
||||
<Directory Id="AwakeInstallFolder" Name="$(var.AwakeProjectName)">
|
||||
@@ -429,6 +436,8 @@
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.FancyZonesProjectName)\ModernWpf.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.FancyZonesProjectName)\ModernWpf.Controls.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.FancyZonesProjectName)\System.Text.Json.dll" />
|
||||
|
||||
<File Id="FancyZones_interop" Source="$(var.BinX64Dir)modules\$(var.FancyZonesProjectName)\PowerToysInterop.dll" />
|
||||
<File Id="FancyZones_ManagedCommon" Source="$(var.BinX64Dir)modules\$(var.FancyZonesProjectName)\ManagedCommon.dll" />
|
||||
<File Id="FancyZones_Microsoft.PowerToys.Common.UI" Source="$(var.BinX64Dir)modules\$(var.FancyZonesProjectName)\Microsoft.PowerToys.Common.UI.dll" />
|
||||
<File Id="FancyZones_Telemetry.dll" Source="$(var.BinX64Dir)modules\$(var.FancyZonesProjectName)\ManagedTelemetry.dll" />
|
||||
@@ -442,6 +451,9 @@
|
||||
<Component Id="BugReportTool_exe" Guid="0F8E3E9F-2E86-4660-A3BF-AE4DD431B93C" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)BugReportTool\BugReportTool.exe" Id="BugReportTool.exe" KeyPath="yes" Checksum="yes" />
|
||||
</Component>
|
||||
<Component Id="WebcamReportTool_exe" Guid="B6005DAC-8C26-4865-91B3-99F098422C13" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)WebcamReportTool\WebcamReportTool.exe" Id="WebcamReportTool.exe" Checksum="yes" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<DirectoryRef Id="ModulesInstallFolder" FileSource="$(var.BinX64Dir)modules\">
|
||||
@@ -637,6 +649,37 @@
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- TODO(yuyoyuppe): uncomment when VCM should be enabled -->
|
||||
<!-- <DirectoryRef Id="VideoConferenceInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\">
|
||||
<Component Id="Module_VideoConference" Guid="5996527a-40fc-432e-b3ac-abc0b4bd3887" Win64="yes">
|
||||
<Condition>WINDOWSBUILDNUMBER >= 18362</Condition>
|
||||
<File SelfRegCost="1" Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\VideoConferenceProxyFilter_x64.dll" KeyPath="yes">
|
||||
<Class Id="{31AD75E9-8C3A-49C8-B9ED-5880D6B4A764}" Context="InprocServer32" ThreadingModel="apartment" Description="PowerToys VideoConference Mute" />
|
||||
</File>
|
||||
<File SelfRegCost="1" Source="$(var.BinX32Dir)modules\$(var.VideoConferenceProjectName)\VideoConferenceProxyFilter_x86.dll">
|
||||
<Class Id="{31AD75E9-8C3A-49C8-B9ED-5880D6B4A732}" Context="InprocServer32" ThreadingModel="apartment" Description="PowerToys VideoConference Mute" />
|
||||
</File>
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\VideoConferenceModule.dll" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="VideoConferenceIconsFolder" FileSource="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons">
|
||||
<Component Id="Module_VideoConferenceIcons" Guid="5996527a-40fc-432e-b34c-abc0b4bd3887" Win64="yes">
|
||||
<Condition>WINDOWSBUILDNUMBER >= 18362</Condition>
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\Off-NotInUse Dark.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\Off-NotInUse Light.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\Off-Off Dark.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\Off-Off Light.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\Off-On Dark.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\Off-On Light.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\On-NotInUse Dark.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\On-NotInUse Light.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\On-Off Light.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\On-Off Dark.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\On-On Dark.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\On-On Light.png" />
|
||||
</Component>
|
||||
</DirectoryRef> -->
|
||||
|
||||
<DirectoryRef Id="ShortcutGuideExecutableInstallFolder" FileSource="$(var.ShortcutGuideExecutable)">
|
||||
<Component Id="Module_ShortcutGuideExecutable" Guid="DA6E5710-F1DF-44EB-A316-300FA39544E9" Win64="yes">
|
||||
<File Source="$(var.ShortcutGuideExecutable)\PowerToys.ShortcutGuide.exe" KeyPath="yes" />
|
||||
@@ -791,7 +834,7 @@
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="SettingsV2AssetsModulesInstallFolder" FileSource="$(var.BinX64Dir)Settings\Assets\Modules">
|
||||
<Component Id="SettingsV2AssetsModules" Guid="A0B961A9-77D0-4223-88A9-E3B41BD9C329" Win64="yes">
|
||||
<?foreach File in ColorPicker.png;FancyZones.png;Awake.png;ImageResizer.png;KBM.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ShortcutGuide.png?>
|
||||
<?foreach File in ColorPicker.png;FancyZones.png;Awake.png;ImageResizer.png;KBM.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ShortcutGuide.png;VideoConference.png?>
|
||||
<File Id="SettingsV2AssetsModules_$(var.File)" Source="$(var.BinX64Dir)Settings\Assets\Modules\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
@@ -882,6 +925,9 @@
|
||||
<ComponentRef Id="ShortcutGuideSvgs" />
|
||||
<ComponentRef Id="Module_ShortcutGuideModuleInterface" />
|
||||
<ComponentRef Id="Module_ShortcutGuideExecutable" />
|
||||
<!-- TODO(yuyoyuppe): uncomment when VCM should be enabled -->
|
||||
<!-- <ComponentRef Id="Module_VideoConference" />
|
||||
<ComponentRef Id="Module_VideoConferenceIcons" /> -->
|
||||
<ComponentRef Id="Module_FancyZones" />
|
||||
<ComponentRef Id="DesktopShortcut" />
|
||||
<ComponentRef Id="Module_PowerRename" />
|
||||
@@ -911,6 +957,7 @@
|
||||
</ComponentGroup>
|
||||
<ComponentGroup Id="ToolComponents" Directory="ToolsFolder">
|
||||
<ComponentRef Id="BugReportTool_exe" />
|
||||
<ComponentRef Id="WebcamReportTool_exe" />
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ TRACELOGGING_DEFINE_PROVIDER(
|
||||
const DWORD USERNAME_DOMAIN_LEN = DNLEN + UNLEN + 2; // Domain Name + '\' + User Name + '\0'
|
||||
const DWORD USERNAME_LEN = UNLEN + 1; // User Name + '\0'
|
||||
|
||||
static const wchar_t* POWERTOYS_EXE_COMPONENT = L"{A2C66D91-3485-4D00-B04D-91844E6B345B}";
|
||||
static const wchar_t* POWERTOYS_UPGRADE_CODE = L"{42B84BF7-5FBF-473B-9C8B-049DC16F7708}";
|
||||
|
||||
// Creates a Scheduled Task to run at logon for the current user.
|
||||
@@ -596,6 +597,165 @@ UINT __stdcall DetectPrevInstallPathCA(MSIHANDLE hInstall)
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall CertifyVirtualCameraDriverCA(MSIHANDLE hInstall)
|
||||
{
|
||||
#ifdef CIBuild // On pipeline we are using microsoft certification
|
||||
WcaInitialize(hInstall, "CertifyVirtualCameraDriverCA");
|
||||
return WcaFinalize(ERROR_SUCCESS);
|
||||
#else
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
LPWSTR certificatePath = nullptr;
|
||||
HCERTSTORE hCertStore = nullptr;
|
||||
HANDLE hfile = nullptr;
|
||||
DWORD size = INVALID_FILE_SIZE;
|
||||
char * pFileContent = nullptr;
|
||||
|
||||
hr = WcaInitialize(hInstall, "CertifyVirtualCameraDriverCA");
|
||||
ExitOnFailure(hr, "Failed to initialize", hr);
|
||||
|
||||
hr = WcaGetProperty(L"CustomActionData", &certificatePath);
|
||||
ExitOnFailure(hr, "Failed to get install preperty", hr);
|
||||
|
||||
hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"AuthRoot");
|
||||
if (!hCertStore)
|
||||
{
|
||||
hr = GetLastError();
|
||||
ExitOnFailure(hr, "Cannot put principal run level: %x", hr);
|
||||
}
|
||||
|
||||
hfile = CreateFile(certificatePath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (hfile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
hr = GetLastError();
|
||||
ExitOnFailure(hr, "Certificate file open failed", hr);
|
||||
}
|
||||
|
||||
size = GetFileSize(hfile, nullptr);
|
||||
if (size == INVALID_FILE_SIZE)
|
||||
{
|
||||
hr = GetLastError();
|
||||
ExitOnFailure(hr, "Certificate file size not valid", hr);
|
||||
}
|
||||
|
||||
pFileContent = (char*)malloc(size);
|
||||
|
||||
DWORD sizeread;
|
||||
if (!ReadFile(hfile, pFileContent, size, &sizeread, nullptr))
|
||||
{
|
||||
hr = GetLastError();
|
||||
ExitOnFailure(hr, "Certificate file read failed", hr);
|
||||
}
|
||||
|
||||
if (!CertAddEncodedCertificateToStore(hCertStore,
|
||||
X509_ASN_ENCODING,
|
||||
(const BYTE*)pFileContent,
|
||||
size,
|
||||
CERT_STORE_ADD_ALWAYS,
|
||||
nullptr))
|
||||
{
|
||||
hr = GetLastError();
|
||||
ExitOnFailure(hr, "Adding certificate failed", hr);
|
||||
}
|
||||
|
||||
free(pFileContent);
|
||||
|
||||
LExit:
|
||||
ReleaseStr(certificatePath);
|
||||
if (hCertStore)
|
||||
{
|
||||
CertCloseStore(hCertStore, 0);
|
||||
}
|
||||
if (hfile)
|
||||
{
|
||||
CloseHandle(hfile);
|
||||
}
|
||||
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
PMSIHANDLE hRecord = MsiCreateRecord(0);
|
||||
MsiRecordSetString(hRecord, 0, TEXT("Failed to add certificate to store"));
|
||||
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_WARNING + MB_OK), hRecord);
|
||||
}
|
||||
|
||||
|
||||
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
|
||||
return WcaFinalize(er);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
UINT __stdcall InstallVirtualCameraDriverCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
LPWSTR driverPath = nullptr;
|
||||
|
||||
hr = WcaInitialize(hInstall, "InstallVirtualCameraDriverCA");
|
||||
ExitOnFailure(hr, "Failed to initialize");
|
||||
|
||||
hr = WcaGetProperty(L"CustomActionData", &driverPath);
|
||||
ExitOnFailure(hr, "Failed to get install preperty");
|
||||
|
||||
BOOL requiresReboot;
|
||||
DiInstallDriverW(GetConsoleWindow(), driverPath, DIIRFLAG_FORCE_INF, &requiresReboot);
|
||||
|
||||
hr = GetLastError();
|
||||
ExitOnFailure(hr, "Failed to install driver");
|
||||
|
||||
LExit:
|
||||
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
PMSIHANDLE hRecord = MsiCreateRecord(0);
|
||||
MsiRecordSetString(hRecord, 0, TEXT("Failed to install virtual camera driver"));
|
||||
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_WARNING + MB_OK), hRecord);
|
||||
}
|
||||
|
||||
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall UninstallVirtualCameraDriverCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
LPWSTR driverPath = nullptr;
|
||||
|
||||
hr = WcaInitialize(hInstall, "UninstallVirtualCameraDriverCA");
|
||||
ExitOnFailure(hr, "Failed to initialize");
|
||||
|
||||
hr = WcaGetProperty(L"CustomActionData", &driverPath);
|
||||
ExitOnFailure(hr, "Failed to get uninstall preperty");
|
||||
|
||||
BOOL requiresReboot;
|
||||
DiUninstallDriverW(GetConsoleWindow(), driverPath, 0, &requiresReboot);
|
||||
|
||||
switch (GetLastError())
|
||||
{
|
||||
case ERROR_ACCESS_DENIED:
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
case ERROR_INVALID_FLAGS:
|
||||
case ERROR_IN_WOW64:
|
||||
{
|
||||
hr = GetLastError();
|
||||
ExitOnFailure(hr, "Failed to uninstall driver");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LExit:
|
||||
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
PMSIHANDLE hRecord = MsiCreateRecord(0);
|
||||
MsiRecordSetString(hRecord, 0, TEXT("Filed to iminstall virtual camera driver"));
|
||||
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_WARNING + MB_OK), hRecord);
|
||||
}
|
||||
|
||||
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
|
||||
{
|
||||
@@ -614,10 +774,14 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
|
||||
}
|
||||
processes.resize(bytes / sizeof(processes[0]));
|
||||
|
||||
std::array<std::wstring_view, 4> processesToTerminate = {
|
||||
std::array<std::wstring_view, 8> processesToTerminate = {
|
||||
L"PowerLauncher.exe",
|
||||
L"PowerToys.Settings.exe",
|
||||
L"PowerToys.Awake.exe",
|
||||
L"PowerToys.FancyZones.exe",
|
||||
L"Microsoft.PowerToys.Settings.UI.exe",
|
||||
L"FancyZonesEditor.exe",
|
||||
L"ColorPickerUI.exe",
|
||||
L"PowerToys.exe"
|
||||
};
|
||||
|
||||
|
||||
@@ -12,4 +12,8 @@ EXPORTS
|
||||
TelemetryLogUninstallFailCA
|
||||
TelemetryLogRepairCancelCA
|
||||
TelemetryLogRepairFailCA
|
||||
TerminateProcessesCA
|
||||
TerminateProcessesCA
|
||||
TerminateProcessesCA
|
||||
CertifyVirtualCameraDriverCA
|
||||
InstallVirtualCameraDriverCA
|
||||
UninstallVirtualCameraDriverCA
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalLibraryDirectories>$(WIX)sdk\$(WixPlatformToolset)\lib\x64;$(SolutionDir)\packages\WiX.3.11.2\tools\sdk\vs2017\lib\x64;..\..\$(PlatformShortName)\$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>msi.lib;wcautil.lib;Psapi.lib;Pathcch.lib;comsupp.lib;taskschd.lib;Secur32.lib;msi.lib;dutil.lib;wcautil.lib;Version.lib;ApplicationUpdate.lib;Notifications.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Newdev.lib;Crypt32.lib;msi.lib;wcautil.lib;Psapi.lib;Pathcch.lib;comsupp.lib;taskschd.lib;Secur32.lib;msi.lib;dutil.lib;wcautil.lib;Version.lib;ApplicationUpdate.lib;Notifications.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@@ -124,4 +124,4 @@
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\WiX.3.11.2\build\wix.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\WiX.3.11.2\build\wix.props'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#define DPSAPI_VERSION 1
|
||||
// Windows Header Files:
|
||||
#include <windows.h>
|
||||
#include <newdev.h>
|
||||
#include <strsafe.h>
|
||||
#include <msiquery.h>
|
||||
#include <Msi.h>
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
|
||||
#include <thread>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
class FileWatcher
|
||||
{
|
||||
@@ -28,10 +28,12 @@
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="settings_helpers.h" />
|
||||
<ClInclude Include="settings_objects.h" />
|
||||
<ClInclude Include="FileWatcher.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="settings_helpers.cpp" />
|
||||
<ClCompile Include="settings_objects.cpp" />
|
||||
<ClCompile Include="FileWatcher.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace PTSettingsHelper
|
||||
{
|
||||
constexpr inline const wchar_t* log_settings_filename = L"log_settings.json";
|
||||
|
||||
std::wstring get_powertoys_general_save_file_location();
|
||||
std::wstring get_module_save_file_location(std::wstring_view powertoy_key);
|
||||
std::wstring get_module_save_folder_location(std::wstring_view powertoy_name);
|
||||
std::wstring get_root_save_folder_location();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <TraceLoggingProvider.h>
|
||||
#include <TraceLoggingDefines.h>
|
||||
#include "TraceLoggingProvider.h"
|
||||
#include "TraceLoggingDefines.h"
|
||||
|
||||
TRACELOGGING_DECLARE_PROVIDER(g_hProvider);
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>PowerToysInterop;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)src\common\interop;../../;../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<OmitDefaultLibName>false</OmitDefaultLibName>
|
||||
@@ -83,6 +84,8 @@
|
||||
<WriteLinesToFile File="Generated Files\AssemblyInfo.cpp" Lines="@(HeaderLines)" Overwrite="true" Encoding="Unicode" WriteOnlyWhenDifferent="true" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\modules\videoconference\VideoConferenceShared\MicrophoneDevice.h" />
|
||||
<ClInclude Include="..\..\modules\videoconference\VideoConferenceShared\VideoCaptureDeviceList.h" />
|
||||
<ClInclude Include="HotkeyManager.h" />
|
||||
<ClInclude Include="KeyboardHook.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
@@ -90,6 +93,12 @@
|
||||
<ClInclude Include="shared_constants.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\modules\videoconference\VideoConferenceShared\MicrophoneDevice.cpp">
|
||||
<CompileAsManaged>false</CompileAsManaged>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\videoconference\VideoConferenceShared\VideoCaptureDeviceList.cpp">
|
||||
<CompileAsManaged>false</CompileAsManaged>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Generated Files\AssemblyInfo.cpp" />
|
||||
<ClCompile Include="HotkeyManager.cpp" />
|
||||
<ClCompile Include="interop.cpp" />
|
||||
@@ -109,6 +118,12 @@
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200902.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200902.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
</ImportGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
||||
@@ -27,7 +27,13 @@
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="shared_constants.h">
|
||||
<ClInclude Include="..\..\modules\videoconference\VideoConferenceShared\MicrophoneDevice.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\videoconference\VideoConferenceShared\VideoCaptureDeviceList.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="shared_constants.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
@@ -50,10 +56,16 @@
|
||||
<ClCompile Include="keyboard_layout.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\videoconference\VideoConferenceShared\MicrophoneDevice.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\videoconference\VideoConferenceShared\VideoCaptureDeviceList.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="interop.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -13,12 +13,17 @@
|
||||
// Therefore the simplest way is to compile these functions as native using the pragmas below.
|
||||
#pragma managed(push, off)
|
||||
#include "../utils/os-detect.h"
|
||||
// TODO: move to a separate library in common
|
||||
#include "../../modules/videoconference/VideoConferenceShared/MicrophoneDevice.h"
|
||||
#include "../../modules/videoconference/VideoConferenceShared/VideoCaptureDeviceList.h"
|
||||
#pragma managed(pop)
|
||||
|
||||
#include <common/version/version.h>
|
||||
|
||||
|
||||
using namespace System;
|
||||
using namespace System::Runtime::InteropServices;
|
||||
using System::Collections::Generic::List;
|
||||
|
||||
// https://docs.microsoft.com/en-us/cpp/dotnet/how-to-wrap-native-class-for-use-by-csharp?view=vs-2019
|
||||
namespace interop
|
||||
@@ -122,6 +127,32 @@ public
|
||||
static String ^ GetProductVersion() {
|
||||
return gcnew String(get_product_version().c_str());
|
||||
}
|
||||
|
||||
static List<String ^> ^ GetAllActiveMicrophoneDeviceNames() {
|
||||
auto names = gcnew List<String ^>();
|
||||
for (const auto& device : MicrophoneDevice::getAllActive())
|
||||
{
|
||||
names->Add(gcnew String(device.name().data()));
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
static List<String ^> ^
|
||||
GetAllVideoCaptureDeviceNames() {
|
||||
auto names = gcnew List<String ^>();
|
||||
VideoCaptureDeviceList vcdl;
|
||||
vcdl.EnumerateDevices();
|
||||
|
||||
for (UINT32 i = 0; i < vcdl.Count(); ++i)
|
||||
{
|
||||
auto name = gcnew String(vcdl.GetDeviceName(i).data());
|
||||
if (name != L"PowerToys VideoConference Mute")
|
||||
{
|
||||
names->Add(name);
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
};
|
||||
|
||||
public
|
||||
@@ -148,6 +179,10 @@ public
|
||||
return gcnew String(CommonSharedConstants::RUN_EXIT_EVENT);
|
||||
}
|
||||
|
||||
static String ^ FZEExitEvent() {
|
||||
return gcnew String(CommonSharedConstants::FZE_EXIT_EVENT);
|
||||
}
|
||||
|
||||
static String ^ ColorPickerSendSettingsTelemetryEvent() {
|
||||
return gcnew String(CommonSharedConstants::COLOR_PICKER_SEND_SETTINGS_TELEMETRY_EVENT);
|
||||
}
|
||||
@@ -155,5 +190,9 @@ public
|
||||
static String ^ ShowColorPickerSharedEvent() {
|
||||
return gcnew String(CommonSharedConstants::SHOW_COLOR_PICKER_SHARED_EVENT);
|
||||
}
|
||||
|
||||
static String ^ AwakeExitEvent() {
|
||||
return gcnew String(CommonSharedConstants::AWAKE_EXIT_EVENT);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
4
src/common/interop/packages.config
Normal file
4
src/common/interop/packages.config
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.200902.2" targetFramework="native" />
|
||||
</packages>
|
||||
@@ -18,6 +18,8 @@ namespace CommonSharedConstants
|
||||
const wchar_t RUN_SEND_SETTINGS_TELEMETRY_EVENT[] = L"Local\\PowerToysRunInvokeEvent-638ec522-0018-4b96-837d-6bd88e06f0d6";
|
||||
|
||||
const wchar_t RUN_EXIT_EVENT[] = L"Local\\PowerToysRunExitEvent-3e38e49d-a762-4ef1-88f2-fd4bc7481516";
|
||||
|
||||
const wchar_t FZE_EXIT_EVENT[] = L"Local\\PowerToys-FZE-ExitEvent-ca8c73de-a52c-4274-b691-46e9592d3b43";
|
||||
|
||||
const wchar_t COLOR_PICKER_SEND_SETTINGS_TELEMETRY_EVENT[] = L"Local\\ColorPickerSettingsTelemetryEvent-6c7071d8-4014-46ec-b687-913bd8a422f1";
|
||||
|
||||
@@ -28,6 +30,9 @@ namespace CommonSharedConstants
|
||||
|
||||
const wchar_t FANCY_ZONES_EDITOR_TOGGLE_EVENT[] = L"Local\\FancyZones-ToggleEditorEvent-1e174338-06a3-472b-874d-073b21c62f14";
|
||||
|
||||
// Path to the event used by Awake
|
||||
const wchar_t AWAKE_EXIT_EVENT[] = L"Local\\PowerToysAwakeExitEvent-c0d5e305-35fc-4fb5-83ec-f6070cfaf7fe";
|
||||
|
||||
// Max DWORD for key code to disable keys.
|
||||
const DWORD VK_DISABLED = 0x100;
|
||||
}
|
||||
|
||||
@@ -307,25 +307,17 @@ inline bool run_non_elevated(const std::wstring& file, const std::wstring& param
|
||||
|
||||
inline bool RunNonElevatedEx(const std::wstring& file, const std::wstring& params)
|
||||
{
|
||||
bool failedToStart = false;
|
||||
try
|
||||
{
|
||||
CoInitialize(nullptr);
|
||||
if (!ShellExecuteFromExplorer(file.c_str(), params.c_str()))
|
||||
{
|
||||
failedToStart = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
failedToStart = true;
|
||||
}
|
||||
|
||||
if (failedToStart)
|
||||
{
|
||||
Logger::warn(L"Failed to delegate process creation. Try a fallback");
|
||||
DWORD returnPid;
|
||||
return run_non_elevated(file, params, &returnPid);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <shlwapi.h>
|
||||
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
// Get the executable path or module name for modern apps
|
||||
inline std::wstring get_process_path(DWORD pid) noexcept
|
||||
@@ -28,37 +29,49 @@ inline std::wstring get_process_path(DWORD pid) noexcept
|
||||
inline std::wstring get_process_path(HWND window) noexcept
|
||||
{
|
||||
const static std::wstring app_frame_host = L"ApplicationFrameHost.exe";
|
||||
|
||||
DWORD pid{};
|
||||
GetWindowThreadProcessId(window, &pid);
|
||||
auto name = get_process_path(pid);
|
||||
|
||||
if (name.length() >= app_frame_host.length() &&
|
||||
name.compare(name.length() - app_frame_host.length(), app_frame_host.length(), app_frame_host) == 0)
|
||||
{
|
||||
// It is a UWP app. We will enumerate the windows and look for one created
|
||||
// by something with a different PID
|
||||
// It might take a time to connect the process. That's the reason for the retry loop here
|
||||
DWORD new_pid = pid;
|
||||
EnumChildWindows(
|
||||
window, [](HWND hwnd, LPARAM param) -> BOOL {
|
||||
auto new_pid_ptr = reinterpret_cast<DWORD*>(param);
|
||||
DWORD pid;
|
||||
GetWindowThreadProcessId(hwnd, &pid);
|
||||
if (pid != *new_pid_ptr)
|
||||
{
|
||||
*new_pid_ptr = pid;
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
},
|
||||
reinterpret_cast<LPARAM>(&new_pid));
|
||||
// If we have a new pid, get the new name.
|
||||
if (new_pid != pid)
|
||||
|
||||
const int retryAttempts = 10;
|
||||
for (int retry = 0; retry < retryAttempts && pid == new_pid; retry++)
|
||||
{
|
||||
return get_process_path(new_pid);
|
||||
EnumChildWindows(
|
||||
window, [](HWND hwnd, LPARAM param) -> BOOL {
|
||||
auto new_pid_ptr = reinterpret_cast<DWORD*>(param);
|
||||
DWORD pid;
|
||||
GetWindowThreadProcessId(hwnd, &pid);
|
||||
if (pid != *new_pid_ptr)
|
||||
{
|
||||
*new_pid_ptr = pid;
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
},
|
||||
reinterpret_cast<LPARAM>(&new_pid));
|
||||
|
||||
// If we have a new pid, get the new name.
|
||||
if (new_pid != pid)
|
||||
{
|
||||
return get_process_path(new_pid);
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,18 @@ namespace Awake.Core
|
||||
ES_SYSTEM_REQUIRED = 0x00000001,
|
||||
}
|
||||
|
||||
// See: https://docs.microsoft.com/windows/console/handlerroutine
|
||||
public enum ControlType
|
||||
{
|
||||
CTRL_C_EVENT = 0,
|
||||
CTRL_BREAK_EVENT = 1,
|
||||
CTRL_CLOSE_EVENT = 2,
|
||||
CTRL_LOGOFF_EVENT = 5,
|
||||
CTRL_SHUTDOWN_EVENT = 6,
|
||||
}
|
||||
|
||||
public delegate bool ConsoleEventHandler(ControlType ctrlType);
|
||||
|
||||
/// <summary>
|
||||
/// Helper class that allows talking to Win32 APIs without having to rely on PInvoke in other parts
|
||||
/// of the codebase.
|
||||
@@ -37,6 +49,10 @@ namespace Awake.Core
|
||||
private static CancellationToken _threadToken;
|
||||
|
||||
private static Task? _runnerThread;
|
||||
private static System.Timers.Timer _timedLoopTimer;
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern bool SetConsoleCtrlHandler(ConsoleEventHandler handler, bool add);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
|
||||
@@ -63,10 +79,16 @@ namespace Awake.Core
|
||||
|
||||
static APIHelper()
|
||||
{
|
||||
_timedLoopTimer = new System.Timers.Timer();
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_tokenSource = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
public static void SetConsoleControlHandler(ConsoleEventHandler handler, bool addHandler)
|
||||
{
|
||||
SetConsoleCtrlHandler(handler, addHandler);
|
||||
}
|
||||
|
||||
public static void AllocateConsole()
|
||||
{
|
||||
_log.Debug("Bootstrapping the console allocation routine.");
|
||||
@@ -139,7 +161,7 @@ namespace Awake.Core
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_log.Info("Confirmed background thread cancellation when setting passive keep awake.");
|
||||
_log.Info("Confirmed background thread cancellation when disabling explicit keep awake.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +178,7 @@ namespace Awake.Core
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_log.Info("Confirmed background thread cancellation when setting indefinite keep awake.");
|
||||
_log.Info("Confirmed background thread cancellation when setting timed keep awake.");
|
||||
}
|
||||
|
||||
_tokenSource = new CancellationTokenSource();
|
||||
@@ -184,13 +206,10 @@ namespace Awake.Core
|
||||
if (success)
|
||||
{
|
||||
_log.Info($"Initiated indefinite keep awake in background thread: {GetCurrentThreadId()}. Screen on: {keepDisplayOn}");
|
||||
while (true)
|
||||
{
|
||||
if (_threadToken.IsCancellationRequested)
|
||||
{
|
||||
_threadToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
|
||||
WaitHandle.WaitAny(new[] { _threadToken.WaitHandle });
|
||||
|
||||
return success;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -226,14 +245,25 @@ namespace Awake.Core
|
||||
if (success)
|
||||
{
|
||||
_log.Info($"Initiated temporary keep awake in background thread: {GetCurrentThreadId()}. Screen on: {keepDisplayOn}");
|
||||
var startTime = DateTime.UtcNow;
|
||||
while (DateTime.UtcNow - startTime < TimeSpan.FromSeconds(Math.Abs(seconds)))
|
||||
|
||||
_timedLoopTimer = new System.Timers.Timer(seconds * 1000);
|
||||
_timedLoopTimer.Elapsed += (s, e) =>
|
||||
{
|
||||
if (_threadToken.IsCancellationRequested)
|
||||
{
|
||||
_threadToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
_tokenSource.Cancel();
|
||||
|
||||
_timedLoopTimer.Stop();
|
||||
};
|
||||
|
||||
_timedLoopTimer.Disposed += (s, e) =>
|
||||
{
|
||||
_log.Info("Old timer disposed.");
|
||||
};
|
||||
|
||||
_timedLoopTimer.Start();
|
||||
|
||||
WaitHandle.WaitAny(new[] { _threadToken.WaitHandle });
|
||||
_timedLoopTimer.Stop();
|
||||
_timedLoopTimer.Dispose();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
12
src/modules/awake/Awake/Core/InternalConstants.cs
Normal file
12
src/modules/awake/Awake/Core/InternalConstants.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
// 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.
|
||||
|
||||
namespace Awake.Core
|
||||
{
|
||||
internal static class InternalConstants
|
||||
{
|
||||
internal const string AppName = "Awake";
|
||||
internal const string FullAppName = "PowerToys " + AppName;
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,10 @@ using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using NLog;
|
||||
|
||||
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
||||
#pragma warning disable CS8603 // Possible null reference return.
|
||||
@@ -16,32 +18,43 @@ namespace Awake.Core
|
||||
{
|
||||
internal static class TrayHelper
|
||||
{
|
||||
private static NotifyIcon? trayIcon;
|
||||
private static readonly Logger _log;
|
||||
|
||||
private static NotifyIcon TrayIcon { get => trayIcon; set => trayIcon = value; }
|
||||
private static NotifyIcon? _trayIcon;
|
||||
|
||||
private static SettingsUtils? moduleSettings;
|
||||
private static NotifyIcon TrayIcon { get => _trayIcon; set => _trayIcon = value; }
|
||||
|
||||
private static SettingsUtils ModuleSettings { get => moduleSettings; set => moduleSettings = value; }
|
||||
private static SettingsUtils? _moduleSettings;
|
||||
|
||||
private static SettingsUtils ModuleSettings { get => _moduleSettings; set => _moduleSettings = value; }
|
||||
|
||||
static TrayHelper()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
TrayIcon = new NotifyIcon();
|
||||
ModuleSettings = new SettingsUtils();
|
||||
}
|
||||
|
||||
public static void InitializeTray(string text, Icon icon, ContextMenuStrip? contextMenu = null)
|
||||
{
|
||||
System.Threading.Tasks.Task.Factory.StartNew(
|
||||
Task.Factory.StartNew(
|
||||
(tray) =>
|
||||
{
|
||||
((NotifyIcon?)tray).Text = text;
|
||||
((NotifyIcon?)tray).Icon = icon;
|
||||
((NotifyIcon?)tray).ContextMenuStrip = contextMenu;
|
||||
((NotifyIcon?)tray).Visible = true;
|
||||
{
|
||||
((NotifyIcon?)tray).Text = text;
|
||||
((NotifyIcon?)tray).Icon = icon;
|
||||
((NotifyIcon?)tray).ContextMenuStrip = contextMenu;
|
||||
((NotifyIcon?)tray).Visible = true;
|
||||
|
||||
Application.Run();
|
||||
}, TrayIcon);
|
||||
_log.Info("Setting up the tray.");
|
||||
Application.Run();
|
||||
_log.Info("Tray setup complete.");
|
||||
}, TrayIcon);
|
||||
}
|
||||
|
||||
public static void ClearTray()
|
||||
{
|
||||
TrayIcon.Icon = null;
|
||||
TrayIcon.Dispose();
|
||||
}
|
||||
|
||||
internal static void SetTray(string text, AwakeSettings settings)
|
||||
@@ -50,10 +63,10 @@ namespace Awake.Core
|
||||
text,
|
||||
settings.Properties.KeepDisplayOn,
|
||||
settings.Properties.Mode,
|
||||
PassiveKeepAwakeCallback(text),
|
||||
IndefiniteKeepAwakeCallback(text),
|
||||
TimedKeepAwakeCallback(text),
|
||||
KeepDisplayOnCallback(text),
|
||||
PassiveKeepAwakeCallback(InternalConstants.AppName),
|
||||
IndefiniteKeepAwakeCallback(InternalConstants.AppName),
|
||||
TimedKeepAwakeCallback(InternalConstants.AppName),
|
||||
KeepDisplayOnCallback(InternalConstants.AppName),
|
||||
ExitCallback());
|
||||
}
|
||||
|
||||
@@ -61,7 +74,7 @@ namespace Awake.Core
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
Environment.Exit(0);
|
||||
Environment.Exit(Environment.ExitCode);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -153,28 +166,21 @@ namespace Awake.Core
|
||||
|
||||
public static void SetTray(string text, bool keepDisplayOn, AwakeMode mode, Action passiveKeepAwakeCallback, Action indefiniteKeepAwakeCallback, Action<uint, uint> timedKeepAwakeCallback, Action keepDisplayOnCallback, Action exitCallback)
|
||||
{
|
||||
var contextMenuStrip = new ContextMenuStrip();
|
||||
ContextMenuStrip? contextMenuStrip = new ContextMenuStrip();
|
||||
|
||||
// Main toolstrip.
|
||||
var operationContextMenu = new ToolStripMenuItem
|
||||
ToolStripMenuItem? operationContextMenu = new ToolStripMenuItem
|
||||
{
|
||||
Text = "Mode",
|
||||
};
|
||||
|
||||
// No keep-awake menu item.
|
||||
var passiveMenuItem = new ToolStripMenuItem
|
||||
ToolStripMenuItem? passiveMenuItem = new ToolStripMenuItem
|
||||
{
|
||||
Text = "Off (Passive)",
|
||||
};
|
||||
|
||||
if (mode == AwakeMode.PASSIVE)
|
||||
{
|
||||
passiveMenuItem.Checked = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
passiveMenuItem.Checked = false;
|
||||
}
|
||||
passiveMenuItem.Checked = mode == AwakeMode.PASSIVE;
|
||||
|
||||
passiveMenuItem.Click += (e, s) =>
|
||||
{
|
||||
@@ -183,19 +189,12 @@ namespace Awake.Core
|
||||
};
|
||||
|
||||
// Indefinite keep-awake menu item.
|
||||
var indefiniteMenuItem = new ToolStripMenuItem
|
||||
ToolStripMenuItem? indefiniteMenuItem = new ToolStripMenuItem
|
||||
{
|
||||
Text = "Keep awake indefinitely",
|
||||
};
|
||||
|
||||
if (mode == AwakeMode.INDEFINITE)
|
||||
{
|
||||
indefiniteMenuItem.Checked = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
indefiniteMenuItem.Checked = false;
|
||||
}
|
||||
indefiniteMenuItem.Checked = mode == AwakeMode.INDEFINITE;
|
||||
|
||||
indefiniteMenuItem.Click += (e, s) =>
|
||||
{
|
||||
@@ -203,18 +202,12 @@ namespace Awake.Core
|
||||
indefiniteKeepAwakeCallback();
|
||||
};
|
||||
|
||||
var displayOnMenuItem = new ToolStripMenuItem
|
||||
ToolStripMenuItem? displayOnMenuItem = new ToolStripMenuItem
|
||||
{
|
||||
Text = "Keep screen on",
|
||||
};
|
||||
if (keepDisplayOn)
|
||||
{
|
||||
displayOnMenuItem.Checked = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
displayOnMenuItem.Checked = false;
|
||||
}
|
||||
|
||||
displayOnMenuItem.Checked = keepDisplayOn;
|
||||
|
||||
displayOnMenuItem.Click += (e, s) =>
|
||||
{
|
||||
@@ -223,43 +216,40 @@ namespace Awake.Core
|
||||
};
|
||||
|
||||
// Timed keep-awake menu item
|
||||
var timedMenuItem = new ToolStripMenuItem
|
||||
ToolStripMenuItem? timedMenuItem = new ToolStripMenuItem
|
||||
{
|
||||
Text = "Keep awake temporarily",
|
||||
};
|
||||
if (mode == AwakeMode.TIMED)
|
||||
{
|
||||
timedMenuItem.Checked = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
timedMenuItem.Checked = false;
|
||||
}
|
||||
|
||||
var halfHourMenuItem = new ToolStripMenuItem
|
||||
timedMenuItem.Checked = mode == AwakeMode.TIMED;
|
||||
|
||||
ToolStripMenuItem? halfHourMenuItem = new ToolStripMenuItem
|
||||
{
|
||||
Text = "30 minutes",
|
||||
};
|
||||
|
||||
halfHourMenuItem.Click += (e, s) =>
|
||||
{
|
||||
// User is setting the keep-awake to 30 minutes.
|
||||
timedKeepAwakeCallback(0, 30);
|
||||
};
|
||||
|
||||
var oneHourMenuItem = new ToolStripMenuItem
|
||||
ToolStripMenuItem? oneHourMenuItem = new ToolStripMenuItem
|
||||
{
|
||||
Text = "1 hour",
|
||||
};
|
||||
|
||||
oneHourMenuItem.Click += (e, s) =>
|
||||
{
|
||||
// User is setting the keep-awake to 1 hour.
|
||||
timedKeepAwakeCallback(1, 0);
|
||||
};
|
||||
|
||||
var twoHoursMenuItem = new ToolStripMenuItem
|
||||
ToolStripMenuItem? twoHoursMenuItem = new ToolStripMenuItem
|
||||
{
|
||||
Text = "2 hours",
|
||||
};
|
||||
|
||||
twoHoursMenuItem.Click += (e, s) =>
|
||||
{
|
||||
// User is setting the keep-awake to 2 hours.
|
||||
@@ -267,10 +257,11 @@ namespace Awake.Core
|
||||
};
|
||||
|
||||
// Exit menu item.
|
||||
var exitContextMenu = new ToolStripMenuItem
|
||||
ToolStripMenuItem? exitContextMenu = new ToolStripMenuItem
|
||||
{
|
||||
Text = "Exit",
|
||||
};
|
||||
|
||||
exitContextMenu.Click += (e, s) =>
|
||||
{
|
||||
// User is setting the keep-awake to 2 hours.
|
||||
|
||||
@@ -15,6 +15,7 @@ using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using Awake.Core;
|
||||
using interop;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using NLog;
|
||||
@@ -27,7 +28,6 @@ namespace Awake
|
||||
internal class Program
|
||||
{
|
||||
private static Mutex? _mutex = null;
|
||||
private const string AppName = "Awake";
|
||||
private static FileSystemWatcher? _watcher = null;
|
||||
private static SettingsUtils? _settingsUtils = null;
|
||||
|
||||
@@ -35,17 +35,25 @@ namespace Awake
|
||||
|
||||
private static Logger? _log;
|
||||
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
private static ConsoleEventHandler _handler;
|
||||
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
|
||||
private static ManualResetEvent _exitSignal = new ManualResetEvent(false);
|
||||
|
||||
private static int Main(string[] args)
|
||||
{
|
||||
bool instantiated;
|
||||
LockMutex = new Mutex(true, AppName, out instantiated);
|
||||
// Log initialization needs to always happen before we test whether
|
||||
// only one instance of Awake is running.
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
LockMutex = new Mutex(true, InternalConstants.AppName, out bool instantiated);
|
||||
|
||||
if (!instantiated)
|
||||
{
|
||||
ForceExit(AppName + " is already running! Exiting the application.", 1);
|
||||
Exit(InternalConstants.AppName + " is already running! Exiting the application.", 1, true);
|
||||
}
|
||||
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_settingsUtils = new SettingsUtils();
|
||||
|
||||
_log.Info("Launching PowerToys Awake...");
|
||||
@@ -55,7 +63,7 @@ namespace Awake
|
||||
|
||||
_log.Info("Parsing parameters...");
|
||||
|
||||
var configOption = new Option<bool>(
|
||||
Option<bool>? configOption = new Option<bool>(
|
||||
aliases: new[] { "--use-pt-config", "-c" },
|
||||
getDefaultValue: () => false,
|
||||
description: "Specifies whether PowerToys Awake will be using the PowerToys configuration file for managing the state.")
|
||||
@@ -68,7 +76,7 @@ namespace Awake
|
||||
|
||||
configOption.Required = false;
|
||||
|
||||
var displayOption = new Option<bool>(
|
||||
Option<bool>? displayOption = new Option<bool>(
|
||||
aliases: new[] { "--display-on", "-d" },
|
||||
getDefaultValue: () => true,
|
||||
description: "Determines whether the display should be kept awake.")
|
||||
@@ -81,7 +89,7 @@ namespace Awake
|
||||
|
||||
displayOption.Required = false;
|
||||
|
||||
var timeOption = new Option<uint>(
|
||||
Option<uint>? timeOption = new Option<uint>(
|
||||
aliases: new[] { "--time-limit", "-t" },
|
||||
getDefaultValue: () => 0,
|
||||
description: "Determines the interval, in seconds, during which the computer is kept awake.")
|
||||
@@ -94,7 +102,7 @@ namespace Awake
|
||||
|
||||
timeOption.Required = false;
|
||||
|
||||
var pidOption = new Option<int>(
|
||||
Option<int>? pidOption = new Option<int>(
|
||||
aliases: new[] { "--pid", "-p" },
|
||||
getDefaultValue: () => 0,
|
||||
description: "Bind the execution of PowerToys Awake to another process.")
|
||||
@@ -107,7 +115,7 @@ namespace Awake
|
||||
|
||||
pidOption.Required = false;
|
||||
|
||||
var rootCommand = new RootCommand
|
||||
RootCommand? rootCommand = new RootCommand
|
||||
{
|
||||
configOption,
|
||||
displayOption,
|
||||
@@ -115,7 +123,7 @@ namespace Awake
|
||||
pidOption,
|
||||
};
|
||||
|
||||
rootCommand.Description = AppName;
|
||||
rootCommand.Description = InternalConstants.AppName;
|
||||
|
||||
rootCommand.Handler = CommandHandler.Create<bool, bool, uint, int>(HandleCommandLineArguments);
|
||||
|
||||
@@ -124,15 +132,38 @@ namespace Awake
|
||||
return rootCommand.InvokeAsync(args).Result;
|
||||
}
|
||||
|
||||
private static void ForceExit(string message, int exitCode)
|
||||
private static bool ExitHandler(ControlType ctrlType)
|
||||
{
|
||||
_log.Info($"Exited through handler with control type: {ctrlType}");
|
||||
|
||||
Exit("Exiting from the internal termination handler.", Environment.ExitCode);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void Exit(string message, int exitCode, bool force = false)
|
||||
{
|
||||
_log.Info(message);
|
||||
Console.ReadKey();
|
||||
Environment.Exit(exitCode);
|
||||
|
||||
APIHelper.SetNoKeepAwake();
|
||||
TrayHelper.ClearTray();
|
||||
|
||||
// Because we are running a message loop for the tray, we can't just use Environment.Exit,
|
||||
// but have to make sure that we properly send the termination message.
|
||||
bool cwResult = System.Diagnostics.Process.GetCurrentProcess().CloseMainWindow();
|
||||
_log.Info($"Request to close main window status: {cwResult}");
|
||||
|
||||
if (force)
|
||||
{
|
||||
Environment.Exit(exitCode);
|
||||
}
|
||||
}
|
||||
|
||||
private static void HandleCommandLineArguments(bool usePtConfig, bool displayOn, uint timeLimit, int pid)
|
||||
{
|
||||
_handler += new ConsoleEventHandler(ExitHandler);
|
||||
APIHelper.SetConsoleControlHandler(_handler, true);
|
||||
|
||||
if (pid == 0)
|
||||
{
|
||||
_log.Info("No PID specified. Allocating console...");
|
||||
@@ -150,11 +181,18 @@ namespace Awake
|
||||
// and instead watch for changes in the file.
|
||||
try
|
||||
{
|
||||
#pragma warning disable CS8604 // Possible null reference argument.
|
||||
TrayHelper.InitializeTray(AppName, new Icon(Application.GetResourceStream(new Uri("/Images/Awake.ico", UriKind.Relative)).Stream));
|
||||
#pragma warning restore CS8604 // Possible null reference argument.
|
||||
new Thread(() =>
|
||||
{
|
||||
EventWaitHandle? eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.AwakeExitEvent());
|
||||
if (eventHandle.WaitOne())
|
||||
{
|
||||
Exit("Received a signal to end the process. Making sure we quit...", 0, true);
|
||||
}
|
||||
}).Start();
|
||||
|
||||
var settingsPath = _settingsUtils.GetSettingsFilePath(AppName);
|
||||
TrayHelper.InitializeTray(InternalConstants.FullAppName, new Icon(Application.GetResourceStream(new Uri("/Images/Awake.ico", UriKind.Relative)).Stream));
|
||||
|
||||
string? settingsPath = _settingsUtils.GetSettingsFilePath(InternalConstants.AppName);
|
||||
_log.Info($"Reading configuration file: {settingsPath}");
|
||||
|
||||
_watcher = new FileSystemWatcher
|
||||
@@ -165,22 +203,22 @@ namespace Awake
|
||||
Filter = Path.GetFileName(settingsPath),
|
||||
};
|
||||
|
||||
var changedObservable = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
|
||||
IObservable<System.Reactive.EventPattern<FileSystemEventArgs>>? changedObservable = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
|
||||
h => _watcher.Changed += h,
|
||||
h => _watcher.Changed -= h);
|
||||
|
||||
var createdObservable = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
|
||||
IObservable<System.Reactive.EventPattern<FileSystemEventArgs>>? createdObservable = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
|
||||
cre => _watcher.Created += cre,
|
||||
cre => _watcher.Created -= cre);
|
||||
|
||||
var mergedObservable = Observable.Merge(changedObservable, createdObservable);
|
||||
IObservable<System.Reactive.EventPattern<FileSystemEventArgs>>? mergedObservable = Observable.Merge(changedObservable, createdObservable);
|
||||
|
||||
mergedObservable.Throttle(TimeSpan.FromMilliseconds(25))
|
||||
.SubscribeOn(TaskPoolScheduler.Default)
|
||||
.Select(e => e.EventArgs)
|
||||
.Subscribe(HandleAwakeConfigChange);
|
||||
|
||||
TrayHelper.SetTray(AppName, new AwakeSettings());
|
||||
TrayHelper.SetTray(InternalConstants.FullAppName, new AwakeSettings());
|
||||
|
||||
// Initially the file might not be updated, so we need to start processing
|
||||
// settings right away.
|
||||
@@ -188,14 +226,14 @@ namespace Awake
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errorString = $"There was a problem with the configuration file. Make sure it exists.\n{ex.Message}";
|
||||
string? errorString = $"There was a problem with the configuration file. Make sure it exists.\n{ex.Message}";
|
||||
_log.Info(errorString);
|
||||
_log.Debug(errorString);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var mode = timeLimit <= 0 ? AwakeMode.INDEFINITE : AwakeMode.TIMED;
|
||||
AwakeMode mode = timeLimit <= 0 ? AwakeMode.INDEFINITE : AwakeMode.TIMED;
|
||||
|
||||
if (mode == AwakeMode.INDEFINITE)
|
||||
{
|
||||
@@ -207,22 +245,19 @@ namespace Awake
|
||||
}
|
||||
}
|
||||
|
||||
var exitSignal = new ManualResetEvent(false);
|
||||
if (pid != 0)
|
||||
{
|
||||
RunnerHelper.WaitForPowerToysRunner(pid, () =>
|
||||
{
|
||||
exitSignal.Set();
|
||||
Environment.Exit(0);
|
||||
Exit("Terminating from PowerToys binding hook.", 0, true);
|
||||
});
|
||||
}
|
||||
|
||||
exitSignal.WaitOne();
|
||||
_exitSignal.WaitOne();
|
||||
}
|
||||
|
||||
private static void SetupIndefiniteKeepAwake(bool displayOn)
|
||||
{
|
||||
// Indefinite keep awake.
|
||||
APIHelper.SetIndefiniteKeepAwake(LogCompletedKeepAwakeThread, LogUnexpectedOrCancelledKeepAwakeThreadCompletion, displayOn);
|
||||
}
|
||||
|
||||
@@ -237,7 +272,7 @@ namespace Awake
|
||||
{
|
||||
try
|
||||
{
|
||||
AwakeSettings settings = _settingsUtils.GetSettings<AwakeSettings>(AppName);
|
||||
AwakeSettings settings = _settingsUtils.GetSettings<AwakeSettings>(InternalConstants.AppName);
|
||||
|
||||
if (settings != null)
|
||||
{
|
||||
@@ -251,14 +286,12 @@ namespace Awake
|
||||
|
||||
case AwakeMode.INDEFINITE:
|
||||
{
|
||||
// Indefinite keep awake.
|
||||
SetupIndefiniteKeepAwake(settings.Properties.KeepDisplayOn);
|
||||
break;
|
||||
}
|
||||
|
||||
case AwakeMode.TIMED:
|
||||
{
|
||||
// Timed keep-awake.
|
||||
uint computedTime = (settings.Properties.Hours * 60 * 60) + (settings.Properties.Minutes * 60);
|
||||
SetupTimedKeepAwake(computedTime, settings.Properties.KeepDisplayOn);
|
||||
|
||||
@@ -267,25 +300,25 @@ namespace Awake
|
||||
|
||||
default:
|
||||
{
|
||||
var errorMessage = "Unknown mode of operation. Check config file.";
|
||||
string? errorMessage = "Unknown mode of operation. Check config file.";
|
||||
_log.Info(errorMessage);
|
||||
_log.Debug(errorMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TrayHelper.SetTray(AppName, settings);
|
||||
TrayHelper.SetTray(InternalConstants.FullAppName, settings);
|
||||
}
|
||||
else
|
||||
{
|
||||
var errorMessage = "Settings are null.";
|
||||
string? errorMessage = "Settings are null.";
|
||||
_log.Info(errorMessage);
|
||||
_log.Debug(errorMessage);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errorMessage = $"There was a problem reading the configuration file. Error: {ex.GetType()} {ex.Message}";
|
||||
string? errorMessage = $"There was a problem reading the configuration file. Error: {ex.GetType()} {ex.Message}";
|
||||
_log.Info(errorMessage);
|
||||
_log.Debug(errorMessage);
|
||||
}
|
||||
@@ -307,7 +340,7 @@ namespace Awake
|
||||
|
||||
private static void LogUnexpectedOrCancelledKeepAwakeThreadCompletion()
|
||||
{
|
||||
var errorMessage = "The keep-awake thread was terminated early.";
|
||||
string? errorMessage = "The keep-awake thread was terminated early.";
|
||||
_log.Info(errorMessage);
|
||||
_log.Debug(errorMessage);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <common/utils/winapi_error.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <set>
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
@@ -33,34 +34,23 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// The PowerToy name that will be shown in the settings.
|
||||
const static wchar_t* MODULE_NAME = L"Awake";
|
||||
|
||||
// Add a description that will we shown in the module settings page.
|
||||
const static wchar_t* MODULE_DESC = L"A module that keeps your computer awake on-demand.";
|
||||
|
||||
// Implement the PowerToy Module Interface and all the required methods.
|
||||
class Awake : public PowertoyModuleIface
|
||||
{
|
||||
std::wstring app_name;
|
||||
|
||||
// Contains the non localized key of the powertoy
|
||||
std::wstring app_key;
|
||||
|
||||
private:
|
||||
// The PowerToy state.
|
||||
bool m_enabled = false;
|
||||
|
||||
HANDLE m_hProcess;
|
||||
|
||||
HANDLE send_telemetry_event;
|
||||
|
||||
// Handle to event used to invoke PowerToys Awake
|
||||
HANDLE m_hInvokeEvent;
|
||||
PROCESS_INFORMATION p_info;
|
||||
|
||||
bool is_process_running()
|
||||
{
|
||||
return WaitForSingleObject(m_hProcess, 0) == WAIT_TIMEOUT;
|
||||
return WaitForSingleObject(p_info.hProcess, 0) == WAIT_TIMEOUT;
|
||||
}
|
||||
|
||||
void launch_process()
|
||||
@@ -69,26 +59,22 @@ private:
|
||||
unsigned long powertoys_pid = GetCurrentProcessId();
|
||||
|
||||
std::wstring executable_args = L"--use-pt-config --pid " + std::to_wstring(powertoys_pid);
|
||||
std::wstring application_path = L"modules\\Awake\\PowerToys.Awake.exe";
|
||||
std::wstring full_command_path = application_path + L" " + executable_args.data();
|
||||
Logger::trace(L"PowerToys Awake launching with parameters: " + executable_args);
|
||||
|
||||
SHELLEXECUTEINFOW sei{ sizeof(sei) };
|
||||
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
|
||||
sei.lpFile = L"modules\\Awake\\PowerToys.Awake.exe";
|
||||
sei.nShow = SW_SHOWNORMAL;
|
||||
sei.lpParameters = executable_args.data();
|
||||
if (!ShellExecuteExW(&sei))
|
||||
STARTUPINFO info = { sizeof(info) };
|
||||
|
||||
if (!CreateProcess(application_path.c_str(), full_command_path.data(), NULL, NULL, true, NULL, NULL, NULL, &info, &p_info))
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
std::wstring message = L"PowerToys Awake failed to start with error = ";
|
||||
std::wstring message = L"PowerToys Awake failed to start with error: ";
|
||||
message += std::to_wstring(error);
|
||||
Logger::error(message);
|
||||
}
|
||||
|
||||
m_hProcess = sei.hProcess;
|
||||
}
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
Awake()
|
||||
{
|
||||
app_name = GET_RESOURCE_STRING(IDS_AWAKE_NAME);
|
||||
@@ -99,37 +85,31 @@ public:
|
||||
Logger::info("Launcher object is constructing");
|
||||
};
|
||||
|
||||
// Destroy the powertoy and free memory
|
||||
virtual void destroy() override
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
// Return the display name of the powertoy, this will be cached by the runner
|
||||
virtual const wchar_t* get_name() override
|
||||
{
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
// Return JSON with the configuration options.
|
||||
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
|
||||
{
|
||||
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
||||
|
||||
// Create a Settings object.
|
||||
PowerToysSettings::Settings settings(hinstance, get_name());
|
||||
settings.set_description(MODULE_DESC);
|
||||
|
||||
return settings.serialize_to_buffer(buffer, buffer_size);
|
||||
}
|
||||
|
||||
// Return the non localized key of the powertoy, this will be cached by the runner
|
||||
virtual const wchar_t* get_key() override
|
||||
{
|
||||
return app_key.c_str();
|
||||
}
|
||||
|
||||
// Called by the runner to pass the updated settings values as a serialized JSON.
|
||||
virtual void set_config(const wchar_t* config) override
|
||||
{
|
||||
try
|
||||
@@ -139,7 +119,7 @@ public:
|
||||
PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
||||
|
||||
// If you don't need to do any custom processing of the settings, proceed
|
||||
// to persists the values calling:
|
||||
// to persists the values.
|
||||
values.save_to_settings_file();
|
||||
}
|
||||
catch (std::exception&)
|
||||
@@ -160,15 +140,36 @@ public:
|
||||
{
|
||||
if (m_enabled)
|
||||
{
|
||||
Logger::trace(L"Disabling Awake...");
|
||||
ResetEvent(send_telemetry_event);
|
||||
ResetEvent(m_hInvokeEvent);
|
||||
TerminateProcess(m_hProcess, 1);
|
||||
|
||||
auto exitEvent = CreateEvent(nullptr, false, false, CommonSharedConstants::AWAKE_EXIT_EVENT);
|
||||
if (!exitEvent)
|
||||
{
|
||||
Logger::warn(L"Failed to create exit event for PowerToys Awake. {}", get_last_error_or_default(GetLastError()));
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::trace(L"Signaled exit event for PowerToys Awake.");
|
||||
if (!SetEvent(exitEvent))
|
||||
{
|
||||
Logger::warn(L"Failed to signal exit event for PowerToys Awake. {}", get_last_error_or_default(GetLastError()));
|
||||
|
||||
// For some reason, we couldn't process the signal correctly, so we still
|
||||
// need to terminate the Awake process.
|
||||
TerminateProcess(p_info.hProcess, 1);
|
||||
}
|
||||
|
||||
ResetEvent(exitEvent);
|
||||
CloseHandle(exitEvent);
|
||||
CloseHandle(p_info.hProcess);
|
||||
}
|
||||
}
|
||||
|
||||
m_enabled = false;
|
||||
}
|
||||
|
||||
// Returns if the powertoys is enabled
|
||||
virtual bool is_enabled() override
|
||||
{
|
||||
return m_enabled;
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
#include <colorPicker/ColorPicker/ColorPickerConstants.h>
|
||||
#include <common/interop/shared_constants.h>
|
||||
#include <common/utils/logger_helper.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
@@ -108,7 +110,7 @@ private:
|
||||
|
||||
void launch_process()
|
||||
{
|
||||
Logger::trace(L"Launching ColorPicker process");
|
||||
Logger::trace(L"Starting ColorPicker process");
|
||||
unsigned long powertoys_pid = GetCurrentProcessId();
|
||||
|
||||
std::wstring executable_args = L"";
|
||||
@@ -119,12 +121,13 @@ private:
|
||||
sei.lpFile = L"modules\\ColorPicker\\ColorPickerUI.exe";
|
||||
sei.nShow = SW_SHOWNORMAL;
|
||||
sei.lpParameters = executable_args.data();
|
||||
if (!ShellExecuteExW(&sei))
|
||||
if (ShellExecuteExW(&sei))
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
std::wstring message = L"ColorPicker failed to start with error = ";
|
||||
message += std::to_wstring(error);
|
||||
Logger::error(message);
|
||||
Logger::trace("Successfully started the Color Picker process");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error( L"ColorPicker failed to start. {}", get_last_error_or_default(GetLastError()));
|
||||
}
|
||||
|
||||
m_hProcess = sei.hProcess;
|
||||
@@ -153,6 +156,7 @@ public:
|
||||
{
|
||||
app_name = GET_RESOURCE_STRING(IDS_COLORPICKER_NAME);
|
||||
app_key = ColorPickerConstants::ModuleKey;
|
||||
LoggerHelpers::init_logger(app_key, L"ModuleInterface", "ColorPicker");
|
||||
send_telemetry_event = CreateDefaultEvent(CommonSharedConstants::COLOR_PICKER_SEND_SETTINGS_TELEMETRY_EVENT);
|
||||
m_hInvokeEvent = CreateDefaultEvent(CommonSharedConstants::SHOW_COLOR_PICKER_SHARED_EVENT);
|
||||
init_settings();
|
||||
@@ -169,6 +173,7 @@ public:
|
||||
// Destroy the powertoy and free memory
|
||||
virtual void destroy() override
|
||||
{
|
||||
Logger::trace("ColorPicker::destroy()");
|
||||
delete this;
|
||||
}
|
||||
|
||||
@@ -224,6 +229,7 @@ public:
|
||||
|
||||
virtual void enable()
|
||||
{
|
||||
Logger::trace("ColorPicker::enable()");
|
||||
ResetEvent(send_telemetry_event);
|
||||
ResetEvent(m_hInvokeEvent);
|
||||
launch_process();
|
||||
@@ -232,6 +238,7 @@ public:
|
||||
|
||||
virtual void disable()
|
||||
{
|
||||
Logger::trace("ColorPicker::disable()");
|
||||
if (m_enabled)
|
||||
{
|
||||
ResetEvent(send_telemetry_event);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using ColorPicker.Helpers;
|
||||
using ColorPicker.Mouse;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Common.UI;
|
||||
@@ -30,6 +31,7 @@ namespace ColorPickerUI
|
||||
_instanceMutex = new Mutex(true, @"Local\PowerToys_ColorPicker_InstanceMutex", out bool createdNew);
|
||||
if (!createdNew)
|
||||
{
|
||||
Logger.LogWarning("There is ColorPicker instance running. Exiting Color Picker");
|
||||
_instanceMutex = null;
|
||||
Environment.Exit(0);
|
||||
return;
|
||||
@@ -39,8 +41,10 @@ namespace ColorPickerUI
|
||||
{
|
||||
_ = int.TryParse(_args[0], out _powerToysRunnerPid);
|
||||
|
||||
Logger.LogInfo($"Color Picker started from the PowerToys Runner. Runner pid={_powerToysRunnerPid}");
|
||||
RunnerHelper.WaitForPowerToysRunner(_powerToysRunnerPid, () =>
|
||||
{
|
||||
Logger.LogInfo("PowerToys Runner exited. Exiting ColorPicker");
|
||||
Environment.Exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:p="clr-namespace:ColorPicker.Properties"
|
||||
xmlns:p="clr-namespace:ColorPicker.Properties" xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Border x:Name="MainBorder"
|
||||
@@ -38,7 +38,7 @@
|
||||
IsReadOnly="True"
|
||||
VerticalAlignment="Center"
|
||||
Padding="8"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=FormatNameTextBlock, Path=Text}"
|
||||
AutomationProperties.Name="{x:Static p:Resources.Color_Code}"
|
||||
/>
|
||||
|
||||
<Button x:Name="CopyToClipboardButton"
|
||||
@@ -48,12 +48,15 @@
|
||||
Height="36"
|
||||
Width="36"
|
||||
Grid.Column="2"
|
||||
AutomationProperties.HelpText="{Binding ElementName=FormatNameTextBlock, Path=Text}"
|
||||
AutomationProperties.Name="{x:Static p:Resources.Copy_to_clipboard}"
|
||||
AutomationProperties.HelpText="{Binding ElementName=ColorTextRepresentationTextBlock, Path=Text}"
|
||||
FontSize="12"
|
||||
Style="{StaticResource DefaultButtonStyle}"
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Content="" />
|
||||
FontFamily="Segoe MDL2 Assets">
|
||||
<Button.Content>
|
||||
<TextBlock Text="" AutomationProperties.Name="{x:Static p:Resources.Copy_to_clipboard}" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
</Grid>
|
||||
<Border.Effect>
|
||||
<DropShadowEffect BlurRadius="6" Opacity="0.24" ShadowDepth="1" />
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Automation.Peers;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
@@ -90,6 +91,20 @@ namespace ColorPicker.Controls
|
||||
resize.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseInOut };
|
||||
ColorCopiedNotificationBorder.BeginAnimation(Border.OpacityProperty, opacityAppear);
|
||||
ColorCopiedNotificationBorder.BeginAnimation(Border.HeightProperty, resize);
|
||||
|
||||
var clipboardNotification = ((Decorator)ColorCopiedNotificationBorder).Child;
|
||||
if (clipboardNotification == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var peer = UIElementAutomationPeer.FromElement(clipboardNotification);
|
||||
if (peer == null)
|
||||
{
|
||||
peer = UIElementAutomationPeer.CreatePeerForElement(clipboardNotification);
|
||||
}
|
||||
|
||||
peer.RaiseAutomationEvent(AutomationEvents.MenuOpened);
|
||||
}
|
||||
|
||||
private void HideCopiedIndicator()
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||
mc:Ignorable="d"
|
||||
TabIndex="3"
|
||||
AutomationProperties.Name="{x:Static p:Resources.Color_Palette}"
|
||||
FocusManager.IsFocusScope="True"
|
||||
KeyboardNavigation.TabNavigation="Once"
|
||||
>
|
||||
KeyboardNavigation.TabNavigation="Once">
|
||||
<UserControl.Resources>
|
||||
|
||||
<Style TargetType="Thumb"
|
||||
@@ -252,7 +252,7 @@
|
||||
ui:ControlHelper.CornerRadius="2,0,0,2"
|
||||
Background="LightPink"
|
||||
Click="ColorVariationButton_Click"
|
||||
AutomationProperties.Name="Color shade 1"
|
||||
AutomationProperties.Name="{x:Static p:Resources.Lightest_color}"
|
||||
Style="{DynamicResource ColorShadeButtonStyle}"
|
||||
ToolTipService.ToolTip="{x:Static p:Resources.Select_color}" />
|
||||
<Button x:Name="colorVariation2Button"
|
||||
@@ -260,7 +260,7 @@
|
||||
ui:ControlHelper.CornerRadius="0"
|
||||
Background="LightPink"
|
||||
Click="ColorVariationButton_Click"
|
||||
AutomationProperties.Name="Color shade 2"
|
||||
AutomationProperties.Name="{x:Static p:Resources.Lighter_color}"
|
||||
Style="{DynamicResource ColorShadeButtonStyle}"
|
||||
ToolTipService.ToolTip="{x:Static p:Resources.Select_color}" />
|
||||
<Button x:Name="colorVariation3Button"
|
||||
@@ -268,7 +268,7 @@
|
||||
ui:ControlHelper.CornerRadius="0"
|
||||
Background="LightPink"
|
||||
Click="ColorVariationButton_Click"
|
||||
AutomationProperties.Name="Color shade 3"
|
||||
AutomationProperties.Name="{x:Static p:Resources.Darker_color}"
|
||||
Style="{DynamicResource ColorShadeButtonStyle}"
|
||||
ToolTipService.ToolTip="{x:Static p:Resources.Select_color}" />
|
||||
<Button x:Name="colorVariation4Button"
|
||||
@@ -276,7 +276,7 @@
|
||||
ui:ControlHelper.CornerRadius="0,2,2,0"
|
||||
Background="LightPink"
|
||||
Click="ColorVariationButton_Click"
|
||||
AutomationProperties.Name="Color shade 5"
|
||||
AutomationProperties.Name="{x:Static p:Resources.Darkest_color}"
|
||||
Style="{DynamicResource ColorShadeButtonStyle}"
|
||||
ToolTipService.ToolTip="{x:Static p:Resources.Select_color}" />
|
||||
|
||||
@@ -297,6 +297,7 @@
|
||||
<ui:FlyoutService.Flyout>
|
||||
<ui:Flyout x:Name="DetailsFlyout"
|
||||
Placement="Bottom"
|
||||
Opened="DetailsFlyout_Opened"
|
||||
Closed="DetailsFlyout_Closed">
|
||||
<Grid Margin="0,4,0,12"
|
||||
KeyboardNavigation.TabNavigation="Contained"
|
||||
|
||||
@@ -6,6 +6,7 @@ using System;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows;
|
||||
using System.Windows.Automation.Peers;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
@@ -41,6 +42,11 @@ namespace ColorPicker.Controls
|
||||
UpdateHueGradient(1, 1);
|
||||
}
|
||||
|
||||
protected override AutomationPeer OnCreateAutomationPeer()
|
||||
{
|
||||
return new ColorPickerAutomationPeer(this);
|
||||
}
|
||||
|
||||
public Color SelectedColor
|
||||
{
|
||||
get { return (Color)GetValue(SelectedColorProperty); }
|
||||
@@ -242,6 +248,7 @@ namespace ColorPicker.Controls
|
||||
#pragma warning restore CA1801 // Review unused parameters
|
||||
{
|
||||
HideDetails();
|
||||
AppStateHandler.BlockEscapeKeyClosingColorPickerEditor = false;
|
||||
|
||||
// Revert to original color
|
||||
var originalColorBackground = new SolidColorBrush(_originalColor);
|
||||
@@ -250,6 +257,15 @@ namespace ColorPicker.Controls
|
||||
HexCode.Text = ColorToHex(_originalColor);
|
||||
}
|
||||
|
||||
#pragma warning disable CA1822 // Mark members as static
|
||||
#pragma warning disable CA1801 // Review unused parameters
|
||||
private void DetailsFlyout_Opened(object sender, object e)
|
||||
#pragma warning restore CA1801 // Review unused parameters
|
||||
#pragma warning restore CA1822 // Mark members as static
|
||||
{
|
||||
AppStateHandler.BlockEscapeKeyClosingColorPickerEditor = true;
|
||||
}
|
||||
|
||||
private void ColorVariationButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var selectedColor = ((SolidColorBrush)((Button)sender).Background).Color;
|
||||
@@ -362,4 +378,19 @@ namespace ColorPicker.Controls
|
||||
(sender as System.Windows.Controls.TextBox).SelectAll();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning disable SA1402 // File may only contain a single type
|
||||
public class ColorPickerAutomationPeer : UserControlAutomationPeer
|
||||
#pragma warning restore SA1402 // File may only contain a single type
|
||||
{
|
||||
public ColorPickerAutomationPeer(ColorPickerControl owner)
|
||||
: base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
protected override string GetLocalizedControlTypeCore()
|
||||
{
|
||||
return ColorPicker.Properties.Resources.Color_Picker_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,9 @@ namespace ColorPicker.Helpers
|
||||
private bool _colorPickerShown;
|
||||
private object _colorPickerVisibilityLock = new object();
|
||||
|
||||
// Blocks using the escape key to close the color picker editor when the adjust color flyout is open.
|
||||
public static bool BlockEscapeKeyClosingColorPickerEditor { get; set; }
|
||||
|
||||
[ImportingConstructor]
|
||||
public AppStateHandler(IColorEditorViewModel colorEditorViewModel, IUserSettings userSettings)
|
||||
{
|
||||
@@ -36,6 +39,7 @@ namespace ColorPicker.Helpers
|
||||
|
||||
public void StartUserSession()
|
||||
{
|
||||
EndUserSession(); // Ends current user session if there's an active one.
|
||||
lock (_colorPickerVisibilityLock)
|
||||
{
|
||||
if (!_colorPickerShown && !IsColorPickerEditorVisible())
|
||||
@@ -149,7 +153,7 @@ namespace ColorPicker.Helpers
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsColorPickerEditorVisible()
|
||||
public bool IsColorPickerEditorVisible()
|
||||
{
|
||||
if (_colorEditorWindow != null)
|
||||
{
|
||||
@@ -160,6 +164,11 @@ namespace ColorPicker.Helpers
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsColorPickerVisible()
|
||||
{
|
||||
return _colorPickerShown;
|
||||
}
|
||||
|
||||
private void MainWindow_Closed(object sender, EventArgs e)
|
||||
{
|
||||
AppClosed?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
@@ -70,10 +70,17 @@ namespace ColorPicker.Keyboard
|
||||
var virtualCode = e.KeyboardData.VirtualCode;
|
||||
|
||||
// ESC pressed
|
||||
if (virtualCode == KeyInterop.VirtualKeyFromKey(Key.Escape))
|
||||
if (virtualCode == KeyInterop.VirtualKeyFromKey(Key.Escape)
|
||||
&& e.KeyboardState == GlobalKeyboardHook.KeyboardState.KeyDown
|
||||
)
|
||||
{
|
||||
e.Handled = _appStateHandler.EndUserSession();
|
||||
return;
|
||||
if (_appStateHandler.IsColorPickerVisible()
|
||||
|| !AppStateHandler.BlockEscapeKeyClosingColorPickerEditor
|
||||
)
|
||||
{
|
||||
e.Handled = _appStateHandler.EndUserSession();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((System.Windows.Application.Current as ColorPickerUI.App).IsRunningDetachedFromPowerToys())
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
Topmost="True"
|
||||
Background="Transparent"
|
||||
SizeToContent="WidthAndHeight"
|
||||
AllowsTransparency="True">
|
||||
AllowsTransparency="True"
|
||||
AutomationProperties.Name="Color Picker">
|
||||
<e:Interaction.Behaviors>
|
||||
<behaviors:ChangeWindowPositionBehavior/>
|
||||
<behaviors:AppearAnimationBehavior/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
|
||||
using System.Diagnostics;
|
||||
using ColorPicker.Helpers;
|
||||
using ColorPicker.Mouse;
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace ColorPicker
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
_args = args;
|
||||
Logger.LogInfo($"Color Picker started with pid={Process.GetCurrentProcess().Id}");
|
||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||
try
|
||||
{
|
||||
|
||||
@@ -78,6 +78,42 @@ namespace ColorPicker.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Color code.
|
||||
/// </summary>
|
||||
public static string Color_Code {
|
||||
get {
|
||||
return ResourceManager.GetString("Color_Code", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Color history.
|
||||
/// </summary>
|
||||
public static string Color_History {
|
||||
get {
|
||||
return ResourceManager.GetString("Color_History", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Color palette.
|
||||
/// </summary>
|
||||
public static string Color_Palette {
|
||||
get {
|
||||
return ResourceManager.GetString("Color_Palette", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Color picker control.
|
||||
/// </summary>
|
||||
public static string Color_Picker_Control {
|
||||
get {
|
||||
return ResourceManager.GetString("Color_Picker_Control", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Copied to clipboard.
|
||||
/// </summary>
|
||||
@@ -105,6 +141,24 @@ namespace ColorPicker.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Color dark 1.
|
||||
/// </summary>
|
||||
public static string Darker_color {
|
||||
get {
|
||||
return ResourceManager.GetString("Darker_color", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Color dark 2.
|
||||
/// </summary>
|
||||
public static string Darkest_color {
|
||||
get {
|
||||
return ResourceManager.GetString("Darkest_color", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Green value.
|
||||
/// </summary>
|
||||
@@ -132,6 +186,24 @@ namespace ColorPicker.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Color light 1.
|
||||
/// </summary>
|
||||
public static string Lighter_color {
|
||||
get {
|
||||
return ResourceManager.GetString("Lighter_color", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Color light 2.
|
||||
/// </summary>
|
||||
public static string Lightest_color {
|
||||
get {
|
||||
return ResourceManager.GetString("Lightest color", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Press the Color Picker icon to capture a color from your screen..
|
||||
/// </summary>
|
||||
|
||||
@@ -364,4 +364,28 @@
|
||||
<data name="Select_color" xml:space="preserve">
|
||||
<value>Select color</value>
|
||||
</data>
|
||||
<data name="Color_Code" xml:space="preserve">
|
||||
<value>Color code</value>
|
||||
</data>
|
||||
<data name="Color_History" xml:space="preserve">
|
||||
<value>Color history</value>
|
||||
</data>
|
||||
<data name="Color_Palette" xml:space="preserve">
|
||||
<value>Color palette</value>
|
||||
</data>
|
||||
<data name="Color_Picker_Control" xml:space="preserve">
|
||||
<value>Color picker control</value>
|
||||
</data>
|
||||
<data name="Darker_color" xml:space="preserve">
|
||||
<value>Color dark 1</value>
|
||||
</data>
|
||||
<data name="Darkest_color" xml:space="preserve">
|
||||
<value>Color dark 2</value>
|
||||
</data>
|
||||
<data name="Lighter_color" xml:space="preserve">
|
||||
<value>Color light 1</value>
|
||||
</data>
|
||||
<data name="Lightest color" xml:space="preserve">
|
||||
<value>Color light 2</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -118,10 +118,7 @@ namespace ColorPicker.ViewModels
|
||||
{
|
||||
ColorBrush = new SolidColorBrush(Color.FromArgb(color.A, color.R, color.G, color.B));
|
||||
ColorText = ColorRepresentationHelper.GetStringRepresentation(color, _userSettings.CopiedColorRepresentation.Value);
|
||||
if (_userSettings.ShowColorName.Value)
|
||||
{
|
||||
ColorName = ColorNameHelper.GetColorName(color);
|
||||
}
|
||||
ColorName = ColorNameHelper.GetColorName(color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
Padding="0"
|
||||
TabIndex="2"
|
||||
Width="64"
|
||||
AutomationProperties.Name="{x:Static p:Resources.Color_History}"
|
||||
HorizontalAlignment="Center"
|
||||
ui:FocusVisualHelper.UseSystemFocusVisuals="True"
|
||||
ItemsSource="{Binding ColorsHistory}"
|
||||
@@ -96,13 +97,16 @@
|
||||
<Button Width="64"
|
||||
Height="32"
|
||||
TabIndex="0"
|
||||
Content=""
|
||||
Command="{Binding OpenColorPickerCommand}"
|
||||
Background="Transparent"
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
ui:FocusVisualHelper.FocusVisualMargin="-1"
|
||||
ToolTipService.ToolTip="{x:Static p:Resources.Pick_color}"
|
||||
AutomationProperties.Name="{x:Static p:Resources.Pick_color}"/>
|
||||
AutomationProperties.Name="{x:Static p:Resources.Pick_color}">
|
||||
<Button.Content>
|
||||
<TextBlock Text="" AutomationProperties.Name="{x:Static p:Resources.Pick_color}" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
|
||||
@@ -115,7 +119,7 @@
|
||||
<ItemsControl IsTabStop="False"
|
||||
TabIndex="4"
|
||||
FocusManager.IsFocusScope="True"
|
||||
KeyboardNavigation.TabNavigation="Once"
|
||||
KeyboardNavigation.TabNavigation="Continue"
|
||||
ItemsSource="{Binding ColorRepresentations}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
@@ -173,7 +177,9 @@
|
||||
<TextBlock FontSize="16"
|
||||
Foreground="White"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center" >
|
||||
VerticalAlignment="Center"
|
||||
AutomationProperties.LiveSetting="Assertive"
|
||||
AutomationProperties.Name="{x:Static p:Resources.Copied_to_clipboard}">
|
||||
<Run Text=" " FontFamily="Segoe MDL2 Assets"/>
|
||||
<Run Text="{x:Static p:Resources.Copied_to_clipboard}" FontWeight="SemiBold"/>
|
||||
</TextBlock>
|
||||
|
||||
@@ -35,14 +35,18 @@
|
||||
VerticalAlignment="Stretch"
|
||||
BorderBrush="{DynamicResource WindowBorderBrush}"
|
||||
BorderThickness="1"
|
||||
x:Name="ColorBorderSmall"
|
||||
CornerRadius="4"/>
|
||||
|
||||
<TextBlock Margin="8,5,8,8"
|
||||
<TextBlock
|
||||
x:Name="ColorTextBlock"
|
||||
Margin="8,5,8,8"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource PrimaryForegroundBrush}"
|
||||
Grid.Column="1"
|
||||
AutomationProperties.LiveSetting="Assertive"
|
||||
AutomationProperties.LabeledBy="{Binding ColorName}"
|
||||
AutomationProperties.Name="{Binding ColorName}"
|
||||
Text="{Binding ColorText}"/>
|
||||
</Grid>
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
// 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.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Automation.Peers;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace ColorPicker.Views
|
||||
@@ -11,7 +14,41 @@ namespace ColorPicker.Views
|
||||
/// </summary>
|
||||
public partial class MainView : UserControl
|
||||
{
|
||||
private void EnableNarratorColorChangesAnnouncements()
|
||||
{
|
||||
INotifyPropertyChanged viewModel = (INotifyPropertyChanged)this.DataContext;
|
||||
viewModel.PropertyChanged += (sender, args) =>
|
||||
{
|
||||
if (args.PropertyName != "ColorName")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var colorTextBlock = (TextBlock)FindName("ColorTextBlock");
|
||||
if (colorTextBlock == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var peer = UIElementAutomationPeer.FromElement(colorTextBlock);
|
||||
if (peer == null)
|
||||
{
|
||||
peer = UIElementAutomationPeer.CreatePeerForElement(colorTextBlock);
|
||||
}
|
||||
|
||||
peer.RaiseAutomationEvent(AutomationEvents.MenuOpened);
|
||||
};
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
EnableNarratorColorChangesAnnouncements();
|
||||
}
|
||||
|
||||
public MainView()
|
||||
=> InitializeComponent();
|
||||
{
|
||||
InitializeComponent();
|
||||
Loaded += OnLoaded;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <FancyZonesLib/Generated Files/resource.h>
|
||||
#include <FancyZonesLib/FancyZonesData.h>
|
||||
#include <FancyZonesLib/FancyZonesWinHookEventIDs.h>
|
||||
#include <FancyZonesLib/Settings.h>
|
||||
#include <FancyZonesLib/trace.h>
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/hooks/WinHookEvent.h>
|
||||
#include "Settings.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
interface IZoneWindow;
|
||||
interface IWorkArea;
|
||||
interface IFancyZonesSettings;
|
||||
interface IZoneSet;
|
||||
|
||||
@@ -51,63 +50,6 @@ interface __declspec(uuid("{2CB37E8F-87E6-4AEC-B4B2-E0FDC873343F}")) IFancyZones
|
||||
*/
|
||||
IFACEMETHOD_(bool, OnKeyDown)
|
||||
(PKBDLLHOOKSTRUCT info) = 0;
|
||||
/**
|
||||
* Toggle FancyZones editor application.
|
||||
*/
|
||||
IFACEMETHOD_(void, ToggleEditor)
|
||||
() = 0;
|
||||
/**
|
||||
* Callback triggered when user changes FancyZones settings.
|
||||
*/
|
||||
IFACEMETHOD_(void, SettingsChanged)
|
||||
() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper functions used by each ZoneWindow (representing work area).
|
||||
*/
|
||||
interface __declspec(uuid("{5C8D99D6-34B2-4F4A-A8E5-7483F6869775}")) IZoneWindowHost : public IUnknown
|
||||
{
|
||||
/**
|
||||
* Assign window to appropriate zone inside new zone layout.
|
||||
*/
|
||||
IFACEMETHOD_(void, MoveWindowsOnActiveZoneSetChange)
|
||||
() = 0;
|
||||
/**
|
||||
* @returns Basic zone color.
|
||||
*/
|
||||
IFACEMETHOD_(COLORREF, GetZoneColor)
|
||||
() = 0;
|
||||
/**
|
||||
* @returns Zone border color.
|
||||
*/
|
||||
IFACEMETHOD_(COLORREF, GetZoneBorderColor)
|
||||
() = 0;
|
||||
/**
|
||||
* @returns Color used to highlight zone while giving zone layout hints.
|
||||
*/
|
||||
IFACEMETHOD_(COLORREF, GetZoneHighlightColor)
|
||||
() = 0;
|
||||
/**
|
||||
* @returns Integer in range [0, 100] indicating opacity of highlighted zone (while giving zone layout hints).
|
||||
*/
|
||||
IFACEMETHOD_(int, GetZoneHighlightOpacity)
|
||||
() = 0;
|
||||
/**
|
||||
* @returns Boolean indicating if dragged window should be transparent.
|
||||
*/
|
||||
IFACEMETHOD_(bool, isMakeDraggedWindowTransparentActive)
|
||||
() = 0;
|
||||
/**
|
||||
* @returns Boolean indicating if move/size operation is currently active.
|
||||
*/
|
||||
IFACEMETHOD_(bool, InMoveSize)
|
||||
() = 0;
|
||||
/**
|
||||
* @returns Enumeration value indicating the algorithm used to choose one of multiple overlapped zones to highlight.
|
||||
*/
|
||||
IFACEMETHOD_(Settings::OverlappingZonesAlgorithm, GetOverlappingZonesAlgorithm)
|
||||
() = 0;
|
||||
};
|
||||
|
||||
winrt::com_ptr<IFancyZones> MakeFancyZones(HINSTANCE hinstance, const winrt::com_ptr<IFancyZonesSettings>& settings, std::function<void()> disableCallback) noexcept;
|
||||
|
||||
@@ -196,7 +196,7 @@ bool FancyZonesData::AddDevice(const std::wstring& deviceId)
|
||||
std::scoped_lock lock{ dataLock };
|
||||
if (!deviceInfoMap.contains(deviceId))
|
||||
{
|
||||
// Creates default entry in map when ZoneWindow is created
|
||||
// Creates default entry in map when WorkArea is created
|
||||
GUID guid;
|
||||
auto result{ CoCreateGuid(&guid) };
|
||||
wil::unique_cotaskmem_string guidString;
|
||||
|
||||
@@ -34,8 +34,8 @@ namespace FancyZonesUnitTests
|
||||
class FancyZonesDataUnitTests;
|
||||
class FancyZonesIFancyZonesCallbackUnitTests;
|
||||
class ZoneSetCalculateZonesUnitTests;
|
||||
class ZoneWindowUnitTests;
|
||||
class ZoneWindowCreationUnitTests;
|
||||
class WorkAreaUnitTests;
|
||||
class WorkAreaCreationUnitTests;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -96,8 +96,8 @@ private:
|
||||
#if defined(UNIT_TESTS)
|
||||
friend class FancyZonesUnitTests::FancyZonesDataUnitTests;
|
||||
friend class FancyZonesUnitTests::FancyZonesIFancyZonesCallbackUnitTests;
|
||||
friend class FancyZonesUnitTests::ZoneWindowUnitTests;
|
||||
friend class FancyZonesUnitTests::ZoneWindowCreationUnitTests;
|
||||
friend class FancyZonesUnitTests::WorkAreaUnitTests;
|
||||
friend class FancyZonesUnitTests::WorkAreaCreationUnitTests;
|
||||
friend class FancyZonesUnitTests::ZoneSetCalculateZonesUnitTests;
|
||||
|
||||
inline void SetDeviceInfo(const std::wstring& deviceId, FancyZonesDataTypes::DeviceInfoData data)
|
||||
|
||||
@@ -41,11 +41,11 @@
|
||||
<ClInclude Include="FancyZones.h" />
|
||||
<ClInclude Include="FancyZonesDataTypes.h" />
|
||||
<ClInclude Include="FancyZonesWinHookEventIDs.h" />
|
||||
<ClInclude Include="FileWatcher.h" />
|
||||
<ClInclude Include="GenericKeyHook.h" />
|
||||
<ClInclude Include="FancyZonesData.h" />
|
||||
<ClInclude Include="JsonHelpers.h" />
|
||||
<ClInclude Include="KeyState.h" />
|
||||
<ClInclude Include="MonitorUtils.h" />
|
||||
<ClInclude Include="MonitorWorkAreaHandler.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="Generated Files/resource.h" />
|
||||
@@ -54,11 +54,12 @@
|
||||
<ClInclude Include="Settings.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
<ClInclude Include="util.h" />
|
||||
<ClInclude Include="VirtualDesktopUtils.h" />
|
||||
<ClInclude Include="VirtualDesktop.h" />
|
||||
<ClInclude Include="WindowMoveHandler.h" />
|
||||
<ClInclude Include="Zone.h" />
|
||||
<ClInclude Include="ZoneColors.h" />
|
||||
<ClInclude Include="ZoneSet.h" />
|
||||
<ClInclude Include="ZoneWindow.h" />
|
||||
<ClInclude Include="WorkArea.h" />
|
||||
<ClInclude Include="ZoneWindowDrawing.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -67,8 +68,8 @@
|
||||
<ClCompile Include="FancyZonesDataTypes.cpp" />
|
||||
<ClCompile Include="FancyZonesWinHookEventIDs.cpp" />
|
||||
<ClCompile Include="FancyZonesData.cpp" />
|
||||
<ClCompile Include="FileWatcher.cpp" />
|
||||
<ClCompile Include="JsonHelpers.cpp" />
|
||||
<ClCompile Include="MonitorUtils.cpp" />
|
||||
<ClCompile Include="MonitorWorkAreaHandler.cpp" />
|
||||
<ClCompile Include="OnThreadExecutor.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
@@ -78,11 +79,11 @@
|
||||
<ClCompile Include="Settings.cpp" />
|
||||
<ClCompile Include="trace.cpp" />
|
||||
<ClCompile Include="util.cpp" />
|
||||
<ClCompile Include="VirtualDesktopUtils.cpp" />
|
||||
<ClCompile Include="VirtualDesktop.cpp" />
|
||||
<ClCompile Include="WindowMoveHandler.cpp" />
|
||||
<ClCompile Include="Zone.cpp" />
|
||||
<ClCompile Include="ZoneSet.cpp" />
|
||||
<ClCompile Include="ZoneWindow.cpp" />
|
||||
<ClCompile Include="WorkArea.cpp" />
|
||||
<ClCompile Include="ZoneWindowDrawing.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<ClInclude Include="ZoneSet.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ZoneWindow.h">
|
||||
<ClInclude Include="WorkArea.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FancyZones.h">
|
||||
@@ -42,7 +42,7 @@
|
||||
<ClInclude Include="trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VirtualDesktopUtils.h">
|
||||
<ClInclude Include="VirtualDesktop.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="WindowMoveHandler.h">
|
||||
@@ -78,10 +78,13 @@
|
||||
<ClInclude Include="ZoneWindowDrawing.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FileWatcher.h">
|
||||
<ClInclude Include="CallTracer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CallTracer.h">
|
||||
<ClInclude Include="MonitorUtils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ZoneColors.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
@@ -95,7 +98,7 @@
|
||||
<ClCompile Include="ZoneSet.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZoneWindow.cpp">
|
||||
<ClCompile Include="WorkArea.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FancyZones.cpp">
|
||||
@@ -110,7 +113,7 @@
|
||||
<ClCompile Include="util.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VirtualDesktopUtils.cpp">
|
||||
<ClCompile Include="VirtualDesktop.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="WindowMoveHandler.cpp">
|
||||
@@ -140,10 +143,10 @@
|
||||
<ClCompile Include="OnThreadExecutor.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FileWatcher.cpp">
|
||||
<ClCompile Include="CallTracer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CallTracer.cpp">
|
||||
<ClCompile Include="MonitorUtils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "FancyZonesWinHookEventIDs.h"
|
||||
|
||||
UINT WM_PRIV_MOVESIZESTART;
|
||||
@@ -9,6 +7,14 @@ UINT WM_PRIV_MOVESIZEEND;
|
||||
UINT WM_PRIV_LOCATIONCHANGE;
|
||||
UINT WM_PRIV_NAMECHANGE;
|
||||
UINT WM_PRIV_WINDOWCREATED;
|
||||
UINT WM_PRIV_VD_INIT;
|
||||
UINT WM_PRIV_VD_SWITCH;
|
||||
UINT WM_PRIV_VD_UPDATE;
|
||||
UINT WM_PRIV_EDITOR;
|
||||
UINT WM_PRIV_FILE_UPDATE;
|
||||
UINT WM_PRIV_SNAP_HOTKEY;
|
||||
UINT WM_PRIV_QUICK_LAYOUT_KEY;
|
||||
UINT WM_PRIV_SETTINGS_CHANGED;
|
||||
|
||||
std::once_flag init_flag;
|
||||
|
||||
@@ -20,5 +26,13 @@ void InitializeWinhookEventIds()
|
||||
WM_PRIV_LOCATIONCHANGE = RegisterWindowMessage(L"{d56c5ee7-58e5-481c-8c4f-8844cf4d0347}");
|
||||
WM_PRIV_NAMECHANGE = RegisterWindowMessage(L"{b7b30c61-bfa0-4d95-bcde-fc4f2cbf6d76}");
|
||||
WM_PRIV_WINDOWCREATED = RegisterWindowMessage(L"{bdb10669-75da-480a-9ec4-eeebf09a02d7}");
|
||||
WM_PRIV_VD_INIT = RegisterWindowMessage(L"{469818a8-00fa-4069-b867-a1da484fcd9a}");
|
||||
WM_PRIV_VD_SWITCH = RegisterWindowMessage(L"{128c2cb0-6bdf-493e-abbe-f8705e04aa95}");
|
||||
WM_PRIV_VD_UPDATE = RegisterWindowMessage(L"{b8b72b46-f42f-4c26-9e20-29336cf2f22e}");
|
||||
WM_PRIV_EDITOR = RegisterWindowMessage(L"{87543824-7080-4e91-9d9c-0404642fc7b6}");
|
||||
WM_PRIV_FILE_UPDATE = RegisterWindowMessage(L"{632f17a9-55a7-45f1-a4db-162e39271d92}");
|
||||
WM_PRIV_SNAP_HOTKEY = RegisterWindowMessage(L"{72f4fd8e-23f1-43ab-bbbc-029363df9a84}");
|
||||
WM_PRIV_QUICK_LAYOUT_KEY = RegisterWindowMessage(L"{15baab3d-c67b-4a15-aFF0-13610e05e947}");
|
||||
WM_PRIV_SETTINGS_CHANGED = RegisterWindowMessage(L"{89ca3Daa-bf2d-4e73-9f3f-c60716364e27}");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,5 +5,13 @@ extern UINT WM_PRIV_MOVESIZEEND;
|
||||
extern UINT WM_PRIV_LOCATIONCHANGE;
|
||||
extern UINT WM_PRIV_NAMECHANGE;
|
||||
extern UINT WM_PRIV_WINDOWCREATED;
|
||||
extern UINT WM_PRIV_VD_INIT; // Scheduled when FancyZones is initialized
|
||||
extern UINT WM_PRIV_VD_SWITCH; // Scheduled when virtual desktop switch occurs
|
||||
extern UINT WM_PRIV_VD_UPDATE; // Scheduled on virtual desktops update (creation/deletion)
|
||||
extern UINT WM_PRIV_EDITOR; // Scheduled when the editor exits
|
||||
extern UINT WM_PRIV_FILE_UPDATE; // Scheduled when the a watched zone-settings file is updated
|
||||
extern UINT WM_PRIV_SNAP_HOTKEY; // Scheduled when we receive a snap hotkey key down press
|
||||
extern UINT WM_PRIV_QUICK_LAYOUT_KEY; // Scheduled when we receive a key down press to quickly apply a layout
|
||||
extern UINT WM_PRIV_SETTINGS_CHANGED; // Scheduled when the a watched settings file is updated
|
||||
|
||||
void InitializeWinhookEventIds();
|
||||
|
||||
@@ -61,6 +61,8 @@ namespace NonLocalizable
|
||||
const wchar_t MonitorId[] = L"monitor-id";
|
||||
const wchar_t TopCoordinate[] = L"top-coordinate";
|
||||
const wchar_t LeftCoordinate[] = L"left-coordinate";
|
||||
const wchar_t Width[] = L"width";
|
||||
const wchar_t Height[] = L"height";
|
||||
const wchar_t IsSelected[] = L"is-selected";
|
||||
const wchar_t ProcessId[] = L"process-id";
|
||||
const wchar_t SpanZonesAcrossMonitors[] = L"span-zones-across-monitors";
|
||||
@@ -514,8 +516,8 @@ namespace JSONHelpers
|
||||
result.SetNamedValue(NonLocalizable::MonitorId, json::value(monitor.id));
|
||||
result.SetNamedValue(NonLocalizable::TopCoordinate, json::value(monitor.top));
|
||||
result.SetNamedValue(NonLocalizable::LeftCoordinate, json::value(monitor.left));
|
||||
result.SetNamedValue(L"width", json::value(monitor.width));
|
||||
result.SetNamedValue(L"height", json::value(monitor.height));
|
||||
result.SetNamedValue(NonLocalizable::Width, json::value(monitor.width));
|
||||
result.SetNamedValue(NonLocalizable::Height, json::value(monitor.height));
|
||||
result.SetNamedValue(NonLocalizable::IsSelected, json::value(monitor.isSelected));
|
||||
|
||||
return result;
|
||||
|
||||
76
src/modules/fancyzones/FancyZonesLib/MonitorUtils.cpp
Normal file
76
src/modules/fancyzones/FancyZonesLib/MonitorUtils.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
#include "pch.h"
|
||||
#include "MonitorUtils.h"
|
||||
|
||||
#include <FancyZonesLib/util.h>
|
||||
|
||||
namespace MonitorUtils
|
||||
{
|
||||
constexpr int CUSTOM_POSITIONING_LEFT_TOP_PADDING = 16;
|
||||
|
||||
inline int RectWidth(const RECT& rect)
|
||||
{
|
||||
return rect.right - rect.left;
|
||||
}
|
||||
|
||||
inline int RectHeight(const RECT& rect)
|
||||
{
|
||||
return rect.bottom - rect.top;
|
||||
}
|
||||
|
||||
RECT FitOnScreen(const RECT& windowRect, const RECT& originMonitorRect, const RECT& destMonitorRect)
|
||||
{
|
||||
// New window position on active monitor. If window fits the screen, this will be final position.
|
||||
int left = destMonitorRect.left + (windowRect.left - originMonitorRect.left);
|
||||
int top = destMonitorRect.top + (windowRect.top - originMonitorRect.top);
|
||||
int W = RectWidth(windowRect);
|
||||
int H = RectHeight(windowRect);
|
||||
|
||||
if ((left < destMonitorRect.left) || (left + W > destMonitorRect.right))
|
||||
{
|
||||
// Set left window border to left border of screen (add padding). Resize window width if needed.
|
||||
left = destMonitorRect.left + CUSTOM_POSITIONING_LEFT_TOP_PADDING;
|
||||
W = min(W, RectWidth(destMonitorRect) - CUSTOM_POSITIONING_LEFT_TOP_PADDING);
|
||||
}
|
||||
if ((top < destMonitorRect.top) || (top + H > destMonitorRect.bottom))
|
||||
{
|
||||
// Set top window border to top border of screen (add padding). Resize window height if needed.
|
||||
top = destMonitorRect.top + CUSTOM_POSITIONING_LEFT_TOP_PADDING;
|
||||
H = min(H, RectHeight(destMonitorRect) - CUSTOM_POSITIONING_LEFT_TOP_PADDING);
|
||||
}
|
||||
|
||||
return { .left = left,
|
||||
.top = top,
|
||||
.right = left + W,
|
||||
.bottom = top + H };
|
||||
}
|
||||
|
||||
void OpenWindowOnActiveMonitor(HWND window, HMONITOR monitor) noexcept
|
||||
{
|
||||
// By default Windows opens new window on primary monitor.
|
||||
// Try to preserve window width and height, adjust top-left corner if needed.
|
||||
HMONITOR origin = MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY);
|
||||
if (origin == monitor)
|
||||
{
|
||||
// Certain applications by design open in last known position, regardless of FancyZones.
|
||||
// If that position is on currently active monitor, skip custom positioning.
|
||||
return;
|
||||
}
|
||||
|
||||
WINDOWPLACEMENT placement{};
|
||||
if (GetWindowPlacement(window, &placement))
|
||||
{
|
||||
MONITORINFOEX originMi;
|
||||
originMi.cbSize = sizeof(originMi);
|
||||
if (GetMonitorInfo(origin, &originMi))
|
||||
{
|
||||
MONITORINFOEX destMi;
|
||||
destMi.cbSize = sizeof(destMi);
|
||||
if (GetMonitorInfo(monitor, &destMi))
|
||||
{
|
||||
RECT newPosition = FitOnScreen(placement.rcNormalPosition, originMi.rcWork, destMi.rcWork);
|
||||
FancyZonesUtils::SizeWindowToRect(window, newPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
6
src/modules/fancyzones/FancyZonesLib/MonitorUtils.h
Normal file
6
src/modules/fancyzones/FancyZonesLib/MonitorUtils.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace MonitorUtils
|
||||
{
|
||||
void OpenWindowOnActiveMonitor(HWND window, HMONITOR monitor) noexcept;
|
||||
};
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "pch.h"
|
||||
#include "MonitorWorkAreaHandler.h"
|
||||
#include "VirtualDesktopUtils.h"
|
||||
#include "VirtualDesktop.h"
|
||||
|
||||
winrt::com_ptr<IZoneWindow> MonitorWorkAreaHandler::GetWorkArea(const GUID& desktopId, HMONITOR monitor)
|
||||
winrt::com_ptr<IWorkArea> MonitorWorkAreaHandler::GetWorkArea(const GUID& desktopId, HMONITOR monitor)
|
||||
{
|
||||
auto desktopIt = workAreaMap.find(desktopId);
|
||||
if (desktopIt != std::end(workAreaMap))
|
||||
@@ -17,7 +17,7 @@ winrt::com_ptr<IZoneWindow> MonitorWorkAreaHandler::GetWorkArea(const GUID& desk
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
winrt::com_ptr<IZoneWindow> MonitorWorkAreaHandler::GetWorkAreaFromCursor(const GUID& desktopId)
|
||||
winrt::com_ptr<IWorkArea> MonitorWorkAreaHandler::GetWorkAreaFromCursor(const GUID& desktopId)
|
||||
{
|
||||
auto allMonitorsWorkArea = GetWorkArea(desktopId, NULL);
|
||||
if (allMonitorsWorkArea)
|
||||
@@ -38,41 +38,35 @@ winrt::com_ptr<IZoneWindow> MonitorWorkAreaHandler::GetWorkAreaFromCursor(const
|
||||
}
|
||||
}
|
||||
|
||||
winrt::com_ptr<IZoneWindow> MonitorWorkAreaHandler::GetWorkArea(HWND window)
|
||||
winrt::com_ptr<IWorkArea> MonitorWorkAreaHandler::GetWorkArea(HWND window, const GUID& desktopId)
|
||||
{
|
||||
GUID desktopId{};
|
||||
if (VirtualDesktopUtils::GetWindowDesktopId(window, &desktopId))
|
||||
auto allMonitorsWorkArea = GetWorkArea(desktopId, NULL);
|
||||
if (allMonitorsWorkArea)
|
||||
{
|
||||
auto allMonitorsWorkArea = GetWorkArea(desktopId, NULL);
|
||||
if (allMonitorsWorkArea)
|
||||
{
|
||||
// First, check if there's a work area spanning all monitors (signalled by the NULL monitor handle)
|
||||
return allMonitorsWorkArea;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, look for the work area based on the window's position
|
||||
HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
|
||||
return GetWorkArea(desktopId, monitor);
|
||||
}
|
||||
// First, check if there's a work area spanning all monitors (signalled by the NULL monitor handle)
|
||||
return allMonitorsWorkArea;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, look for the work area based on the window's position
|
||||
HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
|
||||
return GetWorkArea(desktopId, monitor);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::unordered_map<HMONITOR, winrt::com_ptr<IZoneWindow>>& MonitorWorkAreaHandler::GetWorkAreasByDesktopId(const GUID& desktopId)
|
||||
const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& MonitorWorkAreaHandler::GetWorkAreasByDesktopId(const GUID& desktopId)
|
||||
{
|
||||
if (workAreaMap.contains(desktopId))
|
||||
{
|
||||
return workAreaMap[desktopId];
|
||||
}
|
||||
static const std::unordered_map<HMONITOR, winrt::com_ptr<IZoneWindow>> empty;
|
||||
static const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>> empty;
|
||||
return empty;
|
||||
}
|
||||
|
||||
std::vector<winrt::com_ptr<IZoneWindow>> MonitorWorkAreaHandler::GetAllWorkAreas()
|
||||
std::vector<winrt::com_ptr<IWorkArea>> MonitorWorkAreaHandler::GetAllWorkAreas()
|
||||
{
|
||||
std::vector<winrt::com_ptr<IZoneWindow>> workAreas{};
|
||||
std::vector<winrt::com_ptr<IWorkArea>> workAreas{};
|
||||
for (const auto& [desktopId, perDesktopData] : workAreaMap)
|
||||
{
|
||||
std::transform(std::begin(perDesktopData),
|
||||
@@ -83,7 +77,7 @@ std::vector<winrt::com_ptr<IZoneWindow>> MonitorWorkAreaHandler::GetAllWorkAreas
|
||||
return workAreas;
|
||||
}
|
||||
|
||||
void MonitorWorkAreaHandler::AddWorkArea(const GUID& desktopId, HMONITOR monitor, winrt::com_ptr<IZoneWindow>& workArea)
|
||||
void MonitorWorkAreaHandler::AddWorkArea(const GUID& desktopId, HMONITOR monitor, winrt::com_ptr<IWorkArea>& workArea)
|
||||
{
|
||||
if (!workAreaMap.contains(desktopId))
|
||||
{
|
||||
@@ -134,3 +128,25 @@ void MonitorWorkAreaHandler::Clear()
|
||||
{
|
||||
workAreaMap.clear();
|
||||
}
|
||||
|
||||
void MonitorWorkAreaHandler::UpdateZoneColors(const ZoneColors& colors)
|
||||
{
|
||||
for (const auto& workArea : workAreaMap)
|
||||
{
|
||||
for (const auto& zoneWindow : workArea.second)
|
||||
{
|
||||
zoneWindow.second->SetZoneColors(colors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MonitorWorkAreaHandler::UpdateOverlappingAlgorithm(OverlappingZonesAlgorithm overlappingAlgorithm)
|
||||
{
|
||||
for (const auto& workArea : workAreaMap)
|
||||
{
|
||||
for (const auto& zoneWindow : workArea.second)
|
||||
{
|
||||
zoneWindow.second->SetOverlappingZonesAlgorithm(overlappingAlgorithm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
interface IZoneWindow;
|
||||
interface IWorkArea;
|
||||
struct ZoneColors;
|
||||
enum struct OverlappingZonesAlgorithm;
|
||||
|
||||
namespace std
|
||||
{
|
||||
@@ -27,7 +29,7 @@ public:
|
||||
* @returns Object representing single work area, interface to all actions available on work area
|
||||
* (e.g. moving windows through zone layout specified for that work area).
|
||||
*/
|
||||
winrt::com_ptr<IZoneWindow> GetWorkArea(const GUID& desktopId, HMONITOR monitor);
|
||||
winrt::com_ptr<IWorkArea> GetWorkArea(const GUID& desktopId, HMONITOR monitor);
|
||||
|
||||
/**
|
||||
* Get work area based on virtual desktop id and the current cursor position.
|
||||
@@ -37,17 +39,18 @@ public:
|
||||
* @returns Object representing single work area, interface to all actions available on work area
|
||||
* (e.g. moving windows through zone layout specified for that work area).
|
||||
*/
|
||||
winrt::com_ptr<IZoneWindow> GetWorkAreaFromCursor(const GUID& desktopId);
|
||||
winrt::com_ptr<IWorkArea> GetWorkAreaFromCursor(const GUID& desktopId);
|
||||
|
||||
/**
|
||||
* Get work area on which specified window is located.
|
||||
*
|
||||
* @param[in] window Window handle.
|
||||
*
|
||||
* @param[in] desktopId GUID current desktop id
|
||||
*
|
||||
* @returns Object representing single work area, interface to all actions available on work area
|
||||
* (e.g. moving windows through zone layout specified for that work area).
|
||||
*/
|
||||
winrt::com_ptr<IZoneWindow> GetWorkArea(HWND window);
|
||||
winrt::com_ptr<IWorkArea> GetWorkArea(HWND window, const GUID& desktopId);
|
||||
|
||||
/**
|
||||
* Get map of all work areas on single virtual desktop. Key in the map is monitor handle, while value
|
||||
@@ -57,12 +60,12 @@ public:
|
||||
*
|
||||
* @returns Map containing pairs of monitor and work area for that monitor (within same virtual desktop).
|
||||
*/
|
||||
const std::unordered_map<HMONITOR, winrt::com_ptr<IZoneWindow>>& GetWorkAreasByDesktopId(const GUID& desktopId);
|
||||
const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& GetWorkAreasByDesktopId(const GUID& desktopId);
|
||||
|
||||
/**
|
||||
* @returns All registered work areas.
|
||||
*/
|
||||
std::vector<winrt::com_ptr<IZoneWindow>> GetAllWorkAreas();
|
||||
std::vector<winrt::com_ptr<IWorkArea>> GetAllWorkAreas();
|
||||
|
||||
/**
|
||||
* Register new work area.
|
||||
@@ -71,7 +74,7 @@ public:
|
||||
* @param[in] monitor Monitor handle.
|
||||
* @param[in] workAra Object representing single work area.
|
||||
*/
|
||||
void AddWorkArea(const GUID& desktopId, HMONITOR monitor, winrt::com_ptr<IZoneWindow>& workArea);
|
||||
void AddWorkArea(const GUID& desktopId, HMONITOR monitor, winrt::com_ptr<IWorkArea>& workArea);
|
||||
|
||||
/**
|
||||
* Check if work area is already registered.
|
||||
@@ -95,7 +98,17 @@ public:
|
||||
*/
|
||||
void Clear();
|
||||
|
||||
/**
|
||||
* Update zone colors after settings changed
|
||||
*/
|
||||
void UpdateZoneColors(const ZoneColors& colors);
|
||||
|
||||
/**
|
||||
* Update overlapping algorithm after settings changed
|
||||
*/
|
||||
void UpdateOverlappingAlgorithm(OverlappingZonesAlgorithm overlappingAlgorithm);
|
||||
|
||||
private:
|
||||
// Work area is uniquely defined by monitor and virtual desktop id.
|
||||
std::unordered_map<GUID, std::unordered_map<HMONITOR, winrt::com_ptr<IZoneWindow>>> workAreaMap;
|
||||
std::unordered_map<GUID, std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>> workAreaMap;
|
||||
};
|
||||
|
||||
@@ -53,10 +53,6 @@ public:
|
||||
LoadSettings(name, true);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
SetCallback(IFancyZonesCallback* callback) { m_callback = callback; }
|
||||
IFACEMETHODIMP_(void)
|
||||
ResetCallback() { m_callback = nullptr; }
|
||||
IFACEMETHODIMP_(bool)
|
||||
GetConfig(_Out_ PWSTR buffer, _Out_ int* buffer_sizeg) noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
@@ -70,7 +66,6 @@ private:
|
||||
void LoadSettings(PCWSTR config, bool fromFile) noexcept;
|
||||
void SaveSettings() noexcept;
|
||||
|
||||
IFancyZonesCallback* m_callback{};
|
||||
const HINSTANCE m_hinstance;
|
||||
std::wstring m_moduleName{};
|
||||
std::wstring m_moduleKey{};
|
||||
@@ -143,20 +138,12 @@ FancyZonesSettings::SetConfig(PCWSTR serializedPowerToysSettingsJson) noexcept
|
||||
{
|
||||
LoadSettings(serializedPowerToysSettingsJson, false /*fromFile*/);
|
||||
SaveSettings();
|
||||
if (m_callback)
|
||||
{
|
||||
m_callback->SettingsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
FancyZonesSettings::ReloadSettings() noexcept
|
||||
{
|
||||
LoadSettings(m_moduleKey.c_str(), true /*fromFile*/);
|
||||
if (m_callback)
|
||||
{
|
||||
m_callback->SettingsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZonesSettings::LoadSettings(PCWSTR config, bool fromFile) noexcept
|
||||
@@ -226,9 +213,9 @@ void FancyZonesSettings::LoadSettings(PCWSTR config, bool fromFile) noexcept
|
||||
if (auto val = values.get_int_value(NonLocalizable::OverlappingZonesAlgorithmID))
|
||||
{
|
||||
// Avoid undefined behavior
|
||||
if (*val >= 0 || *val < (int)Settings::OverlappingZonesAlgorithm::EnumElements)
|
||||
if (*val >= 0 || *val < (int)OverlappingZonesAlgorithm::EnumElements)
|
||||
{
|
||||
m_settings.overlappingZonesAlgorithm = (Settings::OverlappingZonesAlgorithm)*val;
|
||||
m_settings.overlappingZonesAlgorithm = (OverlappingZonesAlgorithm)*val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,18 @@ namespace ZonedWindowProperties
|
||||
const wchar_t MultiMonitorDeviceID[] = L"FancyZones#MultiMonitorDevice";
|
||||
}
|
||||
|
||||
enum struct OverlappingZonesAlgorithm : int
|
||||
{
|
||||
Smallest = 0,
|
||||
Largest = 1,
|
||||
Positional = 2,
|
||||
ClosestCenter = 3,
|
||||
EnumElements = 4, // number of elements in the enum, not counting this
|
||||
};
|
||||
|
||||
// in reality, this file needs to be kept in sync currently with src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/FZConfigProperties.cs
|
||||
struct Settings
|
||||
{
|
||||
enum struct OverlappingZonesAlgorithm : int
|
||||
{
|
||||
Smallest = 0,
|
||||
Largest = 1,
|
||||
Positional = 2,
|
||||
ClosestCenter = 3,
|
||||
EnumElements = 4, // number of elements in the enum, not counting this
|
||||
};
|
||||
|
||||
// The values specified here are the defaults.
|
||||
bool shiftDrag = true;
|
||||
bool mouseSwitch = false;
|
||||
@@ -54,8 +54,6 @@ struct Settings
|
||||
|
||||
interface __declspec(uuid("{BA4E77C4-6F44-4C5D-93D3-CBDE880495C2}")) IFancyZonesSettings : public IUnknown
|
||||
{
|
||||
IFACEMETHOD_(void, SetCallback)(interface IFancyZonesCallback* callback) = 0;
|
||||
IFACEMETHOD_(void, ResetCallback)() = 0;
|
||||
IFACEMETHOD_(bool, GetConfig)(_Out_ PWSTR buffer, _Out_ int *buffer_size) = 0;
|
||||
IFACEMETHOD_(void, SetConfig)(PCWSTR serializedPowerToysSettings) = 0;
|
||||
IFACEMETHOD_(void, ReloadSettings)() = 0;
|
||||
|
||||
234
src/modules/fancyzones/FancyZonesLib/VirtualDesktop.cpp
Normal file
234
src/modules/fancyzones/FancyZonesLib/VirtualDesktop.cpp
Normal file
@@ -0,0 +1,234 @@
|
||||
#include "pch.h"
|
||||
#include "VirtualDesktop.h"
|
||||
|
||||
// Non-Localizable strings
|
||||
namespace NonLocalizable
|
||||
{
|
||||
const wchar_t RegCurrentVirtualDesktop[] = L"CurrentVirtualDesktop";
|
||||
const wchar_t RegVirtualDesktopIds[] = L"VirtualDesktopIDs";
|
||||
const wchar_t RegKeyVirtualDesktops[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VirtualDesktops";
|
||||
const wchar_t RegKeyVirtualDesktopsFromSession[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SessionInfo\\%d\\VirtualDesktops";
|
||||
}
|
||||
|
||||
const CLSID CLSID_ImmersiveShell = { 0xC2F03A33, 0x21F5, 0x47FA, 0xB4, 0xBB, 0x15, 0x63, 0x62, 0xA2, 0xF2, 0x39 };
|
||||
|
||||
IServiceProvider* GetServiceProvider()
|
||||
{
|
||||
IServiceProvider* provider{ nullptr };
|
||||
if (FAILED(CoCreateInstance(CLSID_ImmersiveShell, nullptr, CLSCTX_LOCAL_SERVER, __uuidof(provider), (PVOID*)&provider)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
|
||||
IVirtualDesktopManager* GetVirtualDesktopManager()
|
||||
{
|
||||
IVirtualDesktopManager* manager{ nullptr };
|
||||
IServiceProvider* serviceProvider = GetServiceProvider();
|
||||
if (serviceProvider == nullptr || FAILED(serviceProvider->QueryService(__uuidof(manager), &manager)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return manager;
|
||||
}
|
||||
|
||||
std::optional<GUID> NewGetCurrentDesktopId()
|
||||
{
|
||||
wil::unique_hkey key{};
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, NonLocalizable::RegKeyVirtualDesktops, 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS)
|
||||
{
|
||||
GUID value{};
|
||||
DWORD size = sizeof(GUID);
|
||||
if (RegQueryValueExW(key.get(), NonLocalizable::RegCurrentVirtualDesktop, 0, nullptr, reinterpret_cast<BYTE*>(&value), &size) == ERROR_SUCCESS)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<GUID> GetDesktopIdFromCurrentSession()
|
||||
{
|
||||
DWORD sessionId;
|
||||
if (!ProcessIdToSessionId(GetCurrentProcessId(), &sessionId))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
wchar_t sessionKeyPath[256]{};
|
||||
if (FAILED(StringCchPrintfW(sessionKeyPath, ARRAYSIZE(sessionKeyPath), NonLocalizable::RegKeyVirtualDesktopsFromSession, sessionId)))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
wil::unique_hkey key{};
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, sessionKeyPath, 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS)
|
||||
{
|
||||
GUID value{};
|
||||
DWORD size = sizeof(GUID);
|
||||
if (RegQueryValueExW(key.get(), NonLocalizable::RegCurrentVirtualDesktop, 0, nullptr, reinterpret_cast<BYTE*>(&value), &size) == ERROR_SUCCESS)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool GetZoneWindowDesktopId(IWorkArea* zoneWindow, GUID* desktopId)
|
||||
{
|
||||
// Format: <device-id>_<resolution>_<virtual-desktop-id>
|
||||
std::wstring uniqueId = zoneWindow->UniqueId();
|
||||
std::wstring virtualDesktopId = uniqueId.substr(uniqueId.rfind('_') + 1);
|
||||
return SUCCEEDED(CLSIDFromString(virtualDesktopId.c_str(), desktopId));
|
||||
}
|
||||
|
||||
HKEY OpenVirtualDesktopsRegKey()
|
||||
{
|
||||
HKEY hKey{ nullptr };
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER, NonLocalizable::RegKeyVirtualDesktops, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
return hKey;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HKEY GetVirtualDesktopsRegKey()
|
||||
{
|
||||
static wil::unique_hkey virtualDesktopsKey{ OpenVirtualDesktopsRegKey() };
|
||||
return virtualDesktopsKey.get();
|
||||
}
|
||||
|
||||
VirtualDesktop::VirtualDesktop(const std::function<void()>& vdInitCallback, const std::function<void()>& vdUpdatedCallback) :
|
||||
m_vdInitCallback(vdInitCallback),
|
||||
m_vdUpdatedCallback(vdUpdatedCallback),
|
||||
m_vdManager(GetVirtualDesktopManager())
|
||||
{
|
||||
}
|
||||
|
||||
void VirtualDesktop::Init()
|
||||
{
|
||||
m_vdInitCallback();
|
||||
|
||||
m_terminateVirtualDesktopTrackerEvent.reset(CreateEvent(nullptr, FALSE, FALSE, nullptr));
|
||||
m_virtualDesktopTrackerThread.submit(OnThreadExecutor::task_t{ [&] { HandleVirtualDesktopUpdates(); } });
|
||||
}
|
||||
|
||||
void VirtualDesktop::UnInit()
|
||||
{
|
||||
if (m_terminateVirtualDesktopTrackerEvent)
|
||||
{
|
||||
SetEvent(m_terminateVirtualDesktopTrackerEvent.get());
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<GUID> VirtualDesktop::GetWindowDesktopId(HWND topLevelWindow) const
|
||||
{
|
||||
GUID desktopId{};
|
||||
if (m_vdManager && SUCCEEDED(m_vdManager->GetWindowDesktopId(topLevelWindow, &desktopId)))
|
||||
{
|
||||
return desktopId;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<GUID> VirtualDesktop::GetCurrentVirtualDesktopId() const
|
||||
{
|
||||
// On newer Windows builds, the current virtual desktop is persisted to
|
||||
// a totally different reg key. Look there first.
|
||||
std::optional<GUID> desktopId = NewGetCurrentDesktopId();
|
||||
if (desktopId.has_value())
|
||||
{
|
||||
return desktopId;
|
||||
}
|
||||
|
||||
// Explorer persists current virtual desktop identifier to registry on a per session basis, but only
|
||||
// after first virtual desktop switch happens. If the user hasn't switched virtual desktops in this
|
||||
// session, value in registry will be empty.
|
||||
desktopId = GetDesktopIdFromCurrentSession();
|
||||
if (desktopId.has_value())
|
||||
{
|
||||
return desktopId;
|
||||
}
|
||||
|
||||
// Fallback scenario is to get array of virtual desktops stored in registry, but not kept per session.
|
||||
// Note that we are taking first element from virtual desktop array, which is primary desktop.
|
||||
// If user has more than one virtual desktop, previous function should return correct value, as desktop
|
||||
// switch occurred in current session.
|
||||
else
|
||||
{
|
||||
auto ids = GetVirtualDesktopIds();
|
||||
if (ids.has_value() && ids->size() > 0)
|
||||
{
|
||||
return ids->at(0);
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::vector<GUID>> VirtualDesktop::GetVirtualDesktopIds(HKEY hKey) const
|
||||
{
|
||||
if (!hKey)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
DWORD bufferCapacity;
|
||||
// request regkey binary buffer capacity only
|
||||
if (RegQueryValueExW(hKey, NonLocalizable::RegVirtualDesktopIds, 0, nullptr, nullptr, &bufferCapacity) != ERROR_SUCCESS)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::unique_ptr<BYTE[]> buffer = std::make_unique<BYTE[]>(bufferCapacity);
|
||||
// request regkey binary content
|
||||
if (RegQueryValueExW(hKey, NonLocalizable::RegVirtualDesktopIds, 0, nullptr, buffer.get(), &bufferCapacity) != ERROR_SUCCESS)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const size_t guidSize = sizeof(GUID);
|
||||
std::vector<GUID> temp;
|
||||
temp.reserve(bufferCapacity / guidSize);
|
||||
for (size_t i = 0; i < bufferCapacity; i += guidSize)
|
||||
{
|
||||
GUID* guid = reinterpret_cast<GUID*>(buffer.get() + i);
|
||||
temp.push_back(*guid);
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
std::optional<std::vector<GUID>> VirtualDesktop::GetVirtualDesktopIds() const
|
||||
{
|
||||
return GetVirtualDesktopIds(GetVirtualDesktopsRegKey());
|
||||
}
|
||||
|
||||
void VirtualDesktop::HandleVirtualDesktopUpdates()
|
||||
{
|
||||
HKEY virtualDesktopsRegKey = GetVirtualDesktopsRegKey();
|
||||
if (!virtualDesktopsRegKey)
|
||||
{
|
||||
return;
|
||||
}
|
||||
HANDLE regKeyEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
HANDLE events[2] = { regKeyEvent, m_terminateVirtualDesktopTrackerEvent.get() };
|
||||
while (1)
|
||||
{
|
||||
if (RegNotifyChangeKeyValue(virtualDesktopsRegKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, regKeyEvent, TRUE) != ERROR_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (WaitForMultipleObjects(2, events, FALSE, INFINITE) != (WAIT_OBJECT_0 + 0))
|
||||
{
|
||||
// if terminateEvent is signalized or WaitForMultipleObjects failed, terminate thread execution
|
||||
return;
|
||||
}
|
||||
|
||||
m_vdUpdatedCallback();
|
||||
}
|
||||
}
|
||||
30
src/modules/fancyzones/FancyZonesLib/VirtualDesktop.h
Normal file
30
src/modules/fancyzones/FancyZonesLib/VirtualDesktop.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "WorkArea.h"
|
||||
#include "on_thread_executor.h"
|
||||
|
||||
class VirtualDesktop
|
||||
{
|
||||
public:
|
||||
VirtualDesktop(const std::function<void()>& vdInitCallback, const std::function<void()>& vdUpdatedCallback);
|
||||
~VirtualDesktop() = default;
|
||||
|
||||
void Init();
|
||||
void UnInit();
|
||||
|
||||
std::optional<GUID> GetWindowDesktopId(HWND topLevelWindow) const;
|
||||
std::optional<GUID> GetCurrentVirtualDesktopId() const;
|
||||
std::optional<std::vector<GUID>> GetVirtualDesktopIds() const;
|
||||
|
||||
private:
|
||||
std::function<void()> m_vdInitCallback;
|
||||
std::function<void()> m_vdUpdatedCallback;
|
||||
|
||||
IVirtualDesktopManager* m_vdManager;
|
||||
|
||||
OnThreadExecutor m_virtualDesktopTrackerThread;
|
||||
wil::unique_handle m_terminateVirtualDesktopTrackerEvent;
|
||||
|
||||
std::optional<std::vector<GUID>> GetVirtualDesktopIds(HKEY hKey) const;
|
||||
void HandleVirtualDesktopUpdates();
|
||||
};
|
||||
@@ -1,224 +0,0 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "VirtualDesktopUtils.h"
|
||||
|
||||
// Non-Localizable strings
|
||||
namespace NonLocalizable
|
||||
{
|
||||
const wchar_t RegCurrentVirtualDesktop[] = L"CurrentVirtualDesktop";
|
||||
const wchar_t RegVirtualDesktopIds[] = L"VirtualDesktopIDs";
|
||||
const wchar_t RegKeyVirtualDesktops[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VirtualDesktops";
|
||||
const wchar_t RegKeyVirtualDesktopsFromSession[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SessionInfo\\%d\\VirtualDesktops";
|
||||
}
|
||||
|
||||
namespace VirtualDesktopUtils
|
||||
{
|
||||
const CLSID CLSID_ImmersiveShell = { 0xC2F03A33, 0x21F5, 0x47FA, 0xB4, 0xBB, 0x15, 0x63, 0x62, 0xA2, 0xF2, 0x39 };
|
||||
|
||||
IServiceProvider* GetServiceProvider()
|
||||
{
|
||||
IServiceProvider* provider{ nullptr };
|
||||
if (FAILED(CoCreateInstance(CLSID_ImmersiveShell, nullptr, CLSCTX_LOCAL_SERVER, __uuidof(provider), (PVOID*)&provider)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
|
||||
IVirtualDesktopManager* GetVirtualDesktopManager()
|
||||
{
|
||||
IVirtualDesktopManager* manager{ nullptr };
|
||||
IServiceProvider* serviceProvider = GetServiceProvider();
|
||||
if (serviceProvider == nullptr || FAILED(serviceProvider->QueryService(__uuidof(manager), &manager)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return manager;
|
||||
}
|
||||
|
||||
bool GetWindowDesktopId(HWND topLevelWindow, GUID* desktopId)
|
||||
{
|
||||
static IVirtualDesktopManager* virtualDesktopManager = GetVirtualDesktopManager();
|
||||
return (virtualDesktopManager != nullptr) &&
|
||||
SUCCEEDED(virtualDesktopManager->GetWindowDesktopId(topLevelWindow, desktopId));
|
||||
}
|
||||
|
||||
bool GetZoneWindowDesktopId(IZoneWindow* zoneWindow, GUID* desktopId)
|
||||
{
|
||||
// Format: <device-id>_<resolution>_<virtual-desktop-id>
|
||||
std::wstring uniqueId = zoneWindow->UniqueId();
|
||||
std::wstring virtualDesktopId = uniqueId.substr(uniqueId.rfind('_') + 1);
|
||||
return SUCCEEDED(CLSIDFromString(virtualDesktopId.c_str(), desktopId));
|
||||
}
|
||||
|
||||
bool NewGetCurrentDesktopId(GUID* desktopId)
|
||||
{
|
||||
wil::unique_hkey key{};
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, NonLocalizable::RegKeyVirtualDesktops, 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS)
|
||||
{
|
||||
GUID value{};
|
||||
DWORD size = sizeof(GUID);
|
||||
if (RegQueryValueExW(key.get(), NonLocalizable::RegCurrentVirtualDesktop, 0, nullptr, reinterpret_cast<BYTE*>(&value), &size) == ERROR_SUCCESS)
|
||||
{
|
||||
*desktopId = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetDesktopIdFromCurrentSession(GUID* desktopId)
|
||||
{
|
||||
DWORD sessionId;
|
||||
if (!ProcessIdToSessionId(GetCurrentProcessId(), &sessionId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
wchar_t sessionKeyPath[256]{};
|
||||
if (FAILED(StringCchPrintfW(sessionKeyPath, ARRAYSIZE(sessionKeyPath), NonLocalizable::RegKeyVirtualDesktopsFromSession, sessionId)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
wil::unique_hkey key{};
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, sessionKeyPath, 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS)
|
||||
{
|
||||
GUID value{};
|
||||
DWORD size = sizeof(GUID);
|
||||
if (RegQueryValueExW(key.get(), NonLocalizable::RegCurrentVirtualDesktop, 0, nullptr, reinterpret_cast<BYTE*>(&value), &size) == ERROR_SUCCESS)
|
||||
{
|
||||
*desktopId = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetCurrentVirtualDesktopId(GUID* desktopId)
|
||||
{
|
||||
// On newer Windows builds, the current virtual desktop is persisted to
|
||||
// a totally different reg key. Look there first.
|
||||
if (NewGetCurrentDesktopId(desktopId))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Explorer persists current virtual desktop identifier to registry on a per session basis, but only
|
||||
// after first virtual desktop switch happens. If the user hasn't switched virtual desktops in this
|
||||
// session, value in registry will be empty.
|
||||
if (GetDesktopIdFromCurrentSession(desktopId))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// Fallback scenario is to get array of virtual desktops stored in registry, but not kept per session.
|
||||
// Note that we are taking first element from virtual desktop array, which is primary desktop.
|
||||
// If user has more than one virtual desktop, previous function should return correct value, as desktop
|
||||
// switch occurred in current session.
|
||||
else
|
||||
{
|
||||
std::vector<GUID> ids{};
|
||||
if (GetVirtualDesktopIds(ids) && ids.size() > 0)
|
||||
{
|
||||
*desktopId = ids[0];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetVirtualDesktopIds(HKEY hKey, std::vector<GUID>& ids)
|
||||
{
|
||||
if (!hKey)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
DWORD bufferCapacity;
|
||||
// request regkey binary buffer capacity only
|
||||
if (RegQueryValueExW(hKey, NonLocalizable::RegVirtualDesktopIds, 0, nullptr, nullptr, &bufferCapacity) != ERROR_SUCCESS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
std::unique_ptr<BYTE[]> buffer = std::make_unique<BYTE[]>(bufferCapacity);
|
||||
// request regkey binary content
|
||||
if (RegQueryValueExW(hKey, NonLocalizable::RegVirtualDesktopIds, 0, nullptr, buffer.get(), &bufferCapacity) != ERROR_SUCCESS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const size_t guidSize = sizeof(GUID);
|
||||
std::vector<GUID> temp;
|
||||
temp.reserve(bufferCapacity / guidSize);
|
||||
for (size_t i = 0; i < bufferCapacity; i += guidSize)
|
||||
{
|
||||
GUID* guid = reinterpret_cast<GUID*>(buffer.get() + i);
|
||||
temp.push_back(*guid);
|
||||
}
|
||||
ids = std::move(temp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetVirtualDesktopIds(std::vector<GUID>& ids)
|
||||
{
|
||||
return GetVirtualDesktopIds(GetVirtualDesktopsRegKey(), ids);
|
||||
}
|
||||
|
||||
bool GetVirtualDesktopIds(std::vector<std::wstring>& ids)
|
||||
{
|
||||
std::vector<GUID> guids{};
|
||||
if (GetVirtualDesktopIds(guids))
|
||||
{
|
||||
for (auto& guid : guids)
|
||||
{
|
||||
wil::unique_cotaskmem_string guidString;
|
||||
if (SUCCEEDED(StringFromCLSID(guid, &guidString)))
|
||||
{
|
||||
ids.push_back(guidString.get());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
HKEY OpenVirtualDesktopsRegKey()
|
||||
{
|
||||
HKEY hKey{ nullptr };
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER, NonLocalizable::RegKeyVirtualDesktops, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
return hKey;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HKEY GetVirtualDesktopsRegKey()
|
||||
{
|
||||
static wil::unique_hkey virtualDesktopsKey{ OpenVirtualDesktopsRegKey() };
|
||||
return virtualDesktopsKey.get();
|
||||
}
|
||||
|
||||
void HandleVirtualDesktopUpdates(HWND window, UINT message, HANDLE terminateEvent)
|
||||
{
|
||||
HKEY virtualDesktopsRegKey = GetVirtualDesktopsRegKey();
|
||||
if (!virtualDesktopsRegKey)
|
||||
{
|
||||
return;
|
||||
}
|
||||
HANDLE regKeyEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
HANDLE events[2] = { regKeyEvent, terminateEvent };
|
||||
while (1)
|
||||
{
|
||||
if (RegNotifyChangeKeyValue(virtualDesktopsRegKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, regKeyEvent, TRUE) != ERROR_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (WaitForMultipleObjects(2, events, FALSE, INFINITE) != (WAIT_OBJECT_0 + 0))
|
||||
{
|
||||
// if terminateEvent is signalized or WaitForMultipleObjects failed, terminate thread execution
|
||||
return;
|
||||
}
|
||||
PostMessage(window, message, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "ZoneWindow.h"
|
||||
|
||||
namespace VirtualDesktopUtils
|
||||
{
|
||||
bool GetWindowDesktopId(HWND topLevelWindow, GUID* desktopId);
|
||||
bool GetZoneWindowDesktopId(IZoneWindow* zoneWindow, GUID* desktopId);
|
||||
bool GetCurrentVirtualDesktopId(GUID* desktopId);
|
||||
bool GetVirtualDesktopIds(std::vector<GUID>& ids);
|
||||
bool GetVirtualDesktopIds(std::vector<std::wstring>& ids);
|
||||
HKEY GetVirtualDesktopsRegKey();
|
||||
void HandleVirtualDesktopUpdates(HWND window, UINT message, HANDLE terminateEvent);
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "FancyZonesData.h"
|
||||
#include "Settings.h"
|
||||
#include "ZoneWindow.h"
|
||||
#include "WorkArea.h"
|
||||
#include "util.h"
|
||||
|
||||
// Non-Localizable strings
|
||||
@@ -59,7 +59,7 @@ WindowMoveHandler::WindowMoveHandler(const winrt::com_ptr<IFancyZonesSettings>&
|
||||
{
|
||||
}
|
||||
|
||||
void WindowMoveHandler::MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
|
||||
void WindowMoveHandler::MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& zoneWindowMap) noexcept
|
||||
{
|
||||
if (!FancyZonesUtils::IsCandidateForZoning(window, m_settings->GetSettings()->excludedAppsArray) || WindowMoveHandlerUtils::IsCursorTypeIndicatingSizeEvent())
|
||||
{
|
||||
@@ -125,7 +125,7 @@ void WindowMoveHandler::MoveSizeStart(HWND window, HMONITOR monitor, POINT const
|
||||
}
|
||||
}
|
||||
|
||||
void WindowMoveHandler::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
|
||||
void WindowMoveHandler::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& zoneWindowMap) noexcept
|
||||
{
|
||||
if (!m_inMoveSize)
|
||||
{
|
||||
@@ -137,7 +137,7 @@ void WindowMoveHandler::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen,
|
||||
|
||||
if (m_zoneWindowMoveSize)
|
||||
{
|
||||
// Update the ZoneWindow already handling move/size
|
||||
// Update the WorkArea already handling move/size
|
||||
if (!m_dragEnabled)
|
||||
{
|
||||
// Drag got disabled, tell it to cancel and hide all windows
|
||||
@@ -180,7 +180,7 @@ void WindowMoveHandler::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen,
|
||||
else if (m_dragEnabled)
|
||||
{
|
||||
// We'll get here if the user presses/releases shift while dragging.
|
||||
// Restart the drag on the ZoneWindow that m_windowMoveSize is on
|
||||
// Restart the drag on the WorkArea that m_windowMoveSize is on
|
||||
MoveSizeStart(m_windowMoveSize, monitor, ptScreen, zoneWindowMap);
|
||||
|
||||
// m_dragEnabled could get set to false if we're moving an elevated window.
|
||||
@@ -192,7 +192,7 @@ void WindowMoveHandler::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen,
|
||||
}
|
||||
}
|
||||
|
||||
void WindowMoveHandler::MoveSizeEnd(HWND window, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
|
||||
void WindowMoveHandler::MoveSizeEnd(HWND window, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& zoneWindowMap) noexcept
|
||||
{
|
||||
if (window != m_windowMoveSize)
|
||||
{
|
||||
@@ -273,7 +273,7 @@ void WindowMoveHandler::MoveSizeEnd(HWND window, POINT const& ptScreen, const st
|
||||
}
|
||||
}
|
||||
|
||||
void WindowMoveHandler::MoveWindowIntoZoneByIndexSet(HWND window, const std::vector<size_t>& indexSet, winrt::com_ptr<IZoneWindow> zoneWindow) noexcept
|
||||
void WindowMoveHandler::MoveWindowIntoZoneByIndexSet(HWND window, const std::vector<size_t>& indexSet, winrt::com_ptr<IWorkArea> zoneWindow) noexcept
|
||||
{
|
||||
if (window != m_windowMoveSize)
|
||||
{
|
||||
@@ -281,17 +281,17 @@ void WindowMoveHandler::MoveWindowIntoZoneByIndexSet(HWND window, const std::vec
|
||||
}
|
||||
}
|
||||
|
||||
bool WindowMoveHandler::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr<IZoneWindow> zoneWindow) noexcept
|
||||
bool WindowMoveHandler::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr<IWorkArea> zoneWindow) noexcept
|
||||
{
|
||||
return zoneWindow && zoneWindow->MoveWindowIntoZoneByDirectionAndIndex(window, vkCode, cycle);
|
||||
}
|
||||
|
||||
bool WindowMoveHandler::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr<IZoneWindow> zoneWindow) noexcept
|
||||
bool WindowMoveHandler::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr<IWorkArea> zoneWindow) noexcept
|
||||
{
|
||||
return zoneWindow && zoneWindow->MoveWindowIntoZoneByDirectionAndPosition(window, vkCode, cycle);
|
||||
}
|
||||
|
||||
bool WindowMoveHandler::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode, winrt::com_ptr<IZoneWindow> zoneWindow) noexcept
|
||||
bool WindowMoveHandler::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode, winrt::com_ptr<IWorkArea> zoneWindow) noexcept
|
||||
{
|
||||
return zoneWindow && zoneWindow->ExtendWindowByDirectionAndPosition(window, vkCode);
|
||||
}
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
#include <functional>
|
||||
|
||||
interface IFancyZonesSettings;
|
||||
interface IZoneWindow;
|
||||
interface IWorkArea;
|
||||
|
||||
class WindowMoveHandler
|
||||
{
|
||||
public:
|
||||
WindowMoveHandler(const winrt::com_ptr<IFancyZonesSettings>& settings, const std::function<void()>& keyUpdateCallback);
|
||||
|
||||
void MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
|
||||
void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
|
||||
void MoveSizeEnd(HWND window, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
|
||||
void MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& zoneWindowMap) noexcept;
|
||||
void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& zoneWindowMap) noexcept;
|
||||
void MoveSizeEnd(HWND window, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& zoneWindowMap) noexcept;
|
||||
|
||||
void MoveWindowIntoZoneByIndexSet(HWND window, const std::vector<size_t>& indexSet, winrt::com_ptr<IZoneWindow> zoneWindow) noexcept;
|
||||
bool MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr<IZoneWindow> zoneWindow) noexcept;
|
||||
bool MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr<IZoneWindow> zoneWindow) noexcept;
|
||||
bool ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode, winrt::com_ptr<IZoneWindow> zoneWindow) noexcept;
|
||||
void MoveWindowIntoZoneByIndexSet(HWND window, const std::vector<size_t>& indexSet, winrt::com_ptr<IWorkArea> zoneWindow) noexcept;
|
||||
bool MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr<IWorkArea> zoneWindow) noexcept;
|
||||
bool MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr<IWorkArea> zoneWindow) noexcept;
|
||||
bool ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode, winrt::com_ptr<IWorkArea> zoneWindow) noexcept;
|
||||
|
||||
inline void OnMouseDown() noexcept
|
||||
{
|
||||
@@ -68,7 +68,7 @@ private:
|
||||
HWND m_windowMoveSize{}; // The window that is being moved/sized
|
||||
bool m_inMoveSize{}; // Whether or not a move/size operation is currently active
|
||||
MoveSizeWindowInfo m_moveSizeWindowInfo; // MoveSizeWindowInfo of the window at the moment when dragging started
|
||||
winrt::com_ptr<IZoneWindow> m_zoneWindowMoveSize; // "Active" ZoneWindow, where the move/size is happening. Will update as drag moves between monitors.
|
||||
winrt::com_ptr<IWorkArea> m_zoneWindowMoveSize; // "Active" WorkArea, where the move/size is happening. Will update as drag moves between monitors.
|
||||
bool m_dragEnabled{}; // True if we should be showing zone hints while dragging
|
||||
|
||||
WindowTransparencyProperties m_windowTransparencyProperties;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "pch.h"
|
||||
#include "WorkArea.h"
|
||||
|
||||
#include <common/logger/logger.h>
|
||||
|
||||
#include "FancyZonesData.h"
|
||||
#include "FancyZonesDataTypes.h"
|
||||
#include "ZoneWindow.h"
|
||||
#include "ZoneWindowDrawing.h"
|
||||
#include "trace.h"
|
||||
#include "util.h"
|
||||
@@ -26,7 +26,7 @@ namespace NonLocalizable
|
||||
|
||||
using namespace FancyZonesUtils;
|
||||
|
||||
struct ZoneWindow;
|
||||
struct WorkArea;
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -57,7 +57,7 @@ namespace
|
||||
|
||||
public:
|
||||
|
||||
HWND NewZoneWindow(Rect position, HINSTANCE hinstance, ZoneWindow* owner)
|
||||
HWND NewZoneWindow(Rect position, HINSTANCE hinstance, WorkArea* owner)
|
||||
{
|
||||
HWND windowFromPool = ExtractWindow();
|
||||
if (windowFromPool == NULL)
|
||||
@@ -103,13 +103,13 @@ namespace
|
||||
WindowPool windowPool;
|
||||
}
|
||||
|
||||
struct ZoneWindow : public winrt::implements<ZoneWindow, IZoneWindow>
|
||||
struct WorkArea : public winrt::implements<WorkArea, IWorkArea>
|
||||
{
|
||||
public:
|
||||
ZoneWindow(HINSTANCE hinstance);
|
||||
~ZoneWindow();
|
||||
WorkArea(HINSTANCE hinstance);
|
||||
~WorkArea();
|
||||
|
||||
bool Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId);
|
||||
bool Init(HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId, const ZoneColors& zoneColors, OverlappingZonesAlgorithm overlappingAlgorithm);
|
||||
|
||||
IFACEMETHODIMP MoveSizeEnter(HWND window) noexcept;
|
||||
IFACEMETHODIMP MoveSizeUpdate(POINT const& ptScreen, bool dragEnabled, bool selectManyZones) noexcept;
|
||||
@@ -125,11 +125,13 @@ public:
|
||||
IFACEMETHODIMP_(bool)
|
||||
ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode) noexcept;
|
||||
IFACEMETHODIMP_(std::wstring)
|
||||
UniqueId() noexcept { return { m_uniqueId }; }
|
||||
UniqueId() const noexcept { return { m_uniqueId }; }
|
||||
IFACEMETHODIMP_(void)
|
||||
SaveWindowProcessToZoneIndex(HWND window) noexcept;
|
||||
IFACEMETHODIMP_(IZoneSet*)
|
||||
ActiveZoneSet() noexcept { return m_activeZoneSet.get(); }
|
||||
ActiveZoneSet() const noexcept { return m_activeZoneSet.get(); }
|
||||
IFACEMETHODIMP_(std::vector<size_t>)
|
||||
GetWindowZoneIndexes(HWND window) const noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
ShowZoneWindow() noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
@@ -140,19 +142,22 @@ public:
|
||||
ClearSelectedZones() noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
FlashZones() noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
SetZoneColors(const ZoneColors& colors) noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
SetOverlappingZonesAlgorithm(OverlappingZonesAlgorithm overlappingAlgorithm) noexcept;
|
||||
|
||||
protected:
|
||||
static LRESULT CALLBACK s_WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept;
|
||||
|
||||
private:
|
||||
void InitializeZoneSets(const std::wstring& parentUniqueId) noexcept;
|
||||
void CalculateZoneSet() noexcept;
|
||||
void CalculateZoneSet(OverlappingZonesAlgorithm overlappingAlgorithm) noexcept;
|
||||
void UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept;
|
||||
LRESULT WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept;
|
||||
std::vector<size_t> ZonesFromPoint(POINT pt) noexcept;
|
||||
void SetAsTopmostWindow() noexcept;
|
||||
|
||||
winrt::com_ptr<IZoneWindowHost> m_host;
|
||||
HMONITOR m_monitor{};
|
||||
std::wstring m_uniqueId; // Parsed deviceId + resolution + virtualDesktopId
|
||||
HWND m_window{}; // Hidden tool window used to represent current monitor desktop work area.
|
||||
@@ -164,9 +169,11 @@ private:
|
||||
WPARAM m_keyLast{};
|
||||
size_t m_keyCycle{};
|
||||
std::unique_ptr<ZoneWindowDrawing> m_zoneWindowDrawing;
|
||||
ZoneColors m_zoneColors;
|
||||
OverlappingZonesAlgorithm m_overlappingAlgorithm;
|
||||
};
|
||||
|
||||
ZoneWindow::ZoneWindow(HINSTANCE hinstance)
|
||||
WorkArea::WorkArea(HINSTANCE hinstance)
|
||||
{
|
||||
WNDCLASSEXW wcex{};
|
||||
wcex.cbSize = sizeof(WNDCLASSEX);
|
||||
@@ -177,14 +184,15 @@ ZoneWindow::ZoneWindow(HINSTANCE hinstance)
|
||||
RegisterClassExW(&wcex);
|
||||
}
|
||||
|
||||
ZoneWindow::~ZoneWindow()
|
||||
WorkArea::~WorkArea()
|
||||
{
|
||||
windowPool.FreeZoneWindow(m_window);
|
||||
}
|
||||
|
||||
bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId)
|
||||
bool WorkArea::Init(HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId, const ZoneColors& zoneColors, OverlappingZonesAlgorithm overlappingAlgorithm)
|
||||
{
|
||||
m_host.copy_from(host);
|
||||
m_zoneColors = zoneColors;
|
||||
m_overlappingAlgorithm = overlappingAlgorithm;
|
||||
|
||||
Rect workAreaRect;
|
||||
m_monitor = monitor;
|
||||
@@ -218,7 +226,7 @@ bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monit
|
||||
return true;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP ZoneWindow::MoveSizeEnter(HWND window) noexcept
|
||||
IFACEMETHODIMP WorkArea::MoveSizeEnter(HWND window) noexcept
|
||||
{
|
||||
m_windowMoveSize = window;
|
||||
m_highlightZone = {};
|
||||
@@ -227,7 +235,7 @@ IFACEMETHODIMP ZoneWindow::MoveSizeEnter(HWND window) noexcept
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP ZoneWindow::MoveSizeUpdate(POINT const& ptScreen, bool dragEnabled, bool selectManyZones) noexcept
|
||||
IFACEMETHODIMP WorkArea::MoveSizeUpdate(POINT const& ptScreen, bool dragEnabled, bool selectManyZones) noexcept
|
||||
{
|
||||
bool redraw = false;
|
||||
POINT ptClient = ptScreen;
|
||||
@@ -265,13 +273,13 @@ IFACEMETHODIMP ZoneWindow::MoveSizeUpdate(POINT const& ptScreen, bool dragEnable
|
||||
|
||||
if (redraw)
|
||||
{
|
||||
m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_host);
|
||||
m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_zoneColors);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP ZoneWindow::MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept
|
||||
IFACEMETHODIMP WorkArea::MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept
|
||||
{
|
||||
if (m_windowMoveSize != window)
|
||||
{
|
||||
@@ -289,7 +297,7 @@ IFACEMETHODIMP ZoneWindow::MoveSizeEnd(HWND window, POINT const& ptScreen) noexc
|
||||
SaveWindowProcessToZoneIndex(window);
|
||||
}
|
||||
}
|
||||
Trace::ZoneWindow::MoveSizeEnd(m_activeZoneSet);
|
||||
Trace::WorkArea::MoveSizeEnd(m_activeZoneSet);
|
||||
|
||||
HideZoneWindow();
|
||||
m_windowMoveSize = nullptr;
|
||||
@@ -297,13 +305,13 @@ IFACEMETHODIMP ZoneWindow::MoveSizeEnd(HWND window, POINT const& ptScreen) noexc
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
ZoneWindow::MoveWindowIntoZoneByIndex(HWND window, size_t index) noexcept
|
||||
WorkArea::MoveWindowIntoZoneByIndex(HWND window, size_t index) noexcept
|
||||
{
|
||||
MoveWindowIntoZoneByIndexSet(window, { index });
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
ZoneWindow::MoveWindowIntoZoneByIndexSet(HWND window, const std::vector<size_t>& indexSet) noexcept
|
||||
WorkArea::MoveWindowIntoZoneByIndexSet(HWND window, const std::vector<size_t>& indexSet) noexcept
|
||||
{
|
||||
if (m_activeZoneSet)
|
||||
{
|
||||
@@ -312,7 +320,7 @@ ZoneWindow::MoveWindowIntoZoneByIndexSet(HWND window, const std::vector<size_t>&
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(bool)
|
||||
ZoneWindow::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle) noexcept
|
||||
WorkArea::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle) noexcept
|
||||
{
|
||||
if (m_activeZoneSet)
|
||||
{
|
||||
@@ -329,7 +337,7 @@ ZoneWindow::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, boo
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(bool)
|
||||
ZoneWindow::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle) noexcept
|
||||
WorkArea::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle) noexcept
|
||||
{
|
||||
if (m_activeZoneSet)
|
||||
{
|
||||
@@ -343,7 +351,7 @@ ZoneWindow::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode,
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(bool)
|
||||
ZoneWindow::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode) noexcept
|
||||
WorkArea::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode) noexcept
|
||||
{
|
||||
if (m_activeZoneSet)
|
||||
{
|
||||
@@ -357,7 +365,7 @@ ZoneWindow::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode) noexce
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
ZoneWindow::SaveWindowProcessToZoneIndex(HWND window) noexcept
|
||||
WorkArea::SaveWindowProcessToZoneIndex(HWND window) noexcept
|
||||
{
|
||||
if (m_activeZoneSet)
|
||||
{
|
||||
@@ -375,19 +383,33 @@ ZoneWindow::SaveWindowProcessToZoneIndex(HWND window) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(std::vector<size_t>)
|
||||
WorkArea::GetWindowZoneIndexes(HWND window) const noexcept
|
||||
{
|
||||
if (m_activeZoneSet)
|
||||
{
|
||||
wil::unique_cotaskmem_string zoneSetId;
|
||||
if (SUCCEEDED(StringFromCLSID(m_activeZoneSet->Id(), &zoneSetId)))
|
||||
{
|
||||
return FancyZonesDataInstance().GetAppLastZoneIndexSet(window, m_uniqueId, zoneSetId.get());
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
ZoneWindow::ShowZoneWindow() noexcept
|
||||
WorkArea::ShowZoneWindow() noexcept
|
||||
{
|
||||
if (m_window)
|
||||
{
|
||||
SetAsTopmostWindow();
|
||||
m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_host);
|
||||
m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_zoneColors);
|
||||
m_zoneWindowDrawing->Show();
|
||||
}
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
ZoneWindow::HideZoneWindow() noexcept
|
||||
WorkArea::HideZoneWindow() noexcept
|
||||
{
|
||||
if (m_window)
|
||||
{
|
||||
@@ -399,40 +421,53 @@ ZoneWindow::HideZoneWindow() noexcept
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
ZoneWindow::UpdateActiveZoneSet() noexcept
|
||||
WorkArea::UpdateActiveZoneSet() noexcept
|
||||
{
|
||||
CalculateZoneSet();
|
||||
CalculateZoneSet(m_overlappingAlgorithm);
|
||||
if (m_window)
|
||||
{
|
||||
m_highlightZone.clear();
|
||||
m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_host);
|
||||
m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_zoneColors);
|
||||
}
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
ZoneWindow::ClearSelectedZones() noexcept
|
||||
WorkArea::ClearSelectedZones() noexcept
|
||||
{
|
||||
if (m_highlightZone.size())
|
||||
{
|
||||
m_highlightZone.clear();
|
||||
m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_host);
|
||||
m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_zoneColors);
|
||||
}
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
ZoneWindow::FlashZones() noexcept
|
||||
WorkArea::FlashZones() noexcept
|
||||
{
|
||||
if (m_window)
|
||||
{
|
||||
SetAsTopmostWindow();
|
||||
m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), {}, m_host);
|
||||
m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), {}, m_zoneColors);
|
||||
m_zoneWindowDrawing->Flash();
|
||||
}
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
WorkArea::SetZoneColors(const ZoneColors& colors) noexcept
|
||||
{
|
||||
m_zoneColors = colors;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
WorkArea::SetOverlappingZonesAlgorithm(OverlappingZonesAlgorithm overlappingAlgorithm) noexcept
|
||||
{
|
||||
m_overlappingAlgorithm = overlappingAlgorithm;
|
||||
}
|
||||
|
||||
|
||||
#pragma region private
|
||||
|
||||
void ZoneWindow::InitializeZoneSets(const std::wstring& parentUniqueId) noexcept
|
||||
void WorkArea::InitializeZoneSets(const std::wstring& parentUniqueId) noexcept
|
||||
{
|
||||
bool deviceAdded = FancyZonesDataInstance().AddDevice(m_uniqueId);
|
||||
// If the device has been added, check if it should inherit the parent's layout
|
||||
@@ -440,10 +475,10 @@ void ZoneWindow::InitializeZoneSets(const std::wstring& parentUniqueId) noexcept
|
||||
{
|
||||
FancyZonesDataInstance().CloneDeviceInfo(parentUniqueId, m_uniqueId);
|
||||
}
|
||||
CalculateZoneSet();
|
||||
CalculateZoneSet(m_overlappingAlgorithm);
|
||||
}
|
||||
|
||||
void ZoneWindow::CalculateZoneSet() noexcept
|
||||
void WorkArea::CalculateZoneSet(OverlappingZonesAlgorithm overlappingAlgorithm) noexcept
|
||||
{
|
||||
const auto& fancyZonesData = FancyZonesDataInstance();
|
||||
const auto deviceInfoData = fancyZonesData.FindDeviceInfo(m_uniqueId);
|
||||
@@ -470,7 +505,7 @@ void ZoneWindow::CalculateZoneSet() noexcept
|
||||
activeZoneSet.type,
|
||||
m_monitor,
|
||||
sensitivityRadius,
|
||||
m_host->GetOverlappingZonesAlgorithm()));
|
||||
overlappingAlgorithm));
|
||||
|
||||
RECT workArea;
|
||||
if (m_monitor)
|
||||
@@ -500,7 +535,7 @@ void ZoneWindow::CalculateZoneSet() noexcept
|
||||
}
|
||||
}
|
||||
|
||||
void ZoneWindow::UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept
|
||||
void WorkArea::UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept
|
||||
{
|
||||
m_activeZoneSet.copy_from(zoneSet);
|
||||
|
||||
@@ -518,7 +553,7 @@ void ZoneWindow::UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept
|
||||
LRESULT WorkArea::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
@@ -540,7 +575,7 @@ LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<size_t> ZoneWindow::ZonesFromPoint(POINT pt) noexcept
|
||||
std::vector<size_t> WorkArea::ZonesFromPoint(POINT pt) noexcept
|
||||
{
|
||||
if (m_activeZoneSet)
|
||||
{
|
||||
@@ -549,7 +584,7 @@ std::vector<size_t> ZoneWindow::ZonesFromPoint(POINT pt) noexcept
|
||||
return {};
|
||||
}
|
||||
|
||||
void ZoneWindow::SetAsTopmostWindow() noexcept
|
||||
void WorkArea::SetAsTopmostWindow() noexcept
|
||||
{
|
||||
if (!m_window)
|
||||
{
|
||||
@@ -569,13 +604,13 @@ void ZoneWindow::SetAsTopmostWindow() noexcept
|
||||
|
||||
#pragma endregion
|
||||
|
||||
LRESULT CALLBACK ZoneWindow::s_WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept
|
||||
LRESULT CALLBACK WorkArea::s_WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept
|
||||
{
|
||||
auto thisRef = reinterpret_cast<ZoneWindow*>(GetWindowLongPtr(window, GWLP_USERDATA));
|
||||
auto thisRef = reinterpret_cast<WorkArea*>(GetWindowLongPtr(window, GWLP_USERDATA));
|
||||
if ((thisRef == nullptr) && (message == WM_CREATE))
|
||||
{
|
||||
auto createStruct = reinterpret_cast<LPCREATESTRUCT>(lparam);
|
||||
thisRef = reinterpret_cast<ZoneWindow*>(createStruct->lpCreateParams);
|
||||
thisRef = reinterpret_cast<WorkArea*>(createStruct->lpCreateParams);
|
||||
SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(thisRef));
|
||||
}
|
||||
|
||||
@@ -583,10 +618,10 @@ LRESULT CALLBACK ZoneWindow::s_WndProc(HWND window, UINT message, WPARAM wparam,
|
||||
DefWindowProc(window, message, wparam, lparam);
|
||||
}
|
||||
|
||||
winrt::com_ptr<IZoneWindow> MakeZoneWindow(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId) noexcept
|
||||
winrt::com_ptr<IWorkArea> MakeWorkArea(HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId, const ZoneColors& zoneColors, OverlappingZonesAlgorithm overlappingAlgorithm) noexcept
|
||||
{
|
||||
auto self = winrt::make_self<ZoneWindow>(hinstance);
|
||||
if (self->Init(host, hinstance, monitor, uniqueId, parentUniqueId))
|
||||
auto self = winrt::make_self<WorkArea>(hinstance);
|
||||
if (self->Init(hinstance, monitor, uniqueId, parentUniqueId, zoneColors, overlappingAlgorithm))
|
||||
{
|
||||
return self;
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
#pragma once
|
||||
#include "FancyZones.h"
|
||||
#include "FancyZonesLib/ZoneSet.h"
|
||||
#include "FancyZonesLib/ZoneColors.h"
|
||||
|
||||
/**
|
||||
* Class representing single work area, which is defined by monitor and virtual desktop.
|
||||
*/
|
||||
interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IZoneWindow : public IUnknown
|
||||
interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IWorkArea : public IUnknown
|
||||
{
|
||||
/**
|
||||
* A window is being moved or resized. Track down window position and give zone layout
|
||||
@@ -96,11 +97,15 @@ interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IZoneWindow
|
||||
/**
|
||||
* @returns Unique work area identifier. Format: <device-id>_<resolution>_<virtual-desktop-id>
|
||||
*/
|
||||
IFACEMETHOD_(std::wstring, UniqueId)() = 0;
|
||||
IFACEMETHOD_(std::wstring, UniqueId)() const = 0;
|
||||
/**
|
||||
* @returns Active zone layout for this work area.
|
||||
*/
|
||||
IFACEMETHOD_(IZoneSet*, ActiveZoneSet)() = 0;
|
||||
IFACEMETHOD_(IZoneSet*, ActiveZoneSet)() const = 0;
|
||||
/*
|
||||
* @returns Zone index of the window
|
||||
*/
|
||||
IFACEMETHOD_(std::vector<size_t>, GetWindowZoneIndexes)(HWND window) const = 0;
|
||||
IFACEMETHOD_(void, ShowZoneWindow)() = 0;
|
||||
IFACEMETHOD_(void, HideZoneWindow)() = 0;
|
||||
/**
|
||||
@@ -108,14 +113,21 @@ interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IZoneWindow
|
||||
*/
|
||||
IFACEMETHOD_(void, UpdateActiveZoneSet)() = 0;
|
||||
/**
|
||||
* Clear the selected zones when this ZoneWindow loses focus.
|
||||
* Clear the selected zones when this WorkArea loses focus.
|
||||
*/
|
||||
IFACEMETHOD_(void, ClearSelectedZones)() = 0;
|
||||
/*
|
||||
* Display the layout on the screen and then hide it.
|
||||
*/
|
||||
IFACEMETHOD_(void, FlashZones)() = 0;
|
||||
/*
|
||||
* Set zone colors
|
||||
*/
|
||||
IFACEMETHOD_(void, SetZoneColors)(const ZoneColors& colors) = 0;
|
||||
/*
|
||||
* Set overlapping algorithm
|
||||
*/
|
||||
IFACEMETHOD_(void, SetOverlappingZonesAlgorithm)(OverlappingZonesAlgorithm overlappingAlgorithm) = 0;
|
||||
};
|
||||
|
||||
winrt::com_ptr<IZoneWindow> MakeZoneWindow(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor,
|
||||
const std::wstring& uniqueId, const std::wstring& parentUniqueId) noexcept;
|
||||
winrt::com_ptr<IWorkArea> MakeWorkArea(HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId, const ZoneColors& zoneColors, OverlappingZonesAlgorithm overlappingAlgorithm) noexcept;
|
||||
@@ -26,7 +26,7 @@ interface __declspec(uuid("{8228E934-B6EF-402A-9892-15A1441BF8B0}")) IZone : pub
|
||||
* Compute the coordinates of the rectangle to which a window should be resized.
|
||||
*
|
||||
* @param window Handle of window which should be assigned to zone.
|
||||
* @param zoneWindow The m_window of a ZoneWindow, it's a hidden window representing the
|
||||
* @param zoneWindow The m_window of a WorkArea, it's a hidden window representing the
|
||||
* current monitor desktop work area.
|
||||
* @returns a RECT structure, describing global coordinates to which a window should be resized
|
||||
*/
|
||||
|
||||
10
src/modules/fancyzones/FancyZonesLib/ZoneColors.h
Normal file
10
src/modules/fancyzones/FancyZonesLib/ZoneColors.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include <windef.h>
|
||||
|
||||
struct ZoneColors
|
||||
{
|
||||
COLORREF primaryColor;
|
||||
COLORREF borderColor;
|
||||
COLORREF highlightColor;
|
||||
int highlightOpacity;
|
||||
};
|
||||
@@ -254,7 +254,7 @@ ZoneSet::ZonesFromPoint(POINT pt) const noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
using Algorithm = Settings::OverlappingZonesAlgorithm;
|
||||
using Algorithm = OverlappingZonesAlgorithm;
|
||||
|
||||
switch (m_config.SelectionAlgorithm)
|
||||
{
|
||||
|
||||
@@ -53,7 +53,7 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet :
|
||||
* Assign window to the zone based on zone index inside zone layout.
|
||||
*
|
||||
* @param window Handle of window which should be assigned to zone.
|
||||
* @param workAreaWindow The m_window of a ZoneWindow, it's a hidden window representing the
|
||||
* @param workAreaWindow The m_window of a WorkArea, it's a hidden window representing the
|
||||
* current monitor desktop work area.
|
||||
* @param index Zone index within zone layout.
|
||||
*/
|
||||
@@ -63,7 +63,7 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet :
|
||||
* Assign window to the zones based on the set of zone indices inside zone layout.
|
||||
*
|
||||
* @param window Handle of window which should be assigned to zone.
|
||||
* @param workAreaWindow The m_window of a ZoneWindow, it's a hidden window representing the
|
||||
* @param workAreaWindow The m_window of a WorkArea, it's a hidden window representing the
|
||||
* current monitor desktop work area.
|
||||
* @param indexSet The set of zone indices within zone layout.
|
||||
*/
|
||||
@@ -74,7 +74,7 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet :
|
||||
* not their on-screen position.
|
||||
*
|
||||
* @param window Handle of window which should be assigned to zone.
|
||||
* @param workAreaWindow The m_window of a ZoneWindow, it's a hidden window representing the
|
||||
* @param workAreaWindow The m_window of a WorkArea, it's a hidden window representing the
|
||||
* current monitor desktop work area.
|
||||
* @param vkCode Pressed arrow key.
|
||||
* @param cycle Whether we should move window to the first zone if we reached last zone in layout.
|
||||
@@ -89,7 +89,7 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet :
|
||||
* their on-screen position.
|
||||
*
|
||||
* @param window Handle of window which should be assigned to zone.
|
||||
* @param workAreaWindow The m_window of a ZoneWindow, it's a hidden window representing the
|
||||
* @param workAreaWindow The m_window of a WorkArea, it's a hidden window representing the
|
||||
* current monitor desktop work area.
|
||||
* @param vkCode Pressed arrow key.
|
||||
* @param cycle Whether we should move window to the first zone if we reached last zone in layout.
|
||||
@@ -104,7 +104,7 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet :
|
||||
* their on-screen position.
|
||||
*
|
||||
* @param window Handle of window which should be assigned to zone.
|
||||
* @param workAreaWindow The m_window of a ZoneWindow, it's a hidden window representing the
|
||||
* @param workAreaWindow The m_window of a WorkArea, it's a hidden window representing the
|
||||
* current monitor desktop work area.
|
||||
* @param vkCode Pressed arrow key.
|
||||
*
|
||||
@@ -117,7 +117,7 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet :
|
||||
* Assign window to the zone based on cursor coordinates.
|
||||
*
|
||||
* @param window Handle of window which should be assigned to zone.
|
||||
* @param workAreaWindow The m_window of a ZoneWindow, it's a hidden window representing the
|
||||
* @param workAreaWindow The m_window of a WorkArea, it's a hidden window representing the
|
||||
* current monitor desktop work area.
|
||||
* @param pt Cursor coordinates.
|
||||
*/
|
||||
@@ -159,7 +159,7 @@ struct ZoneSetConfig
|
||||
FancyZonesDataTypes::ZoneSetLayoutType layoutType,
|
||||
HMONITOR monitor,
|
||||
int sensitivityRadius,
|
||||
Settings::OverlappingZonesAlgorithm selectionAlgorithm = {}) noexcept :
|
||||
OverlappingZonesAlgorithm selectionAlgorithm = {}) noexcept :
|
||||
Id(id),
|
||||
LayoutType(layoutType),
|
||||
Monitor(monitor),
|
||||
@@ -172,7 +172,7 @@ struct ZoneSetConfig
|
||||
FancyZonesDataTypes::ZoneSetLayoutType LayoutType{};
|
||||
HMONITOR Monitor{};
|
||||
int SensitivityRadius;
|
||||
Settings::OverlappingZonesAlgorithm SelectionAlgorithm = Settings::OverlappingZonesAlgorithm::Smallest;
|
||||
OverlappingZonesAlgorithm SelectionAlgorithm = OverlappingZonesAlgorithm::Smallest;
|
||||
};
|
||||
|
||||
winrt::com_ptr<IZoneSet> MakeZoneSet(ZoneSetConfig const& config) noexcept;
|
||||
|
||||
@@ -279,19 +279,19 @@ void ZoneWindowDrawing::Flash()
|
||||
|
||||
void ZoneWindowDrawing::DrawActiveZoneSet(const IZoneSet::ZonesMap& zones,
|
||||
const std::vector<size_t>& highlightZones,
|
||||
winrt::com_ptr<IZoneWindowHost> host)
|
||||
const ZoneColors& colors)
|
||||
{
|
||||
_TRACER_;
|
||||
std::unique_lock lock(m_mutex);
|
||||
|
||||
m_sceneRects = {};
|
||||
|
||||
auto borderColor = ConvertColor(host->GetZoneBorderColor());
|
||||
auto inactiveColor = ConvertColor(host->GetZoneColor());
|
||||
auto highlightColor = ConvertColor(host->GetZoneHighlightColor());
|
||||
auto borderColor = ConvertColor(colors.borderColor);
|
||||
auto inactiveColor = ConvertColor(colors.primaryColor);
|
||||
auto highlightColor = ConvertColor(colors.highlightColor);
|
||||
|
||||
inactiveColor.a = host->GetZoneHighlightOpacity() / 100.f;
|
||||
highlightColor.a = host->GetZoneHighlightOpacity() / 100.f;
|
||||
inactiveColor.a = colors.highlightOpacity / 100.f;
|
||||
highlightColor.a = colors.highlightOpacity / 100.f;
|
||||
|
||||
std::vector<bool> isHighlighted(zones.size() + 1, false);
|
||||
for (size_t x : highlightZones)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "Zone.h"
|
||||
#include "ZoneSet.h"
|
||||
#include "FancyZones.h"
|
||||
#include "ZoneColors.h"
|
||||
|
||||
class ZoneWindowDrawing
|
||||
{
|
||||
@@ -65,5 +66,5 @@ public:
|
||||
void Flash();
|
||||
void DrawActiveZoneSet(const IZoneSet::ZonesMap& zones,
|
||||
const std::vector<size_t>& highlightZones,
|
||||
winrt::com_ptr<IZoneWindowHost> host);
|
||||
const ZoneColors& colors);
|
||||
};
|
||||
|
||||
@@ -294,7 +294,7 @@ void Trace::VirtualDesktopChanged() noexcept
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
||||
|
||||
void Trace::ZoneWindow::KeyUp(WPARAM wParam) noexcept
|
||||
void Trace::WorkArea::KeyUp(WPARAM wParam) noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
@@ -304,7 +304,7 @@ void Trace::ZoneWindow::KeyUp(WPARAM wParam) noexcept
|
||||
TraceLoggingValue(wParam, KeyboardValueKey));
|
||||
}
|
||||
|
||||
void Trace::ZoneWindow::MoveSizeEnd(_In_opt_ winrt::com_ptr<IZoneSet> activeSet) noexcept
|
||||
void Trace::WorkArea::MoveSizeEnd(_In_opt_ winrt::com_ptr<IZoneSet> activeSet) noexcept
|
||||
{
|
||||
auto const zoneInfo = GetZoneSetInfo(activeSet);
|
||||
TraceLoggingWrite(
|
||||
@@ -317,7 +317,7 @@ void Trace::ZoneWindow::MoveSizeEnd(_In_opt_ winrt::com_ptr<IZoneSet> activeSet)
|
||||
TraceLoggingValue(zoneInfo.NumberOfWindows, NumberOfWindowsKey));
|
||||
}
|
||||
|
||||
void Trace::ZoneWindow::CycleActiveZoneSet(_In_opt_ winrt::com_ptr<IZoneSet> activeSet, InputMode mode) noexcept
|
||||
void Trace::WorkArea::CycleActiveZoneSet(_In_opt_ winrt::com_ptr<IZoneSet> activeSet, InputMode mode) noexcept
|
||||
{
|
||||
auto const zoneInfo = GetZoneSetInfo(activeSet);
|
||||
TraceLoggingWrite(
|
||||
|
||||
@@ -23,7 +23,7 @@ public:
|
||||
static void SettingsTelemetry(const Settings& settings) noexcept;
|
||||
static void VirtualDesktopChanged() noexcept;
|
||||
|
||||
class ZoneWindow
|
||||
class WorkArea
|
||||
{
|
||||
public:
|
||||
enum class InputMode
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace NonLocalizable
|
||||
{
|
||||
const wchar_t PowerToysAppPowerLauncher[] = L"POWERLAUNCHER.EXE";
|
||||
const wchar_t PowerToysAppFZEditor[] = L"FANCYZONESEDITOR.EXE";
|
||||
const wchar_t SplashClassName[] = L"MsoSplash";
|
||||
}
|
||||
|
||||
bool find_app_name_in_path(const std::wstring& where, const std::vector<std::wstring>& what)
|
||||
@@ -604,6 +605,17 @@ namespace FancyZonesUtils
|
||||
return SUCCEEDED(CLSIDFromString(str.c_str(), &id));
|
||||
}
|
||||
|
||||
std::optional<std::wstring> GuidToString(const GUID& guid) noexcept
|
||||
{
|
||||
wil::unique_cotaskmem_string guidString;
|
||||
if (SUCCEEDED(StringFromCLSID(guid, &guidString)))
|
||||
{
|
||||
return guidString.get();
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool IsValidDeviceId(const std::wstring& str)
|
||||
{
|
||||
std::wstring monitorName;
|
||||
@@ -862,4 +874,15 @@ namespace FancyZonesUtils
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsSplashScreen(HWND window)
|
||||
{
|
||||
wchar_t className[MAX_PATH];
|
||||
if (GetClassName(window, className, MAX_PATH) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return wcscmp(NonLocalizable::SplashClassName, className) == 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -203,6 +203,7 @@ namespace FancyZonesUtils
|
||||
void RestoreWindowOrigin(HWND window) noexcept;
|
||||
|
||||
bool IsValidGuid(const std::wstring& str);
|
||||
std::optional<std::wstring> GuidToString(const GUID& guid) noexcept;
|
||||
|
||||
std::wstring GenerateUniqueId(HMONITOR monitor, const std::wstring& devideId, const std::wstring& virtualDesktopId);
|
||||
std::wstring GenerateUniqueIdAllMonitorsArea(const std::wstring& virtualDesktopId);
|
||||
@@ -216,4 +217,6 @@ namespace FancyZonesUtils
|
||||
|
||||
// If HWND is already dead, we assume it wasn't elevated
|
||||
bool IsProcessOfWindowElevated(HWND window);
|
||||
|
||||
bool IsSplashScreen(HWND window);
|
||||
}
|
||||
|
||||
@@ -98,6 +98,13 @@ public:
|
||||
virtual void destroy() override
|
||||
{
|
||||
Disable(false);
|
||||
|
||||
if (m_toggleEditorEvent)
|
||||
{
|
||||
CloseHandle(m_toggleEditorEvent);
|
||||
m_toggleEditorEvent = nullptr;
|
||||
}
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
@@ -114,6 +121,15 @@ public:
|
||||
m_settings = MakeFancyZonesSettings(reinterpret_cast<HINSTANCE>(&__ImageBase), FancyZonesModuleInterface::get_name(), FancyZonesModuleInterface::get_key());
|
||||
|
||||
m_toggleEditorEvent = CreateDefaultEvent(CommonSharedConstants::FANCY_ZONES_EDITOR_TOGGLE_EVENT);
|
||||
if (!m_toggleEditorEvent)
|
||||
{
|
||||
Logger::error(L"Failed to create toggle editor event");
|
||||
auto message = get_last_error_message(GetLastError());
|
||||
if (message.has_value())
|
||||
{
|
||||
Logger::error(message.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -147,27 +163,49 @@ private:
|
||||
m_hProcess = sei.hProcess;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SendFZECloseEvent()
|
||||
{
|
||||
auto exitEvent = CreateEventW(nullptr, false, false, CommonSharedConstants::FZE_EXIT_EVENT);
|
||||
if (!exitEvent)
|
||||
{
|
||||
Logger::warn(L"Failed to create exitEvent. {}", get_last_error_or_default(GetLastError()));
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::trace(L"Signaled exitEvent");
|
||||
if (!SetEvent(exitEvent))
|
||||
{
|
||||
Logger::warn(L"Failed to signal exitEvent. {}", get_last_error_or_default(GetLastError()));
|
||||
}
|
||||
|
||||
ResetEvent(exitEvent);
|
||||
CloseHandle(exitEvent);
|
||||
}
|
||||
}
|
||||
|
||||
void Disable(bool const traceEvent)
|
||||
{
|
||||
m_enabled = false;
|
||||
// Log telemetry
|
||||
|
||||
if (traceEvent)
|
||||
{
|
||||
Trace::FancyZones::EnableFancyZones(false);
|
||||
}
|
||||
|
||||
ResetEvent(m_toggleEditorEvent);
|
||||
CloseHandle(m_toggleEditorEvent);
|
||||
|
||||
if (m_toggleEditorEvent)
|
||||
{
|
||||
ResetEvent(m_toggleEditorEvent);
|
||||
}
|
||||
|
||||
if (m_hProcess)
|
||||
{
|
||||
TerminateProcess(m_hProcess, 0);
|
||||
SendFZECloseEvent();
|
||||
m_hProcess = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::wstring app_name;
|
||||
//contains the non localized key of the powertoy
|
||||
std::wstring app_key;
|
||||
|
||||
@@ -55,231 +55,6 @@ namespace FancyZonesUnitTests
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CLASS (FancyZonesIZoneWindowHostUnitTests)
|
||||
{
|
||||
HINSTANCE m_hInst{};
|
||||
std::wstring m_moduleName = L"FancyZonesUnitTests";
|
||||
std::wstring m_moduleKey = L"FancyZonesUnitTests";
|
||||
winrt::com_ptr<IFancyZonesSettings> m_settings = nullptr;
|
||||
winrt::com_ptr<IZoneWindowHost> m_zoneWindowHost = nullptr;
|
||||
|
||||
std::wstring serializedPowerToySettings(const Settings& settings)
|
||||
{
|
||||
PowerToysSettings::Settings ptSettings(HINSTANCE{}, L"FancyZonesUnitTests");
|
||||
|
||||
ptSettings.add_hotkey(L"fancyzones_editor_hotkey", IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL, settings.editorHotkey);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_shiftDrag", IDS_SETTING_DESCRIPTION_SHIFTDRAG, settings.shiftDrag);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_mouseSwitch", IDS_SETTING_DESCRIPTION_MOUSESWITCH, settings.mouseSwitch);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_overrideSnapHotkeys", IDS_SETTING_DESCRIPTION_OVERRIDE_SNAP_HOTKEYS, settings.overrideSnapHotkeys);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_moveWindowAcrossMonitors", IDS_SETTING_DESCRIPTION_MOVE_WINDOW_ACROSS_MONITORS, settings.moveWindowAcrossMonitors);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_moveWindowsBasedOnPosition", IDS_SETTING_DESCRIPTION_MOVE_WINDOWS_BASED_ON_POSITION, settings.moveWindowsBasedOnPosition);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_zoneSetChange_flashZones", IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES, settings.zoneSetChange_flashZones);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_displayChange_moveWindows", IDS_SETTING_DESCRIPTION_DISPLAYCHANGE_MOVEWINDOWS, settings.displayChange_moveWindows);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_zoneSetChange_moveWindows", IDS_SETTING_DESCRIPTION_ZONESETCHANGE_MOVEWINDOWS, settings.zoneSetChange_moveWindows);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_appLastZone_moveWindows", IDS_SETTING_DESCRIPTION_APPLASTZONE_MOVEWINDOWS, settings.appLastZone_moveWindows);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_restoreSize", IDS_SETTING_DESCRIPTION_RESTORESIZE, settings.restoreSize);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_quickLayoutSwitch", IDS_SETTING_DESCRIPTION_QUICKLAYOUTSWITCH, settings.quickLayoutSwitch);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_flashZonesOnQuickSwitch", IDS_SETTING_DESCRIPTION_FLASHZONESONQUICKSWITCH, settings.flashZonesOnQuickSwitch);
|
||||
ptSettings.add_bool_toggle(L"use_cursorpos_editor_startupscreen", IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN, settings.use_cursorpos_editor_startupscreen);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_show_on_all_monitors", IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS, settings.showZonesOnAllMonitors);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_multi_monitor_mode", IDS_SETTING_DESCRIPTION_SPAN_ZONES_ACROSS_MONITORS, settings.spanZonesAcrossMonitors);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_makeDraggedWindowTransparent", IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT, settings.makeDraggedWindowTransparent);
|
||||
ptSettings.add_int_spinner(L"fancyzones_highlight_opacity", IDS_SETTINGS_HIGHLIGHT_OPACITY, settings.zoneHighlightOpacity, 0, 100, 1);
|
||||
ptSettings.add_color_picker(L"fancyzones_zoneColor", IDS_SETTING_DESCRIPTION_ZONECOLOR, settings.zoneColor);
|
||||
ptSettings.add_color_picker(L"fancyzones_zoneBorderColor", IDS_SETTING_DESCRIPTION_ZONE_BORDER_COLOR, settings.zoneBorderColor);
|
||||
ptSettings.add_color_picker(L"fancyzones_zoneHighlightColor", IDS_SETTING_DESCRIPTION_ZONEHIGHLIGHTCOLOR, settings.zoneHighlightColor);
|
||||
ptSettings.add_multiline_string(L"fancyzones_excluded_apps", IDS_SETTING_EXCLUDED_APPS_DESCRIPTION, settings.excludedApps);
|
||||
|
||||
return ptSettings.serialize();
|
||||
}
|
||||
|
||||
TEST_METHOD_INITIALIZE(Init)
|
||||
{
|
||||
m_hInst = (HINSTANCE)GetModuleHandleW(nullptr);
|
||||
m_settings = MakeFancyZonesSettings(m_hInst, m_moduleName.c_str(), m_moduleKey.c_str());
|
||||
Assert::IsTrue(m_settings != nullptr);
|
||||
|
||||
auto fancyZones = MakeFancyZones(m_hInst, m_settings, nullptr);
|
||||
Assert::IsTrue(fancyZones != nullptr);
|
||||
|
||||
m_zoneWindowHost = fancyZones.as<IZoneWindowHost>();
|
||||
Assert::IsTrue(m_zoneWindowHost != nullptr);
|
||||
}
|
||||
|
||||
TEST_METHOD_CLEANUP(Cleanup)
|
||||
{
|
||||
auto settingsFolder = PTSettingsHelper::get_module_save_folder_location(m_moduleName);
|
||||
const auto settingsFile = settingsFolder + L"\\settings.json";
|
||||
std::filesystem::remove(settingsFile);
|
||||
std::filesystem::remove(settingsFolder);
|
||||
}
|
||||
|
||||
TEST_METHOD (GetZoneColor)
|
||||
{
|
||||
const auto expected = RGB(171, 175, 238);
|
||||
const Settings settings{
|
||||
.shiftDrag = true,
|
||||
.mouseSwitch = true,
|
||||
.displayChange_moveWindows = true,
|
||||
.zoneSetChange_flashZones = false,
|
||||
.zoneSetChange_moveWindows = true,
|
||||
.overrideSnapHotkeys = false,
|
||||
.moveWindowAcrossMonitors = false,
|
||||
.moveWindowsBasedOnPosition = false,
|
||||
.appLastZone_moveWindows = true,
|
||||
.restoreSize = false,
|
||||
.use_cursorpos_editor_startupscreen = true,
|
||||
.spanZonesAcrossMonitors = false,
|
||||
.zoneColor = L"#abafee",
|
||||
.zoneBorderColor = L"FAFAFA",
|
||||
.zoneHighlightColor = L"#FAFAFA",
|
||||
.zoneHighlightOpacity = 45,
|
||||
.editorHotkey = PowerToysSettings::HotkeyObject::from_settings(false, false, false, false, VK_OEM_3),
|
||||
.excludedApps = L"app\r\napp2",
|
||||
.excludedAppsArray = { L"APP", L"APP2" },
|
||||
};
|
||||
|
||||
auto config = serializedPowerToySettings(settings);
|
||||
m_settings->SetConfig(config.c_str());
|
||||
|
||||
const auto actual = m_zoneWindowHost->GetZoneColor();
|
||||
Assert::AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD (GetZoneBorderColor)
|
||||
{
|
||||
const auto expected = RGB(171, 175, 238);
|
||||
const Settings settings{
|
||||
.shiftDrag = true,
|
||||
.mouseSwitch = true,
|
||||
.displayChange_moveWindows = true,
|
||||
.zoneSetChange_flashZones = false,
|
||||
.zoneSetChange_moveWindows = true,
|
||||
.overrideSnapHotkeys = false,
|
||||
.moveWindowAcrossMonitors = false,
|
||||
.moveWindowsBasedOnPosition = false,
|
||||
.appLastZone_moveWindows = true,
|
||||
.restoreSize = false,
|
||||
.use_cursorpos_editor_startupscreen = true,
|
||||
.spanZonesAcrossMonitors = false,
|
||||
.zoneColor = L"#FAFAFA",
|
||||
.zoneBorderColor = L"#abafee",
|
||||
.zoneHighlightColor = L"#FAFAFA",
|
||||
.zoneHighlightOpacity = 45,
|
||||
.editorHotkey = PowerToysSettings::HotkeyObject::from_settings(false, false, false, false, VK_OEM_3),
|
||||
.excludedApps = L"app\r\napp2",
|
||||
.excludedAppsArray = { L"APP", L"APP2" },
|
||||
};
|
||||
|
||||
auto config = serializedPowerToySettings(settings);
|
||||
m_settings->SetConfig(config.c_str());
|
||||
|
||||
const auto actual = m_zoneWindowHost->GetZoneBorderColor();
|
||||
Assert::AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD (GetZoneHighlightColor)
|
||||
{
|
||||
const auto expected = RGB(171, 175, 238);
|
||||
const Settings settings{
|
||||
.shiftDrag = true,
|
||||
.mouseSwitch = true,
|
||||
.displayChange_moveWindows = true,
|
||||
.zoneSetChange_flashZones = false,
|
||||
.zoneSetChange_moveWindows = true,
|
||||
.overrideSnapHotkeys = false,
|
||||
.moveWindowAcrossMonitors = false,
|
||||
.moveWindowsBasedOnPosition = false,
|
||||
.appLastZone_moveWindows = true,
|
||||
.restoreSize = false,
|
||||
.use_cursorpos_editor_startupscreen = true,
|
||||
.showZonesOnAllMonitors = false,
|
||||
.spanZonesAcrossMonitors = false,
|
||||
.makeDraggedWindowTransparent = true,
|
||||
.zoneColor = L"#FAFAFA",
|
||||
.zoneBorderColor = L"FAFAFA",
|
||||
.zoneHighlightColor = L"#abafee",
|
||||
.zoneHighlightOpacity = 45,
|
||||
.editorHotkey = PowerToysSettings::HotkeyObject::from_settings(false, false, false, false, VK_OEM_3),
|
||||
.excludedApps = L"app\r\napp2",
|
||||
.excludedAppsArray = { L"APP", L"APP2" },
|
||||
};
|
||||
|
||||
auto config = serializedPowerToySettings(settings);
|
||||
m_settings->SetConfig(config.c_str());
|
||||
|
||||
const auto actual = m_zoneWindowHost->GetZoneHighlightColor();
|
||||
Assert::AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD (GetZoneHighlightOpacity)
|
||||
{
|
||||
const auto expected = 88;
|
||||
const Settings settings{
|
||||
.shiftDrag = true,
|
||||
.mouseSwitch = true,
|
||||
.displayChange_moveWindows = true,
|
||||
.zoneSetChange_flashZones = false,
|
||||
.zoneSetChange_moveWindows = true,
|
||||
.overrideSnapHotkeys = false,
|
||||
.moveWindowAcrossMonitors = false,
|
||||
.moveWindowsBasedOnPosition = false,
|
||||
.appLastZone_moveWindows = true,
|
||||
.restoreSize = false,
|
||||
.use_cursorpos_editor_startupscreen = true,
|
||||
.showZonesOnAllMonitors = false,
|
||||
.spanZonesAcrossMonitors = false,
|
||||
.makeDraggedWindowTransparent = true,
|
||||
.zoneColor = L"#FAFAFA",
|
||||
.zoneBorderColor = L"FAFAFA",
|
||||
.zoneHighlightColor = L"#abafee",
|
||||
.zoneHighlightOpacity = expected,
|
||||
.editorHotkey = PowerToysSettings::HotkeyObject::from_settings(false, false, false, false, VK_OEM_3),
|
||||
.excludedApps = L"app\r\napp2",
|
||||
.excludedAppsArray = { L"APP", L"APP2" },
|
||||
};
|
||||
|
||||
auto config = serializedPowerToySettings(settings);
|
||||
m_settings->SetConfig(config.c_str());
|
||||
|
||||
const auto actual = m_zoneWindowHost->GetZoneHighlightOpacity();
|
||||
Assert::AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD (IsMakeDraggenWindowTransparentActive)
|
||||
{
|
||||
const auto expected = true;
|
||||
const Settings settings{
|
||||
.shiftDrag = true,
|
||||
.mouseSwitch = true,
|
||||
.displayChange_moveWindows = true,
|
||||
.zoneSetChange_flashZones = false,
|
||||
.zoneSetChange_moveWindows = true,
|
||||
.overrideSnapHotkeys = false,
|
||||
.moveWindowAcrossMonitors = false,
|
||||
.moveWindowsBasedOnPosition = false,
|
||||
.appLastZone_moveWindows = true,
|
||||
.restoreSize = false,
|
||||
.use_cursorpos_editor_startupscreen = true,
|
||||
.showZonesOnAllMonitors = false,
|
||||
.spanZonesAcrossMonitors = false,
|
||||
.makeDraggedWindowTransparent = true,
|
||||
.zoneColor = L"#FAFAFA",
|
||||
.zoneBorderColor = L"FAFAFA",
|
||||
.zoneHighlightColor = L"#abafee",
|
||||
.zoneHighlightOpacity = expected,
|
||||
.editorHotkey = PowerToysSettings::HotkeyObject::from_settings(false, false, false, false, VK_OEM_3),
|
||||
.excludedApps = L"app\r\napp2",
|
||||
.excludedAppsArray = { L"APP", L"APP2" },
|
||||
};
|
||||
|
||||
auto config = serializedPowerToySettings(settings);
|
||||
m_settings->SetConfig(config.c_str());
|
||||
|
||||
Assert::AreEqual(expected, m_zoneWindowHost->isMakeDraggedWindowTransparentActive());
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CLASS (FancyZonesIFancyZonesCallbackUnitTests)
|
||||
{
|
||||
HINSTANCE m_hInst{};
|
||||
|
||||
@@ -396,160 +396,6 @@ namespace FancyZonesUnitTests
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CLASS (FancyZonesSettingsCallbackUnitTests)
|
||||
{
|
||||
winrt::com_ptr<IFancyZonesSettings> m_settings = nullptr;
|
||||
PCWSTR m_moduleName = L"FancyZonesUnitTests";
|
||||
PCWSTR m_moduleKey = L"FancyZonesUnitTests";
|
||||
|
||||
struct FZCallback : public winrt::implements<FZCallback, IFancyZonesCallback>
|
||||
{
|
||||
public:
|
||||
FZCallback(bool* callFlag) :
|
||||
m_callFlag(callFlag)
|
||||
{
|
||||
*m_callFlag = false;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(bool)
|
||||
InMoveSize() noexcept { return false; }
|
||||
IFACEMETHODIMP_(void)
|
||||
MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen) noexcept {}
|
||||
IFACEMETHODIMP_(void)
|
||||
MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen) noexcept {}
|
||||
IFACEMETHODIMP_(void)
|
||||
MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept {}
|
||||
IFACEMETHODIMP_(void)
|
||||
HandleWinHookEvent(const WinHookEvent* data) noexcept {}
|
||||
IFACEMETHODIMP_(void)
|
||||
VirtualDesktopChanged() noexcept {}
|
||||
IFACEMETHODIMP_(void)
|
||||
VirtualDesktopInitialize() noexcept {}
|
||||
IFACEMETHODIMP_(void)
|
||||
WindowCreated(HWND window) noexcept {}
|
||||
IFACEMETHODIMP_(bool)
|
||||
OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept { return false; }
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
ToggleEditor() noexcept
|
||||
{
|
||||
Assert::IsNotNull(m_callFlag);
|
||||
*m_callFlag = true;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
SettingsChanged() noexcept
|
||||
{
|
||||
Assert::IsNotNull(m_callFlag);
|
||||
*m_callFlag = true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool* m_callFlag = nullptr;
|
||||
};
|
||||
|
||||
TEST_METHOD_INITIALIZE(Init)
|
||||
{
|
||||
HINSTANCE hInst = (HINSTANCE)GetModuleHandleW(nullptr);
|
||||
const Settings expected{
|
||||
.shiftDrag = false,
|
||||
.mouseSwitch = false,
|
||||
.displayChange_moveWindows = true,
|
||||
.zoneSetChange_flashZones = true,
|
||||
.zoneSetChange_moveWindows = true,
|
||||
.overrideSnapHotkeys = false,
|
||||
.moveWindowAcrossMonitors = false,
|
||||
.moveWindowsBasedOnPosition = false,
|
||||
.appLastZone_moveWindows = false,
|
||||
.openWindowOnActiveMonitor = false,
|
||||
.restoreSize = false,
|
||||
.use_cursorpos_editor_startupscreen = true,
|
||||
.showZonesOnAllMonitors = false,
|
||||
.spanZonesAcrossMonitors = false,
|
||||
.makeDraggedWindowTransparent = true,
|
||||
.zoneColor = L"FAFAFA",
|
||||
.zoneBorderColor = L"CCDDEE",
|
||||
.zoneHighlightColor = L"#00FFD7",
|
||||
.zoneHighlightOpacity = 45,
|
||||
.editorHotkey = PowerToysSettings::HotkeyObject::from_settings(false, true, true, false, VK_OEM_3),
|
||||
.excludedApps = L"app",
|
||||
.excludedAppsArray = { L"APP" },
|
||||
};
|
||||
|
||||
PowerToysSettings::PowerToyValues values(m_moduleName, m_moduleKey);
|
||||
values.add_property(L"fancyzones_shiftDrag", expected.shiftDrag);
|
||||
values.add_property(L"fancyzones_mouseSwitch", expected.mouseSwitch);
|
||||
values.add_property(L"fancyzones_displayChange_moveWindows", expected.displayChange_moveWindows);
|
||||
values.add_property(L"fancyzones_zoneSetChange_flashZones", expected.zoneSetChange_flashZones);
|
||||
values.add_property(L"fancyzones_zoneSetChange_moveWindows", expected.zoneSetChange_moveWindows);
|
||||
values.add_property(L"fancyzones_overrideSnapHotkeys", expected.overrideSnapHotkeys);
|
||||
values.add_property(L"fancyzones_moveWindowAcrossMonitors", expected.moveWindowAcrossMonitors);
|
||||
values.add_property(L"fancyzones_moveWindowsBasedOnPosition", expected.moveWindowsBasedOnPosition);
|
||||
values.add_property(L"fancyzones_appLastZone_moveWindows", expected.appLastZone_moveWindows);
|
||||
values.add_property(L"fancyzones_openWindowOnActiveMonitor", expected.openWindowOnActiveMonitor);
|
||||
values.add_property(L"fancyzones_restoreSize", expected.restoreSize);
|
||||
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
|
||||
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
|
||||
values.add_property(L"fancyzones_multi_monitor_mode", expected.spanZonesAcrossMonitors);
|
||||
values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent);
|
||||
values.add_property(L"fancyzones_zoneColor", expected.zoneColor);
|
||||
values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor);
|
||||
values.add_property(L"fancyzones_zoneHighlightColor", expected.zoneHighlightColor);
|
||||
values.add_property(L"fancyzones_highlight_opacity", expected.zoneHighlightOpacity);
|
||||
values.add_property(L"fancyzones_editor_hotkey", expected.editorHotkey.get_json());
|
||||
values.add_property(L"fancyzones_excluded_apps", expected.excludedApps);
|
||||
|
||||
values.save_to_settings_file();
|
||||
|
||||
m_settings = MakeFancyZonesSettings(hInst, m_moduleName, m_moduleKey);
|
||||
Assert::IsTrue(m_settings != nullptr);
|
||||
}
|
||||
|
||||
TEST_METHOD_CLEANUP(Cleanup)
|
||||
{
|
||||
std::filesystem::remove_all(PTSettingsHelper::get_module_save_folder_location(m_moduleName));
|
||||
}
|
||||
|
||||
TEST_METHOD (CallbackSetConfig)
|
||||
{
|
||||
bool flag = false;
|
||||
winrt::com_ptr<FZCallback> callback = winrt::make_self<FZCallback>(&flag);
|
||||
|
||||
json::JsonObject json{};
|
||||
json.SetNamedValue(L"name", json::JsonValue::CreateStringValue(L"name"));
|
||||
|
||||
m_settings->SetCallback(callback.get());
|
||||
m_settings->SetConfig(json.Stringify().c_str());
|
||||
|
||||
Assert::IsTrue(flag);
|
||||
}
|
||||
|
||||
TEST_METHOD (CallbackGetConfig)
|
||||
{
|
||||
bool flag = false;
|
||||
winrt::com_ptr<FZCallback> callback = winrt::make_self<FZCallback>(&flag);
|
||||
|
||||
m_settings->SetCallback(callback.get());
|
||||
|
||||
int bufSize = 1;
|
||||
wchar_t buffer{};
|
||||
m_settings->GetConfig(&buffer, &bufSize);
|
||||
|
||||
Assert::IsFalse(flag);
|
||||
}
|
||||
|
||||
TEST_METHOD (CallbackGetSettings)
|
||||
{
|
||||
bool flag = false;
|
||||
winrt::com_ptr<FZCallback> callback = winrt::make_self<FZCallback>(&flag);
|
||||
|
||||
m_settings->SetCallback(callback.get());
|
||||
m_settings->GetSettings();
|
||||
|
||||
Assert::IsFalse(flag);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CLASS (FancyZonesSettingsUnitTests)
|
||||
{
|
||||
winrt::com_ptr<IFancyZonesSettings> m_settings = nullptr;
|
||||
|
||||
@@ -2028,9 +2028,9 @@ namespace FancyZonesUnitTests
|
||||
TEST_METHOD(MonitorToJson)
|
||||
{
|
||||
const auto deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}";
|
||||
MonitorInfo monitor{ 144, deviceId, -10, 0, true };
|
||||
MonitorInfo monitor{ 144, deviceId, -10, 0, 1920, 1080, true };
|
||||
|
||||
const auto expectedStr = L"{\"dpi\": 144, \"monitor-id\": \"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}\", \"top-coordinate\": -10, \"left-coordinate\": 0, \"is-selected\": true}";
|
||||
const auto expectedStr = L"{\"dpi\": 144, \"monitor-id\": \"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}\", \"top-coordinate\": -10, \"left-coordinate\": 0, \"width\": 1920, \"height\": 1080, \"is-selected\": true}";
|
||||
const auto expected = json::JsonObject::Parse(expectedStr);
|
||||
|
||||
const auto actual = MonitorInfo::ToJson(monitor);
|
||||
@@ -2040,14 +2040,14 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD(EditorArgsToJson)
|
||||
{
|
||||
MonitorInfo monitor1{ 144, L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}", -10, 0, true };
|
||||
MonitorInfo monitor2{ 96, L"AOC2460#4&fe3a015&0&UID65793_1920_1080_{39B25DD2-130D-4B5D-8851-4791D66B1538}", 0, 1920, false };
|
||||
MonitorInfo monitor1{ 144, L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}", -10, 0, 1920, 1080, true };
|
||||
MonitorInfo monitor2{ 96, L"AOC2460#4&fe3a015&0&UID65793_1920_1080_{39B25DD2-130D-4B5D-8851-4791D66B1538}", 0, 1920, 1920, 1080, false };
|
||||
EditorArgs args{
|
||||
1, true, std::vector<MonitorInfo>{ monitor1, monitor2 }
|
||||
};
|
||||
|
||||
const std::wstring expectedMonitor1 = L"{\"dpi\": 144, \"monitor-id\": \"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}\", \"top-coordinate\": -10, \"left-coordinate\": 0, \"is-selected\": true}";
|
||||
const std::wstring expectedMonitor2 = L"{\"dpi\": 96, \"monitor-id\": \"AOC2460#4&fe3a015&0&UID65793_1920_1080_{39B25DD2-130D-4B5D-8851-4791D66B1538}\", \"top-coordinate\": 0, \"left-coordinate\": 1920, \"is-selected\": false}";
|
||||
const std::wstring expectedMonitor1 = L"{\"dpi\": 144, \"monitor-id\": \"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}\", \"top-coordinate\": -10, \"left-coordinate\": 0, \"width\": 1920, \"height\": 1080, \"is-selected\": true}";
|
||||
const std::wstring expectedMonitor2 = L"{\"dpi\": 96, \"monitor-id\": \"AOC2460#4&fe3a015&0&UID65793_1920_1080_{39B25DD2-130D-4B5D-8851-4791D66B1538}\", \"top-coordinate\": 0, \"left-coordinate\": 1920, \"width\": 1920, \"height\": 1080, \"is-selected\": false}";
|
||||
const std::wstring expectedStr = L"{\"process-id\": 1, \"span-zones-across-monitors\": true, \"monitors\": [" + expectedMonitor1 + L", " + expectedMonitor2 + L"]}";
|
||||
|
||||
const auto expected = json::JsonObject::Parse(expectedStr);
|
||||
|
||||
@@ -49,9 +49,9 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="Util.Spec.cpp" />
|
||||
<ClCompile Include="Util.cpp" />
|
||||
<ClCompile Include="WorkArea.Spec.cpp" />
|
||||
<ClCompile Include="Zone.Spec.cpp" />
|
||||
<ClCompile Include="ZoneSet.Spec.cpp" />
|
||||
<ClCompile Include="ZoneWindow.Spec.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
|
||||
@@ -27,9 +27,6 @@
|
||||
<ClCompile Include="Util.Spec.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZoneWindow.Spec.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="JsonHelpers.Tests.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@@ -42,6 +39,9 @@
|
||||
<ClCompile Include="FancyZones.Spec.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="WorkArea.Spec.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h">
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
|
||||
#include <FancyZonesLib/util.h>
|
||||
#include <FancyZonesLib/ZoneSet.h>
|
||||
#include <FancyZonesLib/ZoneWindow.h>
|
||||
#include <FancyZonesLib/WorkArea.h>
|
||||
#include <FancyZonesLib/FancyZones.h>
|
||||
#include <FancyZonesLib/FancyZonesData.h>
|
||||
#include <FancyZonesLib/FancyZonesDataTypes.h>
|
||||
#include <FancyZonesLib/JsonHelpers.h>
|
||||
#include <FancyZonesLib/ZoneColors.h>
|
||||
#include "Util.h"
|
||||
|
||||
#include <common/utils/process_path.h>
|
||||
@@ -17,58 +18,10 @@ using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
|
||||
namespace FancyZonesUnitTests
|
||||
{
|
||||
struct MockZoneWindowHost : public winrt::implements<MockZoneWindowHost, IZoneWindowHost>
|
||||
{
|
||||
IFACEMETHODIMP_(void)
|
||||
MoveWindowsOnActiveZoneSetChange() noexcept {};
|
||||
IFACEMETHODIMP_(COLORREF)
|
||||
GetZoneColor() noexcept
|
||||
{
|
||||
return RGB(0xFF, 0xFF, 0xFF);
|
||||
}
|
||||
IFACEMETHODIMP_(COLORREF)
|
||||
GetZoneBorderColor() noexcept
|
||||
{
|
||||
return RGB(0xFF, 0xFF, 0xFF);
|
||||
}
|
||||
IFACEMETHODIMP_(COLORREF)
|
||||
GetZoneHighlightColor() noexcept
|
||||
{
|
||||
return RGB(0xFF, 0xFF, 0xFF);
|
||||
}
|
||||
IFACEMETHODIMP_(IZoneWindow*)
|
||||
GetParentZoneWindow(HMONITOR monitor) noexcept
|
||||
{
|
||||
return m_zoneWindow;
|
||||
}
|
||||
IFACEMETHODIMP_(int)
|
||||
GetZoneHighlightOpacity() noexcept
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
IFACEMETHODIMP_(bool)
|
||||
isMakeDraggedWindowTransparentActive() noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
IFACEMETHODIMP_(bool)
|
||||
InMoveSize() noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
IFACEMETHODIMP_(Settings::OverlappingZonesAlgorithm)
|
||||
GetOverlappingZonesAlgorithm() noexcept
|
||||
{
|
||||
return Settings::OverlappingZonesAlgorithm::Smallest;
|
||||
}
|
||||
|
||||
IZoneWindow* m_zoneWindow;
|
||||
};
|
||||
|
||||
const std::wstring m_deviceId = L"\\\\?\\DISPLAY#DELA026#5&10a58c63&0&UID16777488#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}";
|
||||
const std::wstring m_virtualDesktopId = L"MyVirtualDesktopId";
|
||||
|
||||
TEST_CLASS (ZoneWindowCreationUnitTests)
|
||||
TEST_CLASS (WorkAreaCreationUnitTests)
|
||||
{
|
||||
std::wstringstream m_parentUniqueId;
|
||||
std::wstringstream m_uniqueId;
|
||||
@@ -77,15 +30,17 @@ namespace FancyZonesUnitTests
|
||||
HMONITOR m_monitor{};
|
||||
MONITORINFOEX m_monitorInfo{};
|
||||
GUID m_virtualDesktopGuid{};
|
||||
ZoneColors m_zoneColors{};
|
||||
OverlappingZonesAlgorithm m_overlappingAlgorithm = OverlappingZonesAlgorithm::Positional;
|
||||
|
||||
FancyZonesData& m_fancyZonesData = FancyZonesDataInstance();
|
||||
|
||||
void testZoneWindow(winrt::com_ptr<IZoneWindow> zoneWindow)
|
||||
void testWorkArea(winrt::com_ptr<IWorkArea> workArea)
|
||||
{
|
||||
const std::wstring expectedWorkArea = std::to_wstring(m_monitorInfo.rcMonitor.right) + L"_" + std::to_wstring(m_monitorInfo.rcMonitor.bottom);
|
||||
|
||||
Assert::IsNotNull(zoneWindow.get());
|
||||
Assert::AreEqual(m_uniqueId.str().c_str(), zoneWindow->UniqueId().c_str());
|
||||
Assert::IsNotNull(workArea.get());
|
||||
Assert::AreEqual(m_uniqueId.str().c_str(), workArea->UniqueId().c_str());
|
||||
}
|
||||
|
||||
TEST_METHOD_INITIALIZE(Init)
|
||||
@@ -105,82 +60,89 @@ namespace FancyZonesUnitTests
|
||||
auto guid = Helpers::StringToGuid(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}");
|
||||
Assert::IsTrue(guid.has_value());
|
||||
m_virtualDesktopGuid = *guid;
|
||||
|
||||
m_zoneColors = ZoneColors{
|
||||
.primaryColor = FancyZonesUtils::HexToRGB(L"#4287f5"),
|
||||
.borderColor = FancyZonesUtils::HexToRGB(L"#FFFFFF"),
|
||||
.highlightColor = FancyZonesUtils::HexToRGB(L"#42eff5"),
|
||||
.highlightOpacity = 50,
|
||||
};
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateZoneWindow)
|
||||
TEST_METHOD (CreateWorkArea)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, m_uniqueId.str(), {});
|
||||
testZoneWindow(zoneWindow);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
testWorkArea(workArea);
|
||||
|
||||
auto* activeZoneSet{ zoneWindow->ActiveZoneSet() };
|
||||
auto* activeZoneSet{ workArea->ActiveZoneSet() };
|
||||
Assert::IsNotNull(activeZoneSet);
|
||||
Assert::AreEqual(static_cast<int>(activeZoneSet->LayoutType()), static_cast<int>(FancyZonesDataTypes::ZoneSetLayoutType::PriorityGrid));
|
||||
Assert::AreEqual(activeZoneSet->GetZones().size(), static_cast<size_t>(3));
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateZoneWindowNoHinst)
|
||||
TEST_METHOD (CreateWorkAreaNoHinst)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), {}, m_monitor, m_uniqueId.str(), {});
|
||||
testZoneWindow(zoneWindow);
|
||||
auto workArea = MakeWorkArea({}, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
testWorkArea(workArea);
|
||||
|
||||
auto* activeZoneSet{ zoneWindow->ActiveZoneSet() };
|
||||
auto* activeZoneSet{ workArea->ActiveZoneSet() };
|
||||
Assert::IsNotNull(activeZoneSet);
|
||||
Assert::AreEqual(static_cast<int>(activeZoneSet->LayoutType()), static_cast<int>(FancyZonesDataTypes::ZoneSetLayoutType::PriorityGrid));
|
||||
Assert::AreEqual(activeZoneSet->GetZones().size(), static_cast<size_t>(3));
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateZoneWindowNoHinstFlashZones)
|
||||
TEST_METHOD (CreateWorkAreaNoHinstFlashZones)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), {}, m_monitor, m_uniqueId.str(), {});
|
||||
testZoneWindow(zoneWindow);
|
||||
auto workArea = MakeWorkArea({}, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
testWorkArea(workArea);
|
||||
|
||||
auto* activeZoneSet{ zoneWindow->ActiveZoneSet() };
|
||||
auto* activeZoneSet{ workArea->ActiveZoneSet() };
|
||||
Assert::IsNotNull(activeZoneSet);
|
||||
Assert::AreEqual(static_cast<int>(activeZoneSet->LayoutType()), static_cast<int>(FancyZonesDataTypes::ZoneSetLayoutType::PriorityGrid));
|
||||
Assert::AreEqual(activeZoneSet->GetZones().size(), static_cast<size_t>(3));
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateZoneWindowNoMonitor)
|
||||
TEST_METHOD (CreateWorkAreaNoMonitor)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, {}, m_uniqueId.str(), {});
|
||||
testZoneWindow(zoneWindow);
|
||||
auto workArea = MakeWorkArea(m_hInst, {}, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
testWorkArea(workArea);
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateZoneWindowNoDeviceId)
|
||||
TEST_METHOD (CreateWorkAreaNoDeviceId)
|
||||
{
|
||||
// Generate unique id without device id
|
||||
std::wstring uniqueId = FancyZonesUtils::GenerateUniqueId(m_monitor, {}, m_virtualDesktopId);
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, uniqueId, {});
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, uniqueId, {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
|
||||
const std::wstring expectedWorkArea = std::to_wstring(m_monitorInfo.rcMonitor.right) + L"_" + std::to_wstring(m_monitorInfo.rcMonitor.bottom);
|
||||
const std::wstring expectedUniqueId = L"FallbackDevice_" + std::to_wstring(m_monitorInfo.rcMonitor.right) + L"_" + std::to_wstring(m_monitorInfo.rcMonitor.bottom) + L"_" + m_virtualDesktopId;
|
||||
|
||||
Assert::IsNotNull(zoneWindow.get());
|
||||
Assert::AreEqual(expectedUniqueId.c_str(), zoneWindow->UniqueId().c_str());
|
||||
Assert::IsNotNull(workArea.get());
|
||||
Assert::AreEqual(expectedUniqueId.c_str(), workArea->UniqueId().c_str());
|
||||
|
||||
auto* activeZoneSet{ zoneWindow->ActiveZoneSet() };
|
||||
auto* activeZoneSet{ workArea->ActiveZoneSet() };
|
||||
Assert::IsNotNull(activeZoneSet);
|
||||
Assert::AreEqual(static_cast<int>(activeZoneSet->LayoutType()), static_cast<int>(FancyZonesDataTypes::ZoneSetLayoutType::PriorityGrid));
|
||||
Assert::AreEqual(activeZoneSet->GetZones().size(), static_cast<size_t>(3));
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateZoneWindowNoDesktopId)
|
||||
TEST_METHOD (CreateWorkAreaNoDesktopId)
|
||||
{
|
||||
// Generate unique id without virtual desktop id
|
||||
std::wstring uniqueId = FancyZonesUtils::GenerateUniqueId(m_monitor, m_deviceId, {});
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, uniqueId, {});
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, uniqueId, {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
|
||||
const std::wstring expectedWorkArea = std::to_wstring(m_monitorInfo.rcMonitor.right) + L"_" + std::to_wstring(m_monitorInfo.rcMonitor.bottom);
|
||||
Assert::IsNotNull(zoneWindow.get());
|
||||
Assert::IsTrue(zoneWindow->UniqueId().empty());
|
||||
Assert::IsNotNull(workArea.get());
|
||||
Assert::IsTrue(workArea->UniqueId().empty());
|
||||
|
||||
auto* activeZoneSet{ zoneWindow->ActiveZoneSet() };
|
||||
auto* activeZoneSet{ workArea->ActiveZoneSet() };
|
||||
Assert::IsNotNull(activeZoneSet);
|
||||
Assert::AreEqual(static_cast<int>(activeZoneSet->LayoutType()), static_cast<int>(FancyZonesDataTypes::ZoneSetLayoutType::PriorityGrid));
|
||||
Assert::AreEqual(activeZoneSet->GetZones().size(), static_cast<size_t>(3));
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateZoneWindowClonedFromParent)
|
||||
TEST_METHOD (CreateWorkAreaClonedFromParent)
|
||||
{
|
||||
using namespace FancyZonesDataTypes;
|
||||
|
||||
@@ -192,14 +154,12 @@ namespace FancyZonesUnitTests
|
||||
const auto parentDeviceInfo = DeviceInfoData{ parentZoneSet, true, spacing, zoneCount };
|
||||
m_fancyZonesData.SetDeviceInfo(m_parentUniqueId.str(), parentDeviceInfo);
|
||||
|
||||
winrt::com_ptr<MockZoneWindowHost> zoneWindowHost = winrt::make_self<MockZoneWindowHost>();
|
||||
auto parentZoneWindow = MakeZoneWindow(zoneWindowHost.get(), m_hInst, m_monitor, m_parentUniqueId.str(), {});
|
||||
zoneWindowHost->m_zoneWindow = parentZoneWindow.get();
|
||||
auto parentWorkArea = MakeWorkArea(m_hInst, m_monitor, m_parentUniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
|
||||
// newWorkArea = false - workArea won't be cloned from parent
|
||||
auto actualWorkArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
|
||||
// newWorkArea = false - zoneWindow won't be cloned from parent
|
||||
auto actualZoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, m_uniqueId.str(), {});
|
||||
|
||||
Assert::IsNotNull(actualZoneWindow->ActiveZoneSet());
|
||||
Assert::IsNotNull(actualWorkArea->ActiveZoneSet());
|
||||
|
||||
Assert::IsTrue(m_fancyZonesData.GetDeviceInfoMap().contains(m_uniqueId.str()));
|
||||
auto currentDeviceInfo = m_fancyZonesData.GetDeviceInfoMap().at(m_uniqueId.str());
|
||||
@@ -211,13 +171,15 @@ namespace FancyZonesUnitTests
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CLASS (ZoneWindowUnitTests)
|
||||
TEST_CLASS (WorkAreaUnitTests)
|
||||
{
|
||||
std::wstringstream m_uniqueId;
|
||||
|
||||
HINSTANCE m_hInst{};
|
||||
HMONITOR m_monitor{};
|
||||
MONITORINFO m_monitorInfo{};
|
||||
ZoneColors m_zoneColors{};
|
||||
OverlappingZonesAlgorithm m_overlappingAlgorithm = OverlappingZonesAlgorithm::Positional;
|
||||
|
||||
FancyZonesData& m_fancyZonesData = FancyZonesDataInstance();
|
||||
|
||||
@@ -233,73 +195,80 @@ namespace FancyZonesUnitTests
|
||||
|
||||
m_fancyZonesData.SetSettingsModulePath(L"FancyZonesUnitTests");
|
||||
m_fancyZonesData.clear_data();
|
||||
|
||||
m_zoneColors = ZoneColors{
|
||||
.primaryColor = FancyZonesUtils::HexToRGB(L"#4287f5"),
|
||||
.borderColor = FancyZonesUtils::HexToRGB(L"#FFFFFF"),
|
||||
.highlightColor = FancyZonesUtils::HexToRGB(L"#42eff5"),
|
||||
.highlightOpacity = 50,
|
||||
};
|
||||
}
|
||||
|
||||
public:
|
||||
TEST_METHOD (MoveSizeEnter)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, m_uniqueId.str(), {});
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
|
||||
const auto expected = S_OK;
|
||||
const auto actual = zoneWindow->MoveSizeEnter(Mocks::Window());
|
||||
const auto actual = workArea->MoveSizeEnter(Mocks::Window());
|
||||
|
||||
Assert::AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD (MoveSizeEnterTwice)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, m_uniqueId.str(), {});
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
|
||||
const auto expected = S_OK;
|
||||
|
||||
zoneWindow->MoveSizeEnter(Mocks::Window());
|
||||
const auto actual = zoneWindow->MoveSizeEnter(Mocks::Window());
|
||||
workArea->MoveSizeEnter(Mocks::Window());
|
||||
const auto actual = workArea->MoveSizeEnter(Mocks::Window());
|
||||
|
||||
Assert::AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD (MoveSizeUpdate)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, m_uniqueId.str(), {});
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
|
||||
const auto expected = S_OK;
|
||||
const auto actual = zoneWindow->MoveSizeUpdate(POINT{ 0, 0 }, true, false);
|
||||
const auto actual = workArea->MoveSizeUpdate(POINT{ 0, 0 }, true, false);
|
||||
|
||||
Assert::AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD (MoveSizeUpdatePointNegativeCoordinates)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, m_uniqueId.str(), {});
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
|
||||
const auto expected = S_OK;
|
||||
const auto actual = zoneWindow->MoveSizeUpdate(POINT{ -10, -10 }, true, false);
|
||||
const auto actual = workArea->MoveSizeUpdate(POINT{ -10, -10 }, true, false);
|
||||
|
||||
Assert::AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD (MoveSizeUpdatePointBigCoordinates)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, m_uniqueId.str(), {});
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
|
||||
const auto expected = S_OK;
|
||||
const auto actual = zoneWindow->MoveSizeUpdate(POINT{ m_monitorInfo.rcMonitor.right + 1, m_monitorInfo.rcMonitor.bottom + 1 }, true, false);
|
||||
const auto actual = workArea->MoveSizeUpdate(POINT{ m_monitorInfo.rcMonitor.right + 1, m_monitorInfo.rcMonitor.bottom + 1 }, true, false);
|
||||
|
||||
Assert::AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD (MoveSizeEnd)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, m_uniqueId.str(), {});
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
|
||||
const auto window = Mocks::Window();
|
||||
zoneWindow->MoveSizeEnter(window);
|
||||
workArea->MoveSizeEnter(window);
|
||||
|
||||
const auto expected = S_OK;
|
||||
const auto actual = zoneWindow->MoveSizeEnd(window, POINT{ 0, 0 });
|
||||
const auto actual = workArea->MoveSizeEnd(window, POINT{ 0, 0 });
|
||||
Assert::AreEqual(expected, actual);
|
||||
|
||||
const auto zoneSet = zoneWindow->ActiveZoneSet();
|
||||
const auto zoneSet = workArea->ActiveZoneSet();
|
||||
zoneSet->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0);
|
||||
const auto actualZoneIndexSet = zoneSet->GetZoneIndexSetFromWindow(window);
|
||||
Assert::IsFalse(std::vector<size_t>{} == actualZoneIndexSet);
|
||||
@@ -307,55 +276,55 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (MoveSizeEndWindowNotAdded)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, m_uniqueId.str(), {});
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
|
||||
const auto window = Mocks::Window();
|
||||
zoneWindow->MoveSizeEnter(window);
|
||||
workArea->MoveSizeEnter(window);
|
||||
|
||||
const auto expected = S_OK;
|
||||
const auto actual = zoneWindow->MoveSizeEnd(window, POINT{ -100, -100 });
|
||||
const auto actual = workArea->MoveSizeEnd(window, POINT{ -100, -100 });
|
||||
Assert::AreEqual(expected, actual);
|
||||
|
||||
const auto zoneSet = zoneWindow->ActiveZoneSet();
|
||||
const auto zoneSet = workArea->ActiveZoneSet();
|
||||
const auto actualZoneIndexSet = zoneSet->GetZoneIndexSetFromWindow(window);
|
||||
Assert::IsTrue(std::vector<size_t>{} == actualZoneIndexSet);
|
||||
}
|
||||
|
||||
TEST_METHOD (MoveSizeEndDifferentWindows)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, m_uniqueId.str(), {});
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
|
||||
const auto window = Mocks::Window();
|
||||
zoneWindow->MoveSizeEnter(window);
|
||||
workArea->MoveSizeEnter(window);
|
||||
|
||||
const auto expected = E_INVALIDARG;
|
||||
const auto actual = zoneWindow->MoveSizeEnd(Mocks::Window(), POINT{ 0, 0 });
|
||||
const auto actual = workArea->MoveSizeEnd(Mocks::Window(), POINT{ 0, 0 });
|
||||
|
||||
Assert::AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD (MoveSizeEndWindowNotSet)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, m_uniqueId.str(), {});
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
|
||||
const auto expected = E_INVALIDARG;
|
||||
const auto actual = zoneWindow->MoveSizeEnd(Mocks::Window(), POINT{ 0, 0 });
|
||||
const auto actual = workArea->MoveSizeEnd(Mocks::Window(), POINT{ 0, 0 });
|
||||
|
||||
Assert::AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD (MoveSizeEndInvalidPoint)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, m_uniqueId.str(), {});
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
|
||||
const auto window = Mocks::Window();
|
||||
zoneWindow->MoveSizeEnter(window);
|
||||
workArea->MoveSizeEnter(window);
|
||||
|
||||
const auto expected = S_OK;
|
||||
const auto actual = zoneWindow->MoveSizeEnd(window, POINT{ -1, -1 });
|
||||
const auto actual = workArea->MoveSizeEnd(window, POINT{ -1, -1 });
|
||||
Assert::AreEqual(expected, actual);
|
||||
|
||||
const auto zoneSet = zoneWindow->ActiveZoneSet();
|
||||
const auto zoneSet = workArea->ActiveZoneSet();
|
||||
zoneSet->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0);
|
||||
const auto actualZoneIndex = zoneSet->GetZoneIndexSetFromWindow(window);
|
||||
Assert::IsFalse(std::vector<size_t>{} == actualZoneIndex); // with invalid point zone remains the same
|
||||
@@ -363,21 +332,21 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (MoveWindowIntoZoneByIndex)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, m_uniqueId.str(), {});
|
||||
Assert::IsNotNull(zoneWindow->ActiveZoneSet());
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
Assert::IsNotNull(workArea->ActiveZoneSet());
|
||||
|
||||
zoneWindow->MoveWindowIntoZoneByIndex(Mocks::Window(), 0);
|
||||
workArea->MoveWindowIntoZoneByIndex(Mocks::Window(), 0);
|
||||
|
||||
const auto actual = zoneWindow->ActiveZoneSet();
|
||||
const auto actual = workArea->ActiveZoneSet();
|
||||
}
|
||||
|
||||
TEST_METHOD (MoveWindowIntoZoneByDirectionAndIndex)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, m_uniqueId.str(), {});
|
||||
Assert::IsNotNull(zoneWindow->ActiveZoneSet());
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
Assert::IsNotNull(workArea->ActiveZoneSet());
|
||||
|
||||
const auto window = Mocks::WindowCreate(m_hInst);
|
||||
zoneWindow->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true);
|
||||
workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true);
|
||||
|
||||
const auto& actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap();
|
||||
Assert::AreEqual((size_t)1, actualAppZoneHistory.size());
|
||||
@@ -388,13 +357,13 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (MoveWindowIntoZoneByDirectionManyTimes)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, m_uniqueId.str(), {});
|
||||
Assert::IsNotNull(zoneWindow->ActiveZoneSet());
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
Assert::IsNotNull(workArea->ActiveZoneSet());
|
||||
|
||||
const auto window = Mocks::WindowCreate(m_hInst);
|
||||
zoneWindow->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true);
|
||||
zoneWindow->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true);
|
||||
zoneWindow->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true);
|
||||
workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true);
|
||||
workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true);
|
||||
workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true);
|
||||
|
||||
const auto& actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap();
|
||||
Assert::AreEqual((size_t)1, actualAppZoneHistory.size());
|
||||
@@ -405,10 +374,10 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (SaveWindowProcessToZoneIndexNullptrWindow)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, m_uniqueId.str(), {});
|
||||
Assert::IsNotNull(zoneWindow->ActiveZoneSet());
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
Assert::IsNotNull(workArea->ActiveZoneSet());
|
||||
|
||||
zoneWindow->SaveWindowProcessToZoneIndex(nullptr);
|
||||
workArea->SaveWindowProcessToZoneIndex(nullptr);
|
||||
|
||||
const auto actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap();
|
||||
Assert::IsTrue(actualAppZoneHistory.empty());
|
||||
@@ -416,14 +385,14 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (SaveWindowProcessToZoneIndexNoWindowAdded)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, m_uniqueId.str(), {});
|
||||
Assert::IsNotNull(zoneWindow->ActiveZoneSet());
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
Assert::IsNotNull(workArea->ActiveZoneSet());
|
||||
|
||||
auto window = Mocks::WindowCreate(m_hInst);
|
||||
auto zone = MakeZone(RECT{ 0, 0, 100, 100 }, 1);
|
||||
zoneWindow->ActiveZoneSet()->AddZone(zone);
|
||||
workArea->ActiveZoneSet()->AddZone(zone);
|
||||
|
||||
zoneWindow->SaveWindowProcessToZoneIndex(window);
|
||||
workArea->SaveWindowProcessToZoneIndex(window);
|
||||
|
||||
const auto actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap();
|
||||
Assert::IsTrue(actualAppZoneHistory.empty());
|
||||
@@ -431,13 +400,13 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (SaveWindowProcessToZoneIndexNoWindowAddedWithFilledAppZoneHistory)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, m_uniqueId.str(), {});
|
||||
Assert::IsNotNull(zoneWindow->ActiveZoneSet());
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
Assert::IsNotNull(workArea->ActiveZoneSet());
|
||||
|
||||
const auto window = Mocks::WindowCreate(m_hInst);
|
||||
const auto processPath = get_process_path(window);
|
||||
const auto deviceId = zoneWindow->UniqueId();
|
||||
const auto zoneSetId = zoneWindow->ActiveZoneSet()->Id();
|
||||
const auto deviceId = workArea->UniqueId();
|
||||
const auto zoneSetId = workArea->ActiveZoneSet()->Id();
|
||||
|
||||
// fill app zone history map
|
||||
Assert::IsTrue(m_fancyZonesData.SetAppLastZones(window, deviceId, Helpers::GuidToString(zoneSetId), { 0 }));
|
||||
@@ -448,9 +417,9 @@ namespace FancyZonesUnitTests
|
||||
|
||||
// add zone without window
|
||||
const auto zone = MakeZone(RECT{ 0, 0, 100, 100 }, 1);
|
||||
zoneWindow->ActiveZoneSet()->AddZone(zone);
|
||||
workArea->ActiveZoneSet()->AddZone(zone);
|
||||
|
||||
zoneWindow->SaveWindowProcessToZoneIndex(window);
|
||||
workArea->SaveWindowProcessToZoneIndex(window);
|
||||
Assert::AreEqual((size_t)1, m_fancyZonesData.GetAppZoneHistoryMap().size());
|
||||
const auto& appHistoryArray2 = m_fancyZonesData.GetAppZoneHistoryMap().at(processPath);
|
||||
Assert::AreEqual((size_t)1, appHistoryArray2.size());
|
||||
@@ -459,17 +428,17 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (SaveWindowProcessToZoneIndexWindowAdded)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, m_uniqueId.str(), {});
|
||||
Assert::IsNotNull(zoneWindow->ActiveZoneSet());
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
Assert::IsNotNull(workArea->ActiveZoneSet());
|
||||
|
||||
auto window = Mocks::WindowCreate(m_hInst);
|
||||
const auto processPath = get_process_path(window);
|
||||
const auto deviceId = zoneWindow->UniqueId();
|
||||
const auto zoneSetId = zoneWindow->ActiveZoneSet()->Id();
|
||||
const auto deviceId = workArea->UniqueId();
|
||||
const auto zoneSetId = workArea->ActiveZoneSet()->Id();
|
||||
|
||||
auto zone = MakeZone(RECT{ 0, 0, 100, 100 }, 1);
|
||||
zoneWindow->ActiveZoneSet()->AddZone(zone);
|
||||
zoneWindow->MoveWindowIntoZoneByIndex(window, 0);
|
||||
workArea->ActiveZoneSet()->AddZone(zone);
|
||||
workArea->MoveWindowIntoZoneByIndex(window, 0);
|
||||
|
||||
//fill app zone history map
|
||||
Assert::IsTrue(m_fancyZonesData.SetAppLastZones(window, deviceId, Helpers::GuidToString(zoneSetId), { 2 }));
|
||||
@@ -478,19 +447,19 @@ namespace FancyZonesUnitTests
|
||||
Assert::AreEqual((size_t)1, appHistoryArray.size());
|
||||
Assert::IsTrue(std::vector<size_t>{ 2 } == appHistoryArray[0].zoneIndexSet);
|
||||
|
||||
zoneWindow->SaveWindowProcessToZoneIndex(window);
|
||||
workArea->SaveWindowProcessToZoneIndex(window);
|
||||
|
||||
const auto& actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap();
|
||||
Assert::AreEqual((size_t)1, actualAppZoneHistory.size());
|
||||
const auto& expected = zoneWindow->ActiveZoneSet()->GetZoneIndexSetFromWindow(window);
|
||||
const auto& expected = workArea->ActiveZoneSet()->GetZoneIndexSetFromWindow(window);
|
||||
const auto& actual = appHistoryArray[0].zoneIndexSet;
|
||||
Assert::IsTrue(expected == actual);
|
||||
}
|
||||
|
||||
TEST_METHOD (WhenWindowIsNotResizablePlacingItIntoTheZoneShouldNotResizeIt)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().get(), m_hInst, m_monitor, m_uniqueId.str(), {});
|
||||
Assert::IsNotNull(zoneWindow->ActiveZoneSet());
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm);
|
||||
Assert::IsNotNull(workArea->ActiveZoneSet());
|
||||
|
||||
auto window = Mocks::WindowCreate(m_hInst);
|
||||
|
||||
@@ -501,9 +470,9 @@ namespace FancyZonesUnitTests
|
||||
SetWindowLong(window, GWL_STYLE, GetWindowLong(window, GWL_STYLE) & ~WS_SIZEBOX);
|
||||
|
||||
auto zone = MakeZone(RECT{ 50, 50, 300, 300 }, 1);
|
||||
zoneWindow->ActiveZoneSet()->AddZone(zone);
|
||||
workArea->ActiveZoneSet()->AddZone(zone);
|
||||
|
||||
zoneWindow->MoveWindowIntoZoneByDirectionAndIndex(window, VK_LEFT, true);
|
||||
workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_LEFT, true);
|
||||
|
||||
RECT inZoneRect;
|
||||
GetWindowRect(window, &inZoneRect);
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "FancyZonesLib\FancyZonesData.h"
|
||||
#include "FancyZonesLib\FancyZonesDataTypes.h"
|
||||
#include "FancyZonesLib\JsonHelpers.h"
|
||||
#include "FancyZonesLib\VirtualDesktopUtils.h"
|
||||
#include "FancyZonesLib\VirtualDesktop.h"
|
||||
#include "FancyZonesLib\ZoneSet.h"
|
||||
|
||||
#include <filesystem>
|
||||
@@ -27,7 +27,7 @@ namespace FancyZonesUnitTests
|
||||
auto hres = CoCreateGuid(&m_id);
|
||||
Assert::AreEqual(S_OK, hres);
|
||||
|
||||
ZoneSetConfig m_config = ZoneSetConfig(m_id, m_layoutType, Mocks::Monitor(), DefaultValues::SensitivityRadius, Settings::OverlappingZonesAlgorithm::Smallest);
|
||||
ZoneSetConfig m_config = ZoneSetConfig(m_id, m_layoutType, Mocks::Monitor(), DefaultValues::SensitivityRadius, OverlappingZonesAlgorithm::Smallest);
|
||||
m_set = MakeZoneSet(m_config);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:FancyZonesEditor"
|
||||
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||
Startup="OnStartup">
|
||||
Startup="OnStartup"
|
||||
Exit="OnExit">
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
|
||||
@@ -57,6 +57,8 @@ namespace FancyZonesEditor
|
||||
|
||||
private ThemeManager _themeManager;
|
||||
|
||||
private EventWaitHandle _eventHandle;
|
||||
|
||||
public static bool DebugMode
|
||||
{
|
||||
get
|
||||
@@ -80,6 +82,15 @@ namespace FancyZonesEditor
|
||||
FancyZonesEditorIO = new FancyZonesEditorIO();
|
||||
Overlay = new Overlay();
|
||||
MainWindowSettings = new MainWindowSettingsModel();
|
||||
|
||||
new Thread(() =>
|
||||
{
|
||||
_eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, interop.Constants.FZEExitEvent());
|
||||
if (_eventHandle.WaitOne())
|
||||
{
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}).Start();
|
||||
}
|
||||
|
||||
private void OnStartup(object sender, StartupEventArgs e)
|
||||
@@ -145,6 +156,14 @@ namespace FancyZonesEditor
|
||||
Overlay.Show();
|
||||
}
|
||||
|
||||
private void OnExit(object sender, ExitEventArgs e)
|
||||
{
|
||||
if (_eventHandle != null)
|
||||
{
|
||||
_eventHandle.Set();
|
||||
}
|
||||
}
|
||||
|
||||
public void App_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == System.Windows.Input.Key.LeftShift || e.Key == System.Windows.Input.Key.RightShift)
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:FancyZonesEditor"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="300">
|
||||
<Grid x:Name="Body">
|
||||
|
||||
@@ -34,8 +34,7 @@
|
||||
<StackPanel Margin="16"
|
||||
FocusManager.FocusedElement="{Binding ElementName=newZoneButton}">
|
||||
|
||||
<Button x:Name="newZoneButton"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=newZoneName}"
|
||||
<local:ClickAutomationEventButton x:Name="newZoneButton"
|
||||
HorizontalAlignment="Stretch"
|
||||
Height="64"
|
||||
Width="64"
|
||||
@@ -49,7 +48,8 @@
|
||||
ToolTip="{x:Static props:Resources.Add_zone}"
|
||||
DataContext="{Binding Path=Model, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"
|
||||
IsEnabled="{Binding IsZoneAddingAllowed}"
|
||||
Click="OnAddZone" />
|
||||
Click="OnAddZone"
|
||||
OnClickAutomationValue="{x:Static props:Resources.New_zone_added}" />
|
||||
|
||||
<Grid Margin="0,24,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<Button x:Class="FancyZonesEditor.ClickAutomationEventButton"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:FancyZonesEditor"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
</Button>
|
||||
@@ -0,0 +1,105 @@
|
||||
// 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.Windows;
|
||||
using System.Windows.Automation;
|
||||
using System.Windows.Automation.Peers;
|
||||
using System.Windows.Automation.Provider;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace FancyZonesEditor
|
||||
{
|
||||
public partial class ClickAutomationEventButton : Button
|
||||
{
|
||||
public ClickAutomationEventButton()
|
||||
: base()
|
||||
{
|
||||
InitializeComponent();
|
||||
Click += OnClick;
|
||||
}
|
||||
|
||||
public string OnClickAutomationValue
|
||||
{
|
||||
get { return (string)GetValue(OnClickAutomationValueProperty); }
|
||||
set { SetValue(OnClickAutomationValueProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty OnClickAutomationValueProperty =
|
||||
DependencyProperty.Register(
|
||||
"Value", typeof(string), typeof(ClickAutomationEventButton));
|
||||
|
||||
private void OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (AutomationPeer.ListenerExists(AutomationEvents.PropertyChanged))
|
||||
{
|
||||
ClickAutomationEventButtonAutomationPeer peer =
|
||||
UIElementAutomationPeer.FromElement(this) as ClickAutomationEventButtonAutomationPeer;
|
||||
|
||||
if (peer != null)
|
||||
{
|
||||
peer.RaisePropertyChangedEvent(
|
||||
ValuePatternIdentifiers.ValueProperty,
|
||||
null,
|
||||
OnClickAutomationValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override AutomationPeer OnCreateAutomationPeer()
|
||||
{
|
||||
return new ClickAutomationEventButtonAutomationPeer(this);
|
||||
}
|
||||
|
||||
public class ClickAutomationEventButtonAutomationPeer : FrameworkElementAutomationPeer, IValueProvider
|
||||
{
|
||||
public ClickAutomationEventButtonAutomationPeer(ClickAutomationEventButton control)
|
||||
: base(control)
|
||||
{
|
||||
}
|
||||
|
||||
protected override string GetClassNameCore()
|
||||
{
|
||||
return nameof(ClickAutomationEventButton);
|
||||
}
|
||||
|
||||
protected override AutomationControlType GetAutomationControlTypeCore()
|
||||
{
|
||||
return AutomationControlType.Button;
|
||||
}
|
||||
|
||||
public override object GetPattern(PatternInterface patternInterface)
|
||||
{
|
||||
if (patternInterface == PatternInterface.Value)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
return base.GetPattern(patternInterface);
|
||||
}
|
||||
|
||||
public void SetValue(string value)
|
||||
{
|
||||
MyOwner.OnClickAutomationValue = value;
|
||||
}
|
||||
|
||||
private ClickAutomationEventButton MyOwner
|
||||
{
|
||||
get
|
||||
{
|
||||
return (ClickAutomationEventButton)Owner;
|
||||
}
|
||||
}
|
||||
|
||||
public string Value
|
||||
{
|
||||
get { return MyOwner.OnClickAutomationValue; }
|
||||
}
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get { return !IsEnabled(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,6 +81,7 @@
|
||||
<Resource Include="images\FancyZonesEditor.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\common\interop\PowerToysInterop.vcxproj" />
|
||||
<ProjectReference Include="..\..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
<ProjectReference Include="..\..\..\..\common\Microsoft.PowerToys.Common.UI\Microsoft.PowerToys.Common.UI.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -528,6 +528,15 @@ namespace FancyZonesEditor.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to New zone added.
|
||||
/// </summary>
|
||||
public static string New_zone_added {
|
||||
get {
|
||||
return ResourceManager.GetString("New_zone_added", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Create or duplicate a layout to get started.
|
||||
/// </summary>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user