merge master

This commit is contained in:
ryanbodrug-microsoft 2020-05-06 00:49:46 -07:00
commit 640fade438
183 changed files with 1973 additions and 1311 deletions

View file

@ -1,4 +1,4 @@
The MIT License (MIT)
The MIT License
Copyright (c) Microsoft Corporation. All rights reserved.

View file

@ -1,22 +1,5 @@
# NOTICES AND INFORMATION
Do Not Translate or Localize
This software incorporates material from third parties. Microsoft makes certain
open source code available at http://3rdpartysource.microsoft.com, or you may
send a check or money order for US $5.00, including the product name, the open
source component name, and version number, to:
```
Source Code Compliance Team
Microsoft Corporation
One Microsoft Way
Redmond, WA 98052
USA
```
Notwithstanding any other terms, you may reverse engineer this software to the
extent required to debug changes to any libraries licensed under the GNU Lesser
General Public License.
This software incorporates material from third parties.
## PowerToy: ImageResizer

View file

@ -8,12 +8,12 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
[![Build Status](https://dev.azure.com/ms/PowerToys/_apis/build/status/microsoft.PowerToys?branchName=master)](https://dev.azure.com/ms/PowerToys/_build?definitionId=219)
## Installing and running Microsoft PowerToys 0.16
## Installing and running Microsoft PowerToys 0.17
👉 **Note:** Microsoft PowerToys requires Windows 10 1803 (build 17134) or later.
### Via Github with MSI [Recommended]
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.16.1-x64.msi` 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.17.0-x64.msi` to download the PowerToys installer.
This is our preferred method.
@ -90,36 +90,27 @@ Our plan for all the [goals and utilities for v1.0 detailed over here in the wik
## What's Happening
### March 2020 Update
### April 2020 Update
Our mantra for the 0.16 was adding in new features along with a continual push for quality and stability. We are working toward getting a way to auto-update PowerToys and have a good plan for this. We want to proactively thank the community for quickly identifying a few bugs inside 0.15 and allowing us to quickly release 0.15.1 and 0.15.2.
Our goals for 0.17 release cycle were updatability and stability.
Below are just a few of the bullet items from this release.
**Auto-updating:** We just added in the code for doing updating, so the first chance to experience this will be when 0.18 is released. Were also seeing how aggressive everyone wants with this so right now, youll have to click “Install” for it to kick off the installer. This is something wed love feedback on.
- We shipped [v0.16][github-release-link]!
- FancyZone improvement:
- Multi-Monitor improvement: Zone flipping switching now works between monitors!
- Simplified UX: Removed layout hot-swap and flashing feature due to need to improve multi-monitor support
- New Utilities!
- Markdown Preview pane extension
- SVG Preview pane extension
- Image Resizer Window Shell extension
- Window Walker, an alt-tab alternative
- Fixed over 100 issues!
- Testing improvements
- 54 UX Functional tests
- 161 new Unit tests
For [0.17](https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F3), we are proactively working on:
Another thing we did was utilized telemetry from PowerToys to prioritize virtual desktop FancyZone work. We knew there was a subset of bugs caused by an underlying issue and seeing how many users it affected helped us reprioritize to do the work sooner.
- We shipped [v0.17][github-release-link]!
- Auto-updating
- FancyZone improvement:
- Virtual desktop support should be much better!
- Better taskbar positioning
- Fixed non-admin install regression.
- Lots of bug fixes!
For [0.18](https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F4), we are proactively working on:
- Win+R replacement (Launcher)
- Keyboard remapping
- Performance improvements with FancyZones
- A testing utility for FancyZones to be sure we can test different window configurations.
Future release work, we are proactively working on:
- Settings v2 / Fix bug #243
## Developer Guidance

View file

@ -3,25 +3,17 @@
This file captures the prioritized list of issues the FancyZones team will tackle
## On deck
Implement multi-mon editor support [195](https://github.com/microsoft/PowerToys/issues/195)
Add telemetry to new editor [196](https://github.com/microsoft/PowerToys/issues/196)
## Backlog
Add tests to the new editor [197](https://github.com/microsoft/PowerToys/issues/197)
Hitting Esc while dragging should cancel the drag and not move the window into a zone [170](https://github.com/microsoft/PowerToys/issues/170)
Flash Zones is wayyyy too slow with multiple large monitors [167](https://github.com/microsoft/PowerToys/issues/167)
Cycle through windows in a Zone [175](https://github.com/microsoft/PowerToys/issues/175)
Minimize/restore windows in a zone as a group [174](https://github.com/microsoft/PowerToys/issues/174)
FancyZones should support custom layouts for different "environments" [177](https://github.com/microsoft/PowerToys/issues/177)
Win+arrow works between monitors [161](https://github.com/microsoft/PowerToys/issues/161)
Win+arrow is directional based on zone rect [162](https://github.com/microsoft/PowerToys/issues/162)
Dragging a zoned window should restore size to a checkpointed size instead of current rect [166](https://github.com/microsoft/PowerToys/issues/166)
FancyZones should merge with MTND and include zone moves in the pop-up [178](https://github.com/microsoft/PowerToys/issues/178)
Drag to edge of screen automatically switches virtual desktops [168](https://github.com/microsoft/PowerToys/issues/168)
Different color schemes [165](https://github.com/microsoft/PowerToys/issues/165)
Ensure you can easily see zone while dragging [163](https://github.com/microsoft/PowerToys/issues/163)
Visual updates for Win+Arrow [171](https://github.com/microsoft/PowerToys/issues/171)
Add a CLI for FancyZones [180](https://github.com/microsoft/PowerToys/issues/180)
Add "magnetic dragging and resizing" mode to FancyZones [181](https://github.com/microsoft/PowerToys/issues/181)
Create layout from current windows [159](https://github.com/microsoft/PowerToys/issues/159)
Zone sets that have a dynamic number of zones [160](https://github.com/microsoft/PowerToys/issues/160)

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Version>0.17.0</Version>
<Version>0.17.1</Version>
<DefineConstants>Version=$(Version);</DefineConstants>
</PropertyGroup>
</Project>

14
src/Directory.Build.props Normal file
View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_PropertySheetDisplayName>PowerToys.Root.Props</_PropertySheetDisplayName>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<ConformanceMode>false</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
</ItemDefinitionGroup>
</Project>

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@ -22,7 +23,7 @@
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}</ProjectGuid>
<RootNamespace>actionrunner</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
<ProjectName>action_runner</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@ -93,7 +94,6 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<TreatWarningAsError>true</TreatWarningAsError>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@ -111,7 +111,6 @@
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -123,7 +122,6 @@
<WarningLevel>Level4</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<TreatWarningAsError>true</TreatWarningAsError>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@ -141,7 +139,6 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -164,7 +161,18 @@
<ItemGroup>
<ClInclude Include="..\runner\updating.h" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View file

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

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
@ -15,7 +16,7 @@
<ProjectGuid>{1A066C63-64B3-45F8-92FE-664E1CCE8077}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>UnitTestsCommonLib</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
<ProjectSubType>NativeUnitTestProject</ProjectSubType>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@ -113,7 +114,18 @@
<Project>{74485049-c722-400f-abe5-86ac52d929b3}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View file

@ -33,4 +33,7 @@
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

View file

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

View file

@ -9,8 +9,9 @@
// add headers that you want to pre-compile here
#include <Windows.h>
#include <winrt\base.h>
#include <winrt/base.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include "CppUnitTest.h"
#endif //PCH_H

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" />
<Import Project="..\..\installer\Version.props" />
<Target Name="GenerateVersionData" BeforeTargets="PrepareForBuild">
<ItemGroup>
@ -25,7 +26,7 @@
<ProjectGuid>{74485049-C722-400F-ABE5-86AC52D929B3}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>common</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
<ProjectName>common</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@ -70,7 +71,6 @@
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpplatest</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@ -94,7 +94,6 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@ -178,11 +177,14 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View file

@ -1,6 +1,7 @@
#pragma once
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Data.Json.h>
#include <optional>

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@ -23,7 +24,7 @@
<ProjectGuid>{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>notificationsdll</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@ -96,7 +97,6 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;NOTIFICATIONSDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpplatest</LanguageStandard>
<AdditionalOptions>/await %(AdditionalOptions)</AdditionalOptions>
@ -119,7 +119,6 @@
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;NOTIFICATIONSDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
@ -134,7 +133,6 @@
<WarningLevel>Level4</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;NOTIFICATIONSDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpplatest</LanguageStandard>
<AdditionalOptions>/await %(AdditionalOptions)</AdditionalOptions>
@ -157,7 +155,6 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;NOTIFICATIONSDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
@ -171,6 +168,7 @@
<ItemGroup>
<None Include="cpp.hint" />
<None Include="notifications.def" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h" />
@ -187,10 +185,18 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<ItemGroup>
<ProjectReference Include="..\notifications_winrt\notifications.vcxproj">
<Project>{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}</Project>
</ProjectReference>
</ItemGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View file

@ -19,6 +19,7 @@
<None Include="notifications.def">
<Filter>Resource Files</Filter>
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h">

View file

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

View file

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<!--
To customize common C++/WinRT project properties:
* right-click the project node
* expand the Common Properties item
* select the C++/WinRT property page
For more advanced scenarios, and complete documentation, please see:
https://github.com/Microsoft/cppwinrt/tree/master/nuget
-->
<PropertyGroup />
<ItemDefinitionGroup />
</Project>

View file

@ -14,7 +14,7 @@
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<WindowsTargetPlatformVersion Condition=" '$(WindowsTargetPlatformVersion)' == '' ">10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion Condition=" '$(WindowsTargetPlatformVersion)' == '' ">10.0.17134.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.17134.0</WindowsTargetPlatformMinVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@ -69,9 +69,6 @@
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="PropertySheet.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<TargetName>notifications</TargetName>
@ -105,7 +102,6 @@
<ClCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</TreatWarningAsError>
<ConformanceMode Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ConformanceMode>
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">stdcpplatest</LanguageStandard>
</ClCompile>
</ItemDefinitionGroup>
@ -113,7 +109,6 @@
<ClCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</TreatWarningAsError>
<ConformanceMode Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ConformanceMode>
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|x64'">stdcpplatest</LanguageStandard>
</ClCompile>
<Link>

View file

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

View file

@ -1,4 +1,5 @@
#include <winrt/base.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <Windows.h>
#include <dxgi1_3.h>
#include <d3d11_2.h>

View file

@ -7,7 +7,6 @@
#include <msi.h>
#include <common/common.h>
#include <common/json.h>
#include <common/version.h>
#include <common/settings_helpers.h>
#include <common/winstore.h>
#include <common/notifications.h>

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@ -23,7 +24,7 @@
<ProjectGuid>{17DA04DF-E393-4397-9CF0-84DABE11032E}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>updating</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
<ProjectName>updating</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@ -95,7 +96,6 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpplatest</LanguageStandard>
<TreatWarningAsError>true</TreatWarningAsError>
@ -120,7 +120,6 @@
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
@ -135,7 +134,6 @@
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpplatest</LanguageStandard>
<TreatWarningAsError>true</TreatWarningAsError>
@ -160,7 +158,6 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
@ -189,7 +186,18 @@
<Project>{74485049-c722-400f-abe5-86ac52d929b3}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View file

@ -30,4 +30,7 @@
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
@ -15,7 +16,7 @@
<ProjectGuid>{44CC9375-3E6E-4D99-8913-7FB748807EBD}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>examplepowertoy</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
@ -60,7 +61,6 @@
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\..\common\inc;..\..\common\Telemetry;..\;..\..\;..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@ -81,7 +81,6 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\..\common\inc;..\..\common\Telemetry;..\;..\..\;..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@ -118,7 +117,18 @@
<ItemGroup>
<ResourceCompile Include="example_powertoy.rc" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View file

@ -13,4 +13,7 @@
<ItemGroup>
<ResourceCompile Include="example_powertoy.rc" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

View file

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

View file

@ -1,4 +1,6 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <ProjectTelemetry.h>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 983 KiB

After

Width:  |  Height:  |  Size: 319 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

View file

@ -1,43 +1,64 @@
# Overview
Fancy Zones is a window manager that is designed to make it easy to arrange and snap windows into efficient layouts for your workflow and also to restore these layouts quickly. Fancy Zones allows the user to define a set of window locations for a desktop that are drag targets for windows. When the user drags a window into a zone, the windows is resized and repositioned to fill that zone.
FancyZones is a window manager that is designed to make it easy to arrange and snap windows into efficient layouts for your workflow and also to restore these layouts quickly. FancyZones allows the user to define a set of window locations for a desktop that are drag targets for windows. When the user drags a window into a zone, the window is resized and repositioned to fill that zone.
![Fancy Zones](FancyZones.png)
![FancyZones](FancyZones.png)
To get started with Fancy Zones, you need to enable the utility in Power Toys settings and then invoke the Fancy Zones setup UI. There is a button in settings to invoke this UI, or you can press Win+` (note that this shortcut can be changed in the settings dialog) to launch it. When first launched, the UI presents a list of zone layouts that can be quickly adjusted by how many windows are on the monitor. Choosing a layout shows a preview of that layout on the monitor. Pressing the save and close button sets that layout to the monitor.
To get started with FancyZones, you need to enable the utility in PowerToys settings and then invoke the FancyZones editor UI.
There is a button in settings to invoke the editor, or you can press <code>Win+&grave;</code> (note that this shortcut can be changed in the settings dialog) to launch it.
If you have multiple monitors, to edit the zone settings on each monitor, move the mouse to the desired monitor and then press <code>Win+&grave;</code> to launch the editor UI for that monitor, or move the PowerToys settings window to the desired monitor and then launch the editor UI using the `Edit zones` button.
![Fancy Zones Picker](Picker.png)
When first launched, the UI presents a list of zone layouts that can be quickly adjusted by how many windows are on the monitor. Choosing a layout shows a preview of that layout on the monitor. Pressing the save and close button sets that layout to the monitor.
The editor also supports creating and saving custom layouts. This functionality is in the “Custom” tab in the editor UI. There are two ways to create custom zone layouts, window layout and table layout. These can also be thought of as additive and subtractive models. The additive window layout model starts with a blank layout and supports adding zones that can be dragged and resized similar to windows.
![FancyZones Picker](Picker.png)
![Fancy Zones Window Editor Mode](WindowEditor.png)
The editor also supports creating and saving custom layouts. This functionality is in the `Custom` tab in the editor UI.
There are two ways to create custom zone layouts, window layout and table layout. These can also be thought of as additive and subtractive models.
The additive window layout model starts with a blank layout and supports adding zones that can be dragged and resized similar to windows.
![FancyZones Window Editor Mode](WindowEditor.png)
The subtractive table layout model starts with a table layout and allows zones to be created by splitting and merging zones and then resizing the gutter between zones.
To merge two zone, press and hold the left mouse button and drag the mouse until a second zone is selected, then release the button and a popup menu will show up.
![Fancy Zones Table Editor Mode](TableEditor.png)
![FancyZones Table Editor Mode](TableEditor.png)
The backlog for the utility can be found [here](https://github.com/Microsoft/PowerToys/tree/master/doc/planning/FancyZonesBacklog.md) and the source code is [here](https://github.com/Microsoft/PowerToys/tree/master/src/modules/fancyzones).
# Snapping a window to two zones (EXPERIMENTAL)
If two zones are adjacent, a window can be snapped to the sum of their area (rounded to the minimum rectangle that contains both). When the mouse cursor in near the common edge of two zones, both zones are activated simultaneously, allowing to drop the window on both.
**NOTE:** when snapping a window to two zones, restoring the window when the app is restarted is not supported yet.
![Two Zones Activation](TwoZonesActivation.png)
# Shortcut Keys
| Shortcut | Action |
| ----------- | ----------- |
| Win + ` | Launches editor (this shortcut is editable in the settings dialog) |
| Win+Ctrl+\<Number> | Cycles through saved layouts with the corresponding number of zones |
| Win+Left/Right Arrow | Move focused window between zones (only if Override snap hotkeys setting is enabled, in that case only the `Win+Left Arrow` and `Win+Right Arrow` are overriden, while the `Win+Up Arrow` and `Win+Down Arrow` keep working as usual) |
| Win+Left/Right Arrow | Move focused window between zones (only if `Override Windows Snap hotkeys` setting is turned on, in that case only the `Win+Left Arrow` and `Win+Right Arrow` are overriden, while the `Win+Up Arrow` and `Win+Down Arrow` keep working as usual) |
FancyZones doesn't override the Windows 10 `Win+Shift+Arrow` to quickly move a window to an adjacent monitor.
# Settings
| Setting | Description |
| --------- | ------------- |
| Configure the zone editor hotkey | To change the default hotkey, click on the textbox (it's not necessary to select or delete the text) and then press on the keyboard the desired key combination |
| Enable zones while dragging with the shift key | Toggles between auto-snap mode with the shift key disabling snapping during a drag and manual snap mode where pressing the shift key during a drag enables snapping |
| Override Windows Snap hotkeys (win+arrow) to move between zones | When this option is on and Fancy Zones is running, it overrides two Windows Snap keys: `Win+Left Arrow` and `Win+Right Arrow` |
| Flash zones when the active FancyZones layout changes | Briefly flash the zone layout when the layout changes or a new virtual desktop is activated |
| Keep windows in their zones when the screen resolution changes | After a screen resolution change, if this setting is enabled, Fancy Zones will resize and reposition windows into the zones they were previously in |
| Keep windows in their zones when the active FancyZones layout changes | When this option is on, Fancy Zones will resize and position windows into the new zone layout by maintaining the previous zone number location of each window |
| Override Windows Snap hotkeys (Win+Arrow) to move between zones | When this option is on and FancyZones is running, it overrides two Windows Snap keys: `Win+Left Arrow` and `Win+Right Arrow` |
| Keep windows in their zones when the screen resolution changes | After a screen resolution change, if this setting is enabled, FancyZones will resize and reposition windows into the zones they were previously in |
| Keep windows in their zones when the active FancyZones layout changes | When this option is on, FancyZones will resize and position windows into the new zone layout by maintaining the previous zone number location of each window |
| Keep windows in their zones when the active virtual desktop changes | If an application is pinned to all virtual desktops, this setting will keep that window in the same zone on all desktops |
| Move newly created windows to the last known zone | Automatically move a newly opened window into the last zone location that application was in |
| Follow mouse cursor instead of focus when launching editor in a multi screen environment | When this option is on, the editor hotkey will launch the editor on the monitor where the mouse cursor is, when this option is off, the editor hotkey will launch the editor on monitor where the current active window is |
| Zone Highlight Color (Default #0078D7) | the color that a zone becomes when it is the active drop target during a window drag |
| Follow mouse cursor instead of focus when launching editor in a multi-monitor environment | When this option is on, the editor hotkey will launch the editor on the monitor where the mouse cursor is, when this option is off, the editor hotkey will launch the editor on monitor where the current active window is |
| Show zones on all monitors while dragging a window | By default FancyZones shows only the zones available on the current monitor, this feature may have performance impact when turned on |
| Show zones on all monitors while dragging a window | When the zones are activated, the dragged window is made transparent to improve the zones visibility |
| Zone highlight color (Default #008CFF) | The color that a zone becomes when it is the active drop target during a window drag |
| Zone Inactive color (Default #F5FCFF) | The color that zones become when they are not an active drop during a window drag |
| Zone border color (Default #FFFFFF) | The color of the border of active and inactive zones |
| Zone opacity (%) (Default 50%) | The percentage of opacity of active and inactive zones |
| Exclude applications from snapping to zones | Add the applications name, or part of the name, one per line (e.g., adding `Notepa` will match both `Notepad.exe` and `Notepad++.exe`, to match only `Notepad.exe` add the `.exe` extension) |
![Fancy Zones Settings UI](FancyZonesSettings.png)
![FancyZones Settings UI](FancyZonesSettings1.png)
![FancyZones Settings UI](FancyZonesSettings2.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 238 KiB

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 937 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 KiB

After

Width:  |  Height:  |  Size: 1.3 MiB

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
@ -15,7 +16,7 @@
<ProjectGuid>{48804216-2A0E-4168-A6D8-9CD068D14227}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>fancyzones</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
<ProjectName>fancyzones</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@ -37,6 +38,7 @@
</ImportGroup>
<ImportGroup Label="Shared">
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
@ -62,7 +64,6 @@
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;FANCYZONES_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\;..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;..\..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@ -84,7 +85,6 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;FANCYZONES_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\;..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;..\..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@ -132,5 +132,7 @@
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View file

@ -10,24 +10,25 @@
#include <lib/trace.h>
#include <lib/Settings.h>
#include <lib/FancyZones.h>
#include <lib/FancyZonesWinHookEventIDs.h>
extern "C" IMAGE_DOS_HEADER __ImageBase;
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
Trace::RegisterProvider();
break;
case DLL_PROCESS_ATTACH:
Trace::RegisterProvider();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
Trace::UnregisterProvider();
break;
case DLL_PROCESS_DETACH:
Trace::UnregisterProvider();
break;
}
return TRUE;
}
@ -45,13 +46,12 @@ public:
// nullptr as the last element of the array. Nullptr can also be retured for empty list.
virtual PCWSTR* get_events() override
{
static PCWSTR events[] = { ll_keyboard, win_hook_event, nullptr };
return events;
return nullptr;
}
// Return JSON with the configuration options.
// These are the settings shown on the settings page along with their current values.
virtual bool get_config(_Out_ PWSTR buffer, _Out_ int *buffer_size) override
virtual bool get_config(_Out_ PWSTR buffer, _Out_ int* buffer_size) override
{
return m_settings->GetConfig(buffer, buffer_size);
}
@ -75,8 +75,37 @@ public:
{
if (!m_app)
{
InitializeWinhookEventIds();
Trace::FancyZones::EnableFancyZones(true);
m_app = MakeFancyZones(reinterpret_cast<HINSTANCE>(&__ImageBase), m_settings);
s_llKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), NULL);
if (!s_llKeyboardHook)
{
MessageBoxW(NULL, L"Cannot install keyboard listener.", L"PowerToys - FancyZones", MB_OK | MB_ICONERROR);
}
std::array<DWORD, 6> events_to_subscribe = {
EVENT_SYSTEM_MOVESIZESTART,
EVENT_SYSTEM_MOVESIZEEND,
EVENT_OBJECT_NAMECHANGE,
EVENT_OBJECT_UNCLOAKED,
EVENT_OBJECT_SHOW,
EVENT_OBJECT_CREATE
};
for (const auto event : events_to_subscribe)
{
auto hook = SetWinEventHook(event, event, nullptr, WinHookProc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
if (hook)
{
m_staticWinEventHooks.emplace_back(hook);
}
else
{
MessageBoxW(NULL, L"Cannot install Windows event listener.", L"PowerToys - FancyZones", MB_OK | MB_ICONERROR);
}
}
if (m_app)
{
m_app->Run();
@ -96,27 +125,14 @@ public:
return (m_app != nullptr);
}
// Handle incoming event, data is event-specific
// PowertoyModuleIface method, unused
virtual intptr_t signal_event(const wchar_t* name, intptr_t data) override
{
if (m_app)
{
if (wcscmp(name, ll_keyboard) == 0)
{
// Return 1 if the keypress is to be suppressed (not forwarded to Windows), otherwise return 0.
return HandleKeyboardHookEvent(reinterpret_cast<LowlevelKeyboardEvent*>(data));
}
else if (wcscmp(name, win_hook_event) == 0)
{
// Return value is ignored
HandleWinHookEvent(reinterpret_cast<WinHookEvent*>(data));
}
}
return 0;
}
virtual void register_system_menu_helper(PowertoySystemMenuIface* helper) override { }
virtual void signal_system_menu_action(const wchar_t* name) override { }
virtual void register_system_menu_helper(PowertoySystemMenuIface* helper) override {}
virtual void signal_system_menu_action(const wchar_t* name) override {}
// Destroy the powertoy and free memory
virtual void destroy() override
@ -130,67 +146,129 @@ public:
app_name = GET_RESOURCE_STRING(IDS_FANCYZONES);
m_settings = MakeFancyZonesSettings(reinterpret_cast<HINSTANCE>(&__ImageBase), FancyZonesModule::get_name());
JSONHelpers::FancyZonesDataInstance().LoadFancyZonesData();
s_instance = this;
}
private:
void Disable(bool const traceEvent)
{
if (m_app) {
if (traceEvent)
if (m_app)
{
if (traceEvent)
{
Trace::FancyZones::EnableFancyZones(false);
}
m_app->Destroy();
m_app = nullptr;
m_settings->ResetCallback();
if (s_llKeyboardHook)
{
if (UnhookWindowsHookEx(s_llKeyboardHook))
{
s_llKeyboardHook = nullptr;
}
}
m_staticWinEventHooks.erase(std::remove_if(begin(m_staticWinEventHooks),
end(m_staticWinEventHooks),
[](const HWINEVENTHOOK hook) {
return UnhookWinEvent(hook);
}),
end(m_staticWinEventHooks));
if (m_objectLocationWinEventHook)
{
if (UnhookWinEvent(m_objectLocationWinEventHook))
{
m_objectLocationWinEventHook = nullptr;
}
}
}
}
intptr_t HandleKeyboardHookEvent(LowlevelKeyboardEvent* data) noexcept;
void HandleWinHookEvent(WinHookEvent* data) noexcept;
void MoveSizeStart(HWND window, POINT const& ptScreen) noexcept;
void MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept;
void MoveSizeUpdate(POINT const& ptScreen) noexcept;
winrt::com_ptr<IFancyZones> m_app;
winrt::com_ptr<IFancyZonesSettings> m_settings;
std::wstring app_name;
static inline FancyZonesModule* s_instance;
static inline HHOOK s_llKeyboardHook;
std::vector<HWINEVENTHOOK> m_staticWinEventHooks;
HWINEVENTHOOK m_objectLocationWinEventHook;
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
LowlevelKeyboardEvent event;
if (nCode == HC_ACTION && wParam == WM_KEYDOWN)
{
event.lParam = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
event.wParam = wParam;
if (s_instance)
{
return s_instance->HandleKeyboardHookEvent(&event);
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
static void CALLBACK WinHookProc(HWINEVENTHOOK winEventHook,
DWORD event,
HWND window,
LONG object,
LONG child,
DWORD eventThread,
DWORD eventTime)
{
WinHookEvent data{ event, window, object, child, eventThread, eventTime };
if (s_instance)
{
s_instance->HandleWinHookEvent(&data);
}
}
};
intptr_t FancyZonesModule::HandleKeyboardHookEvent(LowlevelKeyboardEvent* data) noexcept
{
if (data->wParam == WM_KEYDOWN)
{
return m_app.as<IFancyZonesCallback>()->OnKeyDown(data->lParam) ? 1 : 0;
}
return 0;
return m_app.as<IFancyZonesCallback>()->OnKeyDown(data->lParam);
}
void FancyZonesModule::HandleWinHookEvent(WinHookEvent* data) noexcept
{
POINT ptScreen;
GetPhysicalCursorPos(&ptScreen);
auto fzCallback = m_app.as<IFancyZonesCallback>();
switch (data->event)
{
case EVENT_SYSTEM_MOVESIZESTART:
{
MoveSizeStart(data->hwnd, ptScreen);
fzCallback->HandleWinHookEvent(data);
if (!m_objectLocationWinEventHook)
{
m_objectLocationWinEventHook = SetWinEventHook(EVENT_OBJECT_LOCATIONCHANGE,
EVENT_OBJECT_LOCATIONCHANGE,
nullptr,
WinHookProc,
0,
0,
WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
}
}
break;
case EVENT_SYSTEM_MOVESIZEEND:
{
MoveSizeEnd(data->hwnd, ptScreen);
if (UnhookWinEvent(m_objectLocationWinEventHook))
{
m_objectLocationWinEventHook = nullptr;
}
fzCallback->HandleWinHookEvent(data);
}
break;
case EVENT_OBJECT_LOCATIONCHANGE:
{
if (m_app.as<IFancyZonesCallback>()->InMoveSize())
{
MoveSizeUpdate(ptScreen);
}
fzCallback->HandleWinHookEvent(data);
}
break;
@ -210,10 +288,7 @@ void FancyZonesModule::HandleWinHookEvent(WinHookEvent* data) noexcept
case EVENT_OBJECT_SHOW:
case EVENT_OBJECT_CREATE:
{
if (data->idObject == OBJID_WINDOW)
{
m_app.as<IFancyZonesCallback>()->WindowCreated(data->hwnd);
}
fzCallback->HandleWinHookEvent(data);
}
break;
@ -222,30 +297,7 @@ void FancyZonesModule::HandleWinHookEvent(WinHookEvent* data) noexcept
}
}
void FancyZonesModule::MoveSizeStart(HWND window, POINT const& ptScreen) noexcept
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
{
if (auto monitor = MonitorFromPoint(ptScreen, MONITOR_DEFAULTTONULL))
{
m_app.as<IFancyZonesCallback>()->MoveSizeStart(window, monitor, ptScreen);
}
return new FancyZonesModule();
}
void FancyZonesModule::MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept
{
m_app.as<IFancyZonesCallback>()->MoveSizeEnd(window, ptScreen);
}
void FancyZonesModule::MoveSizeUpdate(POINT const& ptScreen) noexcept
{
if (auto monitor = MonitorFromPoint(ptScreen, MONITOR_DEFAULTTONULL))
{
m_app.as<IFancyZonesCallback>()->MoveSizeUpdate(monitor, ptScreen);
}
}
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
{
return new FancyZonesModule();
}

View file

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

View file

@ -3,6 +3,8 @@
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <Unknwn.h>
#include <winrt/base.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <ProjectTelemetry.h>
#include <TraceLoggingActivity.h>
#include <wil\common.h>

View file

@ -88,7 +88,7 @@ namespace FancyZonesEditor.Properties {
}
/// <summary>
/// Looks up a localized string similar to Choose your layout.
/// Looks up a localized string similar to Choose your layout for this desktop.
/// </summary>
public static string Choose_Layout {
get {

View file

@ -127,7 +127,7 @@
<value>Cancel</value>
</data>
<data name="Choose_Layout" xml:space="preserve">
<value>Choose your layout</value>
<value>Choose your layout for this desktop</value>
</data>
<data name="Custom" xml:space="preserve">
<value>Custom</value>

View file

@ -16,7 +16,7 @@ namespace FancyZonesEditor.Utils
return str;
}
return string.Concat(str.Select((x, i) => i > 0 && char.IsUpper(x) ? "-" + x.ToString() : x.ToString())).ToLower();
return string.Concat(str.Select((x, i) => i > 0 && char.IsUpper(x) ? "-" + x.ToString() : x.ToString())).ToLowerInvariant();
}
}
}

View file

@ -1,24 +1,21 @@
#include "pch.h"
#include "common/dpi_aware.h"
#include "common/on_thread_executor.h"
#include <common/dpi_aware.h>
#include <common/on_thread_executor.h>
#include <common/window_helpers.h>
#include "FancyZones.h"
#include "lib/Settings.h"
#include "lib/ZoneWindow.h"
#include "lib/RegistryHelpers.h"
#include "lib/JsonHelpers.h"
#include "lib/ZoneSet.h"
#include "lib/WindowMoveHandler.h"
#include "lib/FancyZonesWinHookEventIDs.h"
#include "lib/util.h"
#include "trace.h"
#include "VirtualDesktopUtils.h"
#include <functional>
#include <common/common.h>
#include <common/window_helpers.h>
#include <common/notifications.h>
#include <lib/util.h>
#include <unordered_set>
#include <common/notifications/fancyzones_notifications.h>
#include <interface/win_hook_event_data.h>
enum class DisplayChangeType
{
@ -29,8 +26,6 @@ enum class DisplayChangeType
Initialization
};
extern "C" IMAGE_DOS_HEADER __ImageBase;
namespace std
{
template<>
@ -49,7 +44,8 @@ struct FancyZones : public winrt::implements<FancyZones, IFancyZones, IFancyZone
public:
FancyZones(HINSTANCE hinstance, const winrt::com_ptr<IFancyZonesSettings>& settings) noexcept :
m_hinstance(hinstance),
m_settings(settings)
m_settings(settings),
m_windowMoveHandler(settings)
{
m_settings->SetCallback(this);
}
@ -65,26 +61,70 @@ public:
InMoveSize() noexcept
{
std::shared_lock readLock(m_lock);
return m_inMoveSize;
return m_windowMoveHandler.InMoveSize();
}
void MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen) noexcept
{
std::unique_lock writeLock(m_lock);
m_windowMoveHandler.MoveSizeStart(window, monitor, ptScreen, m_zoneWindowMap);
}
void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen) noexcept
{
std::unique_lock writeLock(m_lock);
m_windowMoveHandler.MoveSizeUpdate(monitor, ptScreen, m_zoneWindowMap);
}
void MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept
{
std::unique_lock writeLock(m_lock);
m_windowMoveHandler.MoveSizeEnd(window, ptScreen, m_zoneWindowMap);
}
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;
HandleWinHookEvent(const WinHookEvent* data) noexcept
{
const auto wparam = reinterpret_cast<WPARAM>(data->hwnd);
const LONG lparam = 0;
std::shared_lock readLock(m_lock);
switch (data->event)
{
case EVENT_SYSTEM_MOVESIZESTART:
PostMessageW(m_window, WM_PRIV_MOVESIZESTART, wparam, lparam);
break;
case EVENT_SYSTEM_MOVESIZEEND:
PostMessageW(m_window, WM_PRIV_MOVESIZEEND, wparam, lparam);
break;
case EVENT_OBJECT_LOCATIONCHANGE:
PostMessageW(m_window, WM_PRIV_LOCATIONCHANGE, wparam, lparam);
break;
case EVENT_OBJECT_NAMECHANGE:
PostMessageW(m_window, WM_PRIV_NAMECHANGE, wparam, lparam);
break;
case EVENT_OBJECT_UNCLOAKED:
case EVENT_OBJECT_SHOW:
case EVENT_OBJECT_CREATE:
if (data->idObject == OBJID_WINDOW)
{
PostMessageW(m_window, WM_PRIV_WINDOWCREATED, wparam, lparam);
}
break;
}
}
IFACEMETHODIMP_(void)
VirtualDesktopChanged() noexcept;
IFACEMETHODIMP_(void)
VirtualDesktopInitialize() noexcept;
IFACEMETHODIMP_(void)
WindowCreated(HWND window) noexcept;
IFACEMETHODIMP_(bool)
OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept;
IFACEMETHODIMP_(void)
ToggleEditor() noexcept;
IFACEMETHODIMP_(void)
SettingsChanged() noexcept;
void WindowCreated(HWND window) noexcept;
// IZoneWindowHost
IFACEMETHODIMP_(void)
@ -150,9 +190,6 @@ public:
void OnDisplayChange(DisplayChangeType changeType) noexcept;
void AddZoneWindow(HMONITOR monitor, PCWSTR deviceId) noexcept;
void MoveWindowIntoZoneByIndex(HWND window, HMONITOR monitor, int index) noexcept;
void MoveWindowIntoZoneByIndexSet(HWND window, HMONITOR monitor, const std::vector<int>& indexSet) noexcept;
protected:
static LRESULT CALLBACK s_WndProc(HWND, UINT, WPARAM, LPARAM) noexcept;
@ -181,19 +218,12 @@ private:
}
};
bool IsInterestingWindow(HWND window) noexcept;
bool IsCursorTypeIndicatingSizeEvent();
void UpdateZoneWindows() noexcept;
void MoveWindowsOnDisplayChange() noexcept;
void UpdateDragState(HWND window, require_write_lock) noexcept;
void CycleActiveZoneSet(DWORD vkCode) noexcept;
bool OnSnapHotkey(DWORD vkCode) noexcept;
void MoveSizeStartInternal(HWND window, HMONITOR monitor, POINT const& ptScreen, require_write_lock) noexcept;
void MoveSizeEndInternal(HWND window, POINT const& ptScreen, require_write_lock) noexcept;
void MoveSizeUpdateInternal(HMONITOR monitor, POINT const& ptScreen, require_write_lock) noexcept;
void HandleVirtualDesktopUpdates(HANDLE fancyZonesDestroyedEvent) noexcept;
void RegisterVirtualDesktopUpdates(std::unordered_set<GUID>& currentVirtualDesktopIds) noexcept;
void RegisterVirtualDesktopUpdates(std::vector<GUID>& ids) noexcept;
void RegisterNewWorkArea(GUID virtualDesktopId, HMONITOR monitor) noexcept;
bool IsNewWorkArea(GUID virtualDesktopId, HMONITOR monitor) noexcept;
@ -201,19 +231,14 @@ private:
std::vector<std::pair<HMONITOR, RECT>> GetRawMonitorData() noexcept;
std::vector<HMONITOR> GetMonitorsSorted() noexcept;
bool MoveWindowIntoZoneByDirection(HMONITOR monitor, HWND window, DWORD vkCode, bool cycle);
const HINSTANCE m_hinstance{};
HKEY m_virtualDesktopsRegKey{ nullptr };
mutable std::shared_mutex m_lock;
HWND m_window{};
HWND m_windowMoveSize{}; // The window that is being moved/sized
bool m_inMoveSize{}; // Whether or not a move/size operation is currently active
bool m_dragEnabled{}; // True if we should be showing zone hints while dragging
WindowMoveHandler m_windowMoveHandler;
std::map<HMONITOR, winrt::com_ptr<IZoneWindow>> m_zoneWindowMap; // Map of monitor to ZoneWindow (one per monitor)
winrt::com_ptr<IZoneWindow> m_zoneWindowMoveSize; // "Active" ZoneWindow, where the move/size is happening. Will update as drag moves between monitors.
winrt::com_ptr<IFancyZonesSettings> m_settings{};
GUID m_currentVirtualDesktopId{}; // UUID of the current virtual desktop. Is GUID_NULL until first VD switch per session.
std::unordered_map<GUID, std::vector<HMONITOR>> m_processedWorkAreas; // Work area is defined by monitor and virtual desktop id.
@ -223,9 +248,12 @@ private:
OnThreadExecutor m_dpiUnawareThread;
OnThreadExecutor m_virtualDesktopTrackerThread;
static UINT WM_PRIV_VDCHANGED; // Message to get back on to the UI thread when virtual desktop changes
static UINT WM_PRIV_VDINIT; // Message to get back to the UI thread when FancyZones are initialized
static UINT WM_PRIV_EDITOR; // Message to get back on to the UI thread when the editor exits
static UINT WM_PRIV_VD_INIT; // Scheduled when FancyZones is initialized
static UINT WM_PRIV_VD_SWITCH; // Scheduled when virtual desktop switch occurs
static UINT WM_PRIV_VD_UPDATE; // Scheduled on virtual desktops update (creation/deletion)
static UINT WM_PRIV_EDITOR; // Scheduled when the editor exits
static UINT WM_PRIV_LOWLEVELKB; // Scheduled when we receive a key down press
// Did we terminate the editor or was it closed cleanly?
enum class EditorExitKind : byte
@ -235,9 +263,11 @@ private:
};
};
UINT FancyZones::WM_PRIV_VDCHANGED = RegisterWindowMessage(L"{128c2cb0-6bdf-493e-abbe-f8705e04aa95}");
UINT FancyZones::WM_PRIV_VDINIT = RegisterWindowMessage(L"{469818a8-00fa-4069-b867-a1da484fcd9a}");
UINT FancyZones::WM_PRIV_VD_INIT = RegisterWindowMessage(L"{469818a8-00fa-4069-b867-a1da484fcd9a}");
UINT FancyZones::WM_PRIV_VD_SWITCH = RegisterWindowMessage(L"{128c2cb0-6bdf-493e-abbe-f8705e04aa95}");
UINT FancyZones::WM_PRIV_VD_UPDATE = RegisterWindowMessage(L"{b8b72b46-f42f-4c26-9e20-29336cf2f22e}");
UINT FancyZones::WM_PRIV_EDITOR = RegisterWindowMessage(L"{87543824-7080-4e91-9d9c-0404642fc7b6}");
UINT FancyZones::WM_PRIV_LOWLEVELKB = RegisterWindowMessage(L"{763c03a3-03d9-4cde-8d71-f0358b0b4b52}");
// IFancyZones
IFACEMETHODIMP_(void)
@ -268,12 +298,8 @@ FancyZones::Run() noexcept
} })
.wait();
if (RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VirtualDesktops", 0, KEY_ALL_ACCESS, &m_virtualDesktopsRegKey) == ERROR_SUCCESS)
{
m_terminateVirtualDesktopTrackerEvent.reset(CreateEvent(nullptr, FALSE, FALSE, nullptr));
m_virtualDesktopTrackerThread.submit(
OnThreadExecutor::task_t{ std::bind(&FancyZones::HandleVirtualDesktopUpdates, this, m_terminateVirtualDesktopTrackerEvent.get()) });
}
m_terminateVirtualDesktopTrackerEvent.reset(CreateEvent(nullptr, FALSE, FALSE, nullptr));
m_virtualDesktopTrackerThread.submit(OnThreadExecutor::task_t{ [&] { VirtualDesktopUtils::HandleVirtualDesktopUpdates(m_window, WM_PRIV_VD_UPDATE, m_terminateVirtualDesktopTrackerEvent.get()); } });
}
// IFancyZones
@ -292,58 +318,23 @@ FancyZones::Destroy() noexcept
{
SetEvent(m_terminateVirtualDesktopTrackerEvent.get());
}
if (m_virtualDesktopsRegKey)
{
RegCloseKey(m_virtualDesktopsRegKey);
m_virtualDesktopsRegKey = nullptr;
}
}
// IFancyZonesCallback
IFACEMETHODIMP_(void)
FancyZones::MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen) noexcept
{
if (IsInterestingWindow(window))
{
std::unique_lock writeLock(m_lock);
MoveSizeStartInternal(window, monitor, ptScreen, writeLock);
}
}
// IFancyZonesCallback
IFACEMETHODIMP_(void)
FancyZones::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen) noexcept
{
std::unique_lock writeLock(m_lock);
MoveSizeUpdateInternal(monitor, ptScreen, writeLock);
}
// IFancyZonesCallback
IFACEMETHODIMP_(void)
FancyZones::MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept
{
if (window == m_windowMoveSize || IsInterestingWindow(window))
{
std::unique_lock writeLock(m_lock);
MoveSizeEndInternal(window, ptScreen, writeLock);
}
}
// IFancyZonesCallback
IFACEMETHODIMP_(void)
FancyZones::VirtualDesktopChanged() noexcept
{
// VirtualDesktopChanged is called from another thread but results in new windows being created.
// Jump over to the UI thread to handle it.
// VirtualDesktopChanged is called from a reentrant WinHookProc function, therefore we must postpone the actual logic
// until we're in FancyZones::WndProc, which is not reentrant.
std::shared_lock readLock(m_lock);
PostMessage(m_window, WM_PRIV_VDCHANGED, 0, 0);
PostMessage(m_window, WM_PRIV_VD_SWITCH, 0, 0);
}
// IFancyZonesCallback
IFACEMETHODIMP_(void)
FancyZones::VirtualDesktopInitialize() noexcept
{
PostMessage(m_window, WM_PRIV_VDINIT, 0, 0);
PostMessage(m_window, WM_PRIV_VD_INIT, 0, 0);
}
// IFancyZonesCallback
@ -351,7 +342,7 @@ IFACEMETHODIMP_(void)
FancyZones::WindowCreated(HWND window) noexcept
{
std::shared_lock readLock(m_lock);
if (m_settings->GetSettings()->appLastZone_moveWindows && IsInterestingWindow(window))
if (m_settings->GetSettings()->appLastZone_moveWindows && IsInterestingWindow(window, m_settings->GetSettings()->excludedAppsArray))
{
for (const auto& [monitor, zoneWindow] : m_zoneWindowMap)
{
@ -376,7 +367,7 @@ FancyZones::WindowCreated(HWND window) noexcept
int zoneIndex = fancyZonesData.GetAppLastZoneIndex(window, zoneWindow->UniqueId(), guidString.get());
if (zoneIndex != -1)
{
MoveWindowIntoZoneByIndex(window, monitor, zoneIndex);
m_windowMoveHandler.MoveWindowIntoZoneByIndex(window, monitor, zoneIndex, m_zoneWindowMap);
break;
}
}
@ -391,7 +382,7 @@ FancyZones::OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept
{
// Return true to swallow the keyboard event
bool const shift = GetAsyncKeyState(VK_SHIFT) & 0x8000;
bool const win = GetAsyncKeyState(VK_LWIN) & 0x8000;
bool const win = GetAsyncKeyState(VK_LWIN) & 0x8000 || GetAsyncKeyState(VK_RWIN) & 0x8000;
if (win && !shift)
{
bool const ctrl = GetAsyncKeyState(VK_CONTROL) & 0x8000;
@ -410,9 +401,10 @@ FancyZones::OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept
{
if (m_settings->GetSettings()->overrideSnapHotkeys)
{
// Win+Left, Win+Right will cycle through Zones in the active ZoneSet
Trace::FancyZones::OnKeyDown(info->vkCode, win, ctrl, false /*inMoveSize*/);
return OnSnapHotkey(info->vkCode);
// Win+Left, Win+Right will cycle through Zones in the active ZoneSet when WM_PRIV_LOWLEVELKB's handled
PostMessageW(m_window, WM_PRIV_LOWLEVELKB, 0, info->vkCode);
return true;
}
}
}
@ -424,7 +416,8 @@ FancyZones::OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept
// CycleActiveZoneSet(info->vkCode);
// return false;
//}
if (m_dragEnabled && shift)
if (m_windowMoveHandler.IsDragEnabled() && shift)
{
return true;
}
@ -600,13 +593,28 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
default:
{
if (message == WM_PRIV_VDCHANGED)
POINT ptScreen;
GetPhysicalCursorPos(&ptScreen);
if (message == WM_PRIV_LOWLEVELKB)
{
OnSnapHotkey(static_cast<DWORD>(lparam));
}
else if (message == WM_PRIV_VD_INIT)
{
OnDisplayChange(DisplayChangeType::Initialization);
}
else if (message == WM_PRIV_VD_SWITCH)
{
OnDisplayChange(DisplayChangeType::VirtualDesktop);
}
else if (message == WM_PRIV_VDINIT)
else if (message == WM_PRIV_VD_UPDATE)
{
OnDisplayChange(DisplayChangeType::Initialization);
std::vector<GUID> ids{};
if (VirtualDesktopUtils::GetVirtualDesktopIds(ids))
{
RegisterVirtualDesktopUpdates(ids);
}
}
else if (message == WM_PRIV_EDITOR)
{
@ -622,6 +630,31 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
m_terminateEditorEvent.release();
}
}
else if (message == WM_PRIV_MOVESIZESTART)
{
auto hwnd = reinterpret_cast<HWND>(wparam);
if (auto monitor = MonitorFromPoint(ptScreen, MONITOR_DEFAULTTONULL))
{
MoveSizeStart(hwnd, monitor, ptScreen);
}
}
else if (message == WM_PRIV_MOVESIZEEND)
{
auto hwnd = reinterpret_cast<HWND>(wparam);
MoveSizeEnd(hwnd, ptScreen);
}
else if (message == WM_PRIV_LOCATIONCHANGE && InMoveSize())
{
if (auto monitor = MonitorFromPoint(ptScreen, MONITOR_DEFAULTTONULL))
{
MoveSizeUpdate(monitor, ptScreen);
}
}
else if (message == WM_PRIV_WINDOWCREATED)
{
auto hwnd = reinterpret_cast<HWND>(wparam);
WindowCreated(hwnd);
}
else
{
return DefWindowProc(window, message, wparam, lparam);
@ -632,25 +665,25 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
return 0;
}
void FancyZones::OnDisplayChange(DisplayChangeType changeType) noexcept
{
if (changeType == DisplayChangeType::VirtualDesktop ||
changeType == DisplayChangeType::Initialization)
{
// Explorer persists this value to the registry on a per session basis but only after
// the first virtual desktop switch happens. If the user hasn't switched virtual desktops in this session
// then this value will be empty. This means loading the first virtual desktop's configuration can be
// funky the first time we load up at boot since the user will not have switched virtual desktops yet.
GUID currentVirtualDesktopId{};
if (SUCCEEDED(RegistryHelpers::GetCurrentVirtualDesktop(&currentVirtualDesktopId)))
if (VirtualDesktopUtils::GetCurrentVirtualDesktopId(&currentVirtualDesktopId))
{
std::unique_lock writeLock(m_lock);
m_currentVirtualDesktopId = currentVirtualDesktopId;
}
else
if (changeType == DisplayChangeType::Initialization)
{
// TODO: Use the previous "Desktop 1" fallback
// Need to maintain a map of desktop name to virtual desktop uuid
std::vector<std::wstring> ids{};
if (VirtualDesktopUtils::GetVirtualDesktopIds(ids) && !ids.empty())
{
JSONHelpers::FancyZonesDataInstance().UpdatePrimaryDesktopData(ids[0]);
JSONHelpers::FancyZonesDataInstance().RemoveDeletedDesktops(ids);
}
}
}
@ -707,30 +740,6 @@ void FancyZones::AddZoneWindow(HMONITOR monitor, PCWSTR deviceId) noexcept
}
}
void FancyZones::MoveWindowIntoZoneByIndex(HWND window, HMONITOR monitor, int index) noexcept
{
std::shared_lock readLock(m_lock);
MoveWindowIntoZoneByIndexSet(window, monitor, { index });
}
void FancyZones::MoveWindowIntoZoneByIndexSet(HWND window, HMONITOR monitor, const std::vector<int>& indexSet) noexcept
{
std::shared_lock readLock(m_lock);
if (window != m_windowMoveSize)
{
const HMONITOR hm = (monitor != nullptr) ? monitor : MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
if (hm)
{
auto zoneWindow = m_zoneWindowMap.find(hm);
if (zoneWindow != m_zoneWindowMap.end())
{
const auto& zoneWindowPtr = zoneWindow->second;
zoneWindowPtr->MoveWindowIntoZoneByIndexSet(window, indexSet);
}
}
}
}
LRESULT CALLBACK FancyZones::s_WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept
{
auto thisRef = reinterpret_cast<FancyZones*>(GetWindowLongPtr(window, GWLP_USERDATA));
@ -745,53 +754,6 @@ LRESULT CALLBACK FancyZones::s_WndProc(HWND window, UINT message, WPARAM wparam,
DefWindowProc(window, message, wparam, lparam);
}
bool FancyZones::IsInterestingWindow(HWND window) noexcept
{
auto filtered = get_fancyzones_filtered_window(window);
if (!filtered.zonable)
{
return false;
}
// Filter out user specified apps
CharUpperBuffW(filtered.process_path.data(), (DWORD)filtered.process_path.length());
if (m_settings)
{
const auto& excludedAppsArray = m_settings->GetSettings()->excludedAppsArray;
if (find_app_name_in_path(filtered.process_path, excludedAppsArray))
{
return false;
}
}
return true;
}
bool FancyZones::IsCursorTypeIndicatingSizeEvent()
{
CURSORINFO cursorInfo = { 0 };
cursorInfo.cbSize = sizeof(cursorInfo);
if (::GetCursorInfo(&cursorInfo))
{
if (::LoadCursor(NULL, IDC_SIZENS) == cursorInfo.hCursor)
{
return true;
}
if (::LoadCursor(NULL, IDC_SIZEWE) == cursorInfo.hCursor)
{
return true;
}
if (::LoadCursor(NULL, IDC_SIZENESW) == cursorInfo.hCursor)
{
return true;
}
if (::LoadCursor(NULL, IDC_SIZENWSE) == cursorInfo.hCursor)
{
return true;
}
}
return false;
}
void FancyZones::UpdateZoneWindows() noexcept
{
auto callback = [](HMONITOR monitor, HDC, RECT*, LPARAM data) -> BOOL {
@ -842,63 +804,18 @@ void FancyZones::MoveWindowsOnDisplayChange() noexcept
{
// i is off by 1 since 0 is special.
auto strongThis = reinterpret_cast<FancyZones*>(data);
strongThis->MoveWindowIntoZoneByIndex(window, nullptr, i - 1);
std::unique_lock writeLock(strongThis->m_lock);
strongThis->m_windowMoveHandler.MoveWindowIntoZoneByIndex(window, nullptr, i - 1, strongThis->m_zoneWindowMap);
}
return TRUE;
};
EnumWindows(callback, reinterpret_cast<LPARAM>(this));
}
void FancyZones::UpdateDragState(HWND window, require_write_lock) noexcept
{
const bool shift = GetAsyncKeyState(VK_SHIFT) & 0x8000;
const bool mouseL = GetAsyncKeyState(VK_LBUTTON) & 0x8000;
const bool mouseR = GetAsyncKeyState(VK_RBUTTON) & 0x8000;
const bool mouseM = GetAsyncKeyState(VK_MBUTTON) & 0x8000;
const bool mouseX1 = GetAsyncKeyState(VK_XBUTTON1) & 0x8000;
const bool mouseX2 = GetAsyncKeyState(VK_XBUTTON2) & 0x8000;
// Note, Middle, X1 and X2 can also be used in addition to R/L
bool mouse = mouseM | mouseX1 | mouseX2;
// If the user has swapped their Right and Left Buttons, use the "Right" equivalent
if (GetSystemMetrics(SM_SWAPBUTTON))
{
mouse |= mouseL;
}
else
{
mouse |= mouseR;
}
if (m_settings->GetSettings()->shiftDrag)
{
m_dragEnabled = (shift | mouse);
}
else
{
m_dragEnabled = !(shift | mouse);
}
static bool warning_shown = false;
if (!is_process_elevated() && IsProcessOfWindowElevated(window))
{
m_dragEnabled = false;
if (!warning_shown && !is_cant_drag_elevated_warning_disabled())
{
std::vector<notifications::action_t> actions = {
notifications::link_button{ GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED_LEARN_MORE), L"https://aka.ms/powertoysDetectedElevatedHelp" },
notifications::link_button{ GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED_DIALOG_DONT_SHOW_AGAIN), L"powertoys://cant_drag_elevated_disable/" }
};
notifications::show_toast_with_activations(GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED), {}, std::move(actions));
warning_shown = true;
}
}
}
void FancyZones::CycleActiveZoneSet(DWORD vkCode) noexcept
{
auto window = GetForegroundWindow();
if (IsInterestingWindow(window))
if (IsInterestingWindow(window, m_settings->GetSettings()->excludedAppsArray))
{
const HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
if (monitor)
@ -918,19 +835,20 @@ void FancyZones::CycleActiveZoneSet(DWORD vkCode) noexcept
bool FancyZones::OnSnapHotkey(DWORD vkCode) noexcept
{
auto window = GetForegroundWindow();
if (IsInterestingWindow(window))
if (IsInterestingWindow(window, m_settings->GetSettings()->excludedAppsArray))
{
const HMONITOR current = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
if (current)
{
std::vector<HMONITOR> monitorInfo = GetMonitorsSorted();
if (monitorInfo.size() > 1)
if (monitorInfo.size() > 1 && m_settings->GetSettings()->moveWindowAcrossMonitors)
{
// Multi monitor environment.
auto currMonitorInfo = std::find(std::begin(monitorInfo), std::end(monitorInfo), current);
do
{
if (MoveWindowIntoZoneByDirection(*currMonitorInfo, window, vkCode, false /* cycle through zones */))
std::unique_lock writeLock(m_lock);
if (m_windowMoveHandler.MoveWindowIntoZoneByDirection(*currMonitorInfo, window, vkCode, false /* cycle through zones */, m_zoneWindowMap))
{
return true;
}
@ -956,215 +874,23 @@ bool FancyZones::OnSnapHotkey(DWORD vkCode) noexcept
else
{
// Single monitor environment.
return MoveWindowIntoZoneByDirection(current, window, vkCode, true /* cycle through zones */);
std::unique_lock writeLock(m_lock);
return m_windowMoveHandler.MoveWindowIntoZoneByDirection(current, window, vkCode, true /* cycle through zones */, m_zoneWindowMap);
}
}
}
return false;
}
void FancyZones::MoveSizeStartInternal(HWND window, HMONITOR monitor, POINT const& ptScreen, require_write_lock writeLock) noexcept
{
if (IsCursorTypeIndicatingSizeEvent())
{
return;
}
m_inMoveSize = true;
auto iter = m_zoneWindowMap.find(monitor);
if (iter == end(m_zoneWindowMap))
{
return;
}
m_windowMoveSize = window;
// This updates m_dragEnabled depending on if the shift key is being held down.
UpdateDragState(window, writeLock);
if (m_dragEnabled)
{
m_zoneWindowMoveSize = iter->second;
m_zoneWindowMoveSize->MoveSizeEnter(window, m_dragEnabled);
if (m_settings->GetSettings()->showZonesOnAllMonitors)
{
for (auto [keyMonitor, zoneWindow] : m_zoneWindowMap)
{
// Skip calling ShowZoneWindow for iter->second (m_zoneWindowMoveSize) since it
// was already called in MoveSizeEnter
const bool moveSizeEnterCalled = zoneWindow == m_zoneWindowMoveSize;
if (zoneWindow && !moveSizeEnterCalled)
{
zoneWindow->ShowZoneWindow();
}
}
}
}
else if (m_zoneWindowMoveSize)
{
m_zoneWindowMoveSize->RestoreOrginalTransparency();
m_zoneWindowMoveSize = nullptr;
for (auto [keyMonitor, zoneWindow] : m_zoneWindowMap)
{
if (zoneWindow)
{
zoneWindow->HideZoneWindow();
}
}
}
}
void FancyZones::MoveSizeEndInternal(HWND window, POINT const& ptScreen, require_write_lock) noexcept
{
m_inMoveSize = false;
m_dragEnabled = false;
m_windowMoveSize = nullptr;
if (m_zoneWindowMoveSize)
{
auto zoneWindow = std::move(m_zoneWindowMoveSize);
zoneWindow->MoveSizeEnd(window, ptScreen);
}
else
{
::RemoveProp(window, ZONE_STAMP);
auto monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
if (monitor)
{
auto zoneWindow = m_zoneWindowMap.find(monitor);
if (zoneWindow != m_zoneWindowMap.end())
{
const auto zoneWindowPtr = zoneWindow->second;
const auto activeZoneSet = zoneWindowPtr->ActiveZoneSet();
if (activeZoneSet)
{
wil::unique_cotaskmem_string guidString;
if (SUCCEEDED_LOG(StringFromCLSID(activeZoneSet->Id(), &guidString)))
{
JSONHelpers::FancyZonesDataInstance().RemoveAppLastZone(window, zoneWindowPtr->UniqueId(), guidString.get());
}
}
}
}
}
// Also, hide all windows (regardless of settings)
for (auto [keyMonitor, zoneWindow] : m_zoneWindowMap)
{
if (zoneWindow)
{
zoneWindow->HideZoneWindow();
}
}
}
void FancyZones::MoveSizeUpdateInternal(HMONITOR monitor, POINT const& ptScreen, require_write_lock writeLock) noexcept
{
if (m_inMoveSize)
{
// This updates m_dragEnabled depending on if the shift key is being held down.
UpdateDragState(m_windowMoveSize, writeLock);
if (m_zoneWindowMoveSize)
{
// Update the ZoneWindow already handling move/size
if (!m_dragEnabled)
{
// Drag got disabled, tell it to cancel and hide all windows
m_zoneWindowMoveSize = nullptr;
for (auto [keyMonitor, zoneWindow] : m_zoneWindowMap)
{
if (zoneWindow)
{
zoneWindow->RestoreOrginalTransparency();
zoneWindow->HideZoneWindow();
}
}
}
else
{
auto iter = m_zoneWindowMap.find(monitor);
if (iter != m_zoneWindowMap.end())
{
if (iter->second != m_zoneWindowMoveSize)
{
// The drag has moved to a different monitor.
m_zoneWindowMoveSize->RestoreOrginalTransparency();
if (!m_settings->GetSettings()->showZonesOnAllMonitors)
{
m_zoneWindowMoveSize->HideZoneWindow();
}
m_zoneWindowMoveSize = iter->second;
m_zoneWindowMoveSize->MoveSizeEnter(m_windowMoveSize, m_zoneWindowMoveSize->IsDragEnabled());
}
for (auto [keyMonitor, zoneWindow] : m_zoneWindowMap)
{
zoneWindow->MoveSizeUpdate(ptScreen, m_dragEnabled);
}
}
}
}
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
MoveSizeStartInternal(m_windowMoveSize, monitor, ptScreen, writeLock);
MoveSizeUpdateInternal(monitor, ptScreen, writeLock);
}
}
}
void FancyZones::HandleVirtualDesktopUpdates(HANDLE fancyZonesDestroyedEvent) noexcept
{
HANDLE regKeyEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
HANDLE events[2] = { regKeyEvent, fancyZonesDestroyedEvent };
while (1)
{
if (RegNotifyChangeKeyValue(HKEY_CURRENT_USER, TRUE, REG_NOTIFY_CHANGE_LAST_SET, regKeyEvent, TRUE) != ERROR_SUCCESS)
{
return;
}
if (WaitForMultipleObjects(2, events, FALSE, INFINITE) != (WAIT_OBJECT_0 + 0))
{
// if fancyZonesDestroyedEvent is signalized or WaitForMultipleObjects failed, terminate thread execution
return;
}
DWORD bufferCapacity;
const WCHAR* key = L"VirtualDesktopIDs";
// request regkey binary buffer capacity only
if (RegQueryValueExW(m_virtualDesktopsRegKey, key, 0, nullptr, nullptr, &bufferCapacity) != ERROR_SUCCESS)
{
return;
}
std::unique_ptr<BYTE[]> buffer = std::make_unique<BYTE[]>(bufferCapacity);
// request regkey binary content
if (RegQueryValueExW(m_virtualDesktopsRegKey, key, 0, nullptr, buffer.get(), &bufferCapacity) != ERROR_SUCCESS)
{
return;
}
const size_t guidSize = sizeof(GUID);
std::unordered_set<GUID> temp;
temp.reserve(bufferCapacity / guidSize);
for (size_t i = 0; i < bufferCapacity; i += guidSize)
{
GUID* guid = reinterpret_cast<GUID*>(buffer.get() + i);
temp.insert(*guid);
}
RegisterVirtualDesktopUpdates(temp);
}
}
void FancyZones::RegisterVirtualDesktopUpdates(std::unordered_set<GUID>& currentVirtualDesktopIds) noexcept
void FancyZones::RegisterVirtualDesktopUpdates(std::vector<GUID>& ids) noexcept
{
std::unordered_set<GUID> activeVirtualDesktops(std::begin(ids), std::end(ids));
std::unique_lock writeLock(m_lock);
bool modified{ false };
for (auto it = begin(m_processedWorkAreas); it != end(m_processedWorkAreas);)
for (auto it = std::begin(m_processedWorkAreas); it != std::end(m_processedWorkAreas);)
{
auto iter = currentVirtualDesktopIds.find(it->first);
if (iter == currentVirtualDesktopIds.end())
auto iter = activeVirtualDesktops.find(it->first);
if (iter == activeVirtualDesktops.end())
{
// if we couldn't find the GUID in currentVirtualDesktopIds, we must remove it from both m_processedWorkAreas and deviceInfoMap
wil::unique_cotaskmem_string virtualDesktopId;
@ -1176,7 +902,7 @@ void FancyZones::RegisterVirtualDesktopUpdates(std::unordered_set<GUID>& current
}
else
{
currentVirtualDesktopIds.erase(it->first); // virtual desktop already in map, skip it
activeVirtualDesktops.erase(it->first); // virtual desktop already in map, skip it
++it;
}
}
@ -1185,7 +911,7 @@ void FancyZones::RegisterVirtualDesktopUpdates(std::unordered_set<GUID>& current
JSONHelpers::FancyZonesDataInstance().SaveFancyZonesData();
}
// register new virtual desktops, if any
for (const auto& id : currentVirtualDesktopIds)
for (const auto& id : activeVirtualDesktops)
{
m_processedWorkAreas[id] = std::vector<HMONITOR>();
}
@ -1252,17 +978,6 @@ std::vector<std::pair<HMONITOR, RECT>> FancyZones::GetRawMonitorData() noexcept
return monitorInfo;
}
bool FancyZones::MoveWindowIntoZoneByDirection(HMONITOR monitor, HWND window, DWORD vkCode, bool cycle)
{
auto iter = m_zoneWindowMap.find(monitor);
if (iter != std::end(m_zoneWindowMap))
{
const auto& zoneWindowPtr = iter->second;
return zoneWindowPtr->MoveWindowIntoZoneByDirection(window, vkCode, cycle);
}
return false;
}
winrt::com_ptr<IFancyZones> MakeFancyZones(HINSTANCE hinstance, const winrt::com_ptr<IFancyZonesSettings>& settings) noexcept
{
if (!settings)

View file

@ -4,6 +4,8 @@ interface IZoneWindow;
interface IFancyZonesSettings;
interface IZoneSet;
struct WinHookEvent;
interface __declspec(uuid("{50D3F0F5-736E-4186-BDF4-3D6BEE150C3A}")) IFancyZones : public IUnknown
{
/**
@ -21,47 +23,16 @@ interface __declspec(uuid("{50D3F0F5-736E-4186-BDF4-3D6BEE150C3A}")) IFancyZones
*/
interface __declspec(uuid("{2CB37E8F-87E6-4AEC-B4B2-E0FDC873343F}")) IFancyZonesCallback : public IUnknown
{
/**
* @returns Boolean indicating whether a move/size operation is currently active.
*/
IFACEMETHOD_(bool, InMoveSize)() = 0;
/**
* A window is being moved or resized. Track down window position and give zone layout
* hints if dragging functionality is enabled.
*
* @param window Handle of window being moved or resized.
* @param monitor Handle of monitor on which windows is moving / resizing.
* @param ptScreen Cursor coordinates.
*/
IFACEMETHOD_(void, MoveSizeStart)(HWND window, HMONITOR monitor, POINT const& ptScreen) = 0;
/**
* A window has changed location, shape, or size. Track down window position and give zone layout
* hints if dragging functionality is enabled.
*
* @param monitor Handle of monitor on which windows is moving / resizing.
* @param ptScreen Cursor coordinates.
*/
IFACEMETHOD_(void, MoveSizeUpdate)(HMONITOR monitor, POINT const& ptScreen) = 0;
/**
* The movement or resizing of a window has finished. Assign window to the zone if it
* is dropped within zone borders.
*
* @param window Handle of window being moved or resized.
* @param ptScreen Cursor coordinates where window is droped.
*/
IFACEMETHOD_(void, MoveSizeEnd)(HWND window, POINT const& ptScreen) = 0;
/**
* Inform FancyZones that user has switched between virtual desktops.
*/
IFACEMETHOD_(void, VirtualDesktopChanged)() = 0;
/**
* Inform FancyZones that new window is created. FancyZones will try to assign it to the
* zone insde active zone layout (if information about last zone, in which window was located
* before being closed, is available).
* Callback from WinEventHook to FancyZones
*
* @param window Handle of newly created window.
* @param data Handle of window being moved or resized.
*/
IFACEMETHOD_(void, WindowCreated)(HWND window) = 0;
IFACEMETHOD_(void, HandleWinHookEvent)(const WinHookEvent* data) = 0;
/**
* Process keyboard event.
*

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
@ -15,7 +16,7 @@
<ProjectGuid>{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>lib</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
<ProjectName>FancyZonesLib</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@ -61,7 +62,6 @@
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpplatest</LanguageStandard>
<AdditionalIncludeDirectories>..\;..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;..\..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@ -81,7 +81,6 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpplatest</LanguageStandard>
<AdditionalIncludeDirectories>..\;..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;..\..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@ -96,20 +95,22 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="FancyZones.h" />
<ClInclude Include="FancyZonesWinHookEventIDs.h" />
<ClInclude Include="JsonHelpers.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="RegistryHelpers.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="Settings.h" />
<ClInclude Include="trace.h" />
<ClInclude Include="util.h" />
<ClInclude Include="VirtualDesktopUtils.h" />
<ClInclude Include="WindowMoveHandler.h" />
<ClInclude Include="Zone.h" />
<ClInclude Include="ZoneSet.h" />
<ClInclude Include="ZoneWindow.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="FancyZones.cpp" />
<ClCompile Include="FancyZonesWinHookEventIDs.cpp" />
<ClCompile Include="JsonHelpers.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
@ -119,6 +120,7 @@
<ClCompile Include="trace.cpp" />
<ClCompile Include="util.cpp" />
<ClCompile Include="VirtualDesktopUtils.cpp" />
<ClCompile Include="WindowMoveHandler.cpp" />
<ClCompile Include="Zone.cpp" />
<ClCompile Include="ZoneSet.cpp" />
<ClCompile Include="ZoneWindow.cpp" />
@ -132,11 +134,14 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View file

@ -30,9 +30,6 @@
<ClInclude Include="FancyZones.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="RegistryHelpers.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Settings.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -51,6 +48,12 @@
<ClInclude Include="VirtualDesktopUtils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="WindowMoveHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FancyZonesWinHookEventIDs.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
@ -83,6 +86,12 @@
<ClCompile Include="VirtualDesktopUtils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="WindowMoveHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="FancyZonesWinHookEventIDs.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="fancyzones.rc">

View file

@ -0,0 +1,24 @@
#include "pch.h"
#include <mutex>
#include "FancyZonesWinHookEventIDs.h"
UINT WM_PRIV_MOVESIZESTART;
UINT WM_PRIV_MOVESIZEEND;
UINT WM_PRIV_LOCATIONCHANGE;
UINT WM_PRIV_NAMECHANGE;
UINT WM_PRIV_WINDOWCREATED;
std::once_flag init_flag;
void InitializeWinhookEventIds()
{
std::call_once(init_flag, [&] {
WM_PRIV_MOVESIZESTART = RegisterWindowMessage(L"{f48def23-df42-4c0f-a13d-3eb4a9e204d4}");
WM_PRIV_MOVESIZEEND = RegisterWindowMessage(L"{805d643c-804d-4728-b533-907d760ebaf0}");
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}");
});
}

View file

@ -0,0 +1,9 @@
#pragma once
extern UINT WM_PRIV_MOVESIZESTART;
extern UINT WM_PRIV_MOVESIZEEND;
extern UINT WM_PRIV_LOCATIONCHANGE;
extern UINT WM_PRIV_NAMECHANGE;
extern UINT WM_PRIV_WINDOWCREATED;
void InitializeWinhookEventIds();

View file

@ -1,6 +1,5 @@
#include "pch.h"
#include "JsonHelpers.h"
#include "RegistryHelpers.h"
#include "ZoneSet.h"
#include "trace.h"
@ -11,22 +10,10 @@
#include <fstream>
#include <regex>
#include <sstream>
#include <unordered_set>
namespace
{
// Needed for migration of applied zonesets from registry
struct ZoneSetPersistedDataOLD
{
static constexpr inline size_t MAX_ZONES = 40;
DWORD Version{ VERSION_PERSISTEDDATA };
WORD LayoutId{};
DWORD ZoneCount{};
JSONHelpers::ZoneSetLayoutType Layout{};
DWORD PaddingInner{};
DWORD PaddingOuter{};
RECT Zones[MAX_ZONES]{};
};
// From Settings.cs
constexpr int c_focusModelId = 0xFFFF;
constexpr int c_rowsModelId = 0xFFFE;
@ -37,6 +24,7 @@ namespace
const wchar_t* FANCY_ZONES_DATA_FILE = L"zones-settings.json";
const wchar_t* DEFAULT_GUID = L"{00000000-0000-0000-0000-000000000000}";
const wchar_t* REG_SETTINGS = L"Software\\SuperFancyZones";
std::wstring ExtractVirtualDesktopId(const std::wstring& deviceId)
{
@ -321,6 +309,65 @@ namespace JSONHelpers
}
}
void FancyZonesData::UpdatePrimaryDesktopData(const std::wstring& 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 and we will use default GUID in
// that case (00000000-0000-0000-0000-000000000000).
// This method will go through all our persisted data with default GUID and update it with
// valid one.
auto replaceDesktopId = [&desktopId](const std::wstring& deviceId) {
return deviceId.substr(0, deviceId.rfind('_') + 1) + desktopId;
};
std::scoped_lock lock{ dataLock };
for (auto& [path, data] : appZoneHistoryMap)
{
if (ExtractVirtualDesktopId(data.deviceId) == DEFAULT_GUID)
{
data.deviceId = replaceDesktopId(data.deviceId);
}
}
std::vector<std::wstring> toReplace{};
for (const auto& [id, data] : deviceInfoMap)
{
if (ExtractVirtualDesktopId(id) == DEFAULT_GUID)
{
toReplace.push_back(id);
}
}
for (const auto& id : toReplace)
{
auto mapEntry = deviceInfoMap.extract(id);
mapEntry.key() = replaceDesktopId(id);
deviceInfoMap.insert(std::move(mapEntry));
}
if (activeDeviceId == DEFAULT_GUID)
{
activeDeviceId = replaceDesktopId(activeDeviceId);
}
SaveFancyZonesData();
}
void FancyZonesData::RemoveDeletedDesktops(const std::vector<std::wstring>& activeDesktops)
{
std::unordered_set<std::wstring> active(std::begin(activeDesktops), std::end(activeDesktops));
std::scoped_lock lock{ dataLock };
for (auto it = std::begin(deviceInfoMap); it != std::end(deviceInfoMap);)
{
auto foundId = active.find(ExtractVirtualDesktopId(it->first));
if (foundId == std::end(active))
{
it = deviceInfoMap.erase(it);
}
else
{
++it;
}
}
SaveFancyZonesData();
}
int FancyZonesData::GetAppLastZoneIndex(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId) const
{
std::scoped_lock lock{ dataLock };
@ -640,7 +687,7 @@ namespace JSONHelpers
{
std::scoped_lock lock{ dataLock };
wchar_t key[256];
StringCchPrintf(key, ARRAYSIZE(key), L"%s\\%s", RegistryHelpers::REG_SETTINGS, L"Layouts");
StringCchPrintf(key, ARRAYSIZE(key), L"%s\\%s", REG_SETTINGS, L"Layouts");
HKEY hkey;
if (RegOpenKeyExW(HKEY_CURRENT_USER, key, 0, KEY_ALL_ACCESS, &hkey) == ERROR_SUCCESS)
{

View file

@ -233,6 +233,8 @@ namespace JSONHelpers
void AddDevice(const std::wstring& deviceId);
bool RemoveDevicesByVirtualDesktopId(const std::wstring& virtualDesktopId);
void CloneDeviceInfo(const std::wstring& source, const std::wstring& destination);
void UpdatePrimaryDesktopData(const std::wstring& desktopId);
void RemoveDeletedDesktops(const std::vector<std::wstring>& activeDesktops);
int GetAppLastZoneIndex(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId) const;
bool RemoveAppLastZone(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId);

View file

@ -1,38 +0,0 @@
#pragma once
#include <shlwapi.h>
namespace RegistryHelpers
{
static PCWSTR REG_SETTINGS = L"Software\\SuperFancyZones";
static PCWSTR APP_ZONE_HISTORY_SUBKEY = L"AppZoneHistory";
inline HRESULT GetCurrentVirtualDesktop(_Out_ GUID* id)
{
*id = GUID_NULL;
DWORD sessionId;
ProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
wchar_t sessionKeyPath[256]{};
RETURN_IF_FAILED(
StringCchPrintfW(
sessionKeyPath,
ARRAYSIZE(sessionKeyPath),
L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SessionInfo\\%d\\VirtualDesktops",
sessionId));
wil::unique_hkey key{};
GUID value{};
if (RegOpenKeyExW(HKEY_CURRENT_USER, sessionKeyPath, 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS)
{
DWORD size = sizeof(value);
if (RegQueryValueExW(key.get(), L"CurrentVirtualDesktop", 0, nullptr, reinterpret_cast<BYTE*>(&value), &size) == ERROR_SUCCESS)
{
*id = value;
return S_OK;
}
}
return E_FAIL;
}
}

View file

@ -36,9 +36,10 @@ private:
PCWSTR name;
bool* value;
int resourceId;
} m_configBools[9 /* 10 */] = { // "Turning FLASHING_ZONE option off"
} m_configBools[10 /* 11 */] = { // "Turning FLASHING_ZONE option off"
{ L"fancyzones_shiftDrag", &m_settings.shiftDrag, IDS_SETTING_DESCRIPTION_SHIFTDRAG },
{ L"fancyzones_overrideSnapHotkeys", &m_settings.overrideSnapHotkeys, IDS_SETTING_DESCRIPTION_OVERRIDE_SNAP_HOTKEYS },
{ L"fancyzones_moveWindowAcrossMonitors", &m_settings.moveWindowAcrossMonitors, IDS_SETTING_DESCRIPTION_MOVE_WINDOW_ACROSS_MONITORS },
// "Turning FLASHING_ZONE option off"
//{ L"fancyzones_zoneSetChange_flashZones", &m_settings.zoneSetChange_flashZones, IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES },
{ L"fancyzones_displayChange_moveWindows", &m_settings.displayChange_moveWindows, IDS_SETTING_DESCRIPTION_DISPLAYCHANGE_MOVEWINDOWS },

View file

@ -12,6 +12,7 @@ struct Settings
bool zoneSetChange_flashZones = false;
bool zoneSetChange_moveWindows = false;
bool overrideSnapHotkeys = false;
bool moveWindowAcrossMonitors = false;
bool appLastZone_moveWindows = false;
bool use_cursorpos_editor_startupscreen = true;
bool showZonesOnAllMonitors = false;

View file

@ -7,6 +7,10 @@ namespace VirtualDesktopUtils
const CLSID CLSID_ImmersiveShell = { 0xC2F03A33, 0x21F5, 0x47FA, 0xB4, 0xBB, 0x15, 0x63, 0x62, 0xA2, 0xF2, 0x39 };
const wchar_t GUID_EmptyGUID[] = L"{00000000-0000-0000-0000-000000000000}";
const wchar_t RegCurrentVirtualDesktop[] = L"CurrentVirtualDesktop";
const wchar_t RegVirtualDesktopIds[] = L"VirtualDesktopIDs";
const wchar_t RegKeyVirtualDesktops[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VirtualDesktops";
IServiceProvider* GetServiceProvider()
{
IServiceProvider* provider{ nullptr };
@ -46,4 +50,142 @@ namespace VirtualDesktopUtils
}
return SUCCEEDED(CLSIDFromString(virtualDesktopId.c_str(), desktopId));
}
bool GetDesktopIdFromCurrentSession(GUID* desktopId)
{
DWORD sessionId;
ProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
wchar_t sessionKeyPath[256]{};
RETURN_IF_FAILED(
StringCchPrintfW(
sessionKeyPath,
ARRAYSIZE(sessionKeyPath),
L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SessionInfo\\%d\\VirtualDesktops",
sessionId));
wil::unique_hkey key{};
GUID value{};
if (RegOpenKeyExW(HKEY_CURRENT_USER, sessionKeyPath, 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS)
{
DWORD size = sizeof(GUID);
if (RegQueryValueExW(key.get(), RegCurrentVirtualDesktop, 0, nullptr, reinterpret_cast<BYTE*>(&value), &size) == ERROR_SUCCESS)
{
*desktopId = value;
return true;
}
}
return false;
}
bool GetCurrentVirtualDesktopId(GUID* desktopId)
{
if (!GetDesktopIdFromCurrentSession(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 (only primary desktop) in this session value in registry will be empty.
// If this value is empty take first element from array of virtual desktops (not kept per session).
std::vector<GUID> ids{};
if (!GetVirtualDesktopIds(ids) || ids.empty())
{
return false;
}
*desktopId = ids[0];
}
return true;
}
bool GetVirtualDesktopIds(HKEY hKey, std::vector<GUID>& ids)
{
if (!hKey)
{
return false;
}
DWORD bufferCapacity;
// request regkey binary buffer capacity only
if (RegQueryValueExW(hKey, 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, 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, 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);
}
}
}

View file

@ -6,4 +6,9 @@ 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);
}

View file

@ -0,0 +1,362 @@
#include "pch.h"
#include "WindowMoveHandler.h"
#include <common/notifications.h>
#include <common/notifications/fancyzones_notifications.h>
#include <common/window_helpers.h>
#include "lib/Settings.h"
#include "lib/ZoneWindow.h"
#include "lib/util.h"
extern "C" IMAGE_DOS_HEADER __ImageBase;
namespace WindowMoveHandlerUtils
{
bool IsCursorTypeIndicatingSizeEvent()
{
CURSORINFO cursorInfo = { 0 };
cursorInfo.cbSize = sizeof(cursorInfo);
if (::GetCursorInfo(&cursorInfo))
{
if (::LoadCursor(NULL, IDC_SIZENS) == cursorInfo.hCursor)
{
return true;
}
if (::LoadCursor(NULL, IDC_SIZEWE) == cursorInfo.hCursor)
{
return true;
}
if (::LoadCursor(NULL, IDC_SIZENESW) == cursorInfo.hCursor)
{
return true;
}
if (::LoadCursor(NULL, IDC_SIZENWSE) == cursorInfo.hCursor)
{
return true;
}
}
return false;
}
}
class WindowMoveHandlerPrivate
{
public:
WindowMoveHandlerPrivate(const winrt::com_ptr<IFancyZonesSettings>& settings) :
m_settings(settings)
{};
bool IsDragEnabled() const noexcept
{
return m_dragEnabled;
}
bool InMoveSize() const noexcept
{
return m_inMoveSize;
}
void MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
void MoveSizeEnd(HWND window, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
void MoveWindowIntoZoneByIndexSet(HWND window, HMONITOR monitor, const std::vector<int>& indexSet, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
bool MoveWindowIntoZoneByDirection(HMONITOR monitor, HWND window, DWORD vkCode, bool cycle, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap);
private:
void UpdateDragState(HWND window) noexcept;
private:
winrt::com_ptr<IFancyZonesSettings> m_settings{};
HWND m_windowMoveSize{}; // The window that is being moved/sized
bool m_inMoveSize{}; // Whether or not a move/size operation is currently active
winrt::com_ptr<IZoneWindow> m_zoneWindowMoveSize; // "Active" ZoneWindow, 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
};
WindowMoveHandler::WindowMoveHandler(const winrt::com_ptr<IFancyZonesSettings>& settings) :
pimpl(new WindowMoveHandlerPrivate(settings))
{
}
WindowMoveHandler::~WindowMoveHandler()
{
delete pimpl;
}
bool WindowMoveHandler::InMoveSize() const noexcept
{
return pimpl->InMoveSize();
}
bool WindowMoveHandler::IsDragEnabled() const noexcept
{
return pimpl->IsDragEnabled();
}
void WindowMoveHandler::MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
{
pimpl->MoveSizeStart(window, monitor, ptScreen, zoneWindowMap);
}
void WindowMoveHandler::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
{
pimpl->MoveSizeUpdate(monitor, ptScreen, zoneWindowMap);
}
void WindowMoveHandler::MoveSizeEnd(HWND window, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
{
pimpl->MoveSizeEnd(window, ptScreen, zoneWindowMap);
}
void WindowMoveHandler::MoveWindowIntoZoneByIndex(HWND window, HMONITOR monitor, int index, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
{
pimpl->MoveWindowIntoZoneByIndexSet(window, monitor, { index }, zoneWindowMap);
}
bool WindowMoveHandler::MoveWindowIntoZoneByDirection(HMONITOR monitor, HWND window, DWORD vkCode, bool cycle, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap)
{
return pimpl->MoveWindowIntoZoneByDirection(monitor, window, vkCode, cycle, zoneWindowMap);
}
void WindowMoveHandlerPrivate::MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
{
if (!IsInterestingWindow(window, m_settings->GetSettings()->excludedAppsArray) || WindowMoveHandlerUtils::IsCursorTypeIndicatingSizeEvent())
{
return;
}
m_inMoveSize = true;
auto iter = zoneWindowMap.find(monitor);
if (iter == end(zoneWindowMap))
{
return;
}
m_windowMoveSize = window;
// This updates m_dragEnabled depending on if the shift key is being held down.
UpdateDragState(window);
if (m_dragEnabled)
{
m_zoneWindowMoveSize = iter->second;
m_zoneWindowMoveSize->MoveSizeEnter(window, m_dragEnabled);
if (m_settings->GetSettings()->showZonesOnAllMonitors)
{
for (auto [keyMonitor, zoneWindow] : zoneWindowMap)
{
// Skip calling ShowZoneWindow for iter->second (m_zoneWindowMoveSize) since it
// was already called in MoveSizeEnter
const bool moveSizeEnterCalled = zoneWindow == m_zoneWindowMoveSize;
if (zoneWindow && !moveSizeEnterCalled)
{
zoneWindow->ShowZoneWindow();
}
}
}
}
else if (m_zoneWindowMoveSize)
{
m_zoneWindowMoveSize->RestoreOrginalTransparency();
m_zoneWindowMoveSize = nullptr;
for (auto [keyMonitor, zoneWindow] : zoneWindowMap)
{
if (zoneWindow)
{
zoneWindow->HideZoneWindow();
}
}
}
}
void WindowMoveHandlerPrivate::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
{
if (!m_inMoveSize)
{
return;
}
// This updates m_dragEnabled depending on if the shift key is being held down.
UpdateDragState(m_windowMoveSize);
if (m_zoneWindowMoveSize)
{
// Update the ZoneWindow already handling move/size
if (!m_dragEnabled)
{
// Drag got disabled, tell it to cancel and hide all windows
m_zoneWindowMoveSize = nullptr;
for (auto [keyMonitor, zoneWindow] : zoneWindowMap)
{
if (zoneWindow)
{
zoneWindow->RestoreOrginalTransparency();
zoneWindow->HideZoneWindow();
}
}
}
else
{
auto iter = zoneWindowMap.find(monitor);
if (iter != zoneWindowMap.end())
{
if (iter->second != m_zoneWindowMoveSize)
{
// The drag has moved to a different monitor.
m_zoneWindowMoveSize->RestoreOrginalTransparency();
if (!m_settings->GetSettings()->showZonesOnAllMonitors)
{
m_zoneWindowMoveSize->HideZoneWindow();
}
m_zoneWindowMoveSize = iter->second;
m_zoneWindowMoveSize->MoveSizeEnter(m_windowMoveSize, m_zoneWindowMoveSize->IsDragEnabled());
}
for (auto [keyMonitor, zoneWindow] : zoneWindowMap)
{
zoneWindow->MoveSizeUpdate(ptScreen, m_dragEnabled);
}
}
}
}
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
MoveSizeStart(m_windowMoveSize, monitor, ptScreen, zoneWindowMap);
MoveSizeUpdate(monitor, ptScreen, zoneWindowMap);
}
}
void WindowMoveHandlerPrivate::MoveSizeEnd(HWND window, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
{
if (window != m_windowMoveSize && !IsInterestingWindow(window, m_settings->GetSettings()->excludedAppsArray))
{
return;
}
m_inMoveSize = false;
m_dragEnabled = false;
m_windowMoveSize = nullptr;
if (m_zoneWindowMoveSize)
{
auto zoneWindow = std::move(m_zoneWindowMoveSize);
zoneWindow->MoveSizeEnd(window, ptScreen);
}
else
{
::RemoveProp(window, ZONE_STAMP);
auto monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
if (monitor)
{
auto zoneWindow = zoneWindowMap.find(monitor);
if (zoneWindow != zoneWindowMap.end())
{
const auto zoneWindowPtr = zoneWindow->second;
const auto activeZoneSet = zoneWindowPtr->ActiveZoneSet();
if (activeZoneSet)
{
wil::unique_cotaskmem_string guidString;
if (SUCCEEDED_LOG(StringFromCLSID(activeZoneSet->Id(), &guidString)))
{
JSONHelpers::FancyZonesDataInstance().RemoveAppLastZone(window, zoneWindowPtr->UniqueId(), guidString.get());
}
}
}
}
}
// Also, hide all windows (regardless of settings)
for (auto [keyMonitor, zoneWindow] : zoneWindowMap)
{
if (zoneWindow)
{
zoneWindow->HideZoneWindow();
}
}
}
void WindowMoveHandlerPrivate::MoveWindowIntoZoneByIndexSet(HWND window, HMONITOR monitor, const std::vector<int>& indexSet, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
{
if (window != m_windowMoveSize)
{
const HMONITOR hm = (monitor != nullptr) ? monitor : MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
if (hm)
{
auto zoneWindow = zoneWindowMap.find(hm);
if (zoneWindow != zoneWindowMap.end())
{
const auto& zoneWindowPtr = zoneWindow->second;
zoneWindowPtr->MoveWindowIntoZoneByIndexSet(window, indexSet);
}
}
}
}
bool WindowMoveHandlerPrivate::MoveWindowIntoZoneByDirection(HMONITOR monitor, HWND window, DWORD vkCode, bool cycle, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap)
{
auto iter = zoneWindowMap.find(monitor);
if (iter != std::end(zoneWindowMap))
{
const auto& zoneWindowPtr = iter->second;
return zoneWindowPtr->MoveWindowIntoZoneByDirection(window, vkCode, cycle);
}
return false;
}
void WindowMoveHandlerPrivate::UpdateDragState(HWND window) noexcept
{
const bool shift = GetAsyncKeyState(VK_SHIFT) & 0x8000;
const bool mouseL = GetAsyncKeyState(VK_LBUTTON) & 0x8000;
const bool mouseR = GetAsyncKeyState(VK_RBUTTON) & 0x8000;
const bool mouseM = GetAsyncKeyState(VK_MBUTTON) & 0x8000;
const bool mouseX1 = GetAsyncKeyState(VK_XBUTTON1) & 0x8000;
const bool mouseX2 = GetAsyncKeyState(VK_XBUTTON2) & 0x8000;
// Note, Middle, X1 and X2 can also be used in addition to R/L
bool mouse = mouseM | mouseX1 | mouseX2;
// If the user has swapped their Right and Left Buttons, use the "Right" equivalent
if (GetSystemMetrics(SM_SWAPBUTTON))
{
mouse |= mouseL;
}
else
{
mouse |= mouseR;
}
if (m_settings->GetSettings()->shiftDrag)
{
m_dragEnabled = (shift | mouse);
}
else
{
m_dragEnabled = !(shift | mouse);
}
static bool warning_shown = false;
if (!is_process_elevated() && IsProcessOfWindowElevated(window))
{
m_dragEnabled = false;
if (!warning_shown && !is_cant_drag_elevated_warning_disabled())
{
std::vector<notifications::action_t> actions = {
notifications::link_button{ GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED_LEARN_MORE), L"https://aka.ms/powertoysDetectedElevatedHelp" },
notifications::link_button{ GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED_DIALOG_DONT_SHOW_AGAIN), L"powertoys://cant_drag_elevated_disable/" }
};
notifications::show_toast_with_activations(GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED), {}, std::move(actions));
warning_shown = true;
}
}
}

View file

@ -0,0 +1,24 @@
#pragma once
interface IFancyZonesSettings;
interface IZoneWindow;
class WindowMoveHandler
{
public:
WindowMoveHandler(const winrt::com_ptr<IFancyZonesSettings>& settings);
~WindowMoveHandler();
bool InMoveSize() const noexcept;
bool IsDragEnabled() const noexcept;
void MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
void MoveSizeEnd(HWND window, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
void MoveWindowIntoZoneByIndex(HWND window, HMONITOR monitor, int index, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
bool MoveWindowIntoZoneByDirection(HMONITOR monitor, HWND window, DWORD vkCode, bool cycle, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap);
private:
class WindowMoveHandlerPrivate* pimpl;
};

View file

@ -2,7 +2,6 @@
#include "util.h"
#include "lib/ZoneSet.h"
#include "lib/RegistryHelpers.h"
#include <common/dpi_aware.h>

View file

@ -5,7 +5,6 @@
#include "ZoneWindow.h"
#include "trace.h"
#include "util.h"
#include "RegistryHelpers.h"
#include <ShellScalingApi.h>
#include <mutex>
@ -213,7 +212,7 @@ public:
IFACEMETHODIMP_(void)
RestoreOrginalTransparency() noexcept;
IFACEMETHODIMP_(bool)
IsDragEnabled() noexcept;
IsDragEnabled() noexcept { return m_dragEnabled; }
IFACEMETHODIMP_(void)
MoveWindowIntoZoneByIndex(HWND window, int index) noexcept;
IFACEMETHODIMP_(void)
@ -223,13 +222,13 @@ public:
IFACEMETHODIMP_(void)
CycleActiveZoneSet(DWORD vkCode) noexcept;
IFACEMETHODIMP_(std::wstring)
UniqueId() noexcept;
UniqueId() noexcept { return { m_uniqueId }; }
IFACEMETHODIMP_(std::wstring)
WorkAreaKey() noexcept;
WorkAreaKey() noexcept { return { m_workArea }; }
IFACEMETHODIMP_(void)
SaveWindowProcessToZoneIndex(HWND window) noexcept;
IFACEMETHODIMP_(IZoneSet*)
ActiveZoneSet() noexcept;
ActiveZoneSet() noexcept { return m_activeZoneSet.get(); }
IFACEMETHODIMP_(void)
ShowZoneWindow() noexcept;
IFACEMETHODIMP_(void)
@ -267,15 +266,13 @@ private:
static const UINT m_showAnimationDuration = 200; // ms
static const UINT m_flashDuration = 700; // ms
HWND m_draggedWindow = nullptr;
long m_draggedWindowExstyle = 0;
COLORREF m_draggedWindowCrKey = RGB(0, 0, 0);
DWORD m_draggedWindowDwFlags = 0;
BYTE m_draggedWindowInitialAlpha = 0;
HWND draggedWindow = nullptr;
long draggedWindowExstyle = 0;
COLORREF draggedWindowCrKey = RGB(0, 0, 0);
DWORD draggedWindowDwFlags = 0;
BYTE draggedWindowInitialAlpha = 0;
ULONG_PTR m_gdiplusToken;
mutable std::shared_mutex m_mutex;
ULONG_PTR gdiplusToken;
};
ZoneWindow::ZoneWindow(HINSTANCE hinstance)
@ -289,14 +286,12 @@ ZoneWindow::ZoneWindow(HINSTANCE hinstance)
RegisterClassExW(&wcex);
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
}
ZoneWindow::~ZoneWindow()
{
RestoreOrginalTransparency();
Gdiplus::GdiplusShutdown(m_gdiplusToken);
Gdiplus::GdiplusShutdown(gdiplusToken);
}
bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, bool flashZones, bool newWorkArea)
@ -349,26 +344,13 @@ bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monit
IFACEMETHODIMP ZoneWindow::MoveSizeEnter(HWND window, bool dragEnabled) noexcept
{
std::shared_lock lock(m_mutex);
auto windowMoveSize = m_windowMoveSize;
auto hostTransparentActive = m_host->isMakeDraggedWindowTransparentActive();
lock.unlock();
if (windowMoveSize)
if (m_windowMoveSize)
{
return E_INVALIDARG;
}
if (hostTransparentActive)
if (m_host->isMakeDraggedWindowTransparentActive())
{
decltype(m_draggedWindowExstyle) draggedWindowExstyle;
decltype(m_draggedWindow) draggedWindow;
decltype(m_draggedWindowCrKey) draggedWindowCrKey;
decltype(m_draggedWindowInitialAlpha) draggedWindowInitialAlpha;
decltype(m_draggedWindowDwFlags) draggedWindowDwFlags;
RestoreOrginalTransparency();
draggedWindowExstyle = GetWindowLong(window, GWL_EXSTYLE);
draggedWindow = window;
@ -379,45 +361,27 @@ IFACEMETHODIMP ZoneWindow::MoveSizeEnter(HWND window, bool dragEnabled) noexcept
GetLayeredWindowAttributes(window, &draggedWindowCrKey, &draggedWindowInitialAlpha, &draggedWindowDwFlags);
SetLayeredWindowAttributes(window, 0, (255 * 50) / 100, LWA_ALPHA);
std::unique_lock writeLock(m_mutex);
m_draggedWindowExstyle = draggedWindowExstyle;
m_draggedWindow = draggedWindow;
m_draggedWindowCrKey = draggedWindowCrKey;
m_draggedWindowInitialAlpha = draggedWindowInitialAlpha;
m_draggedWindowDwFlags = draggedWindowDwFlags;
}
{
std::unique_lock writeLock(m_mutex);
m_dragEnabled = dragEnabled;
m_windowMoveSize = window;
m_drawHints = true;
m_highlightZone = {};
}
m_dragEnabled = dragEnabled;
m_windowMoveSize = window;
m_drawHints = true;
m_highlightZone = {};
ShowZoneWindow();
return S_OK;
}
IFACEMETHODIMP ZoneWindow::MoveSizeUpdate(POINT const& ptScreen, bool dragEnabled) noexcept
{
std::shared_lock lock(m_mutex);
auto window = m_window.get();
lock.unlock();
bool redraw = false;
POINT ptClient = ptScreen;
MapWindowPoints(nullptr, window, &ptClient, 1);
MapWindowPoints(nullptr, m_window.get(), &ptClient, 1);
std::unique_lock writeLock(m_mutex);
m_dragEnabled = dragEnabled;
if (dragEnabled)
{
writeLock.unlock();
auto highlightZone = ZonesFromPoint(ptClient);
writeLock.lock();
redraw = (highlightZone != m_highlightZone);
m_highlightZone = std::move(highlightZone);
}
@ -427,11 +391,9 @@ IFACEMETHODIMP ZoneWindow::MoveSizeUpdate(POINT const& ptScreen, bool dragEnable
redraw = true;
}
writeLock.unlock();
if (redraw)
{
InvalidateRect(window, nullptr, true);
InvalidateRect(m_window.get(), nullptr, true);
}
return S_OK;
}
@ -440,74 +402,30 @@ IFACEMETHODIMP ZoneWindow::MoveSizeEnd(HWND window, POINT const& ptScreen) noexc
{
RestoreOrginalTransparency();
std::shared_lock lock(m_mutex);
auto windowMoveSize = m_windowMoveSize;
auto thisWindow = m_window.get();
auto activeZoneSet = m_activeZoneSet;
lock.unlock();
if (windowMoveSize != window)
if (m_windowMoveSize != window)
{
return E_INVALIDARG;
}
if (activeZoneSet)
if (m_activeZoneSet)
{
POINT ptClient = ptScreen;
MapWindowPoints(nullptr, thisWindow, &ptClient, 1);
activeZoneSet->MoveWindowIntoZoneByPoint(window, thisWindow, ptClient);
MapWindowPoints(nullptr, m_window.get(), &ptClient, 1);
m_activeZoneSet->MoveWindowIntoZoneByPoint(window, m_window.get(), ptClient);
SaveWindowProcessToZoneIndex(window);
}
Trace::ZoneWindow::MoveSizeEnd(activeZoneSet);
Trace::ZoneWindow::MoveSizeEnd(m_activeZoneSet);
HideZoneWindow();
std::unique_lock writeLock(m_mutex);
m_windowMoveSize = nullptr;
return S_OK;
}
IFACEMETHODIMP_(bool)
ZoneWindow::IsDragEnabled() noexcept
{
std::shared_lock lock(m_mutex);
return m_dragEnabled;
}
IFACEMETHODIMP_(std::wstring)
ZoneWindow::UniqueId() noexcept
{
std::shared_lock lock(m_mutex);
return m_uniqueId;
}
IFACEMETHODIMP_(std::wstring)
ZoneWindow::WorkAreaKey() noexcept
{
std::shared_lock lock(m_mutex);
return m_workArea;
}
IFACEMETHODIMP_(IZoneSet*)
ZoneWindow::ActiveZoneSet() noexcept
{
std::shared_lock lock(m_mutex);
return m_activeZoneSet.get();
}
IFACEMETHODIMP_(void)
ZoneWindow::RestoreOrginalTransparency() noexcept
{
std::shared_lock lock(m_mutex);
auto hostTransparentActive = m_host->isMakeDraggedWindowTransparentActive();
auto draggedWindow = m_draggedWindow;
auto draggedWindowCrKey = m_draggedWindowCrKey;
auto draggedWindowInitialAlpha = m_draggedWindowInitialAlpha;
auto draggedWindowDwFlags = m_draggedWindowDwFlags;
auto draggedWindowExstyle = m_draggedWindowExstyle;
lock.unlock();
if (hostTransparentActive && draggedWindow != nullptr)
if (m_host->isMakeDraggedWindowTransparentActive() && draggedWindow != nullptr)
{
SetLayeredWindowAttributes(draggedWindow, draggedWindowCrKey, draggedWindowInitialAlpha, draggedWindowDwFlags);
SetWindowLong(draggedWindow, GWL_EXSTYLE, draggedWindowExstyle);
@ -524,28 +442,18 @@ ZoneWindow::MoveWindowIntoZoneByIndex(HWND window, int index) noexcept
IFACEMETHODIMP_(void)
ZoneWindow::MoveWindowIntoZoneByIndexSet(HWND window, const std::vector<int>& indexSet) noexcept
{
std::shared_lock lock(m_mutex);
auto thisWindow = m_window.get();
auto activeZoneSet = m_activeZoneSet;
lock.unlock();
if (activeZoneSet)
if (m_activeZoneSet)
{
activeZoneSet->MoveWindowIntoZoneByIndexSet(window, thisWindow, indexSet, false);
m_activeZoneSet->MoveWindowIntoZoneByIndexSet(window, m_window.get(), indexSet, false);
}
}
IFACEMETHODIMP_(bool)
ZoneWindow::MoveWindowIntoZoneByDirection(HWND window, DWORD vkCode, bool cycle) noexcept
{
std::shared_lock lock(m_mutex);
auto thisWindow = m_window.get();
auto activeZoneSet = m_activeZoneSet;
lock.unlock();
if (activeZoneSet)
if (m_activeZoneSet)
{
if (activeZoneSet->MoveWindowIntoZoneByDirection(window, thisWindow, vkCode, cycle))
if (m_activeZoneSet->MoveWindowIntoZoneByDirection(window, m_window.get(), vkCode, cycle))
{
SaveWindowProcessToZoneIndex(window);
return true;
@ -559,14 +467,9 @@ ZoneWindow::CycleActiveZoneSet(DWORD wparam) noexcept
{
CycleActiveZoneSetInternal(wparam, Trace::ZoneWindow::InputMode::Keyboard);
std::shared_lock lock(m_mutex);
auto windowMoveSize = m_windowMoveSize;
auto window = m_window.get();
lock.unlock();
if (windowMoveSize)
if (m_windowMoveSize)
{
InvalidateRect(window, nullptr, true);
InvalidateRect(m_window.get(), nullptr, true);
}
else
{
@ -577,19 +480,15 @@ ZoneWindow::CycleActiveZoneSet(DWORD wparam) noexcept
IFACEMETHODIMP_(void)
ZoneWindow::SaveWindowProcessToZoneIndex(HWND window) noexcept
{
std::shared_lock lock(m_mutex);
auto activeZoneSet = m_activeZoneSet;
lock.unlock();
if (activeZoneSet)
if (m_activeZoneSet)
{
DWORD zoneIndex = static_cast<DWORD>(activeZoneSet->GetZoneIndexFromWindow(window));
DWORD zoneIndex = static_cast<DWORD>(m_activeZoneSet->GetZoneIndexFromWindow(window));
if (zoneIndex != -1)
{
OLECHAR* guidString;
if (StringFromCLSID(activeZoneSet->Id(), &guidString) == S_OK)
if (StringFromCLSID(m_activeZoneSet->Id(), &guidString) == S_OK)
{
JSONHelpers::FancyZonesDataInstance().SetAppLastZone(window, UniqueId(), guidString, zoneIndex);
JSONHelpers::FancyZonesDataInstance().SetAppLastZone(window, m_uniqueId, guidString, zoneIndex);
}
CoTaskMemFree(guidString);
@ -600,43 +499,36 @@ ZoneWindow::SaveWindowProcessToZoneIndex(HWND window) noexcept
IFACEMETHODIMP_(void)
ZoneWindow::ShowZoneWindow() noexcept
{
std::shared_lock lock(m_mutex);
auto window = m_window.get();
HWND windowInsertAfter = m_windowMoveSize;
lock.unlock();
if (window)
if (!window)
{
{
std::unique_lock writeLock(m_mutex);
m_flashMode = false;
}
return;
}
UINT flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE;
m_flashMode = false;
if (windowInsertAfter == nullptr)
{
windowInsertAfter = HWND_TOPMOST;
}
UINT flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE;
SetWindowPos(window, windowInsertAfter, 0, 0, 0, 0, flags);
HWND windowInsertAfter = m_windowMoveSize;
if (windowInsertAfter == nullptr)
{
windowInsertAfter = HWND_TOPMOST;
}
SetWindowPos(window, windowInsertAfter, 0, 0, 0, 0, flags);
std::thread{ [=]() {
AnimateWindow(window, m_showAnimationDuration, AW_BLEND);
InvalidateRect(window, nullptr, true);
}
} }.detach();
}
IFACEMETHODIMP_(void)
ZoneWindow::HideZoneWindow() noexcept
{
std::shared_lock lock(m_mutex);
auto window = m_window.get();
lock.unlock();
if (window)
if (m_window)
{
ShowWindow(window, SW_HIDE);
std::unique_lock writeLock(m_mutex);
ShowWindow(m_window.get(), SW_HIDE);
m_keyLast = 0;
m_windowMoveSize = nullptr;
m_drawHints = false;
@ -648,34 +540,27 @@ ZoneWindow::HideZoneWindow() noexcept
void ZoneWindow::LoadSettings() noexcept
{
JSONHelpers::FancyZonesDataInstance().AddDevice(UniqueId());
JSONHelpers::FancyZonesDataInstance().AddDevice(m_uniqueId);
}
void ZoneWindow::InitializeZoneSets(bool newWorkArea) noexcept
{
std::shared_lock lock(m_mutex);
auto parent = m_host->GetParentZoneWindow(m_monitor);
lock.unlock();
if (newWorkArea && parent)
{
// Update device info with device info from parent virtual desktop (if empty).
JSONHelpers::FancyZonesDataInstance().CloneDeviceInfo(parent->UniqueId(), UniqueId());
JSONHelpers::FancyZonesDataInstance().CloneDeviceInfo(parent->UniqueId(), m_uniqueId);
}
CalculateZoneSet();
}
void ZoneWindow::CalculateZoneSet() noexcept
{
std::unique_lock lock(m_mutex);
auto monitor = m_monitor;
lock.unlock();
const auto& fancyZonesData = JSONHelpers::FancyZonesDataInstance();
const auto deviceInfoData = fancyZonesData.FindDeviceInfo(UniqueId());
const auto deviceInfoData = fancyZonesData.FindDeviceInfo(m_uniqueId);
const auto& activeDeviceId = fancyZonesData.GetActiveDeviceId();
if (!activeDeviceId.empty() && activeDeviceId != UniqueId())
if (!activeDeviceId.empty() && activeDeviceId != m_uniqueId)
{
return;
}
@ -698,11 +583,11 @@ void ZoneWindow::CalculateZoneSet() noexcept
auto zoneSet = MakeZoneSet(ZoneSetConfig(
zoneSetId,
activeZoneSet.type,
monitor,
WorkAreaKey().c_str()));
m_monitor,
m_workArea));
MONITORINFO monitorInfo{};
monitorInfo.cbSize = sizeof(monitorInfo);
if (GetMonitorInfoW(monitor, &monitorInfo))
if (GetMonitorInfoW(m_monitor, &monitorInfo))
{
bool showSpacing = deviceInfoData->showSpacing;
int spacing = showSpacing ? deviceInfoData->spacing : 0;
@ -715,37 +600,30 @@ void ZoneWindow::CalculateZoneSet() noexcept
void ZoneWindow::UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept
{
{
std::unique_lock writeLock(m_mutex);
m_activeZoneSet.copy_from(zoneSet);
}
m_activeZoneSet.copy_from(zoneSet);
if (zoneSet)
if (m_activeZoneSet)
{
wil::unique_cotaskmem_string zoneSetId;
if (SUCCEEDED_LOG(StringFromCLSID(zoneSet->Id(), &zoneSetId)))
if (SUCCEEDED_LOG(StringFromCLSID(m_activeZoneSet->Id(), &zoneSetId)))
{
JSONHelpers::ZoneSetData data{
.uuid = zoneSetId.get(),
.type = zoneSet->LayoutType()
.type = m_activeZoneSet->LayoutType()
};
JSONHelpers::FancyZonesDataInstance().SetActiveZoneSet(UniqueId(), data);
JSONHelpers::FancyZonesDataInstance().SetActiveZoneSet(m_uniqueId, data);
}
}
}
LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept
{
std::shared_lock lock(m_mutex);
auto window = m_window.get();
lock.unlock();
switch (message)
{
case WM_NCDESTROY:
{
::DefWindowProc(window, message, wparam, lparam);
SetWindowLongPtr(window, GWLP_USERDATA, 0);
::DefWindowProc(m_window.get(), message, wparam, lparam);
SetWindowLongPtr(m_window.get(), GWLP_USERDATA, 0);
}
break;
@ -759,14 +637,14 @@ LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept
wil::unique_hdc hdc{ reinterpret_cast<HDC>(wparam) };
if (!hdc)
{
hdc.reset(BeginPaint(window, &ps));
hdc.reset(BeginPaint(m_window.get(), &ps));
}
OnPaint(hdc);
if (wparam == 0)
{
EndPaint(window, &ps);
EndPaint(m_window.get(), &ps);
}
hdc.release();
@ -775,7 +653,7 @@ LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept
default:
{
return DefWindowProc(window, message, wparam, lparam);
return DefWindowProc(m_window.get(), message, wparam, lparam);
}
}
return 0;
@ -783,17 +661,8 @@ LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept
void ZoneWindow::OnPaint(wil::unique_hdc& hdc) noexcept
{
std::shared_lock lock(m_mutex);
auto host = m_host;
auto highlightZone = m_highlightZone;
auto flashMode = m_flashMode;
auto drawHints = m_drawHints;
HWND window = m_window.get();
auto activeZoneSet = m_activeZoneSet;
lock.unlock();
RECT clientRect;
GetClientRect(window, &clientRect);
GetClientRect(m_window.get(), &clientRect);
wil::unique_hdc hdcMem;
HPAINTBUFFER bufferedPaint = BeginBufferedPaint(hdc.get(), &clientRect, BPBF_TOPDOWNDIB, nullptr, &hdcMem);
@ -801,17 +670,17 @@ void ZoneWindow::OnPaint(wil::unique_hdc& hdc) noexcept
{
ZoneWindowDrawUtils::DrawBackdrop(hdcMem, clientRect);
if (activeZoneSet && host)
if (m_activeZoneSet && m_host)
{
ZoneWindowDrawUtils::DrawActiveZoneSet(hdcMem,
host->GetZoneColor(),
host->GetZoneBorderColor(),
host->GetZoneHighlightColor(),
host->GetZoneHighlightOpacity(),
activeZoneSet->GetZones(),
highlightZone,
flashMode,
drawHints);
m_host->GetZoneColor(),
m_host->GetZoneBorderColor(),
m_host->GetZoneHighlightColor(),
m_host->GetZoneHighlightOpacity(),
m_activeZoneSet->GetZones(),
m_highlightZone,
m_flashMode,
m_drawHints);
}
EndBufferedPaint(bufferedPaint, TRUE);
@ -820,56 +689,43 @@ void ZoneWindow::OnPaint(wil::unique_hdc& hdc) noexcept
void ZoneWindow::OnKeyUp(WPARAM wparam) noexcept
{
std::shared_lock lock(m_mutex);
auto window = m_window.get();
lock.unlock();
bool fRedraw = false;
Trace::ZoneWindow::KeyUp(wparam);
if ((wparam >= '0') && (wparam <= '9'))
{
CycleActiveZoneSetInternal(static_cast<DWORD>(wparam), Trace::ZoneWindow::InputMode::Keyboard);
InvalidateRect(window, nullptr, true);
InvalidateRect(m_window.get(), nullptr, true);
}
}
std::vector<int> ZoneWindow::ZonesFromPoint(POINT pt) noexcept
{
auto activeZoneSet = ActiveZoneSet();
if (activeZoneSet)
if (m_activeZoneSet)
{
return activeZoneSet->ZonesFromPoint(pt);
return m_activeZoneSet->ZonesFromPoint(pt);
}
return {};
}
void ZoneWindow::CycleActiveZoneSetInternal(DWORD wparam, Trace::ZoneWindow::InputMode mode) noexcept
{
std::shared_lock lock(m_mutex);
auto activeZoneSet = m_activeZoneSet;
auto keyLast = m_keyLast;
auto keyCycle = m_keyCycle;
auto zoneSets = m_zoneSets;
auto host = m_host;
lock.unlock();
Trace::ZoneWindow::CycleActiveZoneSet(activeZoneSet, mode);
if (keyLast != wparam)
Trace::ZoneWindow::CycleActiveZoneSet(m_activeZoneSet, mode);
if (m_keyLast != wparam)
{
keyCycle = 0;
m_keyCycle = 0;
}
keyLast = wparam;
m_keyLast = wparam;
bool loopAround = true;
size_t const val = static_cast<size_t>(wparam - L'0');
size_t i = 0;
for (auto zoneSet : zoneSets)
for (auto zoneSet : m_zoneSets)
{
if (zoneSet->GetZones().size() == val)
{
if (i < keyCycle)
if (i < m_keyCycle)
{
i++;
}
@ -882,25 +738,21 @@ void ZoneWindow::CycleActiveZoneSetInternal(DWORD wparam, Trace::ZoneWindow::Inp
}
}
if ((keyCycle > 0) && loopAround)
if ((m_keyCycle > 0) && loopAround)
{
// Cycling through a non-empty group and hit the end
keyCycle = 0;
m_keyCycle = 0;
OnKeyUp(wparam);
}
else
{
keyCycle++;
m_keyCycle++;
}
if (host)
if (m_host)
{
host->MoveWindowsOnActiveZoneSetChange();
m_host->MoveWindowsOnActiveZoneSetChange();
}
std::unique_lock writeLock(m_mutex);
m_keyLast = keyLast;
m_keyCycle = keyCycle;
m_highlightZone = {};
}
@ -912,13 +764,10 @@ void ZoneWindow::FlashZones() noexcept
return;
}
std::unique_lock writeLock(m_mutex);
m_flashMode = true;
auto window = m_window.get();
writeLock.unlock();
ShowWindow(window, SW_SHOWNA);
std::thread([window]() {
ShowWindow(m_window.get(), SW_SHOWNA);
std::thread([window = m_window.get()]() {
AnimateWindow(window, m_flashDuration, AW_HIDE | AW_BLEND);
}).detach();
}

View file

@ -8,6 +8,7 @@ BEGIN
IDS_SETTING_DESCRIPTION "Create window layouts to help make multi-tasking easy"
IDS_SETTING_DESCRIPTION_SHIFTDRAG "On: Hold Shift key or any non-primary mouse button to enable zones while dragging"
IDS_SETTING_DESCRIPTION_OVERRIDE_SNAP_HOTKEYS "Override Windows Snap hotkeys (win+arrow) to move windows between zones"
IDS_SETTING_DESCRIPTION_MOVE_WINDOW_ACROSS_MONITORS "Move windows between zones across all monitors when snapping with win+arrow"
IDS_SETTING_DESCRIPTION_DISPLAYCHANGE_MOVEWINDOWS "Keep windows in their zones when the screen resolution changes"
IDS_SETTING_DESCRIPTION_ZONESETCHANGE_MOVEWINDOWS "During zone layout changes, windows assigned to a zone will match new size/positions"
IDS_SETTING_DESCRIPTION_VIRTUALDESKTOPCHANGE_MOVEWINDOWS "Keep windows pinned to multiple desktops in the same zone when the active desktop changes"

View file

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

View file

@ -4,6 +4,7 @@
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <Unknwn.h>
#include <winrt/base.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <windows.h>
#include <windowsx.h>
#include <dwmapi.h>
@ -13,8 +14,11 @@
#include <TraceLoggingActivity.h>
#include <wil\resource.h>
#include <wil\result.h>
#include <windows.foundation.h>
#include <winrt/windows.foundation.h>
#include <psapi.h>
#include <shared_mutex>
#include <functional>
#include <unordered_set>
#pragma comment(lib, "windowsapp")

View file

@ -1,24 +1,25 @@
#define IDS_SETTING_DESCRIPTION_SHIFTDRAG 101
#define IDS_SETTING_DESCRIPTION_OVERRIDE_SNAP_HOTKEYS 102
#define IDS_SETTING_DESCRIPTION_DISPLAYCHANGE_MOVEWINDOWS 103
#define IDS_SETTING_DESCRIPTION_ZONESETCHANGE_MOVEWINDOWS 104
#define IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES 105
#define IDS_SETTING_DESCRIPTION_VIRTUALDESKTOPCHANGE_MOVEWINDOWS 106
#define IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS 107
#define IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT 108
#define IDS_SETTING_DESCRIPTION_ZONECOLOR 109
#define IDS_SETTING_DESCRIPTION_ZONE_BORDER_COLOR 110
#define IDS_SETTING_DESCRIPTION_ZONEHIGHLIGHTCOLOR 111
#define IDS_SETTING_DESCRIPTION_APPLASTZONE_MOVEWINDOWS 112
#define IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN 113
#define IDS_SETTING_DESCRIPTION 114
#define IDS_SETTING_LAUNCH_EDITOR_LABEL 115
#define IDS_SETTING_LAUNCH_EDITOR_BUTTON 116
#define IDS_SETTING_LAUNCH_EDITOR_DESCRIPTION 117
#define IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL 118
#define IDS_SETTING_EXCLCUDED_APPS_DESCRIPTION 119
#define IDS_SETTINGS_HIGHLIGHT_OPACITY 120
#define IDS_FANCYZONES 121
#define IDS_CANT_DRAG_ELEVATED 122
#define IDS_CANT_DRAG_ELEVATED_LEARN_MORE 123
#define IDS_CANT_DRAG_ELEVATED_DIALOG_DONT_SHOW_AGAIN 124
#define IDS_SETTING_DESCRIPTION_MOVE_WINDOW_ACROSS_MONITORS 103
#define IDS_SETTING_DESCRIPTION_DISPLAYCHANGE_MOVEWINDOWS 104
#define IDS_SETTING_DESCRIPTION_ZONESETCHANGE_MOVEWINDOWS 105
#define IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES 106
#define IDS_SETTING_DESCRIPTION_VIRTUALDESKTOPCHANGE_MOVEWINDOWS 107
#define IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS 108
#define IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT 109
#define IDS_SETTING_DESCRIPTION_ZONECOLOR 110
#define IDS_SETTING_DESCRIPTION_ZONE_BORDER_COLOR 111
#define IDS_SETTING_DESCRIPTION_ZONEHIGHLIGHTCOLOR 112
#define IDS_SETTING_DESCRIPTION_APPLASTZONE_MOVEWINDOWS 113
#define IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN 114
#define IDS_SETTING_DESCRIPTION 115
#define IDS_SETTING_LAUNCH_EDITOR_LABEL 116
#define IDS_SETTING_LAUNCH_EDITOR_BUTTON 117
#define IDS_SETTING_LAUNCH_EDITOR_DESCRIPTION 118
#define IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL 119
#define IDS_SETTING_EXCLCUDED_APPS_DESCRIPTION 120
#define IDS_SETTINGS_HIGHLIGHT_OPACITY 121
#define IDS_FANCYZONES 122
#define IDS_CANT_DRAG_ELEVATED 123
#define IDS_CANT_DRAG_ELEVATED_LEARN_MORE 124
#define IDS_CANT_DRAG_ELEVATED_DIALOG_DONT_SHOW_AGAIN 125

View file

@ -178,6 +178,7 @@ void Trace::SettingsChanged(const Settings& settings) noexcept
TraceLoggingBoolean(settings.zoneSetChange_flashZones, "FlashZonesOnZoneSetChange"),
TraceLoggingBoolean(settings.zoneSetChange_moveWindows, "MoveWindowsOnZoneSetChange"),
TraceLoggingBoolean(settings.overrideSnapHotkeys, "OverrideSnapHotKeys"),
TraceLoggingBoolean(settings.moveWindowAcrossMonitors, "MoveWindowAcrossMonitors"),
TraceLoggingBoolean(settings.appLastZone_moveWindows, "MoveWindowsToLastZoneOnAppOpening"),
TraceLoggingBoolean(settings.use_cursorpos_editor_startupscreen, "UseCursorPosOnEditorStartup"),
TraceLoggingBoolean(settings.showZonesOnAllMonitors, "ShowZonesOnAllMonitors"),

View file

@ -1,6 +1,7 @@
#include "pch.h"
#include "util.h"
#include <common/common.h>
#include <common/dpi_aware.h>
typedef BOOL(WINAPI* GetDpiForMonitorInternalFunc)(HMONITOR, UINT, UINT*, UINT*);
@ -135,3 +136,19 @@ void SizeWindowToRect(HWND window, RECT rect) noexcept
// This fixes Issue #365
::SetWindowPlacement(window, &placement);
}
bool IsInterestingWindow(HWND window, const std::vector<std::wstring>& excludedApps) noexcept
{
auto filtered = get_fancyzones_filtered_window(window);
if (!filtered.zonable)
{
return false;
}
// Filter out user specified apps
CharUpperBuffW(filtered.process_path.data(), (DWORD)filtered.process_path.length());
if (find_app_name_in_path(filtered.process_path, excludedApps))
{
return false;
}
return true;
}

View file

@ -119,3 +119,5 @@ inline BYTE OpacitySettingToAlpha(int opacity)
UINT GetDpiForMonitor(HMONITOR monitor) noexcept;
void OrderMonitors(std::vector<std::pair<HMONITOR, RECT>>& monitorInfo);
void SizeWindowToRect(HWND window, RECT rect) noexcept;
bool IsInterestingWindow(HWND window, const std::vector<std::wstring>& exludedApps) noexcept;

View file

@ -62,6 +62,7 @@ namespace FancyZonesUnitTests
ptSettings.add_hotkey(L"fancyzones_editor_hotkey", IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL, settings.editorHotkey);
ptSettings.add_bool_toogle(L"fancyzones_shiftDrag", IDS_SETTING_DESCRIPTION_SHIFTDRAG, settings.shiftDrag);
ptSettings.add_bool_toogle(L"fancyzones_overrideSnapHotkeys", IDS_SETTING_DESCRIPTION_OVERRIDE_SNAP_HOTKEYS, settings.overrideSnapHotkeys);
ptSettings.add_bool_toogle(L"fancyzones_moveWindowAcrossMonitors", IDS_SETTING_DESCRIPTION_MOVE_WINDOW_ACROSS_MONITORS, settings.moveWindowAcrossMonitors);
ptSettings.add_bool_toogle(L"fancyzones_zoneSetChange_flashZones", IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES, settings.zoneSetChange_flashZones);
ptSettings.add_bool_toogle(L"fancyzones_displayChange_moveWindows", IDS_SETTING_DESCRIPTION_DISPLAYCHANGE_MOVEWINDOWS, settings.displayChange_moveWindows);
ptSettings.add_bool_toogle(L"fancyzones_zoneSetChange_moveWindows", IDS_SETTING_DESCRIPTION_ZONESETCHANGE_MOVEWINDOWS, settings.zoneSetChange_moveWindows);
@ -110,6 +111,7 @@ namespace FancyZonesUnitTests
.zoneSetChange_flashZones = false,
.zoneSetChange_moveWindows = true,
.overrideSnapHotkeys = false,
.moveWindowAcrossMonitors = false,
.appLastZone_moveWindows = true,
.use_cursorpos_editor_startupscreen = true,
.zoneColor = L"#abafee",
@ -138,6 +140,7 @@ namespace FancyZonesUnitTests
.zoneSetChange_flashZones = false,
.zoneSetChange_moveWindows = true,
.overrideSnapHotkeys = false,
.moveWindowAcrossMonitors = false,
.appLastZone_moveWindows = true,
.use_cursorpos_editor_startupscreen = true,
.zoneColor = L"#FAFAFA",
@ -166,6 +169,7 @@ namespace FancyZonesUnitTests
.zoneSetChange_flashZones = false,
.zoneSetChange_moveWindows = true,
.overrideSnapHotkeys = false,
.moveWindowAcrossMonitors = false,
.appLastZone_moveWindows = true,
.use_cursorpos_editor_startupscreen = true,
.showZonesOnAllMonitors = false,
@ -196,6 +200,7 @@ namespace FancyZonesUnitTests
.zoneSetChange_flashZones = false,
.zoneSetChange_moveWindows = true,
.overrideSnapHotkeys = false,
.moveWindowAcrossMonitors = false,
.appLastZone_moveWindows = true,
.use_cursorpos_editor_startupscreen = true,
.showZonesOnAllMonitors = false,
@ -226,6 +231,7 @@ namespace FancyZonesUnitTests
.zoneSetChange_flashZones = false,
.zoneSetChange_moveWindows = true,
.overrideSnapHotkeys = false,
.moveWindowAcrossMonitors = false,
.appLastZone_moveWindows = true,
.use_cursorpos_editor_startupscreen = true,
.showZonesOnAllMonitors = false,
@ -274,6 +280,7 @@ namespace FancyZonesUnitTests
ptSettings.add_hotkey(L"fancyzones_editor_hotkey", IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL, settings.editorHotkey);
ptSettings.add_bool_toogle(L"fancyzones_shiftDrag", IDS_SETTING_DESCRIPTION_SHIFTDRAG, settings.shiftDrag);
ptSettings.add_bool_toogle(L"fancyzones_overrideSnapHotkeys", IDS_SETTING_DESCRIPTION_OVERRIDE_SNAP_HOTKEYS, settings.overrideSnapHotkeys);
ptSettings.add_bool_toogle(L"fancyzones_moveWindowAcrossMonitors", IDS_SETTING_DESCRIPTION_MOVE_WINDOW_ACROSS_MONITORS, settings.moveWindowAcrossMonitors);
ptSettings.add_bool_toogle(L"fancyzones_zoneSetChange_flashZones", IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES, settings.zoneSetChange_flashZones);
ptSettings.add_bool_toogle(L"fancyzones_displayChange_moveWindows", IDS_SETTING_DESCRIPTION_DISPLAYCHANGE_MOVEWINDOWS, settings.displayChange_moveWindows);
ptSettings.add_bool_toogle(L"fancyzones_zoneSetChange_moveWindows", IDS_SETTING_DESCRIPTION_ZONESETCHANGE_MOVEWINDOWS, settings.zoneSetChange_moveWindows);

View file

@ -32,6 +32,7 @@ namespace FancyZonesUnitTests
Assert::AreEqual(expected.zoneSetChange_flashZones, actual.zoneSetChange_flashZones);
Assert::AreEqual(expected.zoneSetChange_moveWindows, actual.zoneSetChange_moveWindows);
Assert::AreEqual(expected.overrideSnapHotkeys, actual.overrideSnapHotkeys);
Assert::AreEqual(expected.moveWindowAcrossMonitors, actual.moveWindowAcrossMonitors);
Assert::AreEqual(expected.appLastZone_moveWindows, actual.appLastZone_moveWindows);
Assert::AreEqual(expected.use_cursorpos_editor_startupscreen, actual.use_cursorpos_editor_startupscreen);
Assert::AreEqual(expected.showZonesOnAllMonitors, actual.showZonesOnAllMonitors);
@ -109,6 +110,7 @@ namespace FancyZonesUnitTests
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_appLastZone_moveWindows", expected.appLastZone_moveWindows);
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
@ -144,6 +146,7 @@ namespace FancyZonesUnitTests
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_appLastZone_moveWindows", expected.appLastZone_moveWindows);
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
@ -173,6 +176,7 @@ namespace FancyZonesUnitTests
.zoneSetChange_flashZones = m_defaultSettings.zoneSetChange_flashZones,
.zoneSetChange_moveWindows = m_defaultSettings.zoneSetChange_moveWindows,
.overrideSnapHotkeys = m_defaultSettings.overrideSnapHotkeys,
.moveWindowAcrossMonitors = m_defaultSettings.moveWindowAcrossMonitors,
.appLastZone_moveWindows = m_defaultSettings.appLastZone_moveWindows,
.use_cursorpos_editor_startupscreen = m_defaultSettings.use_cursorpos_editor_startupscreen,
.showZonesOnAllMonitors = m_defaultSettings.showZonesOnAllMonitors,
@ -215,6 +219,7 @@ namespace FancyZonesUnitTests
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_appLastZone_moveWindows", expected.appLastZone_moveWindows);
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
@ -244,6 +249,7 @@ namespace FancyZonesUnitTests
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_appLastZone_moveWindows", expected.appLastZone_moveWindows);
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
@ -274,6 +280,7 @@ namespace FancyZonesUnitTests
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_appLastZone_moveWindows", expected.appLastZone_moveWindows);
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
@ -305,6 +312,7 @@ namespace FancyZonesUnitTests
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_appLastZone_moveWindows", expected.appLastZone_moveWindows);
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
@ -379,6 +387,8 @@ namespace FancyZonesUnitTests
IFACEMETHODIMP_(void)
MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept {}
IFACEMETHODIMP_(void)
HandleWinHookEvent(const WinHookEvent * data) noexcept {}
IFACEMETHODIMP_(void)
VirtualDesktopChanged() noexcept {}
IFACEMETHODIMP_(void)
VirtualDesktopInitialize() noexcept {}
@ -415,6 +425,7 @@ namespace FancyZonesUnitTests
.zoneSetChange_flashZones = true,
.zoneSetChange_moveWindows = true,
.overrideSnapHotkeys = false,
.moveWindowAcrossMonitors = false,
.appLastZone_moveWindows = false,
.use_cursorpos_editor_startupscreen = true,
.showZonesOnAllMonitors = false,
@ -435,6 +446,7 @@ namespace FancyZonesUnitTests
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_appLastZone_moveWindows", expected.appLastZone_moveWindows);
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
@ -461,12 +473,12 @@ namespace FancyZonesUnitTests
TEST_METHOD (CallbackSetConfig)
{
bool flag = false;
FZCallback callback(&flag);
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);
m_settings->SetCallback(callback.get());
m_settings->SetConfig(json.Stringify().c_str());
Assert::IsTrue(flag);
@ -475,12 +487,12 @@ namespace FancyZonesUnitTests
TEST_METHOD (CallbackCallCustomAction)
{
bool flag = false;
FZCallback callback(&flag);
winrt::com_ptr<FZCallback> callback = winrt::make_self<FZCallback>(&flag);
json::JsonObject action{};
action.SetNamedValue(L"action_name", json::JsonValue::CreateStringValue(L"ToggledFZEditor"));
m_settings->SetCallback(&callback);
m_settings->SetCallback(callback.get());
m_settings->CallCustomAction(action.Stringify().c_str());
Assert::IsTrue(flag);
@ -489,12 +501,12 @@ namespace FancyZonesUnitTests
TEST_METHOD (CallbackCallCustomActionNotToggle)
{
bool flag = false;
FZCallback callback(&flag);
winrt::com_ptr<FZCallback> callback = winrt::make_self<FZCallback>(&flag);
json::JsonObject action{};
action.SetNamedValue(L"action_name", json::JsonValue::CreateStringValue(L"NOT_ToggledFZEditor"));
m_settings->SetCallback(&callback);
m_settings->SetCallback(callback.get());
m_settings->CallCustomAction(action.Stringify().c_str());
Assert::IsFalse(flag);
@ -503,9 +515,9 @@ namespace FancyZonesUnitTests
TEST_METHOD (CallbackGetConfig)
{
bool flag = false;
FZCallback callback(&flag);
winrt::com_ptr<FZCallback> callback = winrt::make_self<FZCallback>(&flag);
m_settings->SetCallback(&callback);
m_settings->SetCallback(callback.get());
int bufSize = 0;
m_settings->GetConfig(L"", &bufSize);
@ -516,9 +528,9 @@ namespace FancyZonesUnitTests
TEST_METHOD (CallbackGetSettings)
{
bool flag = false;
FZCallback callback(&flag);
winrt::com_ptr<FZCallback> callback = winrt::make_self<FZCallback>(&flag);
m_settings->SetCallback(&callback);
m_settings->SetCallback(callback.get());
m_settings->GetSettings();
Assert::IsFalse(flag);
@ -547,6 +559,7 @@ namespace FancyZonesUnitTests
ptSettings.add_hotkey(L"fancyzones_editor_hotkey", IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL, settings.editorHotkey);
ptSettings.add_bool_toogle(L"fancyzones_shiftDrag", IDS_SETTING_DESCRIPTION_SHIFTDRAG, settings.shiftDrag);
ptSettings.add_bool_toogle(L"fancyzones_overrideSnapHotkeys", IDS_SETTING_DESCRIPTION_OVERRIDE_SNAP_HOTKEYS, settings.overrideSnapHotkeys);
ptSettings.add_bool_toogle(L"fancyzones_moveWindowAcrossMonitors", IDS_SETTING_DESCRIPTION_MOVE_WINDOW_ACROSS_MONITORS, settings.moveWindowAcrossMonitors);
ptSettings.add_bool_toogle(L"fancyzones_zoneSetChange_flashZones", IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES, settings.zoneSetChange_flashZones);
ptSettings.add_bool_toogle(L"fancyzones_displayChange_moveWindows", IDS_SETTING_DESCRIPTION_DISPLAYCHANGE_MOVEWINDOWS, settings.displayChange_moveWindows);
ptSettings.add_bool_toogle(L"fancyzones_zoneSetChange_moveWindows", IDS_SETTING_DESCRIPTION_ZONESETCHANGE_MOVEWINDOWS, settings.zoneSetChange_moveWindows);
@ -578,6 +591,7 @@ namespace FancyZonesUnitTests
//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_appLastZone_moveWindows", expected.appLastZone_moveWindows);
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
@ -608,6 +622,7 @@ namespace FancyZonesUnitTests
m_ptSettings->add_hotkey(L"fancyzones_editor_hotkey", IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL, expected.editorHotkey);
m_ptSettings->add_bool_toogle(L"fancyzones_shiftDrag", IDS_SETTING_DESCRIPTION_SHIFTDRAG, expected.shiftDrag);
m_ptSettings->add_bool_toogle(L"fancyzones_overrideSnapHotkeys", IDS_SETTING_DESCRIPTION_OVERRIDE_SNAP_HOTKEYS, expected.overrideSnapHotkeys);
m_ptSettings->add_bool_toogle(L"fancyzones_moveWindowAcrossMonitors", IDS_SETTING_DESCRIPTION_MOVE_WINDOW_ACROSS_MONITORS, expected.moveWindowAcrossMonitors);
//m_ptSettings->add_bool_toogle(L"fancyzones_zoneSetChange_flashZones", IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES, expected.zoneSetChange_flashZones);
m_ptSettings->add_bool_toogle(L"fancyzones_displayChange_moveWindows", IDS_SETTING_DESCRIPTION_DISPLAYCHANGE_MOVEWINDOWS, expected.displayChange_moveWindows);
m_ptSettings->add_bool_toogle(L"fancyzones_zoneSetChange_moveWindows", IDS_SETTING_DESCRIPTION_ZONESETCHANGE_MOVEWINDOWS, expected.zoneSetChange_moveWindows);
@ -680,6 +695,7 @@ namespace FancyZonesUnitTests
.zoneSetChange_flashZones = false,
.zoneSetChange_moveWindows = true,
.overrideSnapHotkeys = false,
.moveWindowAcrossMonitors = false,
.appLastZone_moveWindows = true,
.use_cursorpos_editor_startupscreen = true,
.showZonesOnAllMonitors = false,

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
@ -15,7 +16,7 @@
<ProjectGuid>{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>UnitTests</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
<ProjectSubType>NativeUnitTestProject</ProjectSubType>
<ProjectName>UnitTests-FancyZones</ProjectName>
</PropertyGroup>
@ -131,11 +132,14 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View file

@ -61,8 +61,8 @@ namespace FancyZonesUnitTests
HINSTANCE m_hInst{};
HMONITOR m_monitor{};
MONITORINFO m_monitorInfo{};
MockZoneWindowHost m_zoneWindowHost{};
IZoneWindowHost* m_hostPtr = m_zoneWindowHost.get_strong().get();
winrt::com_ptr<MockZoneWindowHost> m_zoneWindowHost = winrt::make_self<MockZoneWindowHost>();
IZoneWindowHost* m_hostPtr = m_zoneWindowHost.get();
winrt::com_ptr<IZoneWindow> m_zoneWindow;
@ -391,7 +391,7 @@ namespace FancyZonesUnitTests
m_fancyZonesData.SetDeviceInfo(m_parentUniqueId.str(), parentDeviceInfo);
auto parentZoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_parentUniqueId.str(), false, false);
m_zoneWindowHost.m_zoneWindow = parentZoneWindow.get();
m_zoneWindowHost->m_zoneWindow = parentZoneWindow.get();
// newWorkArea = true - zoneWindow will be cloned from parent
auto actualZoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, true);
@ -420,7 +420,7 @@ namespace FancyZonesUnitTests
m_fancyZonesData.SetDeviceInfo(m_parentUniqueId.str(), parentDeviceInfo);
auto parentZoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_parentUniqueId.str(), false, false);
m_zoneWindowHost.m_zoneWindow = parentZoneWindow.get();
m_zoneWindowHost->m_zoneWindow = parentZoneWindow.get();
// newWorkArea = false - zoneWindow won't be cloned from parent
auto actualZoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, false);

View file

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

View file

@ -9,9 +9,10 @@
// add headers that you want to pre-compile here
#include <Windows.h>
#include <winrt\base.h>
#include "lib\pch.h"
#include <winrt/base.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include "lib/pch.h"
#include "CppUnitTest.h"
#endif //PCH_H

View file

@ -1,6 +1,6 @@
// ContextMenuHandler.cpp : Implementation of CContextMenuHandler
#include "stdafx.h"
#include "pch.h"
#include "ContextMenuHandler.h"
#include "HDropIterator.h"
#include "Settings.h"
@ -37,7 +37,7 @@ HRESULT CContextMenuHandler::Initialize(_In_opt_ PCIDLIST_ABSOLUTE pidlFolder, _
{
Uninitialize();
if (!CSettings::GetEnabled())
if (!CSettingsInstance().GetEnabled())
{
return E_FAIL;
}
@ -62,7 +62,7 @@ HRESULT CContextMenuHandler::QueryContextMenu(_In_ HMENU hmenu, UINT indexMenu,
{
return S_OK;
}
if (!CSettings::GetEnabled())
if (!CSettingsInstance().GetEnabled())
{
return E_FAIL;
}
@ -354,7 +354,7 @@ HRESULT __stdcall CContextMenuHandler::GetCanonicalName(GUID* pguidCommandName)
HRESULT __stdcall CContextMenuHandler::GetState(IShellItemArray* psiItemArray, BOOL fOkToBeSlow, EXPCMDSTATE* pCmdState)
{
if (!CSettings::GetEnabled())
if (!CSettingsInstance().GetEnabled())
{
*pCmdState = ECS_HIDDEN;
return S_OK;

View file

@ -2,7 +2,7 @@
#define ID_RESIZE_PICTURES 0
#define RESIZE_PICTURES_VERBW L"resize"
#include "stdafx.h"
#include "pch.h"
#include "resource.h"
#include "ImageResizerExt_i.h"

View file

@ -1,4 +1,4 @@
#include "StdAfx.h"
#include "pch.h"
#include "HDropIterator.h"
HDropIterator::HDropIterator(IDataObject* pdtobj)

View file

@ -1,4 +1,4 @@
#include "stdafx.h"
#include "pch.h"
#include "resource.h"
#include "ImageResizerExt_i.h"
#include "dllmain.h"

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@ -20,8 +21,9 @@
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{0B43679E-EDFA-4DA0-AD30-F4628B308B1B}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
<Keyword>AtlProj</Keyword>
<CppWinRTModernIDL>false</CppWinRTModernIDL>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@ -269,7 +271,7 @@
</PrecompiledHeader>
</ClCompile>
<ClCompile Include="Settings.cpp" />
<ClCompile Include="stdafx.cpp">
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
@ -284,7 +286,7 @@
<ClInclude Include="Settings.h" />
<ClInclude Include="Resource.h" />
<ClInclude Include="ImageResizerExt_i.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="trace.h" />
</ItemGroup>
@ -295,6 +297,7 @@
<None Include="ContextMenuHandler.rgs" />
<None Include="ImageResizerExt.def" />
<None Include="ImageResizerExt.rgs" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Midl Include="ImageResizerExt.idl" />
@ -309,5 +312,13 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View file

@ -19,18 +19,12 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ImageResizerExt.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="dllmain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ImageResizerExt_i.c">
<Filter>Generated Files</Filter>
</ClCompile>
<ClCompile Include="ContextMenuHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@ -46,11 +40,14 @@
<ClInclude Include="trace.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClCompile Include="ImageResizerExt_i.c">
<Filter>Generated Files</Filter>
</ClCompile>
<ClCompile Include="pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -60,9 +57,6 @@
<ClInclude Include="dllmain.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ImageResizerExt_i.h">
<Filter>Generated Files</Filter>
</ClInclude>
<ClInclude Include="ContextMenuHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -72,6 +66,12 @@
<ClInclude Include="Settings.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ImageResizerExt_i.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pch.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="ImageResizerExt.rc">
@ -88,15 +88,16 @@
<None Include="ContextMenuHandler.rgs">
<Filter>Resource Files</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Midl Include="ImageResizerExt.idl">
<Filter>Source Files</Filter>
</Midl>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Image Include="..\ui\Resources\ImageResizer.ico">
<Filter>Resource Files</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<Midl Include="ImageResizerExt.idl">
<Filter>Source Files</Filter>
</Midl>
</ItemGroup>
</Project>

View file

@ -1,66 +1,116 @@
#include "stdafx.h"
#include <commctrl.h>
#include "pch.h"
#include "Settings.h"
const wchar_t c_rootRegPath[] = L"Software\\Microsoft\\ImageResizer";
const wchar_t c_enabled[] = L"Enabled";
const bool c_enabledDefault = true;
#include <common/json.h>
#include <common/settings_helpers.h>
#include <filesystem>
#include <commctrl.h>
bool CSettings::GetEnabled()
namespace
{
return GetRegBoolValue(c_enabled, c_enabledDefault);
}
const wchar_t c_imageResizerDataFilePath[] = L"\\image-resizer-settings.json";
const wchar_t c_rootRegPath[] = L"Software\\Microsoft\\ImageResizer";
const wchar_t c_enabled[] = L"Enabled";
bool CSettings::SetEnabled(_In_ bool enabled)
{
return SetRegBoolValue(c_enabled, enabled);
}
bool CSettings::SetRegBoolValue(_In_ PCWSTR valueName, _In_ bool value)
{
DWORD dwValue = value ? 1 : 0;
return SetRegDWORDValue(valueName, dwValue);
}
bool CSettings::GetRegBoolValue(_In_ PCWSTR valueName, _In_ bool defaultValue)
{
DWORD value = GetRegDWORDValue(valueName, (defaultValue == 0) ? false : true);
return (value == 0) ? false : true;
}
bool CSettings::SetRegDWORDValue(_In_ PCWSTR valueName, _In_ DWORD value)
{
return (SUCCEEDED(HRESULT_FROM_WIN32(SHSetValue(HKEY_CURRENT_USER, c_rootRegPath, valueName, REG_DWORD, &value, sizeof(value)))));
}
DWORD CSettings::GetRegDWORDValue(_In_ PCWSTR valueName, _In_ DWORD defaultValue)
{
DWORD retVal = defaultValue;
DWORD type = REG_DWORD;
DWORD dwEnabled = 0;
DWORD cb = sizeof(dwEnabled);
if (SHGetValue(HKEY_CURRENT_USER, c_rootRegPath, valueName, &type, &dwEnabled, &cb) == ERROR_SUCCESS)
unsigned int RegReadInteger(const std::wstring& valueName, unsigned int defaultValue)
{
retVal = dwEnabled;
DWORD type = REG_DWORD;
DWORD data = 0;
DWORD size = sizeof(DWORD);
if (SHGetValue(HKEY_CURRENT_USER, c_rootRegPath, valueName.c_str(), &type, &data, &size) == ERROR_SUCCESS)
{
return data;
}
return defaultValue;
}
return retVal;
}
bool CSettings::SetRegStringValue(_In_ PCWSTR valueName, _In_ PCWSTR value)
{
ULONG cb = (DWORD)((wcslen(value) + 1) * sizeof(*value));
return (SUCCEEDED(HRESULT_FROM_WIN32(SHSetValue(HKEY_CURRENT_USER, c_rootRegPath, valueName, REG_SZ, (const BYTE*)value, cb))));
}
bool CSettings::GetRegStringValue(_In_ PCWSTR valueName, __out_ecount(cchBuf) PWSTR value, DWORD cchBuf)
{
if (cchBuf > 0)
bool RegReadBoolean(const std::wstring& valueName, bool defaultValue)
{
value[0] = L'\0';
DWORD value = RegReadInteger(valueName.c_str(), defaultValue ? 1 : 0);
return (value == 0) ? false : true;
}
DWORD type = REG_SZ;
ULONG cb = cchBuf * sizeof(*value);
return (SUCCEEDED(HRESULT_FROM_WIN32(SHGetValue(HKEY_CURRENT_USER, c_rootRegPath, valueName, &type, value, &cb) == ERROR_SUCCESS)));
bool LastModifiedTime(const std::wstring& filePath, FILETIME* lpFileTime)
{
WIN32_FILE_ATTRIBUTE_DATA attr{};
if (GetFileAttributesExW(filePath.c_str(), GetFileExInfoStandard, &attr))
{
*lpFileTime = attr.ftLastWriteTime;
return true;
}
return false;
}
}
CSettings::CSettings()
{
std::wstring result = PTSettingsHelper::get_module_save_folder_location(L"ImageResizer");
jsonFilePath = result + std::wstring(c_imageResizerDataFilePath);
Load();
}
void CSettings::Save()
{
json::JsonObject jsonData;
jsonData.SetNamedValue(c_enabled, json::value(settings.enabled));
json::to_file(jsonFilePath, jsonData);
GetSystemTimeAsFileTime(&lastLoadedTime);
}
void CSettings::Load()
{
if (!std::filesystem::exists(jsonFilePath))
{
MigrateFromRegistry();
Save();
}
else
{
ParseJson();
}
}
void CSettings::Reload()
{
// Load json settings from data file if it is modified in the meantime.
FILETIME lastModifiedTime{};
if (LastModifiedTime(jsonFilePath, &lastModifiedTime) &&
CompareFileTime(&lastModifiedTime, &lastLoadedTime) == 1)
{
Load();
}
}
void CSettings::MigrateFromRegistry()
{
settings.enabled = RegReadBoolean(c_enabled, true);
}
void CSettings::ParseJson()
{
auto json = json::from_file(jsonFilePath);
if (json)
{
const json::JsonObject& jsonSettings = json.value();
try
{
if (json::has(jsonSettings, c_enabled, json::JsonValueType::Boolean))
{
settings.enabled = jsonSettings.GetNamedBoolean(c_enabled);
}
}
catch (const winrt::hresult_error&)
{
}
}
GetSystemTimeAsFileTime(&lastLoadedTime);
}
CSettings& CSettingsInstance()
{
static CSettings instance;
return instance;
}

View file

@ -3,14 +3,36 @@
class CSettings
{
public:
static bool GetEnabled();
static bool SetEnabled(_In_ bool enabled);
CSettings();
inline bool GetEnabled()
{
Reload();
return settings.enabled;
}
inline void SetEnabled(bool enabled)
{
settings.enabled = enabled;
Save();
}
void Save();
void Load();
private:
static bool GetRegBoolValue(_In_ PCWSTR valueName, _In_ bool defaultValue);
static bool SetRegBoolValue(_In_ PCWSTR valueName, _In_ bool value);
static bool SetRegDWORDValue(_In_ PCWSTR valueName, _In_ DWORD value);
static DWORD GetRegDWORDValue(_In_ PCWSTR valueName, _In_ DWORD defaultValue);
static bool SetRegStringValue(_In_ PCWSTR valueName, _In_ PCWSTR value);
static bool GetRegStringValue(_In_ PCWSTR valueName, __out_ecount(cchBuf) PWSTR value, DWORD cchBuf);
};
struct Settings
{
bool enabled{ true };
};
void Reload();
void MigrateFromRegistry();
void ParseJson();
Settings settings;
std::wstring jsonFilePath;
FILETIME lastLoadedTime;
};
CSettings& CSettingsInstance();

View file

@ -1,4 +1,4 @@
#include "stdafx.h"
#include "pch.h"
#include "resource.h"
#include "ImageResizerExt_i.h"
#include "dllmain.h"
@ -37,7 +37,7 @@ public:
// Constructor
ImageResizerModule()
{
m_enabled = CSettings::GetEnabled();
m_enabled = CSettingsInstance().GetEnabled();
app_name = GET_RESOURCE_STRING(IDS_IMAGERESIZER);
};
@ -87,7 +87,7 @@ public:
virtual void enable()
{
m_enabled = true;
CSettings::SetEnabled(m_enabled);
CSettingsInstance().SetEnabled(m_enabled);
Trace::EnableImageResizer(m_enabled);
}
@ -95,7 +95,7 @@ public:
virtual void disable()
{
m_enabled = false;
CSettings::SetEnabled(m_enabled);
CSettingsInstance().SetEnabled(m_enabled);
Trace::EnableImageResizer(m_enabled);
}

View file

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

View file

@ -1,2 +1,2 @@
#include "stdafx.h"
#include "pch.h"
#pragma comment(lib, "windowsapp")

View file

@ -13,6 +13,8 @@
#include "resource.h"
#include <winrt/base.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <atlbase.h>
#include <atlcom.h>
#include <atlfile.h>

View file

@ -1,4 +1,4 @@
#include "stdafx.h"
#include "pch.h"
#include "trace.h"
TRACELOGGING_DEFINE_PROVIDER(

View file

@ -27,6 +27,9 @@
<Setter Property="FontSize" Value="12pt"/>
<Setter Property="Foreground" Value="#039"/>
</Style>
<Style TargetType="TextBox">
<Setter Property="VerticalContentAlignment" Value="Center"/>
</Style>
</Application.Resources>
</Application>

View file

@ -113,7 +113,7 @@
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock Grid.Column="6" Margin="5,0,0,0">
<TextBlock Grid.Column="6" Margin="5,0,0,0" VerticalAlignment="Center">
<Hyperlink Command="{Binding DataContext.RemoveSizeCommand,ElementName=_this}" CommandParameter="{Binding}">
<Run Text="{x:Static p:Resources.Advanced_DeleteSize}"/>
</Hyperlink>

View file

@ -24,6 +24,7 @@
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<RadioButton Margin="0,7,0,0"
VerticalContentAlignment="Center"
Focusable="False"
IsChecked="{Binding IsSelected,RelativeSource={RelativeSource TemplatedParent}}">
<ContentPresenter/>

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
@ -15,7 +16,7 @@
<ProjectGuid>{e364f67b-bb12-4e91-b639-355866ebcd8b}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>Wox_Launcher</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
<ProjectName>Microsoft.Launcher</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@ -59,7 +60,6 @@
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;..\..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@ -80,7 +80,6 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;..\..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@ -117,7 +116,18 @@
<ItemGroup>
<ResourceCompile Include="Microsoft.Launcher.rc" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View file

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

View file

@ -1,6 +1,8 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <common/common.h>
#include <ProjectTelemetry.h>
#include <shellapi.h>

View file

@ -1,4 +1,4 @@
#include "stdafx.h"
#include "pch.h"
#include "resource.h"
#include <CLSID.h>

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
@ -15,7 +16,7 @@
<ProjectGuid>{0485F45C-EA7A-4BB5-804B-3E8D14699387}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>PowerRenameUWPUI</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
@ -45,13 +46,11 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>..\lib\;..\ui\;..\dll\;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>..\lib\;..\ui\;..\dll\;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
</PropertyGroup>
@ -65,7 +64,7 @@
<PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>false</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir)..\;$(ProjectDir)..\ui;$(ProjectDir)..\dll;$(ProjectDir)..\lib;$(ProjectDir)..\..\..\common;$(ProjectDir)..\..\..\common\Telemetry;%(AdditionalIncludeDirectories);$(GeneratedFilesDir)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
@ -75,6 +74,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>WindowsApp.lib;Comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;shcore.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>$(ProjectDir)..\ui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
@ -84,24 +86,27 @@
<PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>false</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>$(ProjectDir)..\;$(ProjectDir)..\ui;$(ProjectDir)..\dll;$(ProjectDir)..\lib;$(ProjectDir)..\..\..\common;$(ProjectDir)..\..\..\common\Telemetry;%(AdditionalIncludeDirectories);$(GeneratedFilesDir)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>WindowsApp.lib;Comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;shcore.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>$(ProjectDir)..\ui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\ui\resource.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\dll\PowerRenameExt.cpp" />
<ClCompile Include="PowerRenameUWPUI.cpp" />
<ClCompile Include="stdafx.cpp">
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
@ -123,7 +128,18 @@
<ItemGroup>
<ResourceCompile Include="PowerRenameUWPUI.rc" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View file

@ -18,10 +18,10 @@
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="stdafx.h">
<ClInclude Include="..\ui\resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\ui\resource.h">
<ClInclude Include="pch.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
@ -29,10 +29,10 @@
<ClCompile Include="PowerRenameUWPUI.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="stdafx.cpp">
<ClCompile Include="..\dll\PowerRenameExt.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\dll\PowerRenameExt.cpp">
<ClCompile Include="pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
@ -46,4 +46,7 @@
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

View file

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

View file

@ -0,0 +1 @@
#include "pch.h"

View file

@ -1,7 +1,6 @@
#pragma once
#include "targetver.h"
#include <Unknwn.h>
#include <winrt/base.h>
#include <Shlwapi.h>
#include "winrt/base.h"

View file

@ -1 +0,0 @@
#include "stdafx.h"

View file

@ -1,4 +1,4 @@
#include "stdafx.h"
#include "pch.h"
#include "PowerRenameExt.h"
#include <PowerRenameUI.h>
#include <PowerRenameItem.h>

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