* Add peek dll project

* add spacebar preview and launch on hotkey press

* add todo

* add process handle to handle continuous press of hotkey

* add tool to stop all powertoys processes

* Add a blank Peek page and update nav menu

* Add some initial content to Peek page including a toggle

* refactor settings parsing

* rename spacebar peek to peek viewer

* rename script to stop powertoys processes

* remove tool

* Adding FileUtils for retrieving selected file in File Explorer

* Remove unnecessary SndPeekSettings

* Add shortcut setting

* Set the shortcut to ctrl+space

* Launching viewer with selected FE file

* Add PeekUI WinUI3 project with interop events

* Moving FileTypeUtils into PeekFileUtils project

* execute winui3 app on hotkey

* Fix paths with spaces

* remove winui3 project

* Resolve comment

* add wpf app with toggle visibility on hotkey

* fix visibility on startup

* remove window properties and add todos

* Fixed hidden extension and system file handling

* wip

* Add working WPF app with FileExplorer querying

* remove c++ projects

* Move native awaiter

* Working Image control with image files

* Resize and move window based on explorer monitor

* Image render, window positioning and sizing clean up

* add window management logic and selection logic

* add extension methods to add circular iterating capability to linkedlistnode

* Add OnArrowKeyPresshandler

* Added titlebar with file name and scaling with titlebar height

* fix flashing window on startup and process kept alive when powertoys exits

* remove wait for debugger loop in ui

* Add KeyIsDown method

* Fix KeyDown issue with Key handled and check for repeat

* Add thumbnail logic

* Add all folder items if only one item is selected

* File type helper

* Using hresult

* Add cancellation and rotation handling

* Use extension instead of path

* fIX CONFLICTS

* Fixing some file type checks

* Add new icon for Peek

* Update page with the new Peek icon

* Initialize IsEnabled and hook ActivationShortcut to dllmain

* add icon to taskbar and titlebar

* Add theme sensitive backgrounds

* rename event handlers

* add settings image

* Move window data into obserable object

* Refactor viewmodel, interop and helpers

* Clean up

* Add loading spinner

* Add todos

* Fix conflicts

* Move native code into its own folder

* Add peek to installer

* Fix building peek and peekui projects

* Replace UWP namespaces to WinAppSDK

* Working WASDK placeholder project

* Add exit when powertoys runner exit

* Working winui3 with image display

* Add WIC project with <TreatWarningAsErros> false for now

* Fit content to window

* Use Size from Windows.Foundation

* Change order

* Add some todos

* Refactored native/interop code and added helpers to imagepreviewer

* Rename projects

* Move some code

* Remove using

Co-authored-by: Michael Salmon <miksalmon@users.noreply.github.com>
Co-authored-by: Michael Salmon 🐟 <michaelpsalmon@outlook.com>
Co-authored-by: Alireza Ebadi Ghajari <alirezae@microsoft.com>
Co-authored-by: Jessie Su <Jessie.Su@microsoft.com>
Co-authored-by: sujessie <102062556+sujessie@users.noreply.github.com>
This commit is contained in:
Samuel Chapleau 2022-12-05 09:16:06 -08:00 committed by GitHub
parent df0a14403c
commit c2aae52bba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
193 changed files with 7777 additions and 4 deletions

View File

@ -468,7 +468,21 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FileLocksmithLibInterop", "
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GPOWrapper", "src\common\GPOWrapper\GPOWrapper.vcxproj", "{E599C30B-9DC8-4E5A-BF27-93D4CCEDE788}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GPOWrapperProjection", "src\common\GPOWrapperProjection\GPOWrapperProjection.csproj", "{00EE9BA6-4E8F-43CA-960D-D4882F0FBB97}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GPOWrapperProjection", "src\common\GPOWrapperProjection\GPOWrapperProjection.csproj", "{00EE9BA6-4E8F-43CA-960D-D4882F0FBB97}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Peek", "Peek", "{17B4FA70-001E-4D33-BBBB-0D142DBC2E20}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Peek.UI.WPF", "src\modules\peek\Peek.UI.WPF\Peek.UI.WPF.csproj", "{C0240BC3-95AF-4B38-811A-76E3FD56B576}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Peek", "src\modules\peek\peek\peek.vcxproj", "{A1425B53-3D61-4679-8623-E64A0D3D0A48}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Peek.UI", "src\modules\peek\Peek.UI\Peek.UI.csproj", "{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Peek.Common", "src\modules\peek\Peek.Common\Peek.Common.csproj", "{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Peek.FilePreviewer", "src\modules\peek\Peek.FilePreviewer\Peek.FilePreviewer.csproj", "{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WIC", "src\modules\peek\WIC\WIC.csproj", "{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -1909,6 +1923,84 @@ Global
{00EE9BA6-4E8F-43CA-960D-D4882F0FBB97}.Release|x64.Build.0 = Release|x64
{00EE9BA6-4E8F-43CA-960D-D4882F0FBB97}.Release|x86.ActiveCfg = Release|x64
{00EE9BA6-4E8F-43CA-960D-D4882F0FBB97}.Release|x86.Build.0 = Release|x64
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Debug|ARM64.ActiveCfg = Debug|ARM64
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Debug|ARM64.Build.0 = Debug|ARM64
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Debug|x64.ActiveCfg = Debug|x64
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Debug|x64.Build.0 = Debug|x64
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Debug|x86.ActiveCfg = Debug|x64
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Debug|x86.Build.0 = Debug|x64
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Release|ARM64.ActiveCfg = Release|ARM64
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Release|ARM64.Build.0 = Release|ARM64
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Release|x64.ActiveCfg = Release|x64
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Release|x64.Build.0 = Release|x64
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Release|x86.ActiveCfg = Release|x64
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Release|x86.Build.0 = Release|x64
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Debug|ARM64.ActiveCfg = Debug|x64
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Debug|ARM64.Build.0 = Debug|x64
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Debug|x64.ActiveCfg = Debug|x64
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Debug|x64.Build.0 = Debug|x64
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Debug|x86.ActiveCfg = Debug|x64
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Debug|x86.Build.0 = Debug|x64
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Release|ARM64.ActiveCfg = Release|x64
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Release|ARM64.Build.0 = Release|x64
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Release|x64.ActiveCfg = Release|x64
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Release|x64.Build.0 = Release|x64
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Release|x86.ActiveCfg = Release|x64
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Release|x86.Build.0 = Release|x64
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Debug|ARM64.ActiveCfg = Debug|ARM64
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Debug|ARM64.Build.0 = Debug|ARM64
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Debug|ARM64.Deploy.0 = Debug|ARM64
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Debug|x64.ActiveCfg = Debug|x64
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Debug|x64.Build.0 = Debug|x64
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Debug|x64.Deploy.0 = Debug|x64
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Debug|x86.ActiveCfg = Debug|x86
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Debug|x86.Build.0 = Debug|x86
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Debug|x86.Deploy.0 = Debug|x86
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Release|ARM64.ActiveCfg = Release|ARM64
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Release|ARM64.Build.0 = Release|ARM64
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Release|ARM64.Deploy.0 = Release|ARM64
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Release|x64.ActiveCfg = Release|x64
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Release|x64.Build.0 = Release|x64
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Release|x64.Deploy.0 = Release|x64
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Release|x86.ActiveCfg = Release|x86
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Release|x86.Build.0 = Release|x86
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Release|x86.Deploy.0 = Release|x86
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Debug|ARM64.ActiveCfg = Debug|ARM64
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Debug|ARM64.Build.0 = Debug|ARM64
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Debug|x64.ActiveCfg = Debug|x64
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Debug|x64.Build.0 = Debug|x64
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Debug|x86.ActiveCfg = Debug|x64
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Debug|x86.Build.0 = Debug|x64
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Release|ARM64.ActiveCfg = Release|ARM64
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Release|ARM64.Build.0 = Release|ARM64
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Release|x64.ActiveCfg = Release|x64
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Release|x64.Build.0 = Release|x64
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Release|x86.ActiveCfg = Release|x64
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Release|x86.Build.0 = Release|x64
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Debug|ARM64.ActiveCfg = Debug|ARM64
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Debug|ARM64.Build.0 = Debug|ARM64
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Debug|x64.ActiveCfg = Debug|x64
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Debug|x64.Build.0 = Debug|x64
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Debug|x86.ActiveCfg = Debug|x64
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Debug|x86.Build.0 = Debug|x64
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Release|ARM64.ActiveCfg = Release|ARM64
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Release|ARM64.Build.0 = Release|ARM64
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Release|x64.ActiveCfg = Release|x64
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Release|x64.Build.0 = Release|x64
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Release|x86.ActiveCfg = Release|x64
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Release|x86.Build.0 = Release|x64
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Debug|ARM64.ActiveCfg = Debug|ARM64
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Debug|ARM64.Build.0 = Debug|ARM64
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Debug|x64.ActiveCfg = Debug|x64
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Debug|x64.Build.0 = Debug|x64
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Debug|x86.ActiveCfg = Debug|x64
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Debug|x86.Build.0 = Debug|x64
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Release|ARM64.ActiveCfg = Release|ARM64
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Release|ARM64.Build.0 = Release|ARM64
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Release|x64.ActiveCfg = Release|x64
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Release|x64.Build.0 = Release|x64
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Release|x86.ActiveCfg = Release|x64
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Release|x86.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -2071,6 +2163,13 @@ Global
{C604B37E-9D0E-4484-8778-E8B31B0E1B3A} = {AB82E5DD-C32D-4F28-9746-2C780846188E}
{E599C30B-9DC8-4E5A-BF27-93D4CCEDE788} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{00EE9BA6-4E8F-43CA-960D-D4882F0FBB97} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{17B4FA70-001E-4D33-BBBB-0D142DBC2E20} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{C0240BC3-95AF-4B38-811A-76E3FD56B576} = {17B4FA70-001E-4D33-BBBB-0D142DBC2E20}
{A1425B53-3D61-4679-8623-E64A0D3D0A48} = {17B4FA70-001E-4D33-BBBB-0D142DBC2E20}
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03} = {17B4FA70-001E-4D33-BBBB-0D142DBC2E20}
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB} = {17B4FA70-001E-4D33-BBBB-0D142DBC2E20}
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC} = {17B4FA70-001E-4D33-BBBB-0D142DBC2E20}
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF} = {17B4FA70-001E-4D33-BBBB-0D142DBC2E20}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}

View File

@ -17,6 +17,7 @@
<?define AlwaysOnTopProjectName="AlwaysOnTop"?>
<?define MeasureToolProjectName="MeasureTool"?>
<?define HostsProjectName="Hosts"?>
<?define PeekProjectName="Peek"?>
<?define RepoDir="$(var.ProjectDir)..\..\" ?>
<?if $(var.Platform) = x64?>
@ -53,7 +54,7 @@
<?define SettingsV2Files=backup_restore_settings.json;Ijwhost.dll;ColorCode.Core.dll;ColorCode.WinUI.dll;CommunityToolkit.Common.dll;CommunityToolkit.Labs.WinUI.SettingsControls.dll;CommunityToolkit.WinUI.dll;CommunityToolkit.WinUI.UI.Controls.Core.dll;CommunityToolkit.WinUI.UI.Controls.DataGrid.dll;CommunityToolkit.WinUI.UI.Controls.Input.dll;CommunityToolkit.WinUI.UI.Controls.Layout.dll;CommunityToolkit.WinUI.UI.Controls.Markdown.dll;CommunityToolkit.WinUI.UI.Controls.Media.dll;CommunityToolkit.WinUI.UI.Controls.Primitives.dll;CommunityToolkit.WinUI.UI.dll;icon.ico;Microsoft.Graphics.Canvas.Interop.dll;Microsoft.InteractiveExperiences.Projection.dll;Microsoft.Windows.ApplicationModel.DynamicDependency.Projection.dll;Microsoft.Windows.ApplicationModel.Resources.Projection.dll;Microsoft.Windows.ApplicationModel.WindowsAppRuntime.Projection.dll;Microsoft.Windows.AppLifecycle.Projection.dll;Microsoft.Windows.SDK.NET.dll;Microsoft.Windows.System.Power.Projection.dll;Microsoft.WindowsAppRuntime.Bootstrap.Net.dll;Microsoft.WinUI.dll;Microsoft.Xaml.Interactions.dll;Microsoft.Xaml.Interactivity.dll;PowerToys.ManagedCommon.dll;PowerToys.ManagedTelemetry.dll;PowerToys.Settings.deps.json;PowerToys.Settings.dll;PowerToys.Settings.exe;PowerToys.Settings.runtimeconfig.json;PowerToys.Settings.UI.Lib.dll;resources.pri;System.CodeDom.dll;System.IO.Abstractions.dll;WinRT.Runtime.dll;Microsoft.Graphics.Canvas.dll;System.Management.dll;PowerToys.GPOWrapper.dll?>
<?define SettingsV2AssetsModulesFiles=ColorPicker.png;FancyZones.png;FileLocksmith.png;AlwaysOnTop.png;HostsFileEditor.png;Awake.png;ImageResizer.png;KBM.png;MouseUtils.png;PowerAccent.png;PowerOCR.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ScreenRuler.png;ShortcutGuide.png;VideoConference.png?>
<?define SettingsV2AssetsModulesFiles=ColorPicker.png;FancyZones.png;FileLocksmith.png;AlwaysOnTop.png;HostsFileEditor.png;Awake.png;ImageResizer.png;KBM.png;MouseUtils.png;PowerAccent.png;PowerOCR.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ScreenRuler.png;ShortcutGuide.png;VideoConference.png;Peek.png?>
<?define SettingsV2OOBEAssetsModulesFiles=ColorPicker.gif;AlwaysOnTop.png;HostsFileEditor.png;Awake.png;FancyZones.gif;FileExplorer.png;FileLocksmith.gif;ImageResizer.gif;KBM.gif;MouseUtils.gif;PowerAccent.gif;PowerOCR.gif;PowerRename.gif;Run.gif;ScreenRuler.gif;OOBEShortcutGuide.png;VideoConferenceMute.png;OOBEPTHero.png?>
@ -542,6 +543,12 @@
<Directory Id="ColorPickerResourcesFolder" Name="Resources"/>
</Directory>
<!-- Peek -->
<Directory Id="PeekInstallFolder" Name="$(var.PeekProjectName)">
<Directory Id="PeekResourcesFolder" Name="Resources"/>
<Directory Id="PeekAssetsFolder" Name="Assets" />
</Directory>
<!-- Mouse Utils -->
<Directory Id="MouseUtilsInstallFolder" Name="$(var.MouseUtilsProjectName)">
</Directory>
@ -1032,6 +1039,31 @@
</Component>
</DirectoryRef>
<!-- Peek -->
<DirectoryRef Id="PeekInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.PeekProjectName)">
<!-- !Warning! Make sure to change Component Guid if you update the file list -->
<Component Id="Module_Peek" Guid="6520F12A-C255-4C3E-862B-0589897BEE21" Win64="yes">
<?foreach File in PowerToys.Peek.dll;PowerToys.Peek.UI.exe;PowerToys.Peek.UI.dll;PowerToys.Peek.UI.deps.json;PowerToys.Peek.UI.runtimeconfig.json;PowerToys.Interop.dll;PowerToys.ManagedTelemetry.dll;PowerToys.ManagedCommon.dll;ControlzEx.dll;Microsoft.Xaml.Behaviors.dll;ModernWpf.Controls.dll;ModernWpf.dll;PowerToys.Common.UI.dll;WinRT.Runtime.dll;Microsoft.Windows.SDK.NET.dll;WpfScreenHelper.dll?>
<File Id="PeekFile_$(var.File)" Source="$(var.BinX64Dir)modules\$(var.PeekProjectName)\$(var.File)" />
<?endforeach?>
</Component>
</DirectoryRef>
<!-- Peek Resources -->
<DirectoryRef Id="PeekResourcesFolder" FileSource="$(var.BinX64Dir)modules\$(var.PeekProjectName)\Resources">
<Component Id="Module_Peek_Icon">
<File Id="PeekFile_icon.ico" Source="$(var.BinX64Dir)modules\$(var.PeekProjectName)\Resources\Peek.ico" />
</Component>
</DirectoryRef>
<!-- Peek Assets -->
<DirectoryRef Id="PeekAssetsFolder" FileSource="$(var.BinX64Dir)modules\$(var.PeekProjectName)\Assets">
<!-- !Warning! Make sure to change Component Guid if you update the file list -->
<Component Id="Module_Peek_Assets" Guid="7E781723-60AB-4027-B634-AFCEDDB2B1CD" Win64="yes">
<File Source="$(var.BinX64Dir)modules\$(var.PeekProjectName)\Assets\error.png" />
</Component>
</DirectoryRef>
<!-- KBM -->
<DirectoryRef Id="KeyboardManagerInstallFolder" FileSource="$(var.BinDir)modules\$(var.KeyboardManagerProjectName)\">
<Component Id="Module_KeyboardManager" Win64="yes">
@ -1332,6 +1364,9 @@
<ComponentRef Id="Module_KeyboardManager_Editor" />
<ComponentRef Id="Module_KeyboardManager_Engine" />
<ComponentRef Id="Module_PowerOCR" />
<ComponentRef Id="Module_Peek" />
<ComponentRef Id="Module_Peek_Icon"/>
<ComponentRef Id="Module_Peek_Assets" />
<ComponentRef Id="Module_ColorPicker" />
<ComponentRef Id="Module_ColorPicker_Icon"/>
<ComponentRef Id="Module_ColorPicker_Cursor"/>
@ -1407,7 +1442,7 @@
<Fragment>
<!-- Resource directories should be added only if the installer is built on the build farm -->
<?ifdef env.IsPipeline?>
<?foreach ParentDirectory in LauncherInstallFolder;FancyZonesInstallFolder;ImageResizerInstallFolder;ColorPickerInstallFolder;FileExplorerPreviewInstallFolder;HistoryPluginFolder;CalculatorPluginFolder;FolderPluginFolder;ProgramPluginFolder;ShellPluginFolder;IndexerPluginFolder;UnitConverterPluginFolder;UriPluginFolder;WindowWalkerPluginFolder;OneNotePluginFolder;RegistryPluginFolder;VSCodeWorkspacesPluginFolder;ServicePluginFolder;SystemPluginFolder;TimeDatePluginFolder;TimeZonePluginFolder;WindowsSettingsPluginFolder;WindowsTerminalPluginFolder;WebSearchPluginFolder?>
<?foreach ParentDirectory in LauncherInstallFolder;FancyZonesInstallFolder;ImageResizerInstallFolder;ColorPickerInstallFolder;PeekInstallFolder;FileExplorerPreviewInstallFolder;HistoryPluginFolder;CalculatorPluginFolder;FolderPluginFolder;ProgramPluginFolder;ShellPluginFolder;IndexerPluginFolder;UnitConverterPluginFolder;UriPluginFolder;WindowWalkerPluginFolder;OneNotePluginFolder;RegistryPluginFolder;VSCodeWorkspacesPluginFolder;ServicePluginFolder;SystemPluginFolder;TimeDatePluginFolder;TimeZonePluginFolder;WindowsSettingsPluginFolder;WindowsTerminalPluginFolder;WebSearchPluginFolder?>
<DirectoryRef Id="$(var.ParentDirectory)">
<!-- Resource file directories -->
<?foreach Language in $(var.LocLanguageList)?>
@ -1561,6 +1596,12 @@
Guid="$(var.CompGUIDPrefix)03">
<File Id="ColorPicker_$(var.IdSafeLanguage)_File" Source="$(var.BinDir)modules\$(var.ColorPickerProjectName)\$(var.Language)\PowerToys.ColorPickerUI.resources.dll" />
</Component>
<Component
Id="Peek_$(var.IdSafeLanguage)_Component"
Directory="Resource$(var.IdSafeLanguage)PeekInstallFolder"
Guid="$(var.CompGUIDPrefix)03">
<File Id="Peek_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\$(var.PeekProjectName)\$(var.Language)\PowerToys.Peek.UI.resources.dll" />
</Component>
<Component
Id="MarkdownPreviewHandler_$(var.IdSafeLanguage)_Component"
Directory="Resource$(var.IdSafeLanguage)FileExplorerPreviewInstallFolder"

View File

@ -1230,7 +1230,7 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
}
processes.resize(bytes / sizeof(processes[0]));
std::array<std::wstring_view, 9> processesToTerminate = {
std::array<std::wstring_view, 10> processesToTerminate = {
L"PowerToys.PowerLauncher.exe",
L"PowerToys.Settings.exe",
L"PowerToys.Awake.exe",
@ -1239,6 +1239,7 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
L"PowerToys.FileLocksmithUI.exe",
L"PowerToys.ColorPickerUI.exe",
L"PowerToys.AlwaysOnTop.exe",
L"PowerToys.PeekUI.exe",
L"PowerToys.exe"
};

View File

@ -203,6 +203,10 @@ public
return gcnew String(CommonSharedConstants::AWAKE_EXIT_EVENT);
}
static String^ ShowPeekEvent() {
return gcnew String(CommonSharedConstants::SHOW_PEEK_SHARED_EVENT);
}
static String ^ PowerAccentExitEvent() {
return gcnew String(CommonSharedConstants::POWERACCENT_EXIT_EVENT);
}

View File

@ -44,6 +44,9 @@ namespace CommonSharedConstants
// Path to the event used by PowerOCR
const wchar_t SHOW_POWEROCR_SHARED_EVENT[] = L"Local\\PowerOCREvent-dc864e06-e1af-4ecc-9078-f98bee745e3a";
// Path to the event used to show Peek
const wchar_t SHOW_PEEK_SHARED_EVENT[] = L"Local\\ShowPeekEvent";
// Max DWORD for key code to disable keys.
const DWORD VK_DISABLED = 0x100;
}

View File

@ -0,0 +1,36 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Peek.Common.Models
{
using System;
using System.Threading.Tasks;
using Windows.Storage;
#nullable enable
public class File
{
private StorageFile? storageFile;
public File(string path)
{
Path = path;
}
public string Path { get; init; }
public string Extension => System.IO.Path.GetExtension(Path);
public async Task<StorageFile> GetStorageFileAsync()
{
if (storageFile == null)
{
storageFile = await StorageFile.GetFileFromPathAsync(Path);
}
return storageFile;
}
}
}

View File

@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Peek.Common.Models
{
public enum HResult
{
Ok = 0x0000,
False = 0x0001,
InvalidArguments = unchecked((int)0x80070057),
OutOfMemory = unchecked((int)0x8007000E),
NoInterface = unchecked((int)0x80004002),
Fail = unchecked((int)0x80004005),
ExtractionFailed = unchecked((int)0x8004B200),
ElementNotFound = unchecked((int)0x80070490),
TypeElementNotFound = unchecked((int)0x8002802B),
NoObject = unchecked((int)0x800401E5),
Win32ErrorCanceled = 1223,
Canceled = unchecked((int)0x800704C7),
ResourceInUse = unchecked((int)0x800700AA),
AccessDenied = unchecked((int)0x80030005),
}
}

View File

@ -0,0 +1,41 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Peek.Common.Models
{
using System;
using System.Runtime.InteropServices;
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")]
public interface IShellItem
{
void BindToHandler(
IntPtr pbc,
[MarshalAs(UnmanagedType.LPStruct)] Guid bhid,
[MarshalAs(UnmanagedType.LPStruct)] Guid riid,
out IntPtr ppv);
void GetParent(out IShellItem ppsi);
void GetDisplayName(Sigdn sigdnName, out IntPtr ppszName);
void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs);
void Compare(IShellItem psi, uint hint, out int piOrder);
}
public enum Sigdn : uint
{
NormalDisplay = 0,
ParentRelativeParsing = 0x80018001,
ParentRelativeForAddressBar = 0x8001c001,
DesktopAbsoluteParsing = 0x80028000,
ParentRelativeEditing = 0x80031001,
DesktopAbsoluteEditing = 0x8004c000,
FileSysPath = 0x80058000,
Url = 0x80068000,
}
}

View File

@ -0,0 +1,50 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Peek.Common.Models
{
using System;
using System.Runtime.InteropServices;
[ComImport]
[Guid("bcc18b79-ba16-442f-80c4-8a59c30c463b")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IShellItemImageFactory
{
[PreserveSig]
HResult GetImage(
[In, MarshalAs(UnmanagedType.Struct)] NativeSize size,
[In] ThumbnailOptions flags,
[Out] out IntPtr phbm);
}
[StructLayout(LayoutKind.Sequential)]
public struct NativeSize
{
private int width;
private int height;
public int Width
{
set { width = value; }
}
public int Height
{
set { height = value; }
}
}
[Flags]
public enum ThumbnailOptions
{
None = 0x00,
BiggerSizeOk = 0x01,
InMemoryOnly = 0x02,
IconOnly = 0x04,
ThumbnailOnly = 0x08,
InCacheOnly = 0x10,
ScaleUp = 0x100,
}
}

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0-windows10.0.19041.0</TargetFramework>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<RootNamespace>Peek.Common</RootNamespace>
<RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
<UseWinUI>true</UseWinUI>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.1.5" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22000.194" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,27 @@
<!-- Copyright (c) Microsoft Corporation and Contributors. -->
<!-- Licensed under the MIT License. -->
<UserControl
x:Class="Peek.FilePreviewer.FilePreview"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:animations="using:CommunityToolkit.WinUI.UI.Animations"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Peek.FilePreviewer"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:media="using:CommunityToolkit.WinUI.UI.Media"
mc:Ignorable="d">
<Grid>
<ProgressRing
HorizontalAlignment="Center"
VerticalAlignment="Center"
IsActive="{x:Bind IsPreviewLoading(Previewer.Preview), Mode=OneWay}" />
<Image x:Name="PreviewImage" Source="{x:Bind Previewer.Preview, Mode=OneWay}" />
<!-- TODO: Add WebView2 support. -->
<!-- TODO: Add UnsupportedFilePreview control -->
</Grid>
</UserControl>

View File

@ -0,0 +1,89 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Peek.FilePreviewer
{
using System;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.WinUI.UI.Media.Pipelines;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media.Imaging;
using Peek.Common.Models;
using Peek.FilePreviewer.Models;
using Peek.FilePreviewer.Previewers;
using Windows.Foundation;
[INotifyPropertyChanged]
public sealed partial class FilePreview : UserControl
{
public event EventHandler<PreviewSizeChangedArgs>? PreviewSizeChanged;
public static readonly DependencyProperty FilesProperty =
DependencyProperty.Register(
nameof(File),
typeof(File),
typeof(FilePreview),
new PropertyMetadata(false, async (d, e) => await ((FilePreview)d).OnFilePropertyChanged()));
[ObservableProperty]
private ImagePreviewer? previewer;
public FilePreview()
{
InitializeComponent();
}
public File File
{
get => (File)GetValue(FilesProperty);
set => SetValue(FilesProperty, value);
}
public bool IsPreviewLoading(BitmapSource? bitmapSource)
{
return bitmapSource == null;
}
private async Task OnFilePropertyChanged()
{
if (File == null)
{
return;
}
// TODO: Implement plugin pattern to support any file types.
if (IsSupportedImage(File.Extension))
{
Previewer = new ImagePreviewer(File);
var size = await Previewer.GetPreviewSizeAsync();
PreviewSizeChanged?.Invoke(this, new PreviewSizeChangedArgs(size));
await Previewer.LoadPreviewAsync();
}
else
{
Previewer = null;
PreviewSizeChanged?.Invoke(this, new PreviewSizeChangedArgs(new Size(1280, 720)));
}
}
// TODO: Find all supported file types for the image previewer
private static bool IsSupportedImage(string extension) => extension switch
{
".bmp" => true,
".gif" => true,
".jpg" => true,
".jfif" => true,
".jfi" => true,
".jif" => true,
".jpeg" => true,
".jpe" => true,
".png" => true,
".tif" => true,
".tiff" => true,
_ => false,
};
}
}

View File

@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Peek.FilePreviewer.Models
{
using Windows.Foundation;
public class PreviewSizeChangedArgs
{
public PreviewSizeChangedArgs(Size windowSizeRequested)
{
WindowSizeRequested = windowSizeRequested;
}
public Size WindowSizeRequested { get; init; }
}
}

View File

@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0-windows10.0.19041.0</TargetFramework>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<RootNamespace>Peek.FilePreviewer</RootNamespace>
<RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
<UseWinUI>true</UseWinUI>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<None Remove="FilePreview.xaml" />
<None Remove="Previewers\ImagePreviewer\ImagePreviewer.cs~RFfdea838.TMP" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.0.0" />
<PackageReference Include="CommunityToolkit.WinUI.UI.Media" Version="7.1.2" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.1.5" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22000.194" />
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Peek.Common\Peek.Common.csproj" />
<ProjectReference Include="..\WIC\WIC.csproj" />
</ItemGroup>
<ItemGroup>
<Page Update="FilePreview.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
</Project>

View File

@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Peek.Common
{
using System;
using System.Runtime.InteropServices;
using Peek.Common.Models;
public static class NativeMethods
{
[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int SHCreateItemFromParsingName(
[MarshalAs(UnmanagedType.LPWStr)] string path,
IntPtr pbc,
ref Guid riid,
[MarshalAs(UnmanagedType.Interface)] out IShellItem shellItem);
[DllImport("gdi32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DeleteObject(IntPtr hObject);
}
}

View File

@ -0,0 +1,63 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Peek.FilePreviewer.Previewers
{
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Peek.Common;
using Peek.Common.Models;
public static class ThumbnailHelper
{
// Based on https://stackoverflow.com/questions/21751747/extract-thumbnail-for-any-file-in-windows
private const string IShellItem2Guid = "7E9FB0D3-919F-4307-AB2E-9B1860310C93";
public static readonly NativeSize HighQualityThumbnailSize = new NativeSize { Width = 720, Height = 720, };
public static readonly NativeSize LowQualityThumbnailSize = new NativeSize { Width = 256, Height = 256, };
private static readonly NativeSize FallBackThumbnailSize = new NativeSize { Width = 96, Height = 96, };
private static readonly NativeSize LastFallBackThumbnailSize = new NativeSize { Width = 32, Height = 32, };
private static readonly List<NativeSize> ThumbnailFallBackSizes = new List<NativeSize>
{
HighQualityThumbnailSize,
LowQualityThumbnailSize,
FallBackThumbnailSize,
LastFallBackThumbnailSize,
};
// TODO: Add a re-try system if there is no thumbnail of requested size.
public static HResult GetThumbnail(string filename, out IntPtr hbitmap, NativeSize thumbnailSize)
{
Guid shellItem2Guid = new Guid(IShellItem2Guid);
int retCode = NativeMethods.SHCreateItemFromParsingName(filename, IntPtr.Zero, ref shellItem2Guid, out IShellItem nativeShellItem);
if (retCode != 0)
{
throw Marshal.GetExceptionForHR(retCode)!;
}
var options = ThumbnailOptions.BiggerSizeOk | ThumbnailOptions.ThumbnailOnly | ThumbnailOptions.ScaleUp;
HResult hr = ((IShellItemImageFactory)nativeShellItem).GetImage(thumbnailSize, options, out hbitmap);
// Try to get thumbnail using the fallback sizes order
if (hr != HResult.Ok)
{
var currentThumbnailFallBackIndex = ThumbnailFallBackSizes.IndexOf(thumbnailSize);
var nextThumbnailFallBackIndex = currentThumbnailFallBackIndex + 1;
if (nextThumbnailFallBackIndex < ThumbnailFallBackSizes.Count - 1)
{
hr = GetThumbnail(filename, out hbitmap, ThumbnailFallBackSizes[nextThumbnailFallBackIndex]);
}
}
Marshal.ReleaseComObject(nativeShellItem);
return hr;
}
}
}

View File

@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Peek.FilePreviewer.Previewers
{
using System;
using System.Threading.Tasks;
using WIC;
public static class WICHelper
{
public static Task<Windows.Foundation.Size> GetImageSize(string filePath)
{
return Task.Run(() =>
{
// TODO: Find a way to get file metadata without hydrating files. Look into Shell API/Windows Property System, e.g., IPropertyStore
IWICImagingFactory factory = (IWICImagingFactory)new WICImagingFactoryClass();
var decoder = factory.CreateDecoderFromFilename(filePath, IntPtr.Zero, StreamAccessMode.GENERIC_READ, WICDecodeOptions.WICDecodeMetadataCacheOnLoad);
var frame = decoder?.GetFrame(0);
int width = 0;
int height = 0;
// TODO: Respect EXIF data and find correct orientation
frame?.GetSize(out width, out height);
return new Windows.Foundation.Size(width, height);
});
}
}
}

View File

@ -0,0 +1,169 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Peek.FilePreviewer.Previewers
{
using System;
using System.Drawing.Imaging;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml.Media.Imaging;
using Peek.Common;
using Windows.Foundation;
using File = Peek.Common.Models.File;
[INotifyPropertyChanged]
public partial class ImagePreviewer : IDisposable
{
[ObservableProperty]
private BitmapSource? preview;
public ImagePreviewer(File file)
{
File = file;
Dispatcher = DispatcherQueue.GetForCurrentThread();
}
private File File { get; }
private DispatcherQueue Dispatcher { get; }
private bool IsHighQualityThumbnailLoaded { get; set; }
private bool IsFullImageLoaded { get; set; }
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private CancellationToken CancellationToken => _cancellationTokenSource.Token;
public void Dispose()
{
_cancellationTokenSource.Dispose();
GC.SuppressFinalize(this);
}
public Task<Size> GetPreviewSizeAsync()
{
return WICHelper.GetImageSize(File.Path);
}
public Task LoadPreviewAsync()
{
var lowQualityThumbnailTask = LoadLowQualityThumbnailAsync();
var highQualityThumbnailTask = LoadHighQualityThumbnailAsync();
var fullImageTask = LoadFullQualityImageAsync();
return Task.WhenAll(lowQualityThumbnailTask, highQualityThumbnailTask, fullImageTask);
}
private Task LoadLowQualityThumbnailAsync()
{
var thumbnailTCS = new TaskCompletionSource();
Dispatcher.TryEnqueue(async () =>
{
if (CancellationToken.IsCancellationRequested)
{
_cancellationTokenSource = new CancellationTokenSource();
return;
}
if (!IsFullImageLoaded && !IsHighQualityThumbnailLoaded)
{
// TODO: Handle thumbnail errors
ThumbnailHelper.GetThumbnail(Path.GetFullPath(File.Path), out IntPtr hbitmap, ThumbnailHelper.LowQualityThumbnailSize);
var thumbnailBitmap = await GetBitmapFromHBitmapAsync(hbitmap);
Preview = thumbnailBitmap;
}
thumbnailTCS.SetResult();
});
return thumbnailTCS.Task;
}
private Task LoadHighQualityThumbnailAsync()
{
var thumbnailTCS = new TaskCompletionSource();
Dispatcher.TryEnqueue(async () =>
{
if (CancellationToken.IsCancellationRequested)
{
_cancellationTokenSource = new CancellationTokenSource();
return;
}
if (!IsFullImageLoaded)
{
// TODO: Handle thumbnail errors
ThumbnailHelper.GetThumbnail(Path.GetFullPath(File.Path), out IntPtr hbitmap, ThumbnailHelper.HighQualityThumbnailSize);
var thumbnailBitmap = await GetBitmapFromHBitmapAsync(hbitmap);
IsHighQualityThumbnailLoaded = true;
Preview = thumbnailBitmap;
}
thumbnailTCS.SetResult();
});
return thumbnailTCS.Task;
}
private Task LoadFullQualityImageAsync()
{
var fullImageTCS = new TaskCompletionSource();
Dispatcher.TryEnqueue(async () =>
{
// TODO: Check if this is performant
var bitmap = await GetFullBitmapFromPathAsync(File.Path);
IsFullImageLoaded = true;
if (CancellationToken.IsCancellationRequested)
{
_cancellationTokenSource = new CancellationTokenSource();
return;
}
Preview = bitmap;
fullImageTCS.SetResult();
});
return fullImageTCS.Task;
}
private static async Task<BitmapImage> GetFullBitmapFromPathAsync(string path)
{
var bitmap = new BitmapImage();
using (FileStream stream = System.IO.File.OpenRead(path))
{
await bitmap.SetSourceAsync(stream.AsRandomAccessStream());
}
return bitmap;
}
private static async Task<BitmapSource> GetBitmapFromHBitmapAsync(IntPtr hbitmap)
{
try
{
var bitmap = System.Drawing.Image.FromHbitmap(hbitmap);
var bitmapImage = new BitmapImage();
using (var stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Bmp);
stream.Position = 0;
await bitmapImage.SetSourceAsync(stream.AsRandomAccessStream());
}
return bitmapImage;
}
finally
{
// delete HBitmap to avoid memory leaks
NativeMethods.DeleteObject(hbitmap);
}
}
}
}

View File

@ -0,0 +1,15 @@
<Application
x:Class="Peek.UI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="http://schemas.modernwpf.com/2019"
StartupUri="Views/MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ui:ThemeResources />
<ui:XamlControlsResources />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@ -0,0 +1,94 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Threading;
using System.Windows;
using Common.UI;
using ManagedCommon;
namespace Peek.UI
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application, IDisposable
{
private ThemeManager? _themeManager;
private Mutex? _instanceMutex;
private static string[] _args = Array.Empty<string>();
private int _powerToysRunnerPid;
private bool disposedValue;
// TODO: Make sure no window appears or blinks at startup
protected override void OnStartup(StartupEventArgs e)
{
_args = e?.Args ?? Array.Empty<string>();
// allow only one instance of peek
_instanceMutex = new Mutex(true, @"Local\PowerToys_Peek_InstanceMutex", out bool createdNew);
if (!createdNew)
{
_instanceMutex = null;
Environment.Exit(0);
return;
}
if (_args?.Length > 0)
{
_ = int.TryParse(_args[0], out _powerToysRunnerPid);
RunnerHelper.WaitForPowerToysRunner(_powerToysRunnerPid, () =>
{
Environment.Exit(0);
});
}
else
{
_powerToysRunnerPid = -1;
}
_themeManager = new ThemeManager(this);
base.OnStartup(e);
}
protected override void OnExit(ExitEventArgs e)
{
if (_instanceMutex != null)
{
_instanceMutex.ReleaseMutex();
}
base.OnExit(e);
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
_instanceMutex?.Dispose();
}
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
// TODO: set large fields to null
disposedValue = true;
}
}
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(true);
GC.SuppressFinalize(this);
}
public bool IsRunningDetachedFromPowerToys()
{
return _powerToysRunnerPid == -1;
}
}
}

View File

@ -0,0 +1,10 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, // where theme specific resource dictionaries are located (used if a resource is not found in the page, or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly) // where the generic resource dictionary is locate (used if a resource is not found in the page, app, or any theme specific resource dictionaries)
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
namespace Peek.UI.Extensions
{
public static class LinkedListNodeExtensions
{
public static LinkedListNode<T>? GetNextOrFirst<T>(this LinkedListNode<T> current)
{
return current.Next ?? current.List?.First;
}
public static LinkedListNode<T>? GetPreviousOrLast<T>(this LinkedListNode<T> current)
{
return current.Previous ?? current.List?.Last;
}
}
}

View File

@ -0,0 +1,61 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Windows;
namespace Peek.UI.Extensions
{
public static class SizeExtensions
{
public static Rect Fit(this Size sizeToFit, Rect bounds, Size maxSize, Size minSize, Size allowedGap, double reservedHeight)
{
double resultingWidth = sizeToFit.Width;
double resultingHeight = sizeToFit.Height;
var ratioWidth = sizeToFit.Width / maxSize.Width;
var ratioHeight = sizeToFit.Height / maxSize.Height;
if (ratioWidth > ratioHeight)
{
if (ratioWidth > 1)
{
resultingWidth = maxSize.Width;
resultingHeight = sizeToFit.Height / ratioWidth;
}
}
else
{
if (ratioHeight > 1)
{
resultingWidth = sizeToFit.Width / ratioHeight;
resultingHeight = maxSize.Height;
}
}
if (resultingWidth < minSize.Width - allowedGap.Width)
{
resultingWidth = minSize.Width;
}
if (resultingHeight < minSize.Height - allowedGap.Height)
{
resultingHeight = minSize.Height;
}
resultingHeight += reservedHeight;
// Calculate offsets to center content
double offsetX = (maxSize.Width - resultingWidth) / 2;
double offsetY = (maxSize.Height - resultingHeight) / 2;
var maxWindowLeft = bounds.Left + ((bounds.Right - bounds.Left - maxSize.Width) / 2);
var maxWindowTop = bounds.Top + ((bounds.Bottom - bounds.Top - maxSize.Height) / 2);
var resultingLeft = maxWindowLeft + offsetX;
var resultingTop = maxWindowTop + offsetY;
return new Rect(resultingLeft, resultingTop, resultingWidth, resultingHeight);
}
}
}

View File

@ -0,0 +1,41 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Windows;
using System.Windows.Interop;
using Peek.UI.Native;
using static Peek.UI.Native.NativeModels;
namespace Peek.UI.Extensions
{
public static class WindowExtensions
{
public static void SetToolStyle(this Window window)
{
var handle = new WindowInteropHelper(window).Handle;
_ = NativeMethods.SetWindowLong(handle, GwlExStyle, NativeMethods.GetWindowLong(handle, GwlExStyle) | WsExToolWindow);
}
public static void BringToForeground(this Window window)
{
// Use SendInput hack to allow Activate to work - required to resolve focus issue https://github.com/microsoft/PowerToys/issues/4270
Input input = new Input { Type = InputType.InputMouse, Data = { } };
Input[] inputs = new Input[] { input };
// Send empty mouse event. This makes this thread the last to send input, and hence allows it to pass foreground permission checks
_ = NativeMethods.SendInput(1, inputs, Input.Size);
window.Activate();
}
public static void RoundCorners(this Window window)
{
IntPtr hWnd = new System.Windows.Interop.WindowInteropHelper(Window.GetWindow(window)).EnsureHandle();
var attribute = DwmWindowAttributed.DwmaWindowCornerPreference;
var preference = DwmWindowCornerPreference.DwmCpRound;
NativeMethods.DwmSetWindowAttribute(hWnd, attribute, ref preference, sizeof(uint));
}
}
}

View File

@ -0,0 +1,34 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
namespace Peek.UI.Helpers
{
public static class FileExplorerHelper
{
public static IEnumerable<string> GetSelectedItems(IntPtr handle)
{
var selectedItems = new List<string>();
var shell = new Shell32.Shell();
foreach (SHDocVw.InternetExplorer window in shell.Windows())
{
if (window.HWND == (int)handle)
{
Shell32.FolderItems items = ((Shell32.IShellFolderViewDual2)window.Document).SelectedItems();
if (items != null && items.Count > 0)
{
foreach (Shell32.FolderItem item in items)
{
selectedItems.Add(item.Path);
}
}
}
}
return selectedItems;
}
}
}

View File

@ -0,0 +1,122 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
using Peek.UI.Models;
namespace Peek.UI.Helpers
{
public static class FileLoadHelper
{
public static Task<DimensionData> LoadDimensionsAsync(string filename)
{
return Task.Run(() =>
{
Size size = new Size(0, 0);
try
{
using (FileStream stream = File.OpenRead(filename))
{
string extension = Path.GetExtension(stream.Name);
if (FileTypeHelper.IsSupportedImage(extension))
{
using (System.Drawing.Image sourceImage = System.Drawing.Image.FromStream(stream, false, false))
{
var rotation = EvaluateRotationToApply(sourceImage);
if (rotation == Rotation.Rotate90 || rotation == Rotation.Rotate270)
{
size = new Size(sourceImage.Height, sourceImage.Width);
}
else
{
size = new Size(sourceImage.Width, sourceImage.Height);
}
return Task.FromResult(new DimensionData { Size = size, Rotation = rotation });
}
}
else
{
return Task.FromResult(new DimensionData { Size = size, Rotation = Rotation.Rotate0 });
}
}
}
catch (Exception)
{
return Task.FromResult(new DimensionData { Size = size, Rotation = Rotation.Rotate0 });
}
});
}
public static async Task<BitmapSource> LoadThumbnailAsync(string filename, bool iconFallback)
{
var thumbnail = await Task.Run(() =>
{
var bitmapSource = ThumbnailHelper.GetThumbnail(filename, iconFallback);
bitmapSource.Freeze();
return bitmapSource;
});
return thumbnail;
}
public static Task<BitmapSource> LoadIconAsync(string filename)
{
return Task.Run(() =>
{
var bitmapSource = ThumbnailHelper.GetIcon(filename);
bitmapSource.Freeze();
return bitmapSource;
});
}
public static Task<BitmapImage> LoadFullImageAsync(string filename, Rotation rotation)
{
return Task.Run(() =>
{
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.UriSource = new Uri(filename);
bitmap.Rotation = rotation;
bitmap.EndInit();
bitmap.Freeze();
return bitmap;
});
}
private static Rotation EvaluateRotationToApply(System.Drawing.Image image)
{
PropertyItem? property = image.PropertyItems?.FirstOrDefault(p => p.Id == 274);
if (property != null && property.Value != null && property.Value.Length > 0)
{
int orientation = property.Value[0];
if (orientation == 6)
{
return Rotation.Rotate90;
}
if (orientation == 3)
{
return Rotation.Rotate180;
}
if (orientation == 8)
{
return Rotation.Rotate270;
}
}
return Rotation.Rotate0;
}
}
}

View File

@ -0,0 +1,77 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Peek.UI.Native;
using static Peek.UI.Native.NativeModels;
namespace Peek.UI.Helpers
{
public static class FileTypeHelper
{
public static bool IsSupportedImage(string extension) => extension switch
{
".bmp" => true,
".gif" => true,
".jpg" => true,
".jfif" => true,
".jfi" => true,
".jif" => true,
".jpeg" => true,
".jpe" => true,
".png" => true,
".tif" => true,
".tiff" => true,
_ => false,
};
public static bool IsMedia(string extension)
{
return IsImage(extension) || IsVideo(extension);
}
public static bool IsImage(string extension)
{
return IsPerceivedType(extension, PerceivedType.Image);
}
public static bool IsVideo(string extension)
{
return IsPerceivedType(extension, PerceivedType.Video);
}
public static bool IsDocument(string extension)
{
return IsPerceivedType(extension, PerceivedType.Document);
}
internal static bool IsPerceivedType(string extension, PerceivedType perceivedType)
{
if (string.IsNullOrEmpty(extension))
{
return false;
}
PerceivedType perceived;
Perceived flag;
bool isPerceivedType = false;
try
{
if (NativeMethods.AssocGetPerceivedType(extension, out perceived, out flag, IntPtr.Zero) == HResult.Ok)
{
isPerceivedType = perceived == perceivedType;
}
}
catch (Exception)
{
// TODO: AssocGetPerceivedType throws on some file types (json, ps1, exe, etc.)
// Properly handle these
return false;
}
return isPerceivedType;
}
}
}

View File

@ -0,0 +1,128 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
using Peek.UI.Models;
using Peek.UI.Native;
using static Peek.UI.Native.NativeModels;
namespace Peek.UI.Helpers
{
public static class ThumbnailHelper
{
private static readonly Assembly Assembly = Assembly.GetExecutingAssembly();
public static readonly string ProgramDirectory = Directory.GetParent(Assembly.Location)!.ToString();
public static readonly string ErrorIcon = Path.Combine(ProgramDirectory, "Assets", "error.png");
// Based on https://stackoverflow.com/questions/21751747/extract-thumbnail-for-any-file-in-windows
private const string IShellItem2Guid = "7E9FB0D3-919F-4307-AB2E-9B1860310C93";
public static BitmapSource GetIcon(string fileName)
{
IntPtr hbitmap;
HResult hr = GetIconImpl(Path.GetFullPath(fileName), out hbitmap);
if (hr != HResult.Ok)
{
return new BitmapImage(new Uri(ErrorIcon));
}
try
{
return Imaging.CreateBitmapSourceFromHBitmap(hbitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
}
finally
{
// delete HBitmap to avoid memory leaks
NativeMethods.DeleteObject(hbitmap);
}
}
public static BitmapSource GetThumbnail(string fileName, bool iconFallback)
{
IntPtr hbitmap;
HResult hr = GetThumbnailImpl(Path.GetFullPath(fileName), out hbitmap);
if (hr != HResult.Ok && iconFallback)
{
return GetIcon(fileName);
}
try
{
return Imaging.CreateBitmapSourceFromHBitmap(hbitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
}
finally
{
// delete HBitmap to avoid memory leaks
NativeMethods.DeleteObject(hbitmap);
}
}
private static HResult GetIconImpl(string filename, out IntPtr hbitmap)
{
Guid shellItem2Guid = new Guid(IShellItem2Guid);
int retCode = NativeMethods.SHCreateItemFromParsingName(filename, IntPtr.Zero, ref shellItem2Guid, out IShellItem nativeShellItem);
if (retCode != 0)
{
throw Marshal.GetExceptionForHR(retCode)!;
}
NativeSize large = new NativeSize { Width = 256, Height = 256 };
var options = ThumbnailOptions.BiggerSizeOk | ThumbnailOptions.IconOnly;
HResult hr = ((IShellItemImageFactory)nativeShellItem).GetImage(large, options, out hbitmap);
Marshal.ReleaseComObject(nativeShellItem);
return hr;
}
private static HResult GetThumbnailImpl(string filename, out IntPtr hbitmap)
{
Guid shellItem2Guid = new Guid(IShellItem2Guid);
int retCode = NativeMethods.SHCreateItemFromParsingName(filename, IntPtr.Zero, ref shellItem2Guid, out IShellItem nativeShellItem);
if (retCode != 0)
{
throw Marshal.GetExceptionForHR(retCode)!;
}
var extraLarge = new NativeSize { Width = 1024, Height = 1024, };
var large = new NativeSize { Width = 256, Height = 256 };
var medium = new NativeSize { Width = 96, Height = 96 };
var small = new NativeSize { Width = 32, Height = 32 };
var options = ThumbnailOptions.BiggerSizeOk | ThumbnailOptions.ThumbnailOnly | ThumbnailOptions.ScaleUp;
HResult hr = ((IShellItemImageFactory)nativeShellItem).GetImage(extraLarge, options, out hbitmap);
if (hr != HResult.Ok)
{
hr = ((IShellItemImageFactory)nativeShellItem).GetImage(large, options, out hbitmap);
}
if (hr != HResult.Ok)
{
hr = ((IShellItemImageFactory)nativeShellItem).GetImage(medium, options, out hbitmap);
}
if (hr != HResult.Ok)
{
hr = ((IShellItemImageFactory)nativeShellItem).GetImage(small, options, out hbitmap);
}
Marshal.ReleaseComObject(nativeShellItem);
return hr;
}
}
}

View File

@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
namespace Peek.UI.Models
{
public class DimensionData
{
public Size Size { get; set; }
public Rotation Rotation { get; set; }
}
}

View File

@ -0,0 +1,30 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices;
using static Peek.UI.Native.NativeModels;
namespace Peek.UI.Models
{
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")]
internal interface IShellItem
{
void BindToHandler(
IntPtr pbc,
[MarshalAs(UnmanagedType.LPStruct)] Guid bhid,
[MarshalAs(UnmanagedType.LPStruct)] Guid riid,
out IntPtr ppv);
void GetParent(out IShellItem ppsi);
void GetDisplayName(Sigdn sigdnName, out IntPtr ppszName);
void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs);
void Compare(IShellItem psi, uint hint, out int piOrder);
}
}

View File

@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace Peek.UI.Models
{
public abstract class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View File

@ -0,0 +1,85 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Peek.UI.Models
{
public class ObservableRectangle : ObservableObject
{
private double _left;
public double Left
{
get
{
return _left;
}
set
{
if (_left != value)
{
_left = value;
OnPropertyChanged(nameof(Left));
}
}
}
private double _top;
public double Top
{
get
{
return _top;
}
set
{
if (_top != value)
{
_top = value;
OnPropertyChanged(nameof(Top));
}
}
}
private double _height;
public double Height
{
get
{
return _height;
}
set
{
if (_height != value)
{
_height = value;
OnPropertyChanged(nameof(Height));
}
}
}
private double _width;
public double Width
{
get
{
return _width;
}
set
{
if (_width != value)
{
_width = value;
OnPropertyChanged(nameof(Width));
}
}
}
}
}

View File

@ -0,0 +1,88 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Windows;
namespace Peek.UI.Models
{
public class ObservableWindowData : ObservableObject
{
private double _titleBarHeight;
public double TitleBarHeight
{
get
{
return _titleBarHeight;
}
set
{
if (_titleBarHeight != value)
{
_titleBarHeight = value;
OnPropertyChanged(nameof(TitleBarHeight));
}
}
}
private ObservableRectangle _rectangle = new ObservableRectangle();
public ObservableRectangle Rectangle
{
get
{
return _rectangle;
}
set
{
if (_rectangle != value)
{
_rectangle = value;
OnPropertyChanged(nameof(Rectangle));
}
}
}
private string _title = string.Empty;
public string Title
{
get
{
return _title;
}
set
{
if (_title != value)
{
_title = value;
OnPropertyChanged(nameof(Title));
}
}
}
private Visibility _visibility;
public Visibility Visibility
{
get
{
return _visibility;
}
set
{
if (_visibility != value)
{
_visibility = value;
OnPropertyChanged(nameof(Visibility));
}
}
}
}
}

View File

@ -0,0 +1,28 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Threading;
using System.Windows;
namespace Peek.UI.Native
{
public static class NativeEventWaiter
{
public static void WaitForEventLoop(string eventName, Action callback)
{
new Thread(() =>
{
var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName);
while (true)
{
if (eventHandle.WaitOne())
{
Application.Current.Dispatcher.Invoke(callback);
}
}
}).Start();
}
}
}

View File

@ -0,0 +1,54 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices;
using Peek.UI.Models;
using static Peek.UI.Native.NativeModels;
namespace Peek.UI.Native
{
public static class NativeMethods
{
[DllImport("dwmapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern long DwmSetWindowAttribute(
IntPtr hwnd,
DwmWindowAttributed attribute,
ref DwmWindowCornerPreference pvAttribute,
uint cbAttribute);
[DllImport("gdi32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DeleteObject(IntPtr hObject);
[DllImport("Shlwapi.dll", ExactSpelling = true, PreserveSig = false)]
internal static extern HResult AssocGetPerceivedType(
[MarshalAs(UnmanagedType.LPWStr)] string extension,
out PerceivedType perceivedType,
out Perceived perceivedFlags,
IntPtr ptrType);
[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int SHCreateItemFromParsingName(
[MarshalAs(UnmanagedType.LPWStr)] string path,
IntPtr pbc,
ref Guid riid,
[MarshalAs(UnmanagedType.Interface)] out IShellItem shellItem);
[DllImport("user32.dll", SetLastError = true)]
internal static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
internal static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
internal static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);
[DllImport("user32.dll")]
internal static extern uint SendInput(uint nInputs, Input[] pInputs, int cbSize);
}
}

View File

@ -0,0 +1,182 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices;
namespace Peek.UI.Native
{
public class NativeModels
{
public const int GwlExStyle = -20;
public const int WsExToolWindow = 0x00000080;
public enum PerceivedType
{
Folder = -1,
Unknown = 0,
Image = 2,
Video = 4,
Document = 6,
}
public enum Perceived
{
Undefined = 0x0000,
Softcoded = 0x0001,
Hardcoded = 0x0002,
NativeSupport = 0x0004,
GdiPlus = 0x0010,
WMSDK = 0x0020,
ZipFolder = 0x0040,
}
public enum HResult
{
Ok = 0x0000,
False = 0x0001,
InvalidArguments = unchecked((int)0x80070057),
OutOfMemory = unchecked((int)0x8007000E),
NoInterface = unchecked((int)0x80004002),
Fail = unchecked((int)0x80004005),
ExtractionFailed = unchecked((int)0x8004B200),
ElementNotFound = unchecked((int)0x80070490),
TypeElementNotFound = unchecked((int)0x8002802B),
NoObject = unchecked((int)0x800401E5),
Win32ErrorCanceled = 1223,
Canceled = unchecked((int)0x800704C7),
ResourceInUse = unchecked((int)0x800700AA),
AccessDenied = unchecked((int)0x80030005),
}
[StructLayout(LayoutKind.Sequential)]
public struct Input
{
public InputType Type;
public InputUnion Data;
public static int Size
{
get { return Marshal.SizeOf(typeof(Input)); }
}
}
[StructLayout(LayoutKind.Explicit)]
public struct InputUnion
{
[FieldOffset(0)]
public MouseInput Mi;
[FieldOffset(0)]
public KeybdInput Ki;
[FieldOffset(0)]
public HardwareInput Hi;
}
[StructLayout(LayoutKind.Sequential)]
public struct MouseInput
{
public int Dx;
public int Dy;
public int MouseData;
public uint DwFlags;
public uint Time;
public UIntPtr DwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct KeybdInput
{
public short WVk;
public short WScan;
public uint DwFlags;
public int Time;
public UIntPtr DwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct HardwareInput
{
public int UMsg;
public short WParamL;
public short WParamH;
}
public enum InputType : uint
{
InputMouse = 0,
InputKeyboard = 1,
InputHardware = 2,
}
public enum Sigdn : uint
{
NormalDisplay = 0,
ParentRelativeParsing = 0x80018001,
ParentRelativeForAddressBar = 0x8001c001,
DesktopAbsoluteParsing = 0x80028000,
ParentRelativeEditing = 0x80031001,
DesktopAbsoluteEditing = 0x8004c000,
FileSysPath = 0x80058000,
Url = 0x80068000,
}
public enum DwmWindowAttributed
{
DwmaWindowCornerPreference = 33,
}
// The DWM_WINDOW_CORNER_PREFERENCE enum for DwmSetWindowAttribute's third parameter, which tells the function
// what value of the enum to set.
public enum DwmWindowCornerPreference
{
DwmCpDefault = 0,
DwmCpDoNotRound = 1,
DwmCpRound = 2,
DwmCpRoundSmall = 3,
}
[Flags]
public enum ThumbnailOptions
{
None = 0x00,
BiggerSizeOk = 0x01,
InMemoryOnly = 0x02,
IconOnly = 0x04,
ThumbnailOnly = 0x08,
InCacheOnly = 0x10,
ScaleUp = 0x100,
}
[ComImport]
[Guid("bcc18b79-ba16-442f-80c4-8a59c30c463b")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IShellItemImageFactory
{
[PreserveSig]
HResult GetImage(
[In, MarshalAs(UnmanagedType.Struct)] NativeSize size,
[In] ThumbnailOptions flags,
[Out] out IntPtr phbm);
}
[StructLayout(LayoutKind.Sequential)]
internal struct NativeSize
{
private int width;
private int height;
public int Width
{
set { width = value; }
}
public int Height
{
set { height = value; }
}
}
}
}

View File

@ -0,0 +1,90 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows10.0.19041.0</TargetFramework>
<AssemblyName>PowerToys.Peek.UI</AssemblyName>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\modules\Peek\</OutputPath>
<UseWindowsForms>True</UseWindowsForms>
<ApplicationIcon>Resources\FluentIconsPeek.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<COMReference Include="Shell32">
<WrapperTool>tlbimp</WrapperTool>
<VersionMinor>0</VersionMinor>
<VersionMajor>1</VersionMajor>
<Guid>50a7e9b0-70ef-11d1-b75a-00a0c90564fe</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>
<COMReference Include="SHDocVw">
<WrapperTool>tlbimp</WrapperTool>
<VersionMinor>1</VersionMinor>
<VersionMajor>1</VersionMajor>
<Guid>eab22ac0-30c1-11cf-a7eb-0000c05bae0b</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<PropertyGroup>
<ApplicationIcon>Resources\Peek.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Resource Include="Resources\Peek.ico" />
</ItemGroup>
<ItemGroup>
<None Update="Resources\Peek.ico">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Assets\error.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="ModernWpfUI" Version="0.9.4" />
<PackageReference Include="WpfScreenHelper" Version="2.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
<ProjectReference Include="..\..\..\common\interop\PowerToys.Interop.vcxproj" />
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
</ItemGroup>
<ItemGroup>
<Page Update="Themes\Dark.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
</Page>
<Page Update="Themes\HighContrast1.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
</Page>
<Page Update="Themes\HighContrast2.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
</Page>
<Page Update="Themes\HighContrastBlack.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
</Page>
<Page Update="Themes\HighContrastWhite.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
</Page>
<Page Update="Themes\Light.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
</Page>
</ItemGroup>
<ItemGroup>
<Folder Include="Views\" />
</ItemGroup>
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

View File

@ -0,0 +1,19 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=System.Runtime">
<!-- Metadata -->
<system:String x:Key="Theme.Name">Dark.Accent1</system:String>
<system:String x:Key="Theme.Origin">PowerToysPeek</system:String>
<system:String x:Key="Theme.DisplayName">Accent1 (Dark)</system:String>
<system:String x:Key="Theme.BaseColorScheme">Dark</system:String>
<system:String x:Key="Theme.ColorScheme">Accent1</system:String>
<Color x:Key="Theme.PrimaryAccentColor">Black</Color>
<SolidColorBrush x:Key="SecondaryBackgroundBrush" Color="#FF3a3a3a" />
<SolidColorBrush x:Key="PrimaryBackgroundBrush" Color="#FF333333" />
<SolidColorBrush x:Key="PrimaryForegroundBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="SecondaryForegroundBrush" Color="#FF999999" />
<SolidColorBrush x:Key="PrimaryBorderBrush" Color="Transparent" />
</ResourceDictionary>

View File

@ -0,0 +1,19 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=System.Runtime">
<!-- Metadata -->
<system:String x:Key="Theme.Name">HighContrast.Accent2</system:String>
<system:String x:Key="Theme.Origin">PowerToysPeek</system:String>
<system:String x:Key="Theme.DisplayName">Accent2 (HighContrast)</system:String>
<system:String x:Key="Theme.BaseColorScheme">HighContrast</system:String>
<system:String x:Key="Theme.ColorScheme">Accent2</system:String>
<Color x:Key="Theme.PrimaryAccentColor">White</Color>
<SolidColorBrush x:Key="SecondaryBackgroundBrush" Color="#FF3a3a3a" />
<SolidColorBrush x:Key="PrimaryBackgroundBrush" Color="#FF333333" />
<SolidColorBrush x:Key="PrimaryForegroundBrush" Color="#FFffff00" />
<SolidColorBrush x:Key="SecondaryForegroundBrush" Color="#FF00ff00" />
<SolidColorBrush x:Key="PrimaryBorderBrush" Color="#FFffff00" />
</ResourceDictionary>

View File

@ -0,0 +1,19 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=System.Runtime">
<!-- Metadata -->
<system:String x:Key="Theme.Name">HighContrast.Accent3</system:String>
<system:String x:Key="Theme.Origin">PowerToysPeek</system:String>
<system:String x:Key="Theme.DisplayName">Accent3 (HighContrast)</system:String>
<system:String x:Key="Theme.BaseColorScheme">HighContrast</system:String>
<system:String x:Key="Theme.ColorScheme">Accent3</system:String>
<Color x:Key="Theme.PrimaryAccentColor">White</Color>
<SolidColorBrush x:Key="SecondaryBackgroundBrush" Color="#FF3a3a3a" />
<SolidColorBrush x:Key="PrimaryBackgroundBrush" Color="#FF333333" />
<SolidColorBrush x:Key="PrimaryForegroundBrush" Color="#FF00ff00" />
<SolidColorBrush x:Key="SecondaryForegroundBrush" Color="#FFc0c0c0" />
<SolidColorBrush x:Key="PrimaryBorderBrush" Color="#FF00ff00" />
</ResourceDictionary>

View File

@ -0,0 +1,19 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=System.Runtime">
<!-- Metadata -->
<system:String x:Key="Theme.Name">HighContrast.Accent4</system:String>
<system:String x:Key="Theme.Origin">PowerToysPeek</system:String>
<system:String x:Key="Theme.DisplayName">Accent4 (HighContrast)</system:String>
<system:String x:Key="Theme.BaseColorScheme">HighContrast</system:String>
<system:String x:Key="Theme.ColorScheme">Accent4</system:String>
<Color x:Key="Theme.PrimaryAccentColor">White</Color>
<SolidColorBrush x:Key="SecondaryBackgroundBrush" Color="#FF3a3a3a" />
<SolidColorBrush x:Key="PrimaryBackgroundBrush" Color="#FF333333" />
<SolidColorBrush x:Key="PrimaryForegroundBrush" Color="#FFffffff" />
<SolidColorBrush x:Key="SecondaryForegroundBrush" Color="#FF1aebff" />
<SolidColorBrush x:Key="PrimaryBorderBrush" Color="White" />
</ResourceDictionary>

View File

@ -0,0 +1,19 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=System.Runtime">
<!-- Metadata -->
<system:String x:Key="Theme.Name">HighContrast.Accent5</system:String>
<system:String x:Key="Theme.Origin">PowerToysPeek</system:String>
<system:String x:Key="Theme.DisplayName">Accent5 (HighContrast)</system:String>
<system:String x:Key="Theme.BaseColorScheme">HighContrast</system:String>
<system:String x:Key="Theme.ColorScheme">Accent5</system:String>
<Color x:Key="Theme.PrimaryAccentColor">White</Color>
<SolidColorBrush x:Key="SecondaryBackgroundBrush" Color="#FFf3f3f3" />
<SolidColorBrush x:Key="PrimaryBackgroundBrush" Color="#FFffffff" />
<SolidColorBrush x:Key="PrimaryForegroundBrush" Color="#FF000000" />
<SolidColorBrush x:Key="SecondaryForegroundBrush" Color="#FF676666" />
<SolidColorBrush x:Key="PrimaryBorderBrush" Color="Black" />
</ResourceDictionary>

View File

@ -0,0 +1,19 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=System.Runtime">
<!-- Metadata -->
<system:String x:Key="Theme.Name">Light.Accent1</system:String>
<system:String x:Key="Theme.Origin">PowerToysPeek</system:String>
<system:String x:Key="Theme.DisplayName">Accent1 (Light)</system:String>
<system:String x:Key="Theme.BaseColorScheme">Light</system:String>
<system:String x:Key="Theme.ColorScheme">Accent1</system:String>
<Color x:Key="Theme.PrimaryAccentColor">White</Color>
<SolidColorBrush x:Key="SecondaryBackgroundBrush" Color="#FFf3f3f3" />
<SolidColorBrush x:Key="PrimaryBackgroundBrush" Color="#FFffffff" />
<SolidColorBrush x:Key="PrimaryForegroundBrush" Color="#FF000000" />
<SolidColorBrush x:Key="SecondaryForegroundBrush" Color="#FF676666" />
<SolidColorBrush x:Key="PrimaryBorderBrush" Color="Transparent" />
</ResourceDictionary>

View File

@ -0,0 +1,301 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using Peek.UI.Extensions;
using Peek.UI.Helpers;
using Peek.UI.Models;
using Peek.UI.Native;
using WpfScreenHelper;
using Size = System.Windows.Size;
namespace Peek.UI.ViewModels
{
public class MainViewModel : ObservableObject, IDisposable
{
private const double ImageScale = 0.75;
private static readonly Size MinWindowSize = new Size(720, 720);
private static readonly Size AllowedContentGap = new Size(220, 220);
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private CancellationToken CancellationToken => _cancellationTokenSource.Token;
public IntPtr ForegroundWindowHandle { get; internal set; }
public Image ImageControl { get; set; }
public LinkedList<string> SelectedFilePaths { get; set; } = new LinkedList<string>();
private BitmapSource? _bitmap;
public BitmapSource? Bitmap
{
get
{
return _bitmap;
}
set
{
if (_bitmap != value)
{
_bitmap = value;
OnPropertyChanged(nameof(Bitmap));
}
}
}
private LinkedListNode<string>? _currentSelectedFilePath;
public LinkedListNode<string>? CurrentSelectedFilePath
{
get
{
return _currentSelectedFilePath;
}
set
{
if (_currentSelectedFilePath != value)
{
_currentSelectedFilePath = value;
var title = Path.GetFileName(_currentSelectedFilePath?.Value ?? string.Empty);
MainWindowData.Title = title;
OnPropertyChanged(nameof(CurrentSelectedFilePath));
}
}
}
public Visibility IsImageReady => IsLoading ? Visibility.Collapsed : Visibility.Visible;
private bool _isLoading = true;
public bool IsLoading
{
get
{
return _isLoading;
}
set
{
if (_isLoading != value)
{
_isLoading = value;
OnPropertyChanged(nameof(IsLoading));
OnPropertyChanged(nameof(IsImageReady));
}
}
}
private ObservableWindowData _mainWindowData = new ObservableWindowData();
public ObservableWindowData MainWindowData
{
get
{
return _mainWindowData;
}
set
{
if (_mainWindowData != value)
{
_mainWindowData = value;
OnPropertyChanged(nameof(MainWindowData));
}
}
}
public MainViewModel(Image imageControl)
{
ImageControl = imageControl;
}
// TODO: Implement proper disposal pattern
public void Dispose()
{
_cancellationTokenSource.Dispose();
GC.SuppressFinalize(this);
}
public void ClearSelection()
{
_cancellationTokenSource.Cancel();
_cancellationTokenSource = new CancellationTokenSource();
CurrentSelectedFilePath = null;
MainWindowData.Visibility = Visibility.Collapsed;
}
public bool TryUpdateSelectedFilePaths()
{
ForegroundWindowHandle = NativeMethods.GetForegroundWindow();
// TODO: Get all neighborings files in correct sorted order
var selectedItems = FileExplorerHelper.GetSelectedItems(ForegroundWindowHandle);
var isDifferentSelectedItems = !SelectedFilePaths.SequenceEqual(selectedItems);
if (isDifferentSelectedItems)
{
SelectedFilePaths = new LinkedList<string>(selectedItems);
}
CurrentSelectedFilePath = SelectedFilePaths.First;
return isDifferentSelectedItems;
}
// TODO: Implement proper cancellation pattern to support quick navigation
public async Task RenderImageToWindowAsync(string filename)
{
IsLoading = true;
var screen = Screen.FromHandle(ForegroundWindowHandle);
Size maxWindowSize = new Size(screen.WpfBounds.Width * ImageScale, screen.WpfBounds.Height * ImageScale);
// TODO: Support preview or thumbnail for document files
if (FileTypeHelper.IsSupportedImage(Path.GetExtension(filename)))
{
await RenderSupportedImageToWindowAsync(filename, screen.Bounds, maxWindowSize);
}
else if (FileTypeHelper.IsMedia(Path.GetExtension(filename)) || FileTypeHelper.IsDocument(Path.GetExtension(filename)))
{
await RenderMediaOrDocumentToWindowAsync(filename, screen.Bounds, maxWindowSize);
}
else
{
await RenderUnsupportedFileToWindowAsync(filename, screen.Bounds, maxWindowSize);
}
}
private async Task RenderSupportedImageToWindowAsync(string filename, Rect windowBounds, Size maxWindowSize)
{
DimensionData dimensionData = await FileLoadHelper.LoadDimensionsAsync(filename);
if (CancellationToken.IsCancellationRequested)
{
_cancellationTokenSource = new CancellationTokenSource();
return;
}
var windowRect = dimensionData.Size.Fit(windowBounds, maxWindowSize, MinWindowSize, AllowedContentGap, MainWindowData.TitleBarHeight);
MainWindowData.Rectangle.Width = windowRect.Width;
MainWindowData.Rectangle.Height = windowRect.Height;
MainWindowData.Rectangle.Left = windowRect.Left;
MainWindowData.Rectangle.Top = windowRect.Top;
if (dimensionData.Size.Width > MainWindowData.Rectangle.Width || dimensionData.Size.Height > MainWindowData.Rectangle.Height)
{
ImageControl.StretchDirection = StretchDirection.Both;
}
else
{
ImageControl.StretchDirection = StretchDirection.DownOnly;
}
await LoadImageAsync(filename, ImageControl, dimensionData.Rotation, CancellationToken);
}
private async Task RenderMediaOrDocumentToWindowAsync(string filename, Rect windowBounds, Size maxWindowSize)
{
var bitmap = await FileLoadHelper.LoadThumbnailAsync(filename, true);
if (CancellationToken.IsCancellationRequested)
{
_cancellationTokenSource = new CancellationTokenSource();
return;
}
Bitmap = bitmap;
var imageSize = new Size(bitmap.PixelWidth, bitmap.PixelHeight);
var windowRect = imageSize.Fit(windowBounds, maxWindowSize, MinWindowSize, AllowedContentGap, MainWindowData.TitleBarHeight);
MainWindowData.Rectangle.Width = windowRect.Width;
MainWindowData.Rectangle.Height = windowRect.Height;
MainWindowData.Rectangle.Left = windowRect.Left;
MainWindowData.Rectangle.Top = windowRect.Top;
MainWindowData.Visibility = Visibility.Visible;
IsLoading = false;
}
private async Task RenderUnsupportedFileToWindowAsync(string filename, Rect windowBounds, Size maxWindowSize)
{
var contentSize = new Size(0, 0);
var windowRect = contentSize.Fit(windowBounds, maxWindowSize, MinWindowSize, AllowedContentGap, MainWindowData.TitleBarHeight);
MainWindowData.Rectangle.Width = windowRect.Width;
MainWindowData.Rectangle.Height = windowRect.Height;
MainWindowData.Rectangle.Left = windowRect.Left;
MainWindowData.Rectangle.Top = windowRect.Top;
var bitmap = await FileLoadHelper.LoadIconAsync(filename);
if (CancellationToken.IsCancellationRequested)
{
_cancellationTokenSource = new CancellationTokenSource();
return;
}
Bitmap = bitmap;
MainWindowData.Visibility = Visibility.Visible;
IsLoading = false;
}
private Task LoadImageAsync(string filename, System.Windows.Controls.Image imageControl, Rotation rotation, CancellationToken cancellationToken)
{
bool isFullImageLoaded = false;
bool isThumbnailLoaded = false;
var thumbnailLoadTask = imageControl.Dispatcher.Invoke(async () =>
{
var bitmap = await FileLoadHelper.LoadThumbnailAsync(filename, false);
isThumbnailLoaded = true;
if (CancellationToken.IsCancellationRequested)
{
_cancellationTokenSource = new CancellationTokenSource();
return;
}
if (!isFullImageLoaded)
{
Bitmap = bitmap;
MainWindowData.Visibility = Visibility.Visible;
IsLoading = false;
}
});
var fullImageLoadTask = imageControl.Dispatcher.Invoke(async () =>
{
var bitmap = await FileLoadHelper.LoadFullImageAsync(filename, rotation);
isFullImageLoaded = true;
if (CancellationToken.IsCancellationRequested)
{
_cancellationTokenSource = new CancellationTokenSource();
return;
}
Bitmap = bitmap;
if (!isThumbnailLoaded)
{
MainWindowData.Visibility = Visibility.Visible;
IsLoading = false;
}
});
return Task.WhenAll(thumbnailLoadTask, fullImageLoadTask);
}
}
}

View File

@ -0,0 +1,37 @@
<Window
x:Class="Peek.UI.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="http://schemas.modernwpf.com/2019"
xmlns:vm="clr-namespace:Peek.UI.ViewModels"
Title="{Binding MainWindowData.Title, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
Width="{Binding MainWindowData.Rectangle.Width, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Height="{Binding MainWindowData.Rectangle.Height, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
MinWidth="500"
MinHeight="500"
d:DataContext="{d:DesignInstance vm:MainViewModel}"
ui:TitleBar.Background="{DynamicResource PrimaryBackgroundBrush}"
ui:TitleBar.IsIconVisible="True"
ui:WindowHelper.UseModernWindowStyle="True"
Background="{DynamicResource PrimaryBackgroundBrush}"
BorderThickness="1"
Icon="/PowerToys.Peek.UI;component/Resources/Peek.ico"
Left="{Binding MainWindowData.Rectangle.Left, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ResizeMode="NoResize"
Top="{Binding MainWindowData.Rectangle.Top, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Visibility="{Binding MainWindowData.Visibility, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
WindowStartupLocation="Manual"
mc:Ignorable="d">
<Grid>
<ui:ProgressRing IsActive="{Binding IsLoading, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
<!-- TODO: Create UI control that displays unsupported file gracefully -->
<Image
x:Name="ImageControl"
Source="{Binding Bitmap, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
Stretch="Uniform"
StretchDirection="DownOnly"
Visibility="{Binding IsImageReady, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
</Grid>
</Window>

View File

@ -0,0 +1,115 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Windows;
using System.Windows.Input;
using interop;
using ModernWpf.Controls;
using Peek.UI.Extensions;
using Peek.UI.Native;
using Peek.UI.ViewModels;
namespace Peek.UI.Views
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, IDisposable
{
private readonly MainViewModel _viewModel;
public MainWindow()
{
InitializeComponent();
this.RoundCorners();
_viewModel = new MainViewModel(ImageControl);
_viewModel.PropertyChanged += MainViewModel_PropertyChanged;
DataContext = _viewModel;
NativeEventWaiter.WaitForEventLoop(Constants.ShowPeekEvent(), OnPeekHotkey);
Loaded += MainWindow_Loaded;
Closing += MainWindow_Closing;
KeyDown += MainWindow_KeyDown;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
_viewModel.MainWindowData.Visibility = Visibility.Collapsed;
_viewModel.MainWindowData.TitleBarHeight = TitleBar.GetHeight(this);
_viewModel.ImageControl = ImageControl;
}
private void MainWindow_Closing(object? sender, System.ComponentModel.CancelEventArgs e)
{
_viewModel.MainWindowData.Visibility = Visibility.Collapsed;
e.Cancel = true;
}
private void MainWindow_KeyDown(object? sender, KeyEventArgs e)
{
if (!e.IsRepeat && _viewModel.CurrentSelectedFilePath != null)
{
switch (e.Key)
{
case Key.Left:
_viewModel.CurrentSelectedFilePath = _viewModel.CurrentSelectedFilePath.GetPreviousOrLast();
e.Handled = true;
break;
case Key.Right:
_viewModel.CurrentSelectedFilePath = _viewModel.CurrentSelectedFilePath.GetNextOrFirst();
e.Handled = true;
break;
default: break;
}
}
}
public void Dispose()
{
_viewModel.Dispose();
GC.SuppressFinalize(this);
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
this.SetToolStyle();
}
private async void MainViewModel_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case nameof(MainViewModel.CurrentSelectedFilePath):
if (_viewModel.CurrentSelectedFilePath != null)
{
await _viewModel.RenderImageToWindowAsync(_viewModel.CurrentSelectedFilePath.Value);
}
break;
}
}
private void OnPeekHotkey()
{
if (IsActive && _viewModel.MainWindowData.Visibility == Visibility.Visible)
{
_viewModel.ClearSelection();
}
else
{
_viewModel.TryUpdateSelectedFilePaths();
}
this.BringToForeground();
}
}
}

View File

@ -0,0 +1,18 @@
<!-- Copyright (c) Microsoft Corporation and Contributors. -->
<!-- Licensed under the MIT License. -->
<Application
x:Class="Peek.UI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Peek.UI">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<!-- Other merged dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<!-- Other app resources here -->
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@ -0,0 +1,58 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Peek.UI
{
using System;
using System.Diagnostics;
using System.Threading;
using ManagedCommon;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
using WinUIEx;
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
public partial class App : Application
{
public static int PowerToysPID { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="App"/> class.
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
}
/// <summary>
/// Invoked when the application is launched.
/// </summary>
/// <param name="args">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
var cmdArgs = Environment.GetCommandLineArgs();
if (cmdArgs?.Length > 1)
{
if (int.TryParse(cmdArgs[cmdArgs.Length - 1], out int powerToysRunnerPid))
{
RunnerHelper.WaitForPowerToysRunner(powerToysRunnerPid, () =>
{
Environment.Exit(0);
});
}
}
window = new MainWindow();
window.Activate();
window.Hide();
}
private Window? window;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Peek.UI.Extensions
{
using Windows.Foundation;
public static class SizeExtensions
{
public static Size Fit(this Size sizeToFit, Size maxSize, Size minSize)
{
double fittedWidth = sizeToFit.Width;
double fittedHeight = sizeToFit.Height;
double ratioWidth = sizeToFit.Width / maxSize.Width;
double ratioHeight = sizeToFit.Height / maxSize.Height;
if (ratioWidth > ratioHeight)
{
if (ratioWidth > 1)
{
fittedWidth = maxSize.Width;
fittedHeight = sizeToFit.Height / ratioWidth;
}
}
else
{
if (ratioHeight > 1)
{
fittedWidth = sizeToFit.Width / ratioHeight;
fittedHeight = maxSize.Height;
}
}
if (fittedWidth < minSize.Width)
{
fittedWidth = minSize.Width;
}
if (fittedHeight < minSize.Height)
{
fittedHeight = minSize.Height;
}
return new Size(fittedWidth, fittedHeight);
}
}
}

View File

@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Peek.UI.Extensions
{
using System.Drawing;
using Microsoft.UI.Xaml;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.Graphics.Gdi;
using WinUIEx;
public static class WindowExtensions
{
public static Size GetMonitorSize(this Window window)
{
var hwnd = new HWND(window.GetWindowHandle());
var hwndDesktop = PInvoke.MonitorFromWindow(hwnd, MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST);
MONITORINFO info = new ();
info.cbSize = 40;
PInvoke.GetMonitorInfo(hwndDesktop, ref info);
var monitorWidth = info.rcMonitor.left + info.rcMonitor.right;
var monitorHeight = info.rcMonitor.bottom + info.rcMonitor.top;
return new Size(monitorWidth, monitorHeight);
}
}
}

View File

@ -0,0 +1,37 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using Peek.Common.Models;
using Peek.UI.Native;
namespace Peek.UI.Helpers
{
public static class FileExplorerHelper
{
public static List<File> GetSelectedFileExplorerFiles()
{
var foregroundWindowHandle = NativeMethods.GetForegroundWindow();
var selectedItems = new List<File>();
var shell = new Shell32.Shell();
foreach (SHDocVw.InternetExplorer window in shell.Windows())
{
if (window.HWND == (int)foregroundWindowHandle)
{
Shell32.FolderItems items = ((Shell32.IShellFolderViewDual2)window.Document).SelectedItems();
if (items != null && items.Count > 0)
{
foreach (Shell32.FolderItem item in items)
{
selectedItems.Add(new File(item.Path));
}
}
}
}
return selectedItems;
}
}
}

View File

@ -0,0 +1,31 @@
<!-- Copyright (c) Microsoft Corporation and Contributors. -->
<!-- Licensed under the MIT License. -->
<winuiex:WindowEx
x:Class="Peek.UI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:fp="using:Peek.FilePreviewer"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="using:Peek.UI.Views"
xmlns:winuiex="using:WinUIEx"
mc:Ignorable="d">
<winuiex:WindowEx.Backdrop>
<winuiex:MicaSystemBackdrop />
</winuiex:WindowEx.Backdrop>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="32" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<views:TitleBar x:Name="TitleBarControl" Grid.Row="0" />
<fp:FilePreview
Grid.Row="1"
File="{x:Bind ViewModel.CurrentFile, Mode=OneWay}"
PreviewSizeChanged="FilePreviewer_PreviewSizeChanged" />
</Grid>
</winuiex:WindowEx>

View File

@ -0,0 +1,98 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Peek.UI
{
using System.Collections.Generic;
using System.Linq;
using interop;
using Microsoft.UI.Windowing;
using Peek.Common.Models;
using Peek.FilePreviewer.Models;
using Peek.UI.Extensions;
using Peek.UI.Helpers;
using Peek.UI.Native;
using Windows.Foundation;
using WinUIEx;
/// <summary>
/// An empty window that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainWindow : WindowEx
{
public MainWindow()
{
InitializeComponent();
ViewModel = new MainWindowViewModel();
NativeEventWaiter.WaitForEventLoop(Constants.ShowPeekEvent(), OnPeekHotkey);
TitleBarControl.SetToWindow(this);
AppWindow.Closing += AppWindow_Closing;
}
public MainWindowViewModel ViewModel { get; }
/// <summary>
/// Handle Peek hotkey, by toggling the window visibility and querying files when necessary.
/// </summary>
private void OnPeekHotkey()
{
if (AppWindow.IsVisible)
{
this.Hide();
ViewModel.Files = new List<File>();
ViewModel.CurrentFile = null;
}
else
{
var fileExplorerSelectedFiles = FileExplorerHelper.GetSelectedFileExplorerFiles();
if (fileExplorerSelectedFiles.Count == 0)
{
return;
}
ViewModel.Files = fileExplorerSelectedFiles;
ViewModel.CurrentFile = fileExplorerSelectedFiles.First();
}
}
/// <summary>
/// Handle FilePreviewerSizeChanged event to adjust window size and position accordingly.
/// </summary>
/// <param name="sender">object</param>
/// <param name="e">PreviewSizeChangedArgs</param>
private void FilePreviewer_PreviewSizeChanged(object sender, PreviewSizeChangedArgs e)
{
var requestedSize = e.WindowSizeRequested;
var monitorSize = this.GetMonitorSize();
// TODO: Use design-defined rules for adjusted window size
var titleBarHeight = TitleBarControl.ActualHeight;
var maxContentSize = new Size(monitorSize.Width * 0.8, (monitorSize.Height - titleBarHeight) * 0.8);
var minContentSize = new Size(500, 500 - titleBarHeight);
var adjustedContentSize = requestedSize.Fit(maxContentSize, minContentSize);
// TODO: Only re-center if window has not been resized by user (or use design-defined logic).
// TODO: Investigate why portrait images do not perfectly fit edge-to-edge
this.CenterOnScreen(adjustedContentSize.Width, adjustedContentSize.Height + titleBarHeight);
this.Show();
this.BringToFront();
}
/// <summary>
/// Handle AppWindow closing to prevent app termination on close.
/// </summary>
/// <param name="sender">AppWindow</param>
/// <param name="args">AppWindowClosingEventArgs</param>
private void AppWindow_Closing(AppWindow sender, AppWindowClosingEventArgs args)
{
args.Cancel = true;
this.Hide();
}
}
}

View File

@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Peek.UI
{
using System.Collections.Generic;
using CommunityToolkit.Mvvm.ComponentModel;
using Peek.Common.Models;
public partial class MainWindowViewModel : ObservableObject
{
[ObservableProperty]
private File? currentFile;
[ObservableProperty]
private List<File> files = new ();
}
}

View File

@ -0,0 +1,15 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Peek.UI.Native
{
using System;
using System.Runtime.InteropServices;
public static class NativeMethods
{
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
internal static extern IntPtr GetForegroundWindow();
}
}

View File

@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Threading;
using Microsoft.UI.Dispatching;
namespace Peek.UI.Native
{
public static class NativeEventWaiter
{
public static void WaitForEventLoop(string eventName, Action callback)
{
var dispatcherQueue = DispatcherQueue.GetForCurrentThread();
new Thread(() =>
{
var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName);
while (true)
{
if (eventHandle.WaitOne())
{
dispatcherQueue.TryEnqueue(() => callback());
}
}
}).Start();
}
}
}

View File

@ -0,0 +1,2 @@
MonitorFromWindow
GetMonitorInfo

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap rescap">
<Identity
Name="62c2f436-8802-4c26-a73d-b3b8613016fd"
Publisher="CN=sachaple"
Version="1.0.0.0" />
<Properties>
<DisplayName>Peek.UI</DisplayName>
<PublisherDisplayName>sachaple</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="Peek.UI"
Description="Peek.UI"
BackgroundColor="transparent"
Square150x150Logo="Assets\Square150x150Logo.png"
Square44x44Logo="Assets\Square44x44Logo.png">
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" />
<uap:SplashScreen Image="Assets\SplashScreen.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
</Capabilities>
</Package>

View File

@ -0,0 +1,97 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>PowerToys.Peek.UI</AssemblyName>
<AssemblyTitle>PowerToys.Peek.UI</AssemblyTitle>
<AssemblyDescription>PowerToys Peek UI</AssemblyDescription>
<RootNamespace>Peek.UI</RootNamespace>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows10.0.19041.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\modules\Peek\</OutputPath>
<ApplicationManifest>app.manifest</ApplicationManifest>
<Platforms>x86;x64;ARM64</Platforms>
<RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
<UseWinUI>true</UseWinUI>
<EnableMsixTooling>true</EnableMsixTooling>
<GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<EnablePreviewMsixTooling>true</EnablePreviewMsixTooling>
<WindowsPackageType>None</WindowsPackageType>
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<Nullable>Enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Content Remove="Assets\Peek.ico" />
</ItemGroup>
<ItemGroup>
<None Remove="Assets\Peek.ico" />
<None Remove="Views\TitleBar.xaml" />
</ItemGroup>
<ItemGroup>
<COMReference Include="Shell32">
<VersionMinor>0</VersionMinor>
<VersionMajor>1</VersionMajor>
<Guid>50a7e9b0-70ef-11d1-b75a-00a0c90564fe</Guid>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>
<COMReference Include="SHDocVw">
<VersionMinor>1</VersionMinor>
<VersionMajor>1</VersionMajor>
<Guid>eab22ac0-30c1-11cf-a7eb-0000c05bae0b</Guid>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup>
<Content Include="Assets\SplashScreen.scale-200.png" />
<Content Include="Assets\LockScreenLogo.scale-200.png" />
<Content Include="Assets\Square150x150Logo.scale-200.png" />
<Content Include="Assets\Square44x44Logo.scale-200.png" />
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Content Include="Assets\StoreLogo.png" />
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.2.46-beta">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.0.0" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.1.5" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22000.194" />
<PackageReference Include="WinUIEx" Version="1.8.0" />
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>
<!--
Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
Tools extension to be activated for this project even if the Windows App SDK Nuget
package has not yet been restored.
-->
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<ProjectCapability Include="Msix" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\interop\PowerToys.Interop.vcxproj" />
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
<ProjectReference Include="..\Peek.Common\Peek.Common.csproj" />
<ProjectReference Include="..\Peek.FilePreviewer\Peek.FilePreviewer.csproj" />
</ItemGroup>
<ItemGroup>
<Resource Include="Assets\Peek.ico" />
</ItemGroup>
<ItemGroup>
<Page Update="Views\TitleBar.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
</Project>

View File

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AppTitle.Title" xml:space="preserve">
<value>Peek</value>
</data>
<data name="AppTitleText.Text" xml:space="preserve">
<value>Peek</value>
</data>
</root>

View File

@ -0,0 +1,25 @@
<!-- Copyright (c) Microsoft Corporation and Contributors. -->
<!-- Licensed under the MIT License. -->
<UserControl
x:Class="Peek.UI.Views.TitleBar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Peek.UI.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid x:Name="titleBar">
<StackPanel
Margin="16,8,8,8"
VerticalAlignment="Top"
Orientation="Horizontal">
<Image Source="../Assets/Square44x44Logo.png" />
<TextBlock
x:Uid="AppTitleText"
Margin="12,0,0,0"
Style="{StaticResource CaptionTextBlockStyle}" />
</StackPanel>
</Grid>
</UserControl>

View File

@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Peek.UI.Views
{
using System;
using ManagedCommon;
using Microsoft.UI;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml.Controls;
using WinUIEx;
using MUX = Microsoft.UI.Xaml;
public sealed partial class TitleBar : UserControl
{
public TitleBar()
{
InitializeComponent();
}
public void SetToWindow(MainWindow mainWindow)
{
if (AppWindowTitleBar.IsCustomizationSupported())
{
AppWindow window = mainWindow.GetAppWindow();
window.TitleBar.ExtendsContentIntoTitleBar = true;
window.TitleBar.ButtonBackgroundColor = Colors.Transparent;
mainWindow.SetTitleBar(this);
}
else
{
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
ThemeHelpers.SetImmersiveDarkMode(hWnd, ThemeHelpers.GetAppTheme() == AppTheme.Dark);
Visibility = MUX.Visibility.Collapsed;
// Set window icon
WindowId windowId = Win32Interop.GetWindowIdFromWindow(hWnd);
AppWindow appWindow = AppWindow.GetFromWindowId(windowId);
appWindow.SetIcon("Assets/Peek.ico");
}
}
}
}

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="Peek.UI.app"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!--The ID below informs the system that this application is compatible with OS features first introduced in Windows 8.
For more info see https://docs.microsoft.com/windows/win32/sysinfo/targeting-your-application-at-windows-8-1
It is also necessary to support features in unpackaged applications, for example the custom titlebar implementation.-->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<!-- The combination of below two tags have the following effect:
1) Per-Monitor for >= Windows 10 Anniversary Update
2) System < Windows 10 Anniversary Update
-->
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
</windowsSettings>
</application>
</assembly>

View File

@ -0,0 +1,7 @@
namespace WIC
{
internal static class CLSID
{
public const string WICImagingFactory = "cacaf262-9370-4615-a13b-9f5539da4c0a";
}
}

View File

@ -0,0 +1,14 @@
using System.Runtime.InteropServices;
namespace WIC
{
[ComImport]
[Guid(IID.IWICImagingFactory)]
[CoClass(typeof(WICImagingFactoryClass))]
public interface WICImagingFactory : IWICImagingFactory { }
[ComImport]
[Guid(CLSID.WICImagingFactory)]
[ComDefaultInterface(typeof(IWICImagingFactory))]
public class WICImagingFactoryClass { }
}

View File

@ -0,0 +1,43 @@
using System;
using System.Runtime.InteropServices;
namespace WIC
{
internal struct CoTaskMemPtr : IDisposable
{
public static CoTaskMemPtr From<T>(T? nullableStructure) where T : struct
{
IntPtr value;
if (nullableStructure.HasValue)
{
value = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(T)));
Marshal.StructureToPtr(nullableStructure, value, false);
}
else
{
value = IntPtr.Zero;
}
return new CoTaskMemPtr(value);
}
public CoTaskMemPtr(IntPtr value)
{
this.value = value;
}
private IntPtr value;
public static implicit operator IntPtr(CoTaskMemPtr safeIntPtr)
{
return safeIntPtr.value;
}
public void Dispose()
{
if (value != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(value);
}
}
}
}

View File

@ -0,0 +1,16 @@
using System;
namespace WIC
{
public static class ContainerFormat
{
public static readonly Guid Bmp = new Guid(0x0af1d87e, 0xfcfe, 0x4188, 0xbd, 0xeb, 0xa7, 0x90, 0x64, 0x71, 0xcb, 0xe3);
public static readonly Guid Png = new Guid(0x1b7cfaf4, 0x713f, 0x473c, 0xbb, 0xcd, 0x61, 0x37, 0x42, 0x5f, 0xae, 0xaf);
public static readonly Guid Ico = new Guid(0xa3a860c4, 0x338f, 0x4c17, 0x91, 0x9a, 0xfb, 0xa4, 0xb5, 0x62, 0x8f, 0x21);
public static readonly Guid Jpeg = new Guid(0x19e4a5aa, 0x5662, 0x4fc5, 0xa0, 0xc0, 0x17, 0x58, 0x02, 0x8e, 0x10, 0x57);
public static readonly Guid Tiff = new Guid(0x163bcc30, 0xe2e9, 0x4f0b, 0x96, 0x1d, 0xa3, 0xe9, 0xfd, 0xb7, 0x88, 0xa3);
public static readonly Guid Gif = new Guid(0x1f8a5601, 0x7d4d, 0x4cbd, 0x9c, 0x82, 0x1b, 0xc8, 0xd4, 0xee, 0xb9, 0xa5);
public static readonly Guid Wmp = new Guid(0x57a37caa, 0x367a, 0x4540, 0x91, 0x6b, 0xf1, 0x83, 0xc5, 0x09, 0x3a, 0x4b);
public static readonly Guid Dds = new Guid(0x9967cb95, 0x2e85, 0x4ac8, 0x8c, 0xa2, 0x83, 0xd7, 0xcc, 0xd4, 0x25, 0xc9);
}
}

View File

@ -0,0 +1,7 @@
namespace WIC
{
public struct HResult
{
public const int WINCODEC_ERR_PROPERTYNOTFOUND = unchecked((int)0x88982F40);
}
}

View File

@ -0,0 +1,10 @@
using System;
namespace WIC
{
public static class Vendor
{
public static readonly Guid Microsoft = new Guid(0xf0e749ca, 0xedef, 0x4589, 0xa7, 0x3a, 0xee, 0xe, 0x62, 0x6a, 0x2a, 0x2b);
public static readonly Guid MicrosoftBuiltIn = new Guid(0x257a30fd, 0x6b6, 0x462b, 0xae, 0xa4, 0x63, 0xf7, 0xb, 0x86, 0xe5, 0x33);
}
}

View File

@ -0,0 +1,98 @@
using System;
namespace WIC.Constants
{
public static class WICPixelFormat
{
public static readonly Guid WICPixelFormatDontCare = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x00);
public static readonly Guid WICPixelFormat1bppIndexed = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x01);
public static readonly Guid WICPixelFormat2bppIndexed = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x02);
public static readonly Guid WICPixelFormat4bppIndexed = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x03);
public static readonly Guid WICPixelFormat8bppIndexed = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x04);
public static readonly Guid WICPixelFormatBlackWhite = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x05);
public static readonly Guid WICPixelFormat2bppGray = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x06);
public static readonly Guid WICPixelFormat4bppGray = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x07);
public static readonly Guid WICPixelFormat8bppGray = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x08);
public static readonly Guid WICPixelFormat8bppAlpha = new Guid(0xe6cd0116, 0xeeba, 0x4161, 0xaa, 0x85, 0x27, 0xdd, 0x9f, 0xb3, 0xa8, 0x95);
public static readonly Guid WICPixelFormat16bppBGR555 = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x09);
public static readonly Guid WICPixelFormat16bppBGR565 = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0a);
public static readonly Guid WICPixelFormat16bppBGRA5551 = new Guid(0x05ec7c2b, 0xf1e6, 0x4961, 0xad, 0x46, 0xe1, 0xcc, 0x81, 0x0a, 0x87, 0xd2);
public static readonly Guid WICPixelFormat16bppGray = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0b);
public static readonly Guid WICPixelFormat24bppBGR = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0c);
public static readonly Guid WICPixelFormat24bppRGB = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0d);
public static readonly Guid WICPixelFormat32bppBGR = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0e);
public static readonly Guid WICPixelFormat32bppBGRA = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f);
public static readonly Guid WICPixelFormat32bppPBGRA = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x10);
public static readonly Guid WICPixelFormat32bppGrayFloat = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x11);
public static readonly Guid WICPixelFormat32bppRGB = new Guid(0xd98c6b95, 0x3efe, 0x47d6, 0xbb, 0x25, 0xeb, 0x17, 0x48, 0xab, 0x0c, 0xf1);
public static readonly Guid WICPixelFormat32bppRGBA = new Guid(0xf5c7ad2d, 0x6a8d, 0x43dd, 0xa7, 0xa8, 0xa2, 0x99, 0x35, 0x26, 0x1a, 0xe9);
public static readonly Guid WICPixelFormat32bppPRGBA = new Guid(0x3cc4a650, 0xa527, 0x4d37, 0xa9, 0x16, 0x31, 0x42, 0xc7, 0xeb, 0xed, 0xba);
public static readonly Guid WICPixelFormat48bppRGB = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x15);
public static readonly Guid WICPixelFormat48bppBGR = new Guid(0xe605a384, 0xb468, 0x46ce, 0xbb, 0x2e, 0x36, 0xf1, 0x80, 0xe6, 0x43, 0x13);
public static readonly Guid WICPixelFormat64bppRGB = new Guid(0xa1182111, 0x186d, 0x4d42, 0xbc, 0x6a, 0x9c, 0x83, 0x03, 0xa8, 0xdf, 0xf9);
public static readonly Guid WICPixelFormat64bppRGBA = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x16);
public static readonly Guid WICPixelFormat64bppBGRA = new Guid(0x1562ff7c, 0xd352, 0x46f9, 0x97, 0x9e, 0x42, 0x97, 0x6b, 0x79, 0x22, 0x46);
public static readonly Guid WICPixelFormat64bppPRGBA = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x17);
public static readonly Guid WICPixelFormat64bppPBGRA = new Guid(0x8c518e8e, 0xa4ec, 0x468b, 0xae, 0x70, 0xc9, 0xa3, 0x5a, 0x9c, 0x55, 0x30);
public static readonly Guid WICPixelFormat16bppGrayFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x13);
public static readonly Guid WICPixelFormat32bppBGR101010 = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x14);
public static readonly Guid WICPixelFormat48bppRGBFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x12);
public static readonly Guid WICPixelFormat48bppBGRFixedPoint = new Guid(0x49ca140e, 0xcab6, 0x493b, 0x9d, 0xdf, 0x60, 0x18, 0x7c, 0x37, 0x53, 0x2a);
public static readonly Guid WICPixelFormat96bppRGBFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x18);
public static readonly Guid WICPixelFormat96bppRGBFloat = new Guid(0xe3fed78f, 0xe8db, 0x4acf, 0x84, 0xc1, 0xe9, 0x7f, 0x61, 0x36, 0xb3, 0x27);
public static readonly Guid WICPixelFormat128bppRGBAFloat = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x19);
public static readonly Guid WICPixelFormat128bppPRGBAFloat = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1a);
public static readonly Guid WICPixelFormat128bppRGBFloat = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1b);
public static readonly Guid WICPixelFormat32bppCMYK = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1c);
public static readonly Guid WICPixelFormat64bppRGBAFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1d);
public static readonly Guid WICPixelFormat64bppBGRAFixedPoint = new Guid(0x356de33c, 0x54d2, 0x4a23, 0xbb, 0x4, 0x9b, 0x7b, 0xf9, 0xb1, 0xd4, 0x2d);
public static readonly Guid WICPixelFormat64bppRGBFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x40);
public static readonly Guid WICPixelFormat128bppRGBAFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1e);
public static readonly Guid WICPixelFormat128bppRGBFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x41);
public static readonly Guid WICPixelFormat64bppRGBAHalf = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3a);
public static readonly Guid WICPixelFormat64bppPRGBAHalf = new Guid(0x58ad26c2, 0xc623, 0x4d9d, 0xb3, 0x20, 0x38, 0x7e, 0x49, 0xf8, 0xc4, 0x42);
public static readonly Guid WICPixelFormat64bppRGBHalf = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x42);
public static readonly Guid WICPixelFormat48bppRGBHalf = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3b);
public static readonly Guid WICPixelFormat32bppRGBE = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3d);
public static readonly Guid WICPixelFormat16bppGrayHalf = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3e);
public static readonly Guid WICPixelFormat32bppGrayFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3f);
public static readonly Guid WICPixelFormat32bppRGBA1010102 = new Guid(0x25238D72, 0xFCF9, 0x4522, 0xb5, 0x14, 0x55, 0x78, 0xe5, 0xad, 0x55, 0xe0);
public static readonly Guid WICPixelFormat32bppRGBA1010102XR = new Guid(0x00DE6B9A, 0xC101, 0x434b, 0xb5, 0x02, 0xd0, 0x16, 0x5e, 0xe1, 0x12, 0x2c);
public static readonly Guid WICPixelFormat32bppR10G10B10A2 = new Guid(0x604e1bb5, 0x8a3c, 0x4b65, 0xb1, 0x1c, 0xbc, 0x0b, 0x8d, 0xd7, 0x5b, 0x7f);
public static readonly Guid WICPixelFormat32bppR10G10B10A2HDR10 = new Guid(0x9c215c5d, 0x1acc, 0x4f0e, 0xa4, 0xbc, 0x70, 0xfb, 0x3a, 0xe8, 0xfd, 0x28);
public static readonly Guid WICPixelFormat64bppCMYK = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1f);
public static readonly Guid WICPixelFormat24bpp3Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x20);
public static readonly Guid WICPixelFormat32bpp4Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x21);
public static readonly Guid WICPixelFormat40bpp5Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x22);
public static readonly Guid WICPixelFormat48bpp6Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x23);
public static readonly Guid WICPixelFormat56bpp7Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x24);
public static readonly Guid WICPixelFormat64bpp8Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x25);
public static readonly Guid WICPixelFormat48bpp3Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x26);
public static readonly Guid WICPixelFormat64bpp4Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x27);
public static readonly Guid WICPixelFormat80bpp5Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x28);
public static readonly Guid WICPixelFormat96bpp6Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x29);
public static readonly Guid WICPixelFormat112bpp7Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2a);
public static readonly Guid WICPixelFormat128bpp8Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2b);
public static readonly Guid WICPixelFormat40bppCMYKAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2c);
public static readonly Guid WICPixelFormat80bppCMYKAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2d);
public static readonly Guid WICPixelFormat32bpp3ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2e);
public static readonly Guid WICPixelFormat40bpp4ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2f);
public static readonly Guid WICPixelFormat48bpp5ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x30);
public static readonly Guid WICPixelFormat56bpp6ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x31);
public static readonly Guid WICPixelFormat64bpp7ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x32);
public static readonly Guid WICPixelFormat72bpp8ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x33);
public static readonly Guid WICPixelFormat64bpp3ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x34);
public static readonly Guid WICPixelFormat80bpp4ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x35);
public static readonly Guid WICPixelFormat96bpp5ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x36);
public static readonly Guid WICPixelFormat112bpp6ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x37);
public static readonly Guid WICPixelFormat128bpp7ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x38);
public static readonly Guid WICPixelFormat144bpp8ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x39);
public static readonly Guid WICPixelFormat8bppY = new Guid(0x91B4DB54, 0x2DF9, 0x42F0, 0xB4, 0x49, 0x29, 0x09, 0xBB, 0x3D, 0xF8, 0x8E);
public static readonly Guid WICPixelFormat8bppCb = new Guid(0x1339F224, 0x6BFE, 0x4C3E, 0x93, 0x02, 0xE4, 0xF3, 0xA6, 0xD0, 0xCA, 0x2A);
public static readonly Guid WICPixelFormat8bppCr = new Guid(0xB8145053, 0x2116, 0x49F0, 0x88, 0x35, 0xED, 0x84, 0x4B, 0x20, 0x5C, 0x51);
public static readonly Guid WICPixelFormat16bppCbCr = new Guid(0xFF95BA6E, 0x11E0, 0x4263, 0xBB, 0x45, 0x01, 0x72, 0x1F, 0x34, 0x60, 0xA4);
public static readonly Guid WICPixelFormat16bppYQuantizedDctCoefficients = new Guid(0xA355F433, 0x48E8, 0x4A42, 0x84, 0xD8, 0xE2, 0xAA, 0x26, 0xCA, 0x80, 0xA4);
public static readonly Guid WICPixelFormat16bppCbQuantizedDctCoefficients = new Guid(0xD2C4FF61, 0x56A5, 0x49C2, 0x8B, 0x5C, 0x4C, 0x19, 0x25, 0x96, 0x48, 0x37);
public static readonly Guid WICPixelFormat16bppCrQuantizedDctCoefficients = new Guid(0x2FE354F0, 0x1680, 0x42D8, 0x92, 0x31, 0xE7, 0x3C, 0x05, 0x65, 0xBF, 0xC1);
}
}

View File

@ -0,0 +1,8 @@
namespace WIC
{
public enum ExifColorSpace : int
{
SRGB = 1,
AdobeSRGB = 2,
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.ComponentModel;
namespace WIC
{
[Flags]
[EditorBrowsable(EditorBrowsableState.Advanced)]
public enum LOCKTYPE : int
{
LOCK_WRITE = 1,
LOCK_EXCLUSIVE = 2,
LOCK_ONLYONCE = 4,
}
}

View File

@ -0,0 +1,19 @@
using System;
namespace WIC
{
[Flags]
public enum MetadataCreationAndPersistOptions : int
{
WICMetadataCreationDefault = 0x00000000,
WICMetadataCreationAllowUnknown = WICMetadataCreationDefault,
WICMetadataCreationFailUnknown = 0x00010000,
WICPersistOptionDefault = 0x00000000,
WICPersistOptionLittleEndian = 0x00000000,
WICPersistOptionBigEndian = 0x00000001,
WICPersistOptionStrictFormat = 0x00000002,
WICPersistOptionNoCacheStream = 0x00000004,
WICPersistOptionPreferUTF8 = 0x00000008,
}
}

View File

@ -0,0 +1,12 @@
using System.ComponentModel;
namespace WIC
{
[EditorBrowsable(EditorBrowsableState.Advanced)]
public enum STATFLAG : int
{
STATFLAG_DEFAULT = 0,
STATFLAG_NONAME = 1,
STATFLAG_NOOPEN = 2,
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.ComponentModel;
namespace WIC
{
[Flags]
[EditorBrowsable(EditorBrowsableState.Advanced)]
public enum STGC : int
{
STGC_DEFAULT = 0,
STGC_OVERWRITE = 1,
STGC_ONLYIFCURRENT = 2,
STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE = 4,
STGC_CONSOLIDATE = 8,
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.ComponentModel;
namespace WIC
{
[Flags]
[EditorBrowsable(EditorBrowsableState.Advanced)]
public enum STGM : int
{
STGM_READ = 0x00000000,
STGM_WRITE = 0x00000001,
STGM_READWRITE = 0x00000002,
#warning `STGM`: Enumeration incomplete. Consider adding all values.
}
}

View File

@ -0,0 +1,13 @@
using System.ComponentModel;
namespace WIC
{
[EditorBrowsable(EditorBrowsableState.Advanced)]
public enum STGTY : int
{
STGTY_STORAGE = 1,
STGTY_STREAM = 2,
STGTY_LOCKBYTES = 3,
STGTY_PROPERTY = 4,
}
}

View File

@ -0,0 +1,12 @@
using System.ComponentModel;
namespace WIC
{
[EditorBrowsable(EditorBrowsableState.Advanced)]
public enum STREAM_SEEK : int
{
STREAM_SEEK_SET = 0,
STREAM_SEEK_CUR = 1,
STREAM_SEEK_END = 2,
}
}

View File

@ -0,0 +1,11 @@
using System;
namespace WIC
{
[Flags]
public enum StreamAccessMode : int
{
GENERIC_WRITE = 0x40000000,
GENERIC_READ = unchecked((int)0x80000000U),
}
}

View File

@ -0,0 +1,9 @@
namespace WIC
{
public enum WICBitmapAlphaChannelOption : int
{
WICBitmapUseAlpha = 0x00000000,
WICBitmapUsePremultipliedAlpha = 0x00000001,
WICBitmapIgnoreAlpha = 0x00000002,
}
}

View File

@ -0,0 +1,9 @@
namespace WIC
{
public enum WICBitmapCreateCacheOption : int
{
WICBitmapNoCache = 0x00000000,
WICBitmapCacheOnDemand = 0x00000001,
WICBitmapCacheOnLoad = 0x00000002,
}
}

View File

@ -0,0 +1,14 @@
using System;
namespace WIC
{
[Flags]
public enum WICBitmapDecoderCapabilities : int
{
WICBitmapDecoderCapabilitySameEncoder = 0x00000001,
WICBitmapDecoderCapabilityCanDecodeAllImages = 0x00000002,
WICBitmapDecoderCapabilityCanDecodeSomeImages = 0x00000004,
WICBitmapDecoderCapabilityCanEnumerateMetadata = 0x00000008,
WICBitmapDecoderCapabilityCanDecodeThumbnail = 0x00000010,
}
}

View File

@ -0,0 +1,19 @@
namespace WIC
{
public enum WICBitmapDitherType : int
{
WICBitmapDitherTypeNone = 0x00000000,
WICBitmapDitherTypeSolid = 0x00000000,
WICBitmapDitherTypeOrdered4x4 = 0x00000001,
WICBitmapDitherTypeOrdered8x8 = 0x00000002,
WICBitmapDitherTypeOrdered16x16 = 0x00000003,
WICBitmapDitherTypeSpiral4x4 = 0x00000004,
WICBitmapDitherTypeSpiral8x8 = 0x00000005,
WICBitmapDitherTypeDualSpiral4x4 = 0x00000006,
WICBitmapDitherTypeDualSpiral8x8 = 0x00000007,
WICBitmapDitherTypeErrorDiffusion = 0x00000008,
}
}

View File

@ -0,0 +1,9 @@
namespace WIC
{
public enum WICBitmapEncoderCacheOption : int
{
WICBitmapEncoderCacheInMemory = 0x00000000,
WICBitmapEncoderCacheTempFile = 0x00000001,
WICBitmapEncoderNoCache = 0x00000002,
}
}

View File

@ -0,0 +1,14 @@
namespace WIC
{
public enum WICBitmapInterpolationMode : int
{
WICBitmapInterpolationModeNearestNeighbor = 0x00000000,
WICBitmapInterpolationModeLinear = 0x00000001,
WICBitmapInterpolationModeCubic = 0x00000002,
WICBitmapInterpolationModeFant = 0x00000003,
/// <remarks>
/// Supported beginning with Windows 10.
/// </remarks>
WICBitmapInterpolationModeHighQualityCubic = 0x00000004,
}
}

View File

@ -0,0 +1,11 @@
using System;
namespace WIC
{
[Flags]
public enum WICBitmapLockFlags : int
{
WICBitmapLockRead = 0x00000001,
WICBitmapLockWrite = 0x00000002,
}
}

View File

@ -0,0 +1,20 @@
namespace WIC
{
public enum WICBitmapPaletteType : int
{
WICBitmapPaletteTypeCustom = 0x00000000,
WICBitmapPaletteTypeMedianCut = 0x00000001,
WICBitmapPaletteTypeFixedBW = 0x00000002,
WICBitmapPaletteTypeFixedHalftone8 = 0x00000003,
WICBitmapPaletteTypeFixedHalftone27 = 0x00000004,
WICBitmapPaletteTypeFixedHalftone64 = 0x00000005,
WICBitmapPaletteTypeFixedHalftone125 = 0x00000006,
WICBitmapPaletteTypeFixedHalftone216 = 0x00000007,
WICBitmapPaletteTypeFixedWebPalette = WICBitmapPaletteTypeFixedHalftone216,
WICBitmapPaletteTypeFixedHalftone252 = 0x00000008,
WICBitmapPaletteTypeFixedHalftone256 = 0x00000009,
WICBitmapPaletteTypeFixedGray4 = 0x0000000A,
WICBitmapPaletteTypeFixedGray16 = 0x0000000B,
WICBitmapPaletteTypeFixedGray256 = 0x0000000C,
}
}

View File

@ -0,0 +1,17 @@
using System;
namespace WIC
{
[Flags]
public enum WICBitmapTransformOptions : int
{
WICBitmapTransformRotate0 = 0x00000000,
WICBitmapTransformRotate90 = 0x00000001,
WICBitmapTransformRotate180 = 0x00000002,
WICBitmapTransformRotate270 = 0x00000003,
WICBitmapTransformFlipHorizontal = 0x00000008,
WICBitmapTransformFlipVertical = 0x00000010,
}
}

View File

@ -0,0 +1,9 @@
namespace WIC
{
public enum WICColorContextType : int
{
WICColorContextUninitialized = 0x00000000,
WICColorContextProfile = 0x00000001,
WICColorContextExifColorSpace = 0x00000002,
}
}

View File

@ -0,0 +1,14 @@
using System;
namespace WIC
{
[Flags]
public enum WICComponentEnumerateOptions : int
{
WICComponentEnumerateDefault = 0x00000000,
WICComponentEnumerateRefresh = 0x00000001,
WICComponentEnumerateBuiltInOnly = 0x20000000,
WICComponentEnumerateUnsigned = 0x40000000,
WICComponentEnumerateDisabled = unchecked((int)0x80000000U),
}
}

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