mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-31 01:16:59 +01:00
Compare commits
4 Commits
jay/DarkMo
...
leilzh/reg
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5386572092 | ||
|
|
0f1ccaee2d | ||
|
|
68b708f2fd | ||
|
|
3088908202 |
4
.github/actions/spell-check/expect.txt
vendored
4
.github/actions/spell-check/expect.txt
vendored
@@ -115,7 +115,6 @@ bigbar
|
||||
bigobj
|
||||
binlog
|
||||
binres
|
||||
binskim
|
||||
BITMAPFILEHEADER
|
||||
bitmapimage
|
||||
BITMAPINFO
|
||||
@@ -256,7 +255,6 @@ Corpor
|
||||
cotaskmem
|
||||
COULDNOT
|
||||
countof
|
||||
covrun
|
||||
cpcontrols
|
||||
cph
|
||||
cplusplus
|
||||
@@ -637,7 +635,6 @@ hmodule
|
||||
hmonitor
|
||||
homies
|
||||
homljgmgpmcbpjbnjpfijnhipfkiclkd
|
||||
HOOKPROC
|
||||
HORZRES
|
||||
HORZSIZE
|
||||
Hostbackdropbrush
|
||||
@@ -972,7 +969,6 @@ msc
|
||||
mscorlib
|
||||
msctls
|
||||
msdata
|
||||
msdia
|
||||
MSDL
|
||||
MSGFLT
|
||||
MSHCTX
|
||||
|
||||
@@ -64,10 +64,6 @@ extends:
|
||||
tsa:
|
||||
enabled: true
|
||||
configFile: '$(Build.SourcesDirectory)\.pipelines\tsa.json'
|
||||
binskim:
|
||||
enabled: true
|
||||
# Exclude every dll/exe in tests/*, as well as all msdia*, covrun* and vcruntime*
|
||||
analyzeTargetGlob: +:file|$(Build.ArtifactStagingDirectory)/**/*.dll;+:file|$(Build.ArtifactStagingDirectory)/**/*.exe;-:file:regex|tests.*\.(dll|exe)$;-:file:regex|(covrun.*)\.dll$;-:file:regex|(msdia.*)\.dll$;-:file:regex|(vcruntime.*)\.dll$
|
||||
|
||||
stages:
|
||||
- stage: Build
|
||||
|
||||
@@ -5,13 +5,11 @@ MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "src\runner\runner.vcxproj", "{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73} = {031AC72E-FA28-4AB7-B690-6F7B9C28AA73}
|
||||
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC} = {08E71C67-6A7E-4CA1-B04E-2FB336410BAC}
|
||||
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B} = {0B43679E-EDFA-4DA0-AD30-F4628B308B1B}
|
||||
{0B593A6C-4143-4337-860E-DB5710FB87DB} = {0B593A6C-4143-4337-860E-DB5710FB87DB}
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E} = {17DA04DF-E393-4397-9CF0-84DABE11032E}
|
||||
{217DF501-135C-4E38-BFC8-99D4821032EA} = {217DF501-135C-4E38-BFC8-99D4821032EA}
|
||||
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34} = {2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166} = {38177D56-6AD1-4ADF-88C9-2843A7932166}
|
||||
{48804216-2A0E-4168-A6D8-9CD068D14227} = {48804216-2A0E-4168-A6D8-9CD068D14227}
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481} = {5CCC8468-DEC8-4D36-99D4-5C891BEBD481}
|
||||
@@ -264,6 +262,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "utils", "utils", "{B39DC643
|
||||
src\common\utils\EventLocker.h = src\common\utils\EventLocker.h
|
||||
src\common\utils\EventWaiter.h = src\common\utils\EventWaiter.h
|
||||
src\common\utils\excluded_apps.h = src\common\utils\excluded_apps.h
|
||||
src\common\utils\shell_ext_registration.h = src\common\utils\shell_ext_registration.h
|
||||
src\common\utils\exec.h = src\common\utils\exec.h
|
||||
src\common\utils\game_mode.h = src\common\utils\game_mode.h
|
||||
src\common\utils\gpo.h = src\common\utils\gpo.h
|
||||
@@ -790,12 +789,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Window
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.UnitTestBase", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.UnitTestsBase\Microsoft.CmdPal.Ext.UnitTestBase.csproj", "{00D8659C-2068-40B6-8B86-759CD6284BBB}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LightSwitch", "LightSwitch", "{5B201255-53C8-490B-A34F-01F05D48A477}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LightSwitchModuleInterface", "src\modules\LightSwitch\LightSwitchModuleInterface\LightSwitchModuleInterface.vcxproj", "{38177D56-6AD1-4ADF-88C9-2843A7932166}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LightModeService", "src\modules\LightSwitch\LightSwitchService\LightSwitchService.vcxproj", "{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
@@ -2858,22 +2851,6 @@ Global
|
||||
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|x64.ActiveCfg = Release|x64
|
||||
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|x64.Build.0 = Release|x64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Debug|x64.Build.0 = Debug|x64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Release|x64.ActiveCfg = Release|x64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Release|x64.Build.0 = Release|x64
|
||||
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Debug|x64.Build.0 = Debug|x64
|
||||
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Release|x64.ActiveCfg = Release|x64
|
||||
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -3185,9 +3162,6 @@ Global
|
||||
{E816D7AF-4688-4ECB-97CC-3D8E798F3828} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
{E816D7B0-4688-4ECB-97CC-3D8E798F3829} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
{00D8659C-2068-40B6-8B86-759CD6284BBB} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
{5B201255-53C8-490B-A34F-01F05D48A477} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166} = {5B201255-53C8-490B-A34F-01F05D48A477}
|
||||
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC} = {5B201255-53C8-490B-A34F-01F05D48A477}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
||||
@@ -52,7 +52,7 @@ Once you've discussed your proposed feature/fix/etc. with a team member, and an
|
||||
## Rules
|
||||
|
||||
- **Follow the pattern of what you already see in the code.**
|
||||
- [Coding style](style.md).
|
||||
- [Coding style](development/style.md).
|
||||
- Try to package new functionality/components into libraries that have nicely defined interfaces.
|
||||
- Package new functionality into classes or refactor existing functionality into a class as you extend the code.
|
||||
- When adding new classes/methods/changing existing code, add new unit tests or update the existing tests.
|
||||
|
||||
@@ -14,21 +14,6 @@
|
||||
<DirectoryRef Id="FileLocksmithAssetsInstallFolder" FileSource="$(var.FileLocksmithAssetsFilesPath)">
|
||||
<!-- Generated by generateFileComponents.ps1 -->
|
||||
<!--FileLocksmithAssetsFiles_Component_Def-->
|
||||
<!-- !Warning! Make sure to change Component Guid if you update something here -->
|
||||
<Component Id="Module_FileLocksmith" Guid="108D3EC1-E6E0-4E81-88EF-25966133CB41" Win64="yes">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\CLSID\{84D68575-E186-46AD-B0CB-BAEB45EE29C0}">
|
||||
<RegistryValue Type="string" Value="File Locksmith Shell Extension" />
|
||||
<RegistryValue Type="string" Name="ContextMenuOptIn" Value="" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Value="[WinUI3AppsInstallFolder]PowerToys.FileLocksmithExt.dll" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Apartment" />
|
||||
</RegistryKey>
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\AllFileSystemObjects\ShellEx\ContextMenuHandlers\FileLocksmithExt">
|
||||
<RegistryValue Type="string" Value="{84D68575-E186-46AD-B0CB-BAEB45EE29C0}"/>
|
||||
</RegistryKey>
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\Drive\ShellEx\ContextMenuHandlers\FileLocksmithExt">
|
||||
<RegistryValue Type="string" Value="{84D68575-E186-46AD-B0CB-BAEB45EE29C0}"/>
|
||||
</RegistryKey>
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<ComponentGroup Id="FileLocksmithComponentGroup">
|
||||
@@ -38,7 +23,6 @@
|
||||
</RegistryKey>
|
||||
<RemoveFolder Id="RemoveFolderFileLocksmithAssetsFolder" Directory="FileLocksmithAssetsInstallFolder" On="uninstall"/>
|
||||
</Component>
|
||||
<ComponentRef Id="Module_FileLocksmith" />
|
||||
</ComponentGroup>
|
||||
|
||||
</Fragment>
|
||||
|
||||
@@ -16,71 +16,6 @@
|
||||
<!-- Generated by generateFileComponents.ps1 -->
|
||||
<!--ImageResizerAssetsFiles_Component_Def-->
|
||||
|
||||
<Component Id="Module_ImageResizer_Registry" Win64="yes">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\CLSID\{51B4D7E5-7568-4234-B4BB-47FB3C016A69}\InprocServer32">
|
||||
<RegistryValue Value="[WinUI3AppsInstallFolder]PowerToys.ImageResizerExt.dll" Type="string" />
|
||||
<RegistryValue Name="ThreadingModel" Value="Apartment" Type="string" />
|
||||
</RegistryKey>
|
||||
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\Directory\ShellEx\DragDropHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<!-- Registry Keys for the context menu handler for each of the following image formats: bmp, dib, gif, jfif, jpe, jpeg, jpg, jxr, png, rle, tif, tiff, wdp -->
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.bmp\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.dib\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.gif\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.jfif\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.jpe\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.jpeg\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.jpg\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.jxr\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.png\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.rle\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.tif\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.tiff\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.wdp\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
</Component>
|
||||
|
||||
</DirectoryRef>
|
||||
|
||||
<ComponentGroup Id="ImageResizerComponentGroup">
|
||||
@@ -90,7 +25,6 @@
|
||||
</RegistryKey>
|
||||
<RemoveFolder Id="RemoveFolderImageResizerAssetsFolder" Directory="ImageResizerAssetsFolder" On="uninstall"/>
|
||||
</Component>
|
||||
<ComponentRef Id="Module_ImageResizer_Registry" />
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
||||
|
||||
@@ -18,19 +18,6 @@
|
||||
<DirectoryRef Id="NewPlusAssetsInstallFolder" FileSource="$(var.NewPlusAssetsFilesPath)">
|
||||
<!-- Generated by generateFileComponents.ps1 -->
|
||||
<!--NewPlusAssetsFiles_Component_Def-->
|
||||
|
||||
<!-- NewPlus Shell Extension for Win10 registration -->
|
||||
<Component Id="NewPlus_ShellExtension_win10" Guid="D5456D4A-6EEC-4B85-944D-6A6A4A74FFA6" Win64="yes">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\CLSID\{FF90D477-E32A-4BE8-8CC5-A502A97F5401}">
|
||||
<RegistryValue Type="string" Value="NewPlus Shell Extension Win10" />
|
||||
<RegistryValue Type="string" Name="ContextMenuOptIn" Value="" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Value="[WinUI3AppsInstallFolder]PowerToys.NewPlus.ShellExtension.win10.dll" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Apartment" />
|
||||
</RegistryKey>
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="SOFTWARE\Classes\Directory\background\ShellEx\ContextMenuHandlers\NewPlusShellExtensionWin10">
|
||||
<RegistryValue Type="string" Value="{FF90D477-E32A-4BE8-8CC5-A502A97F5401}"/>
|
||||
</RegistryKey>
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<ComponentGroup Id="NewPlusComponentGroup">
|
||||
@@ -40,8 +27,7 @@
|
||||
</RegistryKey>
|
||||
<RemoveFolder Id="RemoveFolderNewPlusAssetsFolder" Directory="NewPlusAssetsInstallFolder" On="uninstall"/>
|
||||
</Component>
|
||||
<ComponentRef Id="NewPlus_ShellExtension_win10" />
|
||||
</ComponentGroup>
|
||||
</ComponentGroup>
|
||||
|
||||
|
||||
<!-- Example templates -->
|
||||
@@ -81,7 +67,7 @@
|
||||
</Component>
|
||||
<ComponentRef Id="NewPlusTemplateFiles_Component" />
|
||||
<ComponentRef Id="NewPlusTemplateSubFiles_Component" />
|
||||
</ComponentGroup>
|
||||
</ComponentGroup>
|
||||
|
||||
</Fragment>
|
||||
</Wix>
|
||||
|
||||
@@ -14,22 +14,6 @@
|
||||
<DirectoryRef Id="PowerRenameAssetsFolder" FileSource="$(var.PowerRenameAssetsFilesPath)">
|
||||
<!-- Generated by generateFileComponents.ps1 -->
|
||||
<!--PowerRenameAssetsFiles_Component_Def-->
|
||||
<!-- !Warning! Make sure to change Component Guid if you update something here -->
|
||||
<Component Id="Module_PowerRename" Guid="40D43079-240E-402D-8CE8-571BFFA71175" Win64="yes">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\CLSID\{0440049F-D1DC-4E46-B27B-98393D79486B}">
|
||||
<RegistryValue Type="string" Value="PowerRename Shell Extension" />
|
||||
<RegistryValue Type="string" Name="ContextMenuOptIn" Value="" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Value="[WinUI3AppsInstallFolder]PowerToys.PowerRenameExt.dll" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Apartment" />
|
||||
</RegistryKey>
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="SOFTWARE\Classes\AllFileSystemObjects\ShellEx\ContextMenuHandlers\PowerRenameExt">
|
||||
<RegistryValue Type="string" Value="{0440049F-D1DC-4E46-B27B-98393D79486B}"/>
|
||||
</RegistryKey>
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="SOFTWARE\Classes\Directory\background\ShellEx\ContextMenuHandlers\PowerRenameExt">
|
||||
<RegistryValue Type="string" Value="{0440049F-D1DC-4E46-B27B-98393D79486B}"/>
|
||||
</RegistryKey>
|
||||
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<ComponentGroup Id="PowerRenameComponentGroup">
|
||||
@@ -39,7 +23,6 @@
|
||||
</RegistryKey>
|
||||
<RemoveFolder Id="RemoveFolderPowerRenameAssetsFolder" Directory="PowerRenameAssetsFolder" On="uninstall"/>
|
||||
</Component>
|
||||
<ComponentRef Id="Module_PowerRename" />
|
||||
</ComponentGroup>
|
||||
|
||||
</Fragment>
|
||||
|
||||
@@ -176,6 +176,18 @@
|
||||
<Custom Action="UnRegisterContextMenuPackages" Before="RemoveFiles">
|
||||
Installed AND (REMOVE="ALL")
|
||||
</Custom>
|
||||
<Custom Action="CleanImageResizerRuntimeRegistry" Before="RemoveFiles">
|
||||
Installed AND (REMOVE="ALL")
|
||||
</Custom>
|
||||
<Custom Action="CleanFileLocksmithRuntimeRegistry" Before="RemoveFiles">
|
||||
Installed AND (REMOVE="ALL")
|
||||
</Custom>
|
||||
<Custom Action="CleanPowerRenameRuntimeRegistry" Before="RemoveFiles">
|
||||
Installed AND (REMOVE="ALL")
|
||||
</Custom>
|
||||
<Custom Action="CleanNewPlusRuntimeRegistry" Before="RemoveFiles">
|
||||
Installed AND (REMOVE="ALL")
|
||||
</Custom>
|
||||
<Custom Action="UnRegisterCmdPalPackage" Before="RemoveFiles">
|
||||
Installed AND (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
|
||||
</Custom>
|
||||
@@ -437,6 +449,35 @@
|
||||
Execute="deferred"
|
||||
BinaryKey="PTCustomActions"
|
||||
DllEntry="UnRegisterContextMenuPackagesCA"
|
||||
/>
|
||||
|
||||
<CustomAction Id="CleanImageResizerRuntimeRegistry"
|
||||
Return="ignore"
|
||||
Impersonate="yes"
|
||||
Execute="deferred"
|
||||
BinaryKey="PTCustomActions"
|
||||
DllEntry="CleanImageResizerRuntimeRegistryCA"
|
||||
/>
|
||||
<CustomAction Id="CleanFileLocksmithRuntimeRegistry"
|
||||
Return="ignore"
|
||||
Impersonate="yes"
|
||||
Execute="deferred"
|
||||
BinaryKey="PTCustomActions"
|
||||
DllEntry="CleanFileLocksmithRuntimeRegistryCA"
|
||||
/>
|
||||
<CustomAction Id="CleanPowerRenameRuntimeRegistry"
|
||||
Return="ignore"
|
||||
Impersonate="yes"
|
||||
Execute="deferred"
|
||||
BinaryKey="PTCustomActions"
|
||||
DllEntry="CleanPowerRenameRuntimeRegistryCA"
|
||||
/>
|
||||
<CustomAction Id="CleanNewPlusRuntimeRegistry"
|
||||
Return="ignore"
|
||||
Impersonate="yes"
|
||||
Execute="deferred"
|
||||
BinaryKey="PTCustomActions"
|
||||
DllEntry="CleanNewPlusRuntimeRegistryCA"
|
||||
/>
|
||||
|
||||
<CustomAction Id="UnRegisterCmdPalPackage"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<Fragment>
|
||||
<!-- Resource directories should be added only if the installer is built on the build farm -->
|
||||
<?ifdef env.IsPipeline?>
|
||||
<?foreach ParentDirectory in INSTALLFOLDER;WinUI3AppsInstallFolder;HistoryPluginFolder;CalculatorPluginFolder;FolderPluginFolder;ProgramPluginFolder;ShellPluginFolder;IndexerPluginFolder;UnitConverterPluginFolder;ValueGeneratorPluginFolder;UriPluginFolder;WindowWalkerPluginFolder;OneNotePluginFolder;RegistryPluginFolder;VSCodeWorkspacesPluginFolder;ServicePluginFolder;SystemPluginFolder;TimeDatePluginFolder;WindowsSettingsPluginFolder;WindowsTerminalPluginFolder;WebSearchPluginFolder;PowerToysPluginFolder?>
|
||||
<?foreach ParentDirectory in INSTALLFOLDER;HistoryPluginFolder;CalculatorPluginFolder;FolderPluginFolder;ProgramPluginFolder;ShellPluginFolder;IndexerPluginFolder;UnitConverterPluginFolder;ValueGeneratorPluginFolder;UriPluginFolder;WindowWalkerPluginFolder;OneNotePluginFolder;RegistryPluginFolder;VSCodeWorkspacesPluginFolder;ServicePluginFolder;SystemPluginFolder;TimeDatePluginFolder;WindowsSettingsPluginFolder;WindowsTerminalPluginFolder;WebSearchPluginFolder;PowerToysPluginFolder?>
|
||||
<DirectoryRef Id="$(var.ParentDirectory)">
|
||||
<!-- Resource file directories -->
|
||||
<?foreach Language in $(var.LocLanguageList)?>
|
||||
@@ -181,7 +181,7 @@
|
||||
</Component>
|
||||
<Component
|
||||
Id="ImageResizer_$(var.IdSafeLanguage)_Component"
|
||||
Directory="Resource$(var.IdSafeLanguage)WinUI3AppsInstallFolder"
|
||||
Directory="Resource$(var.IdSafeLanguage)INSTALLFOLDER"
|
||||
Guid="$(var.CompGUIDPrefix)02">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="ImageResizer_$(var.IdSafeLanguage)_Component" Value="" KeyPath="yes"/>
|
||||
@@ -553,7 +553,6 @@
|
||||
<RemoveFolder Id="RemoveFolderResourcesResource$(var.IdSafeLanguage)HistoryPluginFolder" Directory="Resource$(var.IdSafeLanguage)HistoryPluginFolder" On="uninstall"/>
|
||||
<RemoveFolder Id="RemoveFolderResourcesResource$(var.IdSafeLanguage)PowerToysPluginFolder" Directory="Resource$(var.IdSafeLanguage)PowerToysPluginFolder" On="uninstall"/>
|
||||
<RemoveFolder Id="RemoveFolderResourcesResource$(var.IdSafeLanguage)ValueGeneratorPluginFolder" Directory="Resource$(var.IdSafeLanguage)ValueGeneratorPluginFolder" On="uninstall"/>
|
||||
<RemoveFolder Id="RemoveFolderResourcesResource$(var.IdSafeLanguage)WinUI3AppsInstallFolder" Directory="Resource$(var.IdSafeLanguage)WinUI3AppsInstallFolder" On="uninstall"/>
|
||||
<?undef IdSafeLanguage?>
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
|
||||
@@ -1153,6 +1153,113 @@ UINT __stdcall UnRegisterContextMenuPackagesCA(MSIHANDLE hInstall)
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall CleanImageResizerRuntimeRegistryCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
hr = WcaInitialize(hInstall, "CleanImageResizerRuntimeRegistryCA");
|
||||
|
||||
try
|
||||
{
|
||||
const wchar_t* CLSID_STR = L"{51B4D7E5-7568-4234-B4BB-47FB3C016A69}";
|
||||
const wchar_t* exts[] = { L".bmp", L".dib", L".gif", L".jfif", L".jpe", L".jpeg", L".jpg", L".jxr", L".png", L".rle", L".tif", L".tiff", L".wdp" };
|
||||
|
||||
auto deleteKeyRecursive = [](HKEY root, const std::wstring &path) {
|
||||
RegDeleteTreeW(root, path.c_str());
|
||||
};
|
||||
|
||||
// InprocServer32 chain root CLSID
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" + std::wstring(CLSID_STR));
|
||||
// DragDrop handler
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\Directory\\ShellEx\\DragDropHandlers\\ImageResizer");
|
||||
// Extensions
|
||||
for (auto ext : exts)
|
||||
{
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\SystemFileAssociations\\" + std::wstring(ext) + L"\\ShellEx\\ContextMenuHandlers\\ImageResizer");
|
||||
}
|
||||
// Sentinel
|
||||
RegDeleteTreeW(HKEY_CURRENT_USER, L"Software\\Microsoft\\PowerToys\\ImageResizer");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
er = ERROR_INSTALL_FAILURE;
|
||||
}
|
||||
|
||||
er = er == ERROR_SUCCESS ? (SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE) : er;
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall CleanFileLocksmithRuntimeRegistryCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
hr = WcaInitialize(hInstall, "CleanFileLocksmithRuntimeRegistryCA");
|
||||
try
|
||||
{
|
||||
const wchar_t* CLSID_STR = L"{84D68575-E186-46AD-B0CB-BAEB45EE29C0}";
|
||||
auto deleteKeyRecursive = [](HKEY root, const std::wstring& path) {
|
||||
RegDeleteTreeW(root, path.c_str());
|
||||
};
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" + std::wstring(CLSID_STR));
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\AllFileSystemObjects\\ShellEx\\ContextMenuHandlers\\FileLocksmithExt");
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\Drive\\ShellEx\\ContextMenuHandlers\\FileLocksmithExt");
|
||||
RegDeleteTreeW(HKEY_CURRENT_USER, L"Software\\Microsoft\\PowerToys\\FileLocksmith");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
er = ERROR_INSTALL_FAILURE;
|
||||
}
|
||||
er = er == ERROR_SUCCESS ? (SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE) : er;
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall CleanPowerRenameRuntimeRegistryCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
hr = WcaInitialize(hInstall, "CleanPowerRenameRuntimeRegistryCA");
|
||||
try
|
||||
{
|
||||
const wchar_t* CLSID_STR = L"{0440049F-D1DC-4E46-B27B-98393D79486B}";
|
||||
auto deleteKeyRecursive = [](HKEY root, const std::wstring& path) {
|
||||
RegDeleteTreeW(root, path.c_str());
|
||||
};
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" + std::wstring(CLSID_STR));
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\AllFileSystemObjects\\ShellEx\\ContextMenuHandlers\\PowerRenameExt");
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\Directory\\background\\ShellEx\\ContextMenuHandlers\\PowerRenameExt");
|
||||
RegDeleteTreeW(HKEY_CURRENT_USER, L"Software\\Microsoft\\PowerToys\\PowerRename");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
er = ERROR_INSTALL_FAILURE;
|
||||
}
|
||||
er = er == ERROR_SUCCESS ? (SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE) : er;
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall CleanNewPlusRuntimeRegistryCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
hr = WcaInitialize(hInstall, "CleanNewPlusRuntimeRegistryCA");
|
||||
try
|
||||
{
|
||||
const wchar_t* CLSID_STR = L"{FF90D477-E32A-4BE8-8CC5-A502A97F5401}";
|
||||
auto deleteKeyRecursive = [](HKEY root, const std::wstring& path) {
|
||||
RegDeleteTreeW(root, path.c_str());
|
||||
};
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" + std::wstring(CLSID_STR));
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\Directory\\background\\ShellEx\\ContextMenuHandlers\\NewPlusShellExtensionWin10");
|
||||
RegDeleteTreeW(HKEY_CURRENT_USER, L"Software\\Microsoft\\PowerToys\\NewPlus");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
er = ERROR_INSTALL_FAILURE;
|
||||
}
|
||||
er = er == ERROR_SUCCESS ? (SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE) : er;
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
@@ -28,3 +28,7 @@ EXPORTS
|
||||
UninstallCommandNotFoundModuleCA
|
||||
UpgradeCommandNotFoundModuleCA
|
||||
UnsetAdvancedPasteAPIKeyCA
|
||||
CleanImageResizerRuntimeRegistryCA
|
||||
CleanFileLocksmithRuntimeRegistryCA
|
||||
CleanPowerRenameRuntimeRegistryCA
|
||||
CleanNewPlusRuntimeRegistryCA
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<clear />
|
||||
<add key="PowerToysPublicDependencies" value="https://pkgs.dev.azure.com/shine-oss/PowerToys/_packaging/PowerToysPublicDependencies%40Local/nuget/v3/index.json" />
|
||||
<add key="PowerToysPublicDependencies" value="https://pkgs.dev.azure.com/shine-oss/PowerToys/_packaging/PowerToysPublicDependencies/nuget/v3/index.json" />
|
||||
</packageSources>
|
||||
<packageSourceMapping>
|
||||
<packageSource key="PowerToysPublicDependencies">
|
||||
<package pattern="*" />
|
||||
</packageSource>
|
||||
</packageSourceMapping>
|
||||
</configuration>
|
||||
</configuration>
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace Common.UI
|
||||
Awake,
|
||||
ColorPicker,
|
||||
CmdNotFound,
|
||||
LightSwitch,
|
||||
FancyZones,
|
||||
FileLocksmith,
|
||||
Run,
|
||||
@@ -61,8 +60,6 @@ namespace Common.UI
|
||||
return "ColorPicker";
|
||||
case SettingsWindow.CmdNotFound:
|
||||
return "CmdNotFound";
|
||||
case SettingsWindow.LightSwitch:
|
||||
return "LightSwitch";
|
||||
case SettingsWindow.FancyZones:
|
||||
return "FancyZones";
|
||||
case SettingsWindow.FileLocksmith:
|
||||
|
||||
@@ -28,10 +28,6 @@ namespace winrt::PowerToys::GPOWrapper::implementation
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredCropAndLockEnabledValue());
|
||||
}
|
||||
GpoRuleConfigured GPOWrapper::GetConfiguredLightSwitchEnabledValue()
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredLightSwitchEnabledValue());
|
||||
}
|
||||
GpoRuleConfigured GPOWrapper::GetConfiguredFancyZonesEnabledValue()
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredFancyZonesEnabledValue());
|
||||
|
||||
@@ -13,7 +13,6 @@ namespace winrt::PowerToys::GPOWrapper::implementation
|
||||
static GpoRuleConfigured GetConfiguredCmdPalEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredColorPickerEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredCropAndLockEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredLightSwitchEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredFancyZonesEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredFileLocksmithEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredSvgPreviewEnabledValue();
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace PowerToys
|
||||
static GpoRuleConfigured GetConfiguredCmdPalEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredColorPickerEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredCropAndLockEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredLightSwitchEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredFancyZonesEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredFileLocksmithEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredSvgPreviewEnabledValue();
|
||||
|
||||
@@ -12,7 +12,6 @@ namespace ManagedCommon
|
||||
ColorPicker,
|
||||
CmdPal,
|
||||
CropAndLock,
|
||||
LightSwitch,
|
||||
EnvironmentVariables,
|
||||
FancyZones,
|
||||
FileLocksmith,
|
||||
|
||||
@@ -81,7 +81,6 @@ struct LogSettings
|
||||
inline const static std::string workspacesSnapshotToolLoggerName = "workspaces-snapshot-tool";
|
||||
inline const static std::wstring workspacesSnapshotToolLogPath = L"workspaces-snapshot-tool-log.log";
|
||||
inline const static std::string zoomItLoggerName = "zoom-it";
|
||||
inline const static std::string lightSwitchLoggerName = "light-switch";
|
||||
inline const static int retention = 30;
|
||||
std::wstring logLevel;
|
||||
LogSettings();
|
||||
|
||||
@@ -257,10 +257,7 @@ inline HANDLE run_elevated(const std::wstring& file, const std::wstring& params,
|
||||
exec_info.nShow = SW_HIDE;
|
||||
}
|
||||
|
||||
// failing bc using "runas" with PowerToys.exe already running?
|
||||
BOOL result = ShellExecuteExW(&exec_info);
|
||||
|
||||
return result ? exec_info.hProcess : nullptr;
|
||||
return ShellExecuteExW(&exec_info) ? exec_info.hProcess : nullptr;
|
||||
}
|
||||
|
||||
// Run command as non-elevated user, returns true if succeeded, puts the process id into returnPid if returnPid != NULL
|
||||
|
||||
@@ -30,7 +30,6 @@ namespace powertoys_gpo
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_CMD_NOT_FOUND = L"ConfigureEnabledUtilityCmdNotFound";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_COLOR_PICKER = L"ConfigureEnabledUtilityColorPicker";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_CROP_AND_LOCK = L"ConfigureEnabledUtilityCropAndLock";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_LIGHT_SWITCH = L"ConfigureEnabledUtilityLightSwitch";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_FANCYZONES = L"ConfigureEnabledUtilityFancyZones";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_FILE_LOCKSMITH = L"ConfigureEnabledUtilityFileLocksmith";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_SVG_PREVIEW = L"ConfigureEnabledUtilityFileExplorerSVGPreview";
|
||||
@@ -296,11 +295,6 @@ namespace powertoys_gpo
|
||||
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_CROP_AND_LOCK);
|
||||
}
|
||||
|
||||
inline gpo_rule_configured_t getConfiguredLightSwitchEnabledValue()
|
||||
{
|
||||
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_LIGHT_SWITCH);
|
||||
}
|
||||
|
||||
inline gpo_rule_configured_t getConfiguredFancyZonesEnabledValue()
|
||||
{
|
||||
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_FANCYZONES);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <filesystem>
|
||||
#include <common/version/version.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/logger/logger_settings.h>
|
||||
|
||||
namespace LoggerHelpers
|
||||
{
|
||||
|
||||
266
src/common/utils/shell_ext_registration.h
Normal file
266
src/common/utils/shell_ext_registration.h
Normal file
@@ -0,0 +1,266 @@
|
||||
// Shared runtime shell extension registration utility for PowerToys modules.
|
||||
// Provides a generic EnsureRegistered function so individual modules only need
|
||||
// to supply a specification (CLSID, sentinel, handler key paths, etc.).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <windows.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
#include "../logger/logger.h"
|
||||
|
||||
namespace runtime_shell_ext
|
||||
{
|
||||
struct Spec
|
||||
{
|
||||
// Mandatory
|
||||
std::wstring clsid; // e.g. {GUID}
|
||||
std::wstring sentinelKey; // e.g. Software\\Microsoft\\PowerToys\\ModuleName
|
||||
std::wstring sentinelValue; // e.g. ContextMenuRegistered
|
||||
std::vector<std::wstring> dllFileCandidates; // relative filenames (pick first existing)
|
||||
std::vector<std::wstring> contextMenuHandlerKeyPaths; // full HKCU relative paths where default value = CLSID
|
||||
|
||||
// Optional
|
||||
std::wstring friendlyName; // if non-empty written as default under CLSID root
|
||||
bool writeOptInEmptyValue = true; // write ContextMenuOptIn="" under CLSID root (legacy pattern)
|
||||
bool writeThreadingModel = true; // write Apartment threading model
|
||||
std::vector<std::wstring> extraAssociationPaths; // additional key paths (DragDropHandlers etc.) default=CLSID
|
||||
std::vector<std::wstring> systemFileAssocExtensions; // e.g. .png -> Software\\Classes\\SystemFileAssociations\\.png\\ShellEx\\ContextMenuHandlers\\<HandlerName>
|
||||
std::wstring systemFileAssocHandlerName; // e.g. ImageResizer
|
||||
std::wstring representativeSystemExt; // used to decide if associations need repair (.png)
|
||||
bool logRepairs = true;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// Minimal RAII wrapper for HKEY
|
||||
struct unique_hkey
|
||||
{
|
||||
HKEY h{ nullptr };
|
||||
unique_hkey() = default;
|
||||
explicit unique_hkey(HKEY handle) : h(handle) {}
|
||||
~unique_hkey() { if (h) RegCloseKey(h); }
|
||||
unique_hkey(const unique_hkey&) = delete;
|
||||
unique_hkey& operator=(const unique_hkey&) = delete;
|
||||
unique_hkey(unique_hkey&& other) noexcept : h(other.h) { other.h = nullptr; }
|
||||
unique_hkey& operator=(unique_hkey&& other) noexcept { if (this != &other) { if (h) RegCloseKey(h); h = other.h; other.h = nullptr; } return *this; }
|
||||
HKEY get() const { return h; }
|
||||
HKEY* put() { if (h) { RegCloseKey(h); h = nullptr; } return &h; }
|
||||
};
|
||||
inline std::wstring base_dir_from_module(HMODULE h)
|
||||
{
|
||||
wchar_t buf[MAX_PATH];
|
||||
if (GetModuleFileNameW(h, buf, MAX_PATH))
|
||||
{
|
||||
PathRemoveFileSpecW(buf);
|
||||
return buf;
|
||||
}
|
||||
return L"";
|
||||
}
|
||||
|
||||
inline std::wstring pick_existing_dll(const std::wstring& base, const std::vector<std::wstring>& candidates)
|
||||
{
|
||||
for (const auto& rel : candidates)
|
||||
{
|
||||
std::wstring full = base + L"\\" + rel;
|
||||
if (GetFileAttributesW(full.c_str()) != INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
return full;
|
||||
}
|
||||
}
|
||||
if (!candidates.empty())
|
||||
{
|
||||
return base + L"\\" + candidates.front();
|
||||
}
|
||||
return L"";
|
||||
}
|
||||
|
||||
inline bool sentinel_exists(const Spec& spec)
|
||||
{
|
||||
unique_hkey key;
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, spec.sentinelKey.c_str(), 0, KEY_READ, key.put()) != ERROR_SUCCESS)
|
||||
return false;
|
||||
DWORD v = 0; DWORD sz = sizeof(v);
|
||||
return RegQueryValueExW(key.get(), spec.sentinelValue.c_str(), nullptr, nullptr, reinterpret_cast<LPBYTE>(&v), &sz) == ERROR_SUCCESS && v == 1;
|
||||
}
|
||||
|
||||
inline void write_sentinel(const Spec& spec)
|
||||
{
|
||||
unique_hkey key;
|
||||
if (RegCreateKeyExW(HKEY_CURRENT_USER, spec.sentinelKey.c_str(), 0, nullptr, 0, KEY_WRITE, nullptr, key.put(), nullptr) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD one = 1;
|
||||
RegSetValueExW(key.get(), spec.sentinelValue.c_str(), 0, REG_DWORD, reinterpret_cast<const BYTE*>(&one), sizeof(one));
|
||||
}
|
||||
}
|
||||
|
||||
inline void write_inproc_server(const Spec& spec, const std::wstring& dllPath)
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
std::wstring clsidRoot = L"Software\\Classes\\CLSID\\"s + spec.clsid;
|
||||
std::wstring inprocKey = clsidRoot + L"\\InprocServer32";
|
||||
{
|
||||
unique_hkey key;
|
||||
if (RegCreateKeyExW(HKEY_CURRENT_USER, clsidRoot.c_str(), 0, nullptr, 0, KEY_WRITE, nullptr, key.put(), nullptr) == ERROR_SUCCESS)
|
||||
{
|
||||
if (!spec.friendlyName.empty())
|
||||
{
|
||||
RegSetValueExW(key.get(), nullptr, 0, REG_SZ, reinterpret_cast<const BYTE*>(spec.friendlyName.c_str()), static_cast<DWORD>((spec.friendlyName.size() + 1) * sizeof(wchar_t)));
|
||||
}
|
||||
if (spec.writeOptInEmptyValue)
|
||||
{
|
||||
const wchar_t* optIn = L"ContextMenuOptIn";
|
||||
const wchar_t empty = L'\0';
|
||||
RegSetValueExW(key.get(), optIn, 0, REG_SZ, reinterpret_cast<const BYTE*>(&empty), sizeof(empty));
|
||||
}
|
||||
}
|
||||
}
|
||||
unique_hkey key;
|
||||
if (RegCreateKeyExW(HKEY_CURRENT_USER, inprocKey.c_str(), 0, nullptr, 0, KEY_WRITE, nullptr, key.put(), nullptr) == ERROR_SUCCESS)
|
||||
{
|
||||
RegSetValueExW(key.get(), nullptr, 0, REG_SZ, reinterpret_cast<const BYTE*>(dllPath.c_str()), static_cast<DWORD>((dllPath.size() + 1) * sizeof(wchar_t)));
|
||||
if (spec.writeThreadingModel)
|
||||
{
|
||||
const wchar_t* tm = L"Apartment";
|
||||
RegSetValueExW(key.get(), L"ThreadingModel", 0, REG_SZ, reinterpret_cast<const BYTE*>(tm), static_cast<DWORD>((wcslen(tm) + 1) * sizeof(wchar_t)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline std::wstring read_inproc_server(const Spec& spec)
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
std::wstring inprocKey = L"Software\\Classes\\CLSID\\"s + spec.clsid + L"\\InprocServer32";
|
||||
unique_hkey key;
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, inprocKey.c_str(), 0, KEY_READ, key.put()) != ERROR_SUCCESS)
|
||||
return L"";
|
||||
wchar_t buf[MAX_PATH]; DWORD sz = sizeof(buf);
|
||||
if (RegQueryValueExW(key.get(), nullptr, nullptr, nullptr, reinterpret_cast<LPBYTE>(buf), &sz) == ERROR_SUCCESS)
|
||||
return std::wstring(buf);
|
||||
return L"";
|
||||
}
|
||||
|
||||
inline void write_default_value_key(const std::wstring& keyPath, const std::wstring& value)
|
||||
{
|
||||
unique_hkey key;
|
||||
if (RegCreateKeyExW(HKEY_CURRENT_USER, keyPath.c_str(), 0, nullptr, 0, KEY_WRITE, nullptr, key.put(), nullptr) == ERROR_SUCCESS)
|
||||
{
|
||||
RegSetValueExW(key.get(), nullptr, 0, REG_SZ, reinterpret_cast<const BYTE*>(value.c_str()), static_cast<DWORD>((value.size() + 1) * sizeof(wchar_t)));
|
||||
}
|
||||
}
|
||||
|
||||
inline bool representative_association_exists(const Spec& spec)
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
if (spec.representativeSystemExt.empty() || spec.systemFileAssocHandlerName.empty())
|
||||
return true;
|
||||
std::wstring keyPath = L"Software\\Classes\\SystemFileAssociations\\"s + spec.representativeSystemExt + L"\\ShellEx\\ContextMenuHandlers\\" + spec.systemFileAssocHandlerName;
|
||||
unique_hkey key;
|
||||
return RegOpenKeyExW(HKEY_CURRENT_USER, keyPath.c_str(), 0, KEY_READ, key.put()) == ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool EnsureRegistered(const Spec& spec, HMODULE moduleInstance)
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
auto base = detail::base_dir_from_module(moduleInstance);
|
||||
auto dllPath = detail::pick_existing_dll(base, spec.dllFileCandidates);
|
||||
if (dllPath.empty())
|
||||
{
|
||||
Logger::error(L"Runtime registration: cannot locate dll path for CLSID {}", spec.clsid);
|
||||
return false;
|
||||
}
|
||||
bool exists = detail::sentinel_exists(spec);
|
||||
bool repaired = false;
|
||||
if (exists)
|
||||
{
|
||||
auto current = detail::read_inproc_server(spec);
|
||||
if (_wcsicmp(current.c_str(), dllPath.c_str()) != 0)
|
||||
{
|
||||
detail::write_inproc_server(spec, dllPath);
|
||||
repaired = true;
|
||||
}
|
||||
if (!detail::representative_association_exists(spec))
|
||||
{
|
||||
repaired = true;
|
||||
}
|
||||
}
|
||||
if (!exists)
|
||||
{
|
||||
detail::write_inproc_server(spec, dllPath);
|
||||
}
|
||||
if (!exists || repaired)
|
||||
{
|
||||
for (const auto& path : spec.contextMenuHandlerKeyPaths)
|
||||
{
|
||||
detail::write_default_value_key(path, spec.clsid);
|
||||
}
|
||||
for (const auto& path : spec.extraAssociationPaths)
|
||||
{
|
||||
detail::write_default_value_key(path, spec.clsid);
|
||||
}
|
||||
if (!spec.systemFileAssocExtensions.empty() && !spec.systemFileAssocHandlerName.empty())
|
||||
{
|
||||
for (const auto& ext : spec.systemFileAssocExtensions)
|
||||
{
|
||||
std::wstring path = L"Software\\Classes\\SystemFileAssociations\\"s + ext + L"\\ShellEx\\ContextMenuHandlers\\" + spec.systemFileAssocHandlerName;
|
||||
detail::write_default_value_key(path, spec.clsid);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!exists)
|
||||
{
|
||||
detail::write_sentinel(spec);
|
||||
Logger::info(L"Runtime registration completed for CLSID {}", spec.clsid);
|
||||
}
|
||||
else if (repaired && spec.logRepairs)
|
||||
{
|
||||
Logger::info(L"Runtime registration repaired for CLSID {}", spec.clsid);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Unregister(const Spec& spec)
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
// Remove handler key paths
|
||||
for (const auto& path : spec.contextMenuHandlerKeyPaths)
|
||||
{
|
||||
RegDeleteTreeW(HKEY_CURRENT_USER, path.c_str());
|
||||
}
|
||||
// Remove extra association paths (e.g., drag & drop handlers)
|
||||
for (const auto& path : spec.extraAssociationPaths)
|
||||
{
|
||||
RegDeleteTreeW(HKEY_CURRENT_USER, path.c_str());
|
||||
}
|
||||
// Remove per-extension system file association handler keys
|
||||
if (!spec.systemFileAssocExtensions.empty() && !spec.systemFileAssocHandlerName.empty())
|
||||
{
|
||||
for (const auto& ext : spec.systemFileAssocExtensions)
|
||||
{
|
||||
std::wstring keyPath = L"Software\\Classes\\SystemFileAssociations\\"s + ext + L"\\ShellEx\\ContextMenuHandlers\\" + spec.systemFileAssocHandlerName;
|
||||
RegDeleteTreeW(HKEY_CURRENT_USER, keyPath.c_str());
|
||||
}
|
||||
}
|
||||
// Remove CLSID branch
|
||||
if (!spec.clsid.empty())
|
||||
{
|
||||
std::wstring clsidRoot = L"Software\\Classes\\CLSID\\"s + spec.clsid;
|
||||
RegDeleteTreeW(HKEY_CURRENT_USER, clsidRoot.c_str());
|
||||
}
|
||||
// Remove sentinel value (not deleting entire key to avoid disturbing other values)
|
||||
if (!spec.sentinelKey.empty() && !spec.sentinelValue.empty())
|
||||
{
|
||||
HKEY hKey{};
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, spec.sentinelKey.c_str(), 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
RegDeleteValueW(hKey, spec.sentinelValue.c_str());
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
}
|
||||
Logger::info(L"Successfully unregistered CLSID {}", spec.clsid);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -137,16 +137,6 @@
|
||||
<decimal value="0" />
|
||||
</disabledValue>
|
||||
</policy>
|
||||
<policy name="ConfigureEnabledUtilityLightSwitch" class="Both" displayName="$(string.ConfigureEnabledUtilityLightSwitch)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityLightSwitch">
|
||||
<parentCategory ref="PowerToys" />
|
||||
<supportedOn ref="SUPPORTED_POWERTOYS_0_90_0" />
|
||||
<enabledValue>
|
||||
<decimal value="1" />
|
||||
</enabledValue>
|
||||
<disabledValue>
|
||||
<decimal value="0" />
|
||||
</disabledValue>
|
||||
</policy>
|
||||
<policy name="ConfigureEnabledUtilityEnvironmentVariables" class="Both" displayName="$(string.ConfigureEnabledUtilityEnvironmentVariables)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityEnvironmentVariables">
|
||||
<parentCategory ref="PowerToys" />
|
||||
<supportedOn ref="SUPPORTED_POWERTOYS_0_75_0" />
|
||||
|
||||
@@ -245,7 +245,6 @@ If you don't configure this policy, the user will be able to control the setting
|
||||
<string id="ConfigureEnabledUtilityCmdNotFound">Command Not Found: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityCmdPal">CmdPal: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityCropAndLock">Crop And Lock: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityLightSwitch">Light Switch: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityEnvironmentVariables">Environment Variables: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityFancyZones">FancyZones: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityFileLocksmith">File Locksmith: Configure enabled state</string>
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
<ClInclude Include="ClassFactory.h" />
|
||||
<ClInclude Include="dllmain.h" />
|
||||
<ClInclude Include="ExplorerCommand.h" />
|
||||
<ClInclude Include="RuntimeRegistration.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="resource.base.h" />
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
<ClInclude Include="dllmain.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RuntimeRegistration.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "FileLocksmithLib/Constants.h"
|
||||
#include "FileLocksmithLib/Settings.h"
|
||||
#include "FileLocksmithLib/Trace.h"
|
||||
#include "RuntimeRegistration.h"
|
||||
|
||||
#include "dllmain.h"
|
||||
#include "Generated Files/resource.h"
|
||||
@@ -82,12 +83,17 @@ public:
|
||||
{
|
||||
std::wstring path = get_module_folderpath(globals::instance);
|
||||
std::wstring packageUri = path + L"\\FileLocksmithContextMenuPackage.msix";
|
||||
|
||||
if (!package::IsPackageRegisteredWithPowerToysVersion(constants::nonlocalizable::ContextMenuPackageName))
|
||||
{
|
||||
package::RegisterSparsePackage(path, packageUri);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
FileLocksmithRuntimeRegistration::EnsureRegistered();
|
||||
#endif
|
||||
}
|
||||
|
||||
m_enabled = true;
|
||||
}
|
||||
@@ -95,6 +101,13 @@ public:
|
||||
virtual void disable() override
|
||||
{
|
||||
Logger::info(L"File Locksmith disabled");
|
||||
if (!package::IsWin11OrGreater())
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
FileLocksmithRuntimeRegistration::Unregister();
|
||||
Logger::info(L"File Locksmith context menu unregistered (Win10)");
|
||||
#endif
|
||||
}
|
||||
m_enabled = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// Header-only runtime registration for FileLocksmith context menu extension.
|
||||
#pragma once
|
||||
|
||||
#include <common/utils/shell_ext_registration.h>
|
||||
|
||||
namespace globals { extern HMODULE instance; }
|
||||
|
||||
namespace FileLocksmithRuntimeRegistration
|
||||
{
|
||||
namespace
|
||||
{
|
||||
inline runtime_shell_ext::Spec BuildSpec()
|
||||
{
|
||||
runtime_shell_ext::Spec spec;
|
||||
spec.clsid = L"{84D68575-E186-46AD-B0CB-BAEB45EE29C0}";
|
||||
spec.sentinelKey = L"Software\\Microsoft\\PowerToys\\FileLocksmith";
|
||||
spec.sentinelValue = L"ContextMenuRegistered";
|
||||
spec.dllFileCandidates = { L"PowerToys.FileLocksmithExt.dll" };
|
||||
spec.contextMenuHandlerKeyPaths = {
|
||||
L"Software\\Classes\\AllFileSystemObjects\\ShellEx\\ContextMenuHandlers\\FileLocksmithExt",
|
||||
L"Software\\Classes\\Drive\\ShellEx\\ContextMenuHandlers\\FileLocksmithExt" };
|
||||
spec.friendlyName = L"File Locksmith Shell Extension";
|
||||
return spec;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool EnsureRegistered()
|
||||
{
|
||||
return runtime_shell_ext::EnsureRegistered(BuildSpec(), globals::instance);
|
||||
}
|
||||
|
||||
inline void Unregister()
|
||||
{
|
||||
runtime_shell_ext::Unregister(BuildSpec());
|
||||
}
|
||||
}
|
||||
@@ -298,34 +298,5 @@ namespace Hosts.Tests
|
||||
var hidden = fileSystem.FileInfo.New(service.HostsFilePath).Attributes.HasFlag(FileAttributes.Hidden);
|
||||
Assert.IsTrue(hidden);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task NoLeadingSpaces_Disabled_RemovesIndent()
|
||||
{
|
||||
var content =
|
||||
@"10.1.1.1 host host.local # comment
|
||||
10.1.1.2 host2 host2.local # another comment
|
||||
";
|
||||
|
||||
var expected =
|
||||
@"10.1.1.1 host host.local # comment
|
||||
10.1.1.2 host2 host2.local # another comment
|
||||
# 10.1.1.30 host30 host30.local # new entry
|
||||
";
|
||||
|
||||
var fs = new CustomMockFileSystem();
|
||||
var settings = new Mock<IUserSettings>();
|
||||
settings.Setup(s => s.NoLeadingSpaces).Returns(true);
|
||||
var svc = new HostsService(fs, settings.Object, _elevationHelper.Object);
|
||||
fs.AddFile(svc.HostsFilePath, new MockFileData(content));
|
||||
|
||||
var data = await svc.ReadAsync();
|
||||
var entries = data.Entries.ToList();
|
||||
entries.Add(new Entry(0, "10.1.1.30", "host30 host30.local", "new entry", false));
|
||||
await svc.WriteAsync(data.AdditionalLines, entries);
|
||||
|
||||
var result = fs.GetFile(svc.HostsFilePath);
|
||||
Assert.AreEqual(expected, result.TextContents);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,6 @@ namespace Hosts.Settings
|
||||
|
||||
private bool _loopbackDuplicates;
|
||||
|
||||
public bool NoLeadingSpaces { get; private set; }
|
||||
|
||||
public bool LoopbackDuplicates
|
||||
{
|
||||
get => _loopbackDuplicates;
|
||||
@@ -90,7 +88,6 @@ namespace Hosts.Settings
|
||||
AdditionalLinesPosition = (HostsAdditionalLinesPosition)settings.Properties.AdditionalLinesPosition;
|
||||
Encoding = (HostsEncoding)settings.Properties.Encoding;
|
||||
LoopbackDuplicates = settings.Properties.LoopbackDuplicates;
|
||||
NoLeadingSpaces = settings.Properties.NoLeadingSpaces;
|
||||
}
|
||||
|
||||
retry = false;
|
||||
|
||||
@@ -157,7 +157,7 @@ namespace HostsUILib.Helpers
|
||||
{
|
||||
lineBuilder.Append('#').Append(' ');
|
||||
}
|
||||
else if (anyDisabled && !_userSettings.NoLeadingSpaces)
|
||||
else if (anyDisabled)
|
||||
{
|
||||
lineBuilder.Append(' ').Append(' ');
|
||||
}
|
||||
|
||||
@@ -19,7 +19,5 @@ namespace HostsUILib.Settings
|
||||
event EventHandler LoopbackDuplicatesChanged;
|
||||
|
||||
public delegate void OpenSettingsFunction();
|
||||
|
||||
public bool NoLeadingSpaces { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 0,1,0,0
|
||||
PRODUCTVERSION 0,1,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Company Name"
|
||||
VALUE "FileDescription", "Light Switch Module"
|
||||
VALUE "FileVersion", "0.1.0.0"
|
||||
VALUE "InternalName", "Light Switch"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2019 Company Name"
|
||||
VALUE "OriginalFilename", "PowerToys.LightSwitchModuleInterface.dll"
|
||||
VALUE "ProductName", "Light Switch"
|
||||
VALUE "ProductVersion", "0.1.0.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
@@ -1,25 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.14.36127.28 d17.14
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LightSwitchModuleInterface", "LightSwitchModuleInterface.vcxproj", "{38177D56-6AD1-4ADF-88C9-2843A7932166}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Debug|x64.Build.0 = Debug|x64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Release|x64.ActiveCfg = Release|x64
|
||||
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {FAF634A3-0D98-4A45-B082-D93B59782572}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,229 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|ARM64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>ARM64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|ARM64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>ARM64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{38177d56-6ad1-4adf-88c9-2843a7932166}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>LightSwitchModuleInterface</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>LightSwitchModuleInterface</ProjectName>
|
||||
<TargetName>PowerToys.LightSwitchModuleInterface</TargetName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>
|
||||
$(SolutionDir)src\;
|
||||
$(SolutionDir)src\modules;
|
||||
$(SolutionDir)src\common\Telemetry;
|
||||
%(AdditionalIncludeDirectories)
|
||||
</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">$(CoreLibraryDependencies);%(AdditionalDependencies);advapi32.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="ThemeHelper.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ThemeHelper.cpp" />
|
||||
<ClCompile Include="trace.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="LightSwitchModuleInterface.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj">
|
||||
<Project>{4aed67b6-55fd-486f-b917-e543dee2cb3c}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -1,50 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ThemeHelper.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ThemeHelper.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{bbf22ac8-46f8-4206-b44b-9c3897e99ce5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{530ed784-9a70-46a0-8fb6-20d5dee4f7d3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{da1cb871-86d3-414c-adf5-a7e9f2077d2f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="LightSwitchModuleInterface.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,81 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include <windows.h>
|
||||
#include "ThemeHelper.h"
|
||||
|
||||
// Controls changing the themes.
|
||||
|
||||
void SetAppsTheme(bool mode)
|
||||
{
|
||||
HKEY hKey;
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
0,
|
||||
KEY_SET_VALUE,
|
||||
&hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD value = mode;
|
||||
RegSetValueEx(hKey, L"AppsUseLightTheme", 0, REG_DWORD, reinterpret_cast<const BYTE*>(&value), sizeof(value));
|
||||
RegCloseKey(hKey);
|
||||
|
||||
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast<LPARAM>(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||
|
||||
SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void SetSystemTheme(bool mode)
|
||||
{
|
||||
HKEY hKey;
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
0,
|
||||
KEY_SET_VALUE,
|
||||
&hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD value = mode;
|
||||
RegSetValueEx(hKey, L"SystemUsesLightTheme", 0, REG_DWORD, reinterpret_cast<const BYTE*>(&value), sizeof(value));
|
||||
RegCloseKey(hKey);
|
||||
|
||||
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast<LPARAM>(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||
|
||||
SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool GetCurrentSystemTheme()
|
||||
{
|
||||
HKEY hKey;
|
||||
DWORD value = 1; // default = light
|
||||
DWORD size = sizeof(value);
|
||||
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
0,
|
||||
KEY_READ,
|
||||
&hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
RegQueryValueEx(hKey, L"SystemUsesLightTheme", nullptr, nullptr, reinterpret_cast<LPBYTE>(&value), &size);
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
return value == 0; // 0 = dark, 1 = light
|
||||
}
|
||||
|
||||
bool GetCurrentAppsTheme()
|
||||
{
|
||||
HKEY hKey;
|
||||
DWORD value = 1;
|
||||
DWORD size = sizeof(value);
|
||||
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
0,
|
||||
KEY_READ,
|
||||
&hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
RegQueryValueEx(hKey, L"SystemUsesLightTheme", nullptr, nullptr, reinterpret_cast<LPBYTE>(&value), &size);
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
return value == 0;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
void SetSystemTheme(bool dark);
|
||||
void SetAppsTheme(bool dark);
|
||||
bool GetCurrentSystemTheme();
|
||||
bool GetCurrentAppsTheme();
|
||||
@@ -1,669 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include <interface/powertoy_module_interface.h>
|
||||
#include "trace.h"
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
#include <common/utils/logger_helper.h>
|
||||
#include "ThemeHelper.h"
|
||||
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
namespace
|
||||
{
|
||||
const wchar_t JSON_KEY_PROPERTIES[] = L"properties";
|
||||
const wchar_t JSON_KEY_WIN[] = L"win";
|
||||
const wchar_t JSON_KEY_ALT[] = L"alt";
|
||||
const wchar_t JSON_KEY_CTRL[] = L"ctrl";
|
||||
const wchar_t JSON_KEY_SHIFT[] = L"shift";
|
||||
const wchar_t JSON_KEY_CODE[] = L"code";
|
||||
const wchar_t JSON_KEY_FORCE_LIGHT_HOTKEY[] = L"force-light-mode-hotkey";
|
||||
const wchar_t JSON_KEY_FORCE_DARK_HOTKEY[] = L"force-dark-mode-hotkey";
|
||||
const wchar_t JSON_KEY_VALUE[] = L"value";
|
||||
}
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
Trace::RegisterProvider();
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
Trace::UnregisterProvider();
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// The PowerToy name that will be shown in the settings.
|
||||
const static wchar_t* MODULE_NAME = L"LightSwitch";
|
||||
// Add a description that will we shown in the module settings page.
|
||||
const static wchar_t* MODULE_DESC = L"This is a module that allows you to control light/dark theming via set times, sun rise, or directly invoking the change.";
|
||||
|
||||
enum class ScheduleMode
|
||||
{
|
||||
FixedHours,
|
||||
SunsetToSunriseGeo,
|
||||
SunsetToSunriseUser
|
||||
// add more later
|
||||
};
|
||||
|
||||
inline std::wstring ToString(ScheduleMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case ScheduleMode::SunsetToSunriseGeo:
|
||||
return L"SunsetToSunriseGeo";
|
||||
case ScheduleMode::SunsetToSunriseUser:
|
||||
return L"SunsetToSunriseUser";
|
||||
case ScheduleMode::FixedHours:
|
||||
default:
|
||||
return L"FixedHours";
|
||||
}
|
||||
}
|
||||
|
||||
inline ScheduleMode FromString(const std::wstring& str)
|
||||
{
|
||||
if (str == L"SunsetToSunriseGeo")
|
||||
return ScheduleMode::SunsetToSunriseGeo;
|
||||
if (str == L"SunsetToSunriseUser")
|
||||
return ScheduleMode::SunsetToSunriseUser;
|
||||
return ScheduleMode::FixedHours;
|
||||
}
|
||||
|
||||
// These are the properties shown in the Settings page.
|
||||
struct ModuleSettings
|
||||
{
|
||||
bool m_changeSystem = true;
|
||||
bool m_changeApps = true;
|
||||
ScheduleMode m_scheduleMode = ScheduleMode::FixedHours;
|
||||
int m_lightTime = 480;
|
||||
int m_darkTime = 1200;
|
||||
int m_offset = 0;
|
||||
std::wstring m_latitude = L"0.0";
|
||||
std::wstring m_longitude = L"0.0";
|
||||
} g_settings;
|
||||
|
||||
// Implement the PowerToy Module Interface and all the required methods.
|
||||
class LightSwitchInterface : public PowertoyModuleIface
|
||||
{
|
||||
private:
|
||||
// The PowerToy state.
|
||||
bool m_enabled = false;
|
||||
|
||||
HANDLE m_process{ nullptr };
|
||||
HANDLE m_force_light_event_handle;
|
||||
HANDLE m_force_dark_event_handle;
|
||||
|
||||
static const constexpr int NUM_DEFAULT_HOTKEYS = 4;
|
||||
|
||||
Hotkey m_force_light_mode_hotkey = { .win = true, .ctrl = true, .shift = true, .alt = false, .key = 'L' };
|
||||
Hotkey m_force_dark_mode_hotkey = { .win = true, .ctrl = true, .shift = true, .alt = false, .key = 'D' };
|
||||
|
||||
// Load initial settings from the persisted values.
|
||||
void init_settings();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
LightSwitchInterface()
|
||||
{
|
||||
LoggerHelpers::init_logger(L"LightSwitch", L"ModuleInterface", LogSettings::lightSwitchLoggerName);
|
||||
|
||||
m_force_light_event_handle = CreateDefaultEvent(L"POWEROYS_LIGHTSWITCH_FORCE_LIGHT");
|
||||
m_force_dark_event_handle = CreateDefaultEvent(L"POWEROYS_LIGHTSWITCH_FORCE_DARK");
|
||||
|
||||
init_settings();
|
||||
};
|
||||
|
||||
virtual const wchar_t* get_key() override
|
||||
{
|
||||
return L"LightSwitch"; // your unique key string
|
||||
}
|
||||
|
||||
// Destroy the powertoy and free memory
|
||||
virtual void destroy() override
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
// Return the display name of the powertoy, this will be cached by the runner
|
||||
virtual const wchar_t* get_name() override
|
||||
{
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
// Return the configured status for the gpo policy for the module
|
||||
virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override
|
||||
{
|
||||
return powertoys_gpo::getConfiguredLightSwitchEnabledValue();
|
||||
}
|
||||
|
||||
// Return array of the names of all events that this powertoy listens for, with
|
||||
// nullptr as the last element of the array. Nullptr can also be retured for empty
|
||||
// list.
|
||||
//virtual const wchar_t** get_events() override
|
||||
//{
|
||||
// static const wchar_t* events[] = { nullptr };
|
||||
// // Available events:
|
||||
// // - ll_keyboard
|
||||
// // - win_hook_event
|
||||
// //
|
||||
// // static const wchar_t* events[] = { ll_keyboard,
|
||||
// // win_hook_event,
|
||||
// // nullptr };
|
||||
|
||||
// return events;
|
||||
//}
|
||||
|
||||
// Return JSON with the configuration options.
|
||||
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
|
||||
{
|
||||
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
||||
|
||||
// Create a Settings object with your module name
|
||||
PowerToysSettings::Settings settings(hinstance, get_name());
|
||||
settings.set_description(MODULE_DESC);
|
||||
settings.set_overview_link(L"https://aka.ms/powertoys");
|
||||
|
||||
// Boolean toggles
|
||||
settings.add_bool_toggle(
|
||||
L"changeSystem",
|
||||
L"Change System Theme",
|
||||
g_settings.m_changeSystem);
|
||||
|
||||
settings.add_bool_toggle(
|
||||
L"changeApps",
|
||||
L"Change Apps Theme",
|
||||
g_settings.m_changeApps);
|
||||
|
||||
settings.add_choice_group(
|
||||
L"scheduleMode",
|
||||
L"Theme schedule mode",
|
||||
ToString(g_settings.m_scheduleMode),
|
||||
{ { L"FixedHours", L"Set hours manually" },
|
||||
{ L"SunsetToSunriseGeo", L"Use sunrise/sunset times (Geolocation)" },
|
||||
{ L"SunsetToSunriseUser", L"Use sunrise/sunset times (User selected)" } });
|
||||
|
||||
// Integer spinners (for time in minutes since midnight)
|
||||
settings.add_int_spinner(
|
||||
L"lightTime",
|
||||
L"Time to switch to light theme (minutes after midnight).",
|
||||
g_settings.m_lightTime,
|
||||
0,
|
||||
1439,
|
||||
1);
|
||||
|
||||
settings.add_int_spinner(
|
||||
L"darkTime",
|
||||
L"Time to switch to dark theme (minutes after midnight).",
|
||||
g_settings.m_darkTime,
|
||||
0,
|
||||
1439,
|
||||
1);
|
||||
|
||||
settings.add_int_spinner(
|
||||
L"offset",
|
||||
L"Time to offset turning on your light/dark themes.",
|
||||
g_settings.m_offset,
|
||||
0,
|
||||
1439,
|
||||
1);
|
||||
|
||||
// Strings for latitude and longitude
|
||||
settings.add_string(
|
||||
L"latitude",
|
||||
L"Your latitude in decimal degrees (e.g. 39.95).",
|
||||
g_settings.m_latitude);
|
||||
|
||||
settings.add_string(
|
||||
L"longitude",
|
||||
L"Your longitude in decimal degrees (e.g. -75.16).",
|
||||
g_settings.m_longitude);
|
||||
|
||||
// One-shot actions (buttons)
|
||||
settings.add_custom_action(
|
||||
L"forceLight",
|
||||
L"Switch immediately to light theme",
|
||||
L"Force Light",
|
||||
L"{}");
|
||||
|
||||
settings.add_custom_action(
|
||||
L"forceDark",
|
||||
L"Switch immediately to dark theme",
|
||||
L"Force Dark",
|
||||
L"{}");
|
||||
|
||||
PowerToysSettings::HotkeyObject lm_hk = PowerToysSettings::HotkeyObject::from_settings(
|
||||
m_force_light_mode_hotkey.win,
|
||||
m_force_light_mode_hotkey.ctrl,
|
||||
m_force_light_mode_hotkey.alt,
|
||||
m_force_light_mode_hotkey.shift,
|
||||
m_force_light_mode_hotkey.key);
|
||||
|
||||
settings.add_hotkey(
|
||||
L"force-light-hotkey",
|
||||
L"Shortcut to force light theme immediately",
|
||||
lm_hk);
|
||||
|
||||
PowerToysSettings::HotkeyObject dm_hk = PowerToysSettings::HotkeyObject::from_settings(
|
||||
m_force_dark_mode_hotkey.win,
|
||||
m_force_dark_mode_hotkey.ctrl,
|
||||
m_force_dark_mode_hotkey.alt,
|
||||
m_force_dark_mode_hotkey.shift,
|
||||
m_force_dark_mode_hotkey.key);
|
||||
|
||||
settings.add_hotkey(
|
||||
L"force-dark-hotkey",
|
||||
L"Shortcut to force dark theme immediately",
|
||||
dm_hk);
|
||||
|
||||
// Serialize to buffer for the PowerToys runner
|
||||
return settings.serialize_to_buffer(buffer, buffer_size);
|
||||
}
|
||||
|
||||
// Signal from the Settings editor to call a custom action.
|
||||
// This can be used to spawn more complex editors.
|
||||
void call_custom_action(const wchar_t* action) override
|
||||
{
|
||||
try
|
||||
{
|
||||
auto action_object = PowerToysSettings::CustomActionObject::from_json_string(action);
|
||||
|
||||
if (action_object.get_name() == L"forceLight")
|
||||
{
|
||||
Logger::info(L"[Light Switch] Custom action triggered: Force Light");
|
||||
SetSystemTheme(true);
|
||||
SetAppsTheme(true);
|
||||
}
|
||||
else if (action_object.get_name() == L"forceDark")
|
||||
{
|
||||
Logger::info(L"[Light Switch] Custom action triggered: Force Dark");
|
||||
SetSystemTheme(false);
|
||||
SetAppsTheme(false);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"[Light Switch] Invalid custom action JSON");
|
||||
}
|
||||
}
|
||||
|
||||
// Called by the runner to pass the updated settings values as a serialized JSON.
|
||||
virtual void set_config(const wchar_t* config) override
|
||||
{
|
||||
try
|
||||
{
|
||||
auto values = PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
||||
|
||||
parse_hotkey(values);
|
||||
|
||||
if (auto v = values.get_bool_value(L"changeSystem"))
|
||||
{
|
||||
g_settings.m_changeSystem = *v;
|
||||
}
|
||||
|
||||
if (auto v = values.get_bool_value(L"changeApps"))
|
||||
{
|
||||
g_settings.m_changeApps = *v;
|
||||
}
|
||||
|
||||
if (auto v = values.get_string_value(L"scheduleMode"))
|
||||
{
|
||||
g_settings.m_scheduleMode = FromString(*v);
|
||||
}
|
||||
|
||||
if (auto v = values.get_int_value(L"lightTime"))
|
||||
{
|
||||
g_settings.m_lightTime = *v;
|
||||
}
|
||||
|
||||
if (auto v = values.get_int_value(L"darkTime"))
|
||||
{
|
||||
g_settings.m_darkTime = *v;
|
||||
}
|
||||
|
||||
if (auto v = values.get_int_value(L"offset"))
|
||||
{
|
||||
g_settings.m_offset = *v;
|
||||
}
|
||||
|
||||
if (auto v = values.get_string_value(L"latitude"))
|
||||
{
|
||||
g_settings.m_latitude = *v;
|
||||
}
|
||||
if (auto v = values.get_string_value(L"longitude"))
|
||||
{
|
||||
g_settings.m_longitude = *v;
|
||||
}
|
||||
|
||||
|
||||
values.save_to_settings_file();
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
Logger::error("[Light Switch] set_config: Failed to parse or apply config.");
|
||||
}
|
||||
}
|
||||
|
||||
virtual void enable()
|
||||
{
|
||||
m_enabled = true;
|
||||
Logger::info(L"Enabling Light Switch module...");
|
||||
|
||||
unsigned long powertoys_pid = GetCurrentProcessId();
|
||||
std::wstring args = L"--pid " + std::to_wstring(powertoys_pid);
|
||||
std::wstring exe_name = L"LightSwitchService\\PowerToys.LightSwitchService.exe";
|
||||
|
||||
// Resolve the executable path
|
||||
std::wstring resolved_path(MAX_PATH, L'\0');
|
||||
DWORD result = SearchPathW(
|
||||
nullptr,
|
||||
exe_name.c_str(),
|
||||
nullptr,
|
||||
static_cast<DWORD>(resolved_path.size()),
|
||||
resolved_path.data(),
|
||||
nullptr);
|
||||
|
||||
if (result == 0 || result >= resolved_path.size())
|
||||
{
|
||||
Logger::error(L"Failed to locate Light Switch executable: '{}'", exe_name);
|
||||
return;
|
||||
}
|
||||
|
||||
resolved_path.resize(result);
|
||||
Logger::debug(L"Resolved executable path: {}", resolved_path);
|
||||
|
||||
std::wstring command_line = L"\"" + resolved_path + L"\" " + args;
|
||||
|
||||
STARTUPINFO si = { sizeof(si) };
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
if (!CreateProcessW(
|
||||
resolved_path.c_str(), // lpApplicationName
|
||||
command_line.data(), // lpCommandLine (must be mutable)
|
||||
nullptr,
|
||||
nullptr,
|
||||
TRUE,
|
||||
0,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&si,
|
||||
&pi))
|
||||
{
|
||||
Logger::error(L"Failed to launch Light Switch process. {}", get_last_error_or_default(GetLastError()));
|
||||
return;
|
||||
}
|
||||
|
||||
Logger::info(L"Light Switch process launched successfully (PID: {}).", pi.dwProcessId);
|
||||
m_process = pi.hProcess;
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
|
||||
// Disable the powertoy
|
||||
virtual void disable()
|
||||
{
|
||||
Logger::info("Light Switch disabling");
|
||||
m_enabled = false;
|
||||
|
||||
if (m_process)
|
||||
{
|
||||
// Try waiting briefly to allow graceful exit, if needed
|
||||
constexpr DWORD timeout_ms = 1500;
|
||||
DWORD result = WaitForSingleObject(m_process, timeout_ms);
|
||||
|
||||
if (result == WAIT_TIMEOUT)
|
||||
{
|
||||
// Force kill if it didn<64>t exit in time
|
||||
Logger::warn("Light Switch: Process didn't exit in time. Forcing termination.");
|
||||
TerminateProcess(m_process, 0);
|
||||
}
|
||||
|
||||
// Always clean up the handle
|
||||
CloseHandle(m_process);
|
||||
m_process = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns if the powertoys is enabled
|
||||
virtual bool is_enabled() override
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
void parse_hotkey(PowerToysSettings::PowerToyValues& settings)
|
||||
{
|
||||
auto settingsObject = settings.get_raw_json();
|
||||
if (settingsObject.GetView().Size())
|
||||
{
|
||||
try
|
||||
{
|
||||
Hotkey _temp_force_light;
|
||||
auto jsonHotkeyObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_FORCE_LIGHT_HOTKEY).GetNamedObject(JSON_KEY_VALUE);
|
||||
_temp_force_light.win = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_WIN);
|
||||
_temp_force_light.alt = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_ALT);
|
||||
_temp_force_light.shift = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_SHIFT);
|
||||
_temp_force_light.ctrl = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_CTRL);
|
||||
_temp_force_light.key = static_cast<unsigned char>(jsonHotkeyObject.GetNamedNumber(JSON_KEY_CODE));
|
||||
m_force_light_mode_hotkey = _temp_force_light;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error("Failed to initialize Light Switch force light mode shortcut from settings. Value will keep unchanged.");
|
||||
}
|
||||
try
|
||||
{
|
||||
Hotkey _temp_force_dark;
|
||||
auto jsonHotkeyObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_FORCE_DARK_HOTKEY).GetNamedObject(JSON_KEY_VALUE);
|
||||
_temp_force_dark.win = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_WIN);
|
||||
_temp_force_dark.alt = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_ALT);
|
||||
_temp_force_dark.shift = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_SHIFT);
|
||||
_temp_force_dark.ctrl = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_CTRL);
|
||||
_temp_force_dark.key = static_cast<unsigned char>(jsonHotkeyObject.GetNamedNumber(JSON_KEY_CODE));
|
||||
m_force_dark_mode_hotkey = _temp_force_dark;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error("Failed to initialize Light Switch force dark mode shortcut from settings. Value will keep unchanged.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::info("Light Switch settings are empty");
|
||||
}
|
||||
}
|
||||
|
||||
virtual size_t get_hotkeys(Hotkey* hotkeys, size_t buffer_size) override
|
||||
{
|
||||
if (hotkeys && buffer_size >= 2)
|
||||
{
|
||||
hotkeys[0] = m_force_light_mode_hotkey;
|
||||
hotkeys[1] = m_force_dark_mode_hotkey;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
virtual bool on_hotkey(size_t hotkeyId) override
|
||||
{
|
||||
if (m_enabled)
|
||||
{
|
||||
Logger::trace(L"Light Switch hotkey pressed");
|
||||
if (!is_process_running())
|
||||
{
|
||||
enable();
|
||||
}
|
||||
|
||||
if (hotkeyId == 0)
|
||||
{
|
||||
Logger::info(L"[Light Switch] Hotkey triggered: Force Light");
|
||||
SetSystemTheme(true);
|
||||
SetAppsTheme(true);
|
||||
}
|
||||
else if (hotkeyId == 1)
|
||||
{
|
||||
Logger::info(L"[Light Switch] Hotkey triggered: Force Dark");
|
||||
SetSystemTheme(false);
|
||||
SetAppsTheme(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_process_running()
|
||||
{
|
||||
return WaitForSingleObject(m_process, 0) == WAIT_TIMEOUT;
|
||||
}
|
||||
|
||||
// Handle incoming event, data is event-specific
|
||||
//virtual intptr_t signal_event(const wchar_t* name, intptr_t data) override
|
||||
//{
|
||||
// if (wcscmp(name, ll_keyboard) == 0)
|
||||
// {
|
||||
// auto& event = *(reinterpret_cast<LowlevelKeyboardEvent*>(data));
|
||||
// // Return 1 if the keypress is to be suppressed (not forwarded to Windows),
|
||||
// // otherwise return 0.
|
||||
// return 0;
|
||||
// }
|
||||
// else if (wcscmp(name, win_hook_event) == 0)
|
||||
// {
|
||||
// auto& event = *(reinterpret_cast<WinHookEvent*>(data));
|
||||
// // Return value is ignored
|
||||
// return 0;
|
||||
// }
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
//// This methods are part of an experimental features not fully supported yet
|
||||
//virtual void register_system_menu_helper(PowertoySystemMenuIface* helper) override
|
||||
//{
|
||||
//}
|
||||
|
||||
//virtual void signal_system_menu_action(const wchar_t* name) override
|
||||
//{
|
||||
//}
|
||||
};
|
||||
|
||||
std::wstring utf8_to_wstring(const std::string& str)
|
||||
{
|
||||
if (str.empty())
|
||||
return std::wstring();
|
||||
|
||||
int size_needed = MultiByteToWideChar(
|
||||
CP_UTF8,
|
||||
0,
|
||||
str.c_str(),
|
||||
static_cast<int>(str.size()),
|
||||
nullptr,
|
||||
0);
|
||||
|
||||
std::wstring wstr(size_needed, 0);
|
||||
|
||||
MultiByteToWideChar(
|
||||
CP_UTF8,
|
||||
0,
|
||||
str.c_str(),
|
||||
static_cast<int>(str.size()),
|
||||
&wstr[0],
|
||||
size_needed);
|
||||
|
||||
return wstr;
|
||||
}
|
||||
|
||||
// Load the settings file.
|
||||
void LightSwitchInterface::init_settings()
|
||||
{
|
||||
Logger::info(L"[Light Switch] init_settings: starting to load settings for module");
|
||||
|
||||
try
|
||||
{
|
||||
PowerToysSettings::PowerToyValues settings =
|
||||
PowerToysSettings::PowerToyValues::load_from_settings_file(get_name());
|
||||
|
||||
parse_hotkey(settings);
|
||||
|
||||
if (auto v = settings.get_bool_value(L"changeSystem"))
|
||||
g_settings.m_changeSystem = *v;
|
||||
if (auto v = settings.get_bool_value(L"changeApps"))
|
||||
g_settings.m_changeApps = *v;
|
||||
if (auto v = settings.get_string_value(L"scheduleMode"))
|
||||
g_settings.m_scheduleMode = FromString(*v);
|
||||
if (auto v = settings.get_int_value(L"lightTime"))
|
||||
g_settings.m_lightTime = *v;
|
||||
if (auto v = settings.get_int_value(L"darkTime"))
|
||||
g_settings.m_darkTime = *v;
|
||||
if (auto v = settings.get_int_value(L"offset"))
|
||||
g_settings.m_offset = *v;
|
||||
if (auto v = settings.get_string_value(L"latitude"))
|
||||
g_settings.m_latitude = *v;
|
||||
if (auto v = settings.get_string_value(L"longitude"))
|
||||
g_settings.m_longitude = *v;
|
||||
|
||||
Logger::info(L"[Light Switch] init_settings: loaded successfully");
|
||||
}
|
||||
catch (const winrt::hresult_error& e)
|
||||
{
|
||||
Logger::error(L"[Light Switch] init_settings: hresult_error 0x{:08X} - {}", e.code(), e.message().c_str());
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::wstring whatStr = utf8_to_wstring(e.what());
|
||||
Logger::error(L"[Light Switch] init_settings: std::exception - {}", whatStr);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"[Light Switch] init_settings: unknown exception while loading settings");
|
||||
}
|
||||
}
|
||||
|
||||
// This method of saving the module settings is only required if you need to do any
|
||||
// custom processing of the settings before saving them to disk.
|
||||
//void $projectname$::save_settings() {
|
||||
// try {
|
||||
// // Create a PowerToyValues object for this PowerToy
|
||||
// PowerToysSettings::PowerToyValues values(get_name());
|
||||
//
|
||||
// // Save a bool property.
|
||||
// //values.add_property(
|
||||
// // L"bool_toggle_1", // property name
|
||||
// // g_settings.bool_prop // property value
|
||||
// // g_settings.bool_prop // property value
|
||||
// //);
|
||||
//
|
||||
// // Save an int property.
|
||||
// //values.add_property(
|
||||
// // L"int_spinner_1", // property name
|
||||
// // g_settings.int_prop // property value
|
||||
// //);
|
||||
//
|
||||
// // Save a string property.
|
||||
// //values.add_property(
|
||||
// // L"string_text_1", // property name
|
||||
// // g_settings.string_prop // property value
|
||||
// );
|
||||
//
|
||||
// // Save a color property.
|
||||
// //values.add_property(
|
||||
// // L"color_picker_1", // property name
|
||||
// // g_settings.color_prop // property value
|
||||
// //);
|
||||
//
|
||||
// // Save the PowerToyValues JSON to the power toy settings file.
|
||||
// values.save_to_settings_file();
|
||||
// }
|
||||
// catch (std::exception ex) {
|
||||
// // Couldn't save the settings.
|
||||
// }
|
||||
//}
|
||||
|
||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||
{
|
||||
return new LightSwitchInterface();
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "pch.h"
|
||||
#pragma comment(lib, "windowsapp")
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/utils/gpo.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
#include <shlwapi.h>
|
||||
#include <shellapi.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.System.h>
|
||||
#include <winrt/Windows.Globalization.h>
|
||||
#include <winrt/Windows.ApplicationModel.h>
|
||||
#include <winrt/Windows.ApplicationModel.Core.h>
|
||||
@@ -1,30 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "trace.h"
|
||||
#include <TraceLoggingProvider.h>
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
g_hProvider,
|
||||
"Microsoft.PowerToys",
|
||||
// {38e8889b-9731-53f5-e901-e8a7c1753074}
|
||||
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
|
||||
TraceLoggingOptionProjectTelemetry());
|
||||
|
||||
void Trace::RegisterProvider()
|
||||
{
|
||||
TraceLoggingRegister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::UnregisterProvider()
|
||||
{
|
||||
TraceLoggingUnregister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::MyEvent()
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"PowerToyName_MyEvent",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <TraceLoggingActivity.h>
|
||||
#include <common/telemetry/ProjectTelemetry.h>
|
||||
|
||||
TRACELOGGING_DECLARE_PROVIDER(g_hProvider);
|
||||
|
||||
class Trace
|
||||
{
|
||||
public:
|
||||
static void RegisterProvider();
|
||||
static void UnregisterProvider();
|
||||
static void MyEvent();
|
||||
};
|
||||
@@ -1,258 +0,0 @@
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#include "ThemeScheduler.h"
|
||||
#include "ThemeHelper.h"
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <LightSwitchSettings.h>
|
||||
#include <common/utils/gpo.h>
|
||||
|
||||
// Global service variables
|
||||
SERVICE_STATUS g_ServiceStatus = {};
|
||||
SERVICE_STATUS_HANDLE g_StatusHandle = nullptr;
|
||||
HANDLE g_ServiceStopEvent = nullptr;
|
||||
|
||||
// Forward declarations of service functions (we<77>ll define them later)
|
||||
VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv);
|
||||
VOID WINAPI ServiceCtrlHandler(DWORD dwCtrl);
|
||||
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam);
|
||||
|
||||
// Entry point for the executable
|
||||
int _tmain(int argc, TCHAR* argv[])
|
||||
{
|
||||
// Parse args
|
||||
DWORD parentPid = 0;
|
||||
bool debug = false;
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
if (_tcscmp(argv[i], _T("--debug")) == 0)
|
||||
debug = true;
|
||||
else if (_tcscmp(argv[i], _T("--pid")) == 0 && i + 1 < argc)
|
||||
parentPid = _tstoi(argv[++i]);
|
||||
}
|
||||
|
||||
if (debug)
|
||||
{
|
||||
// Create a console window for debug output
|
||||
AllocConsole();
|
||||
FILE* f;
|
||||
freopen_s(&f, "CONOUT$", "w", stdout);
|
||||
freopen_s(&f, "CONOUT$", "w", stderr);
|
||||
|
||||
// Optional: set a title so you can find it easily
|
||||
SetConsoleTitle(L"LightSwitchService Debug");
|
||||
|
||||
// Console mode (debug)
|
||||
g_ServiceStopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
ServiceWorkerThread(reinterpret_cast<void*>(static_cast<ULONG_PTR>(parentPid)));
|
||||
CloseHandle(g_ServiceStopEvent);
|
||||
|
||||
// Keep window open until a key is pressed (optional)
|
||||
// system("pause");
|
||||
|
||||
FreeConsole();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Try to connect to SCM
|
||||
wchar_t serviceName[] = L"LightSwitchService";
|
||||
SERVICE_TABLE_ENTRYW table[] = { { serviceName, ServiceMain }, { nullptr, nullptr } };
|
||||
|
||||
if (!StartServiceCtrlDispatcherW(table))
|
||||
{
|
||||
DWORD err = GetLastError();
|
||||
if (err == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) // not launched by SCM
|
||||
{
|
||||
g_ServiceStopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
HANDLE hThread = CreateThread(
|
||||
nullptr, 0, ServiceWorkerThread, reinterpret_cast<void*>(static_cast<ULONG_PTR>(parentPid)), 0, nullptr);
|
||||
|
||||
// Wait so the process stays alive
|
||||
WaitForSingleObject(hThread, INFINITE);
|
||||
CloseHandle(hThread);
|
||||
CloseHandle(g_ServiceStopEvent);
|
||||
return 0;
|
||||
}
|
||||
return static_cast<int>(err);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Called when the service is launched by Windows
|
||||
VOID WINAPI ServiceMain(DWORD, LPTSTR*)
|
||||
{
|
||||
g_StatusHandle = RegisterServiceCtrlHandler(_T("LightSwitchService"), ServiceCtrlHandler);
|
||||
if (!g_StatusHandle)
|
||||
return;
|
||||
|
||||
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
|
||||
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
|
||||
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
|
||||
|
||||
g_ServiceStopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
if (!g_ServiceStopEvent)
|
||||
{
|
||||
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
|
||||
g_ServiceStatus.dwWin32ExitCode = GetLastError();
|
||||
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
|
||||
return;
|
||||
}
|
||||
|
||||
SECURITY_ATTRIBUTES sa{ sizeof(sa) };
|
||||
sa.bInheritHandle = FALSE;
|
||||
sa.lpSecurityDescriptor = nullptr;
|
||||
|
||||
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
|
||||
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
|
||||
|
||||
HANDLE hThread = CreateThread(nullptr, 0, ServiceWorkerThread, nullptr, 0, nullptr);
|
||||
WaitForSingleObject(hThread, INFINITE);
|
||||
CloseHandle(hThread);
|
||||
|
||||
CloseHandle(g_ServiceStopEvent);
|
||||
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
|
||||
g_ServiceStatus.dwWin32ExitCode = 0;
|
||||
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
|
||||
}
|
||||
|
||||
VOID WINAPI ServiceCtrlHandler(DWORD dwCtrl)
|
||||
{
|
||||
switch (dwCtrl)
|
||||
{
|
||||
case SERVICE_CONTROL_STOP:
|
||||
if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
|
||||
break;
|
||||
|
||||
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
|
||||
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
|
||||
|
||||
// Signal the service to stop
|
||||
SetEvent(g_ServiceStopEvent);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
|
||||
{
|
||||
DWORD parentPid = static_cast<DWORD>(reinterpret_cast<ULONG_PTR>(lpParam));
|
||||
HANDLE hParent = nullptr;
|
||||
if (parentPid)
|
||||
hParent = OpenProcess(SYNCHRONIZE, FALSE, parentPid);
|
||||
|
||||
OutputDebugString(L"[LightSwitchService] Worker thread starting...\n");
|
||||
|
||||
// Initialize settings system
|
||||
LightSwitchSettings::instance().InitFileWatcher();
|
||||
|
||||
auto applyTheme = [](int nowMinutes, int lightMinutes, int darkMinutes, const auto& settings) {
|
||||
bool isLightActive = false;
|
||||
|
||||
if (lightMinutes < darkMinutes)
|
||||
{
|
||||
// Normal case: sunrise < sunset
|
||||
isLightActive = (nowMinutes >= lightMinutes && nowMinutes < darkMinutes);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Wraparound case: e.g. light at 21:00, dark at 06:00
|
||||
isLightActive = (nowMinutes >= lightMinutes || nowMinutes < darkMinutes);
|
||||
}
|
||||
|
||||
if (isLightActive)
|
||||
{
|
||||
if (settings.changeSystem)
|
||||
SetSystemTheme(true);
|
||||
if (settings.changeApps)
|
||||
SetAppsTheme(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (settings.changeSystem)
|
||||
SetSystemTheme(false);
|
||||
if (settings.changeApps)
|
||||
SetAppsTheme(false);
|
||||
}
|
||||
};
|
||||
|
||||
// --- At service start: immediately honor the schedule ---
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
GetLocalTime(&st);
|
||||
int nowMinutes = st.wHour * 60 + st.wMinute;
|
||||
|
||||
LightSwitchSettings::instance().LoadSettings();
|
||||
const auto& settings = LightSwitchSettings::instance().settings();
|
||||
|
||||
applyTheme(nowMinutes, settings.lightTime + settings.offset, settings.darkTime + settings.offset, settings);
|
||||
}
|
||||
|
||||
// --- Main loop: wakes once per minute or stop/parent death ---
|
||||
for (;;)
|
||||
{
|
||||
HANDLE waits[2] = { g_ServiceStopEvent, hParent };
|
||||
DWORD count = hParent ? 2 : 1;
|
||||
|
||||
SYSTEMTIME st;
|
||||
GetLocalTime(&st);
|
||||
int nowMinutes = st.wHour * 60 + st.wMinute;
|
||||
|
||||
LightSwitchSettings::instance().LoadSettings();
|
||||
const auto& settings = LightSwitchSettings::instance().settings();
|
||||
|
||||
// Debug print
|
||||
wchar_t msg[160];
|
||||
swprintf_s(msg,
|
||||
L"[LightSwitchService] now=%02d:%02d | light=%02d:%02d | dark=%02d:%02d\n",
|
||||
st.wHour,
|
||||
st.wMinute,
|
||||
settings.lightTime / 60,
|
||||
settings.lightTime % 60,
|
||||
settings.darkTime / 60,
|
||||
settings.darkTime % 60);
|
||||
OutputDebugString(msg);
|
||||
|
||||
// Apply theme logic
|
||||
applyTheme(nowMinutes, settings.lightTime + settings.offset, settings.darkTime + settings.offset, settings);
|
||||
|
||||
// Sleep until next minute, wake early if stop/parent dies
|
||||
GetLocalTime(&st);
|
||||
int msToNextMinute = (60 - st.wSecond) * 1000 - st.wMilliseconds;
|
||||
if (msToNextMinute < 50)
|
||||
msToNextMinute = 50;
|
||||
|
||||
DWORD wait = WaitForMultipleObjects(count, waits, FALSE, msToNextMinute);
|
||||
if (wait == WAIT_OBJECT_0) // stop event
|
||||
break;
|
||||
if (hParent && wait == WAIT_OBJECT_0 + 1) // parent exited
|
||||
break;
|
||||
}
|
||||
|
||||
if (hParent)
|
||||
CloseHandle(hParent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APIENTRY wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
|
||||
{
|
||||
if (powertoys_gpo::getConfiguredLightSwitchEnabledValue() == powertoys_gpo::gpo_rule_configured_disabled)
|
||||
{
|
||||
wchar_t msg[160];
|
||||
swprintf_s(
|
||||
msg,
|
||||
L"Tried to start with a GPO policy setting the utility to always be disabled. Please contact your systems administrator.\n");
|
||||
OutputDebugString(msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int argc = 0;
|
||||
LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||
int rc = _tmain(argc, argv); // reuse your existing logic
|
||||
LocalFree(argv);
|
||||
return rc;
|
||||
}
|
||||
@@ -1,254 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|ARM64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>ARM64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|ARM64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>ARM64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{08e71c67-6a7e-4ca1-b04e-2fb336410bac}</ProjectGuid>
|
||||
<RootNamespace>LightSwitchService</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.26100.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>LightSwitchService</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\</OutDir>
|
||||
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\</IntDir>
|
||||
<TargetName>PowerToys.LightSwitchService</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>
|
||||
./../;
|
||||
$(SolutionDir)src\common\Telemetry;
|
||||
$(SolutionDir)src\common;
|
||||
$(SolutionDir)src\;
|
||||
$(SolutionDir)deps\spdlog\include;
|
||||
./;
|
||||
%(AdditionalIncludeDirectories)
|
||||
</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>Advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\notifications\notifications.vcxproj">
|
||||
<Project>{1d5be09d-78c0-4fd7-af00-ae7c1af7c525}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\Telemetry\EtwTrace\EtwTrace.vcxproj">
|
||||
<Project>{8f021b46-362b-485c-bfba-ccf83e820cbd}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\common\SettingsAPI\FileWatcher.cpp" />
|
||||
<ClCompile Include="..\..\..\common\SettingsAPI\settings_helpers.cpp" />
|
||||
<ClCompile Include="..\..\..\common\SettingsAPI\settings_objects.cpp" />
|
||||
<ClCompile Include="LightSwitchService.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LightSwitchSettings.cpp" />
|
||||
<ClCompile Include="SettingsConstants.cpp" />
|
||||
<ClCompile Include="ThemeHelper.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ThemeScheduler.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="WinHookEventIDs.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="LightSwitchSettings.h" />
|
||||
<ClInclude Include="SettingsConstants.h" />
|
||||
<ClInclude Include="SettingsObserver.h" />
|
||||
<ClInclude Include="ThemeHelper.h" />
|
||||
<ClInclude Include="ThemeScheduler.h">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">false</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="WinHookEventIDs.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -1,72 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="LightSwitchService.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ThemeScheduler.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ThemeHelper.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\common\SettingsAPI\settings_helpers.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\common\SettingsAPI\settings_objects.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\common\SettingsAPI\FileWatcher.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LightSwitchSettings.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SettingsConstants.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="WinHookEventIDs.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ThemeScheduler.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ThemeHelper.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="LightSwitchSettings.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SettingsConstants.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SettingsObserver.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="WinHookEventIDs.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,148 +0,0 @@
|
||||
#include "LightSwitchSettings.h"
|
||||
#include <common/utils/json.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include "SettingsObserver.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <WinHookEventIDs.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
LightSwitchSettings& LightSwitchSettings::instance()
|
||||
{
|
||||
static LightSwitchSettings inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
LightSwitchSettings::LightSwitchSettings()
|
||||
{
|
||||
LoadSettings();
|
||||
}
|
||||
|
||||
std::wstring LightSwitchSettings::GetSettingsFileName()
|
||||
{
|
||||
// Mirrors AlwaysOnTop: <module name>.json
|
||||
return PTSettingsHelper::get_module_save_file_location(L"LightSwitch");
|
||||
}
|
||||
|
||||
void LightSwitchSettings::InitFileWatcher()
|
||||
{
|
||||
const std::wstring& settingsFileName = GetSettingsFileName();
|
||||
m_settingsFileWatcher = std::make_unique<FileWatcher>(settingsFileName, [&]() {
|
||||
PostMessageW(HWND_BROADCAST, WM_PRIV_SETTINGS_CHANGED, NULL, NULL);
|
||||
});
|
||||
}
|
||||
|
||||
void LightSwitchSettings::AddObserver(SettingsObserver& observer)
|
||||
{
|
||||
m_observers.insert(&observer);
|
||||
}
|
||||
|
||||
void LightSwitchSettings::RemoveObserver(SettingsObserver& observer)
|
||||
{
|
||||
m_observers.erase(&observer);
|
||||
}
|
||||
|
||||
void LightSwitchSettings::NotifyObservers(SettingId id) const
|
||||
{
|
||||
for (auto observer : m_observers)
|
||||
{
|
||||
if (observer->WantsToBeNotified(id))
|
||||
{
|
||||
observer->SettingsUpdate(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LightSwitchSettings::LoadSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
PowerToysSettings::PowerToyValues values =
|
||||
PowerToysSettings::PowerToyValues::load_from_settings_file(L"LightSwitch");
|
||||
|
||||
|
||||
if (const auto jsonVal = values.get_string_value(L"scheduleMode"))
|
||||
{
|
||||
auto val = *jsonVal;
|
||||
auto newMode = FromString(val);
|
||||
if (m_settings.scheduleMode != newMode)
|
||||
{
|
||||
m_settings.scheduleMode = newMode;
|
||||
NotifyObservers(SettingId::ScheduleMode);
|
||||
}
|
||||
}
|
||||
|
||||
// Latitude
|
||||
if (const auto jsonVal = values.get_string_value(L"latitude"))
|
||||
{
|
||||
auto val = *jsonVal;
|
||||
if (m_settings.latitude != val)
|
||||
{
|
||||
m_settings.latitude = val;
|
||||
NotifyObservers(SettingId::Latitude);
|
||||
}
|
||||
}
|
||||
|
||||
// Longitude
|
||||
if (const auto jsonVal = values.get_string_value(L"longitude"))
|
||||
{
|
||||
auto val = *jsonVal;
|
||||
if (m_settings.longitude != val)
|
||||
{
|
||||
m_settings.longitude = val;
|
||||
NotifyObservers(SettingId::Longitude);
|
||||
}
|
||||
}
|
||||
|
||||
// LightTime
|
||||
if (const auto jsonVal = values.get_int_value(L"lightTime"))
|
||||
{
|
||||
auto val = *jsonVal;
|
||||
if (m_settings.lightTime != val)
|
||||
{
|
||||
m_settings.lightTime = val;
|
||||
NotifyObservers(SettingId::LightTime);
|
||||
}
|
||||
}
|
||||
|
||||
// DarkTime
|
||||
if (const auto jsonVal = values.get_int_value(L"darkTime"))
|
||||
{
|
||||
auto val = *jsonVal;
|
||||
if (m_settings.darkTime != val)
|
||||
{
|
||||
m_settings.darkTime = val;
|
||||
NotifyObservers(SettingId::DarkTime);
|
||||
}
|
||||
}
|
||||
|
||||
// ChangeSystem
|
||||
if (const auto jsonVal = values.get_bool_value(L"changeSystem"))
|
||||
{
|
||||
auto val = *jsonVal;
|
||||
if (m_settings.changeSystem != val)
|
||||
{
|
||||
m_settings.changeSystem = val;
|
||||
NotifyObservers(SettingId::ChangeSystem);
|
||||
}
|
||||
}
|
||||
|
||||
// ChangeApps
|
||||
if (const auto jsonVal = values.get_bool_value(L"changeApps"))
|
||||
{
|
||||
auto val = *jsonVal;
|
||||
if (m_settings.changeApps != val)
|
||||
{
|
||||
m_settings.changeApps = val;
|
||||
NotifyObservers(SettingId::ChangeApps);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
//Logger::error(L"[LightSwitchSettings] Failed to read settings file");
|
||||
// Keeps defaults if load fails
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <windows.h>
|
||||
|
||||
#include <common/SettingsAPI/FileWatcher.h>
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include <SettingsConstants.h>
|
||||
|
||||
class SettingsObserver;
|
||||
|
||||
enum class ScheduleMode
|
||||
{
|
||||
FixedHours,
|
||||
SunsetToSunrise
|
||||
// Add more in the future
|
||||
};
|
||||
|
||||
inline std::wstring ToString(ScheduleMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case ScheduleMode::FixedHours:
|
||||
return L"FixedHours";
|
||||
case ScheduleMode::SunsetToSunrise:
|
||||
return L"SunsetToSunrise";
|
||||
default:
|
||||
return L"FixedHours";
|
||||
}
|
||||
}
|
||||
|
||||
inline ScheduleMode FromString(const std::wstring& str)
|
||||
{
|
||||
if (str == L"SunsetToSunrise")
|
||||
return ScheduleMode::SunsetToSunrise;
|
||||
else
|
||||
return ScheduleMode::FixedHours;
|
||||
}
|
||||
|
||||
struct LightSwitchConfig
|
||||
{
|
||||
ScheduleMode scheduleMode = ScheduleMode::FixedHours;
|
||||
|
||||
std::wstring latitude = L"0.0";
|
||||
std::wstring longitude = L"0.0";
|
||||
|
||||
// Stored as minutes since midnight
|
||||
int lightTime = 8 * 60; // 08:00 default
|
||||
int darkTime = 20 * 60; // 20:00 default
|
||||
|
||||
int offset = 0; // offset in minutes to apply to calculated times
|
||||
|
||||
bool changeSystem = false;
|
||||
bool changeApps = false;
|
||||
};
|
||||
|
||||
class LightSwitchSettings
|
||||
{
|
||||
public:
|
||||
static LightSwitchSettings& instance();
|
||||
|
||||
static inline const LightSwitchConfig& settings()
|
||||
{
|
||||
return instance().m_settings;
|
||||
}
|
||||
|
||||
void InitFileWatcher();
|
||||
static std::wstring GetSettingsFileName();
|
||||
|
||||
void AddObserver(SettingsObserver& observer);
|
||||
void RemoveObserver(SettingsObserver& observer);
|
||||
|
||||
void LoadSettings();
|
||||
|
||||
private:
|
||||
LightSwitchSettings();
|
||||
~LightSwitchSettings() = default;
|
||||
|
||||
LightSwitchConfig m_settings;
|
||||
std::unique_ptr<FileWatcher> m_settingsFileWatcher;
|
||||
std::unordered_set<SettingsObserver*> m_observers;
|
||||
|
||||
void NotifyObservers(SettingId id) const;
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
#include "SettingsConstants.h"
|
||||
@@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
enum class SettingId
|
||||
{
|
||||
ScheduleMode = 0,
|
||||
Latitude,
|
||||
Longitude,
|
||||
LightTime,
|
||||
DarkTime,
|
||||
ChangeSystem,
|
||||
ChangeApps
|
||||
};
|
||||
@@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_set>
|
||||
#include "SettingsConstants.h"
|
||||
|
||||
class LightSwitchSettings;
|
||||
|
||||
class SettingsObserver
|
||||
{
|
||||
public:
|
||||
SettingsObserver(std::unordered_set<SettingId> observedSettings) :
|
||||
m_observedSettings(std::move(observedSettings))
|
||||
{
|
||||
LightSwitchSettings::instance().AddObserver(*this);
|
||||
}
|
||||
|
||||
virtual ~SettingsObserver()
|
||||
{
|
||||
LightSwitchSettings::instance().RemoveObserver(*this);
|
||||
}
|
||||
|
||||
// Override this in your class to respond to updates
|
||||
virtual void SettingsUpdate(SettingId type) {}
|
||||
|
||||
bool WantsToBeNotified(SettingId type) const noexcept
|
||||
{
|
||||
return m_observedSettings.contains(type);
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unordered_set<SettingId> m_observedSettings;
|
||||
};
|
||||
@@ -1,80 +0,0 @@
|
||||
#include <windows.h>
|
||||
#include "ThemeHelper.h"
|
||||
|
||||
// Controls changing the themes.
|
||||
|
||||
void SetAppsTheme(bool mode)
|
||||
{
|
||||
HKEY hKey;
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
0,
|
||||
KEY_SET_VALUE,
|
||||
&hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD value = mode;
|
||||
RegSetValueEx(hKey, L"AppsUseLightTheme", 0, REG_DWORD, reinterpret_cast<const BYTE*>(&value), sizeof(value));
|
||||
RegCloseKey(hKey);
|
||||
|
||||
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast<LPARAM>(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||
|
||||
SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void SetSystemTheme(bool mode)
|
||||
{
|
||||
HKEY hKey;
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
0,
|
||||
KEY_SET_VALUE,
|
||||
&hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD value = mode;
|
||||
RegSetValueEx(hKey, L"SystemUsesLightTheme", 0, REG_DWORD, reinterpret_cast<const BYTE*>(&value), sizeof(value));
|
||||
RegCloseKey(hKey);
|
||||
|
||||
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast<LPARAM>(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||
|
||||
SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool GetCurrentSystemTheme()
|
||||
{
|
||||
HKEY hKey;
|
||||
DWORD value = 1; // default = light
|
||||
DWORD size = sizeof(value);
|
||||
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
0,
|
||||
KEY_READ,
|
||||
&hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
RegQueryValueEx(hKey, L"SystemUsesLightTheme", nullptr, nullptr, reinterpret_cast<LPBYTE>(&value), &size);
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
return value == 0; // 0 = dark, 1 = light
|
||||
}
|
||||
|
||||
bool GetCurrentAppsTheme()
|
||||
{
|
||||
HKEY hKey;
|
||||
DWORD value = 1;
|
||||
DWORD size = sizeof(value);
|
||||
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
0,
|
||||
KEY_READ,
|
||||
&hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
RegQueryValueEx(hKey, L"SystemUsesLightTheme", nullptr, nullptr, reinterpret_cast<LPBYTE>(&value), &size);
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
return value == 0;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
void SetSystemTheme(bool dark);
|
||||
void SetAppsTheme(bool dark);
|
||||
bool GetCurrentSystemTheme();
|
||||
bool GetCurrentAppsTheme();
|
||||
@@ -1,89 +0,0 @@
|
||||
#include "ThemeScheduler.h"
|
||||
#include <utility>
|
||||
|
||||
SunTimes CalculateSunriseSunset(double latitude, double longitude, int year, int month, int day)
|
||||
{
|
||||
double zenith = 90.833;
|
||||
int N1 = static_cast<int>(floor(275.0 * month / 9.0));
|
||||
int N2 = static_cast<int>(floor((static_cast<double>(month) + 9) / 12.0));
|
||||
int N3 = static_cast<int>(floor((1.0 + floor((year - 4.0 * floor(year / 4.0) + 2.0) / 3.0))));
|
||||
int N = N1 - (N2 * N3) + day - 30;
|
||||
|
||||
auto calcTime = [&](bool sunrise) -> double {
|
||||
double lngHour = longitude / 15.0;
|
||||
double t = sunrise ? N + ((6 - lngHour) / 24) : N + ((18 - lngHour) / 24);
|
||||
|
||||
double M = (0.9856 * t) - 3.289;
|
||||
double L = M + (1.916 * sin(deg2rad(M))) + (0.020 * sin(2 * deg2rad(M))) + 282.634;
|
||||
if (L < 0)
|
||||
L += 360;
|
||||
if (L > 360)
|
||||
L -= 360;
|
||||
|
||||
double RA = rad2deg(atan(0.91764 * tan(deg2rad(L))));
|
||||
if (RA < 0)
|
||||
RA += 360;
|
||||
if (RA > 360)
|
||||
RA -= 360;
|
||||
|
||||
double Lquadrant = floor(L / 90) * 90;
|
||||
double RAquadrant = floor(RA / 90) * 90;
|
||||
RA = RA + (Lquadrant - RAquadrant);
|
||||
RA /= 15;
|
||||
|
||||
double sinDec = 0.39782 * sin(deg2rad(L));
|
||||
double cosDec = cos(asin(sinDec));
|
||||
|
||||
double cosH = (cos(deg2rad(zenith)) - (sinDec * sin(deg2rad(latitude)))) / (cosDec * cos(deg2rad(latitude)));
|
||||
if (cosH > 1 || cosH < -1)
|
||||
return -1;
|
||||
|
||||
double H = sunrise ? 360 - rad2deg(acos(cosH)) : rad2deg(acos(cosH));
|
||||
H /= 15;
|
||||
|
||||
double T = H + RA - (0.06571 * t) - 6.622;
|
||||
double UT = T - lngHour;
|
||||
while (UT < 0)
|
||||
UT += 24;
|
||||
while (UT >= 24)
|
||||
UT -= 24;
|
||||
|
||||
return UT;
|
||||
};
|
||||
|
||||
double riseUT = calcTime(true);
|
||||
double setUT = calcTime(false);
|
||||
|
||||
auto toLocal = [](double UT) {
|
||||
TIME_ZONE_INFORMATION tz;
|
||||
DWORD state = GetTimeZoneInformation(&tz);
|
||||
double totalBias = tz.Bias;
|
||||
|
||||
if (state == TIME_ZONE_ID_DAYLIGHT)
|
||||
totalBias += tz.DaylightBias;
|
||||
else if (state == TIME_ZONE_ID_STANDARD)
|
||||
totalBias += tz.StandardBias;
|
||||
|
||||
double biasHours = -(totalBias / 60.0);
|
||||
double localTime = UT + biasHours;
|
||||
|
||||
while (localTime < 0)
|
||||
localTime += 24;
|
||||
while (localTime >= 24)
|
||||
localTime -= 24;
|
||||
|
||||
int hour = static_cast<int>(localTime);
|
||||
int minute = static_cast<int>((localTime - hour) * 60);
|
||||
return std::pair<int, int>{ hour, minute };
|
||||
};
|
||||
|
||||
auto [riseHour, riseMinute] = toLocal(riseUT);
|
||||
auto [setHour, setMinute] = toLocal(setUT);
|
||||
|
||||
SunTimes result;
|
||||
result.sunriseHour = riseHour;
|
||||
result.sunriseMinute = riseMinute;
|
||||
result.sunsetHour = setHour;
|
||||
result.sunsetMinute = setMinute;
|
||||
return result;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
#include <windows.h>
|
||||
|
||||
// Struct to hold calculated sunrise/sunset times
|
||||
struct SunTimes
|
||||
{
|
||||
int sunriseHour;
|
||||
int sunriseMinute;
|
||||
int sunsetHour;
|
||||
int sunsetMinute;
|
||||
};
|
||||
|
||||
constexpr double PI = 3.14159265358979323846;
|
||||
constexpr double deg2rad(double deg)
|
||||
{
|
||||
return deg * PI / 180.0;
|
||||
}
|
||||
constexpr double rad2deg(double rad)
|
||||
{
|
||||
return rad * 180.0 / PI;
|
||||
}
|
||||
|
||||
SunTimes CalculateSunriseSunset(double latitude, double longitude, int year, int month, int day);
|
||||
@@ -1,15 +0,0 @@
|
||||
|
||||
#include "WinHookEventIDs.h"
|
||||
#include <wtypes.h>
|
||||
#include <mutex>
|
||||
|
||||
UINT WM_PRIV_SETTINGS_CHANGED = 0;
|
||||
|
||||
std::once_flag init_flag;
|
||||
|
||||
void InitializeWinhookEventIds()
|
||||
{
|
||||
std::call_once(init_flag, [&] {
|
||||
WM_PRIV_SETTINGS_CHANGED = RegisterWindowMessage(L"{11978F7B-221A-4E65-B9A9-693F7D6E4B25}");
|
||||
});
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
|
||||
extern UINT WM_PRIV_SETTINGS_CHANGED; // Scheduled when a watched settings file is updated
|
||||
|
||||
void InitializeWinhookEventIds();
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.231216.1" targetFramework="native" />
|
||||
</packages>
|
||||
@@ -123,6 +123,7 @@ MakeAppx.exe pack /d . /p $(OutDir)NewPlusPackage.msix /nv</Command>
|
||||
<ClInclude Include="settings.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
<ClInclude Include="new_utilities.h" />
|
||||
<ClInclude Include="RuntimeRegistration.h" />
|
||||
<ClInclude Include="resource.base.h" />
|
||||
<ClInclude Include="template_folder.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
|
||||
@@ -84,6 +84,9 @@
|
||||
<ClInclude Include="helpers_variables.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RuntimeRegistration.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// Header-only runtime registration for New+ Win10 context menu.
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
#include <common/utils/shell_ext_registration.h>
|
||||
|
||||
// Provided by dll_main.cpp
|
||||
extern HMODULE module_instance_handle;
|
||||
|
||||
namespace NewPlusRuntimeRegistration
|
||||
{
|
||||
namespace {
|
||||
inline runtime_shell_ext::Spec BuildSpec()
|
||||
{
|
||||
runtime_shell_ext::Spec spec;
|
||||
spec.clsid = L"{FF90D477-E32A-4BE8-8CC5-A502A97F5401}";
|
||||
spec.sentinelKey = L"Software\\Microsoft\\PowerToys\\NewPlus";
|
||||
spec.sentinelValue = L"ContextMenuRegisteredWin10";
|
||||
spec.dllFileCandidates = { L"PowerToys.NewPlus.ShellExtension.win10.dll" };
|
||||
spec.contextMenuHandlerKeyPaths = { L"Software\\Classes\\Directory\\background\\ShellEx\\ContextMenuHandlers\\NewPlusShellExtensionWin10" };
|
||||
spec.friendlyName = L"NewPlus Shell Extension Win10";
|
||||
return spec;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool EnsureRegisteredWin10()
|
||||
{
|
||||
return runtime_shell_ext::EnsureRegistered(BuildSpec(), module_instance_handle);
|
||||
}
|
||||
|
||||
inline void Unregister()
|
||||
{
|
||||
runtime_shell_ext::Unregister(BuildSpec());
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "trace.h"
|
||||
#include "new_utilities.h"
|
||||
#include "Generated Files/resource.h"
|
||||
#include "RuntimeRegistration.h"
|
||||
|
||||
// Note: Settings are managed via Settings and UI Settings
|
||||
class NewModule : public PowertoyModuleIface
|
||||
@@ -93,8 +94,16 @@ public:
|
||||
|
||||
// Log telemetry
|
||||
Trace::EventToggleOnOff(true);
|
||||
|
||||
newplus::utilities::register_msix_package();
|
||||
if (package::IsWin11OrGreater())
|
||||
{
|
||||
newplus::utilities::register_msix_package();
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
NewPlusRuntimeRegistration::EnsureRegisteredWin10();
|
||||
#endif
|
||||
}
|
||||
|
||||
powertoy_new_enabled = true;
|
||||
}
|
||||
@@ -141,6 +150,13 @@ private:
|
||||
{
|
||||
Trace::EventToggleOnOff(false);
|
||||
}
|
||||
if (!package::IsWin11OrGreater())
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
NewPlusRuntimeRegistration::Unregister();
|
||||
Logger::info(L"New+ context menu unregistered (Win10)");
|
||||
#endif
|
||||
}
|
||||
powertoy_new_enabled = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
// 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 Microsoft.CmdPal.Common.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Provides utility methods for building diagnostic and error messages.
|
||||
/// </summary>
|
||||
public static class DiagnosticsHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds a comprehensive exception message with timestamp and detailed diagnostic information.
|
||||
/// </summary>
|
||||
/// <param name="exception">The exception that occurred.</param>
|
||||
/// <param name="extensionHint">A hint about which extension caused the exception to help with debugging.</param>
|
||||
/// <returns>A string containing the exception details, timestamp, and source information for diagnostic purposes.</returns>
|
||||
public static string BuildExceptionMessage(Exception exception, string? extensionHint)
|
||||
{
|
||||
var locationHint = string.IsNullOrWhiteSpace(extensionHint) ? "application" : $"'{extensionHint}' extension";
|
||||
|
||||
// let's try to get a message from the exception or inferred it from the HRESULT
|
||||
// to show at least something
|
||||
var message = exception.Message;
|
||||
if (string.IsNullOrWhiteSpace(message))
|
||||
{
|
||||
var temp = Marshal.GetExceptionForHR(exception.HResult)?.Message;
|
||||
if (!string.IsNullOrWhiteSpace(temp))
|
||||
{
|
||||
message = temp + $" (inferred from HRESULT 0x{exception.HResult:X8})";
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(message))
|
||||
{
|
||||
message = "[No message available]";
|
||||
}
|
||||
|
||||
// note: keep date time kind and format consistent with the log
|
||||
return $"""
|
||||
============================================================
|
||||
😢 An unexpected error occurred in the {locationHint}.
|
||||
|
||||
Summary:
|
||||
Message: {message}
|
||||
Type: {exception.GetType().FullName}
|
||||
Source: {exception.Source ?? "N/A"}
|
||||
Time: {DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss.fffffff}
|
||||
HRESULT: 0x{exception.HResult:X8} ({exception.HResult})
|
||||
|
||||
Stack Trace:
|
||||
{exception.StackTrace ?? "[No stack trace available]"}
|
||||
|
||||
------------------ Full Exception Details ------------------
|
||||
{exception}
|
||||
|
||||
ℹ️ If you need further assistance, please include this information in your support request.
|
||||
ℹ️ Before sending, take a quick look to make sure it doesn't contain any personal or sensitive information.
|
||||
============================================================
|
||||
|
||||
""";
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ public partial class ExtensionHostInstance
|
||||
/// <param name="message">The log message to send</param>
|
||||
public void LogMessage(ILogMessage message)
|
||||
{
|
||||
if (Host is not null)
|
||||
if (Host != null)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
@@ -47,7 +47,7 @@ public partial class ExtensionHostInstance
|
||||
|
||||
public void ShowStatus(IStatusMessage message, StatusContext context)
|
||||
{
|
||||
if (Host is not null)
|
||||
if (Host != null)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
@@ -64,7 +64,7 @@ public partial class ExtensionHostInstance
|
||||
|
||||
public void HideStatus(IStatusMessage message)
|
||||
{
|
||||
if (Host is not null)
|
||||
if (Host != null)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
|
||||
@@ -36,7 +36,7 @@ public abstract partial class AppExtensionHost : IExtensionHost
|
||||
|
||||
public IAsyncAction HideStatus(IStatusMessage? message)
|
||||
{
|
||||
if (message is null)
|
||||
if (message == null)
|
||||
{
|
||||
return Task.CompletedTask.AsAsyncAction();
|
||||
}
|
||||
@@ -55,7 +55,7 @@ public abstract partial class AppExtensionHost : IExtensionHost
|
||||
|
||||
public IAsyncAction LogMessage(ILogMessage? message)
|
||||
{
|
||||
if (message is null)
|
||||
if (message == null)
|
||||
{
|
||||
return Task.CompletedTask.AsAsyncAction();
|
||||
}
|
||||
@@ -80,7 +80,7 @@ public abstract partial class AppExtensionHost : IExtensionHost
|
||||
try
|
||||
{
|
||||
var vm = StatusMessages.Where(messageVM => messageVM.Model.Unsafe == message).FirstOrDefault();
|
||||
if (vm is not null)
|
||||
if (vm != null)
|
||||
{
|
||||
StatusMessages.Remove(vm);
|
||||
}
|
||||
@@ -113,7 +113,7 @@ public abstract partial class AppExtensionHost : IExtensionHost
|
||||
{
|
||||
// If this message is already in the list of messages, just bring it to the top
|
||||
var oldVm = StatusMessages.Where(messageVM => messageVM.Model.Unsafe == message).FirstOrDefault();
|
||||
if (oldVm is not null)
|
||||
if (oldVm != null)
|
||||
{
|
||||
Task.Factory.StartNew(
|
||||
() =>
|
||||
@@ -142,7 +142,7 @@ public abstract partial class AppExtensionHost : IExtensionHost
|
||||
|
||||
public IAsyncAction ShowStatus(IStatusMessage? message, StatusContext context)
|
||||
{
|
||||
if (message is null)
|
||||
if (message == null)
|
||||
{
|
||||
return Task.CompletedTask.AsAsyncAction();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// 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.ObjectModel;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.CmdPal.Core.ViewModels.Messages;
|
||||
@@ -34,13 +35,13 @@ public partial class CommandBarViewModel : ObservableObject,
|
||||
[NotifyPropertyChangedFor(nameof(HasPrimaryCommand))]
|
||||
public partial CommandItemViewModel? PrimaryCommand { get; set; }
|
||||
|
||||
public bool HasPrimaryCommand => PrimaryCommand is not null && PrimaryCommand.ShouldBeVisible;
|
||||
public bool HasPrimaryCommand => PrimaryCommand != null && PrimaryCommand.ShouldBeVisible;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(HasSecondaryCommand))]
|
||||
public partial CommandItemViewModel? SecondaryCommand { get; set; }
|
||||
|
||||
public bool HasSecondaryCommand => SecondaryCommand is not null;
|
||||
public bool HasSecondaryCommand => SecondaryCommand != null;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool ShouldShowContextMenu { get; set; } = false;
|
||||
@@ -57,14 +58,14 @@ public partial class CommandBarViewModel : ObservableObject,
|
||||
|
||||
private void SetSelectedItem(ICommandBarContext? value)
|
||||
{
|
||||
if (value is not null)
|
||||
if (value != null)
|
||||
{
|
||||
PrimaryCommand = value.PrimaryCommand;
|
||||
value.PropertyChanged += SelectedItemPropertyChanged;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SelectedItem is not null)
|
||||
if (SelectedItem != null)
|
||||
{
|
||||
SelectedItem.PropertyChanged -= SelectedItemPropertyChanged;
|
||||
}
|
||||
@@ -87,7 +88,7 @@ public partial class CommandBarViewModel : ObservableObject,
|
||||
|
||||
private void UpdateContextItems()
|
||||
{
|
||||
if (SelectedItem is null)
|
||||
if (SelectedItem == null)
|
||||
{
|
||||
SecondaryCommand = null;
|
||||
ShouldShowContextMenu = false;
|
||||
@@ -126,13 +127,13 @@ public partial class CommandBarViewModel : ObservableObject,
|
||||
public ContextKeybindingResult CheckKeybinding(bool ctrl, bool alt, bool shift, bool win, VirtualKey key)
|
||||
{
|
||||
var keybindings = SelectedItem?.Keybindings();
|
||||
if (keybindings is not null)
|
||||
if (keybindings != null)
|
||||
{
|
||||
// Does the pressed key match any of the keybindings?
|
||||
var pressedKeyChord = KeyChordHelpers.FromModifiers(ctrl, alt, shift, win, key, 0);
|
||||
if (keybindings.TryGetValue(pressedKeyChord, out var matchedItem))
|
||||
{
|
||||
return matchedItem is not null ? PerformCommand(matchedItem) : ContextKeybindingResult.Unhandled;
|
||||
return matchedItem != null ? PerformCommand(matchedItem) : ContextKeybindingResult.Unhandled;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +142,7 @@ public partial class CommandBarViewModel : ObservableObject,
|
||||
|
||||
private ContextKeybindingResult PerformCommand(CommandItemViewModel? command)
|
||||
{
|
||||
if (command is null)
|
||||
if (command == null)
|
||||
{
|
||||
return ContextKeybindingResult.Unhandled;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ public partial class CommandContextItemViewModel(ICommandContextItem contextItem
|
||||
|
||||
public KeyChord? RequestedShortcut { get; private set; }
|
||||
|
||||
public bool HasRequestedShortcut => RequestedShortcut is not null && (RequestedShortcut.Value != nullKeyChord);
|
||||
public bool HasRequestedShortcut => RequestedShortcut != null && (RequestedShortcut.Value != nullKeyChord);
|
||||
|
||||
public override void InitializeProperties()
|
||||
{
|
||||
@@ -32,7 +32,7 @@ public partial class CommandContextItemViewModel(ICommandContextItem contextItem
|
||||
base.InitializeProperties();
|
||||
|
||||
var contextItem = Model.Unsafe;
|
||||
if (contextItem is null)
|
||||
if (contextItem == null)
|
||||
{
|
||||
return; // throw?
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
{
|
||||
get
|
||||
{
|
||||
List<IContextItemViewModel> l = _defaultCommandContextItem is null ?
|
||||
List<IContextItemViewModel> l = _defaultCommandContextItem == null ?
|
||||
new() :
|
||||
[_defaultCommandContextItem];
|
||||
|
||||
@@ -100,7 +100,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
}
|
||||
|
||||
var model = _commandItemModel.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -128,7 +128,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
}
|
||||
|
||||
var model = _commandItemModel.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -136,7 +136,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
Command.InitializeProperties();
|
||||
|
||||
var listIcon = model.Icon;
|
||||
if (listIcon is not null)
|
||||
if (listIcon != null)
|
||||
{
|
||||
_listItemIcon = new(listIcon);
|
||||
_listItemIcon.InitializeProperties();
|
||||
@@ -172,13 +172,13 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
}
|
||||
|
||||
var model = _commandItemModel.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var more = model.MoreCommands;
|
||||
if (more is not null)
|
||||
if (more != null)
|
||||
{
|
||||
MoreCommands = more
|
||||
.Select(item =>
|
||||
@@ -300,7 +300,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
protected virtual void FetchProperty(string propertyName)
|
||||
{
|
||||
var model = this._commandItemModel.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return; // throw?
|
||||
}
|
||||
@@ -308,7 +308,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
switch (propertyName)
|
||||
{
|
||||
case nameof(Command):
|
||||
if (Command is not null)
|
||||
if (Command != null)
|
||||
{
|
||||
Command.PropertyChanged -= Command_PropertyChanged;
|
||||
}
|
||||
@@ -339,7 +339,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
|
||||
case nameof(model.MoreCommands):
|
||||
var more = model.MoreCommands;
|
||||
if (more is not null)
|
||||
if (more != null)
|
||||
{
|
||||
var newContextMenu = more
|
||||
.Select(item =>
|
||||
@@ -394,7 +394,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
// Extensions based on Command Palette SDK < 0.3 CommandItem class won't notify when Title changes because Command
|
||||
// or Command.Name change. This is a workaround to ensure that the Title is always up-to-date for extensions with old SDK.
|
||||
var model = _commandItemModel.Unsafe;
|
||||
if (model is not null)
|
||||
if (model != null)
|
||||
{
|
||||
_itemTitle = model.Title;
|
||||
}
|
||||
@@ -430,7 +430,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
Command.SafeCleanup();
|
||||
|
||||
var model = _commandItemModel.Unsafe;
|
||||
if (model is not null)
|
||||
if (model != null)
|
||||
{
|
||||
model.PropChanged -= Model_PropChanged;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public partial class CommandViewModel : ExtensionObjectViewModel
|
||||
}
|
||||
|
||||
var model = Model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -67,13 +67,13 @@ public partial class CommandViewModel : ExtensionObjectViewModel
|
||||
}
|
||||
|
||||
var model = Model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var ico = model.Icon;
|
||||
if (ico is not null)
|
||||
if (ico != null)
|
||||
{
|
||||
Icon = new(ico);
|
||||
Icon.InitializeProperties();
|
||||
@@ -98,7 +98,7 @@ public partial class CommandViewModel : ExtensionObjectViewModel
|
||||
protected void FetchProperty(string propertyName)
|
||||
{
|
||||
var model = Model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return; // throw?
|
||||
}
|
||||
@@ -125,7 +125,7 @@ public partial class CommandViewModel : ExtensionObjectViewModel
|
||||
Icon = new(null); // necessary?
|
||||
|
||||
var model = Model.Unsafe;
|
||||
if (model is not null)
|
||||
if (model != null)
|
||||
{
|
||||
model.PropChanged -= Model_PropChanged;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public partial class ConfirmResultViewModel(IConfirmationArgs _args, WeakReferen
|
||||
public override void InitializeProperties()
|
||||
{
|
||||
var model = Model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ public abstract partial class ContentPageViewModel : PageViewModel, ICommandBarC
|
||||
public DetailsViewModel? Details { get; private set; }
|
||||
|
||||
[MemberNotNullWhen(true, nameof(Details))]
|
||||
public bool HasDetails => Details is not null;
|
||||
public bool HasDetails => Details != null;
|
||||
|
||||
/////// ICommandBarContext ///////
|
||||
public IEnumerable<IContextItemViewModel> MoreCommands => Commands.Skip(1);
|
||||
@@ -67,7 +67,7 @@ public abstract partial class ContentPageViewModel : PageViewModel, ICommandBarC
|
||||
foreach (var item in newItems)
|
||||
{
|
||||
var viewModel = ViewModelFromContent(item, PageContext);
|
||||
if (viewModel is not null)
|
||||
if (viewModel != null)
|
||||
{
|
||||
viewModel.InitializeProperties();
|
||||
newContent.Add(viewModel);
|
||||
@@ -104,7 +104,7 @@ public abstract partial class ContentPageViewModel : PageViewModel, ICommandBarC
|
||||
base.InitializeProperties();
|
||||
|
||||
var model = _model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return; // throw?
|
||||
}
|
||||
@@ -133,7 +133,7 @@ public abstract partial class ContentPageViewModel : PageViewModel, ICommandBarC
|
||||
});
|
||||
|
||||
var extensionDetails = model.Details;
|
||||
if (extensionDetails is not null)
|
||||
if (extensionDetails != null)
|
||||
{
|
||||
Details = new(extensionDetails, PageContext);
|
||||
Details.InitializeProperties();
|
||||
@@ -156,7 +156,7 @@ public abstract partial class ContentPageViewModel : PageViewModel, ICommandBarC
|
||||
base.FetchProperty(propertyName);
|
||||
|
||||
var model = this._model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return; // throw?
|
||||
}
|
||||
@@ -166,7 +166,7 @@ public abstract partial class ContentPageViewModel : PageViewModel, ICommandBarC
|
||||
case nameof(Commands):
|
||||
|
||||
var more = model.Commands;
|
||||
if (more is not null)
|
||||
if (more != null)
|
||||
{
|
||||
var newContextMenu = more
|
||||
.ToList()
|
||||
@@ -216,7 +216,7 @@ public abstract partial class ContentPageViewModel : PageViewModel, ICommandBarC
|
||||
break;
|
||||
case nameof(Details):
|
||||
var extensionDetails = model.Details;
|
||||
Details = extensionDetails is not null ? new(extensionDetails, PageContext) : null;
|
||||
Details = extensionDetails != null ? new(extensionDetails, PageContext) : null;
|
||||
UpdateDetails();
|
||||
break;
|
||||
}
|
||||
@@ -248,7 +248,7 @@ public abstract partial class ContentPageViewModel : PageViewModel, ICommandBarC
|
||||
[RelayCommand]
|
||||
private void InvokePrimaryCommand(ContentPageViewModel page)
|
||||
{
|
||||
if (PrimaryCommand is not null)
|
||||
if (PrimaryCommand != null)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(PrimaryCommand.Command.Model, PrimaryCommand.Model));
|
||||
}
|
||||
@@ -258,7 +258,7 @@ public abstract partial class ContentPageViewModel : PageViewModel, ICommandBarC
|
||||
[RelayCommand]
|
||||
private void InvokeSecondaryCommand(ContentPageViewModel page)
|
||||
{
|
||||
if (SecondaryCommand is not null)
|
||||
if (SecondaryCommand != null)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(SecondaryCommand.Command.Model, SecondaryCommand.Model));
|
||||
}
|
||||
@@ -285,7 +285,7 @@ public abstract partial class ContentPageViewModel : PageViewModel, ICommandBarC
|
||||
Content.Clear();
|
||||
|
||||
var model = _model.Unsafe;
|
||||
if (model is not null)
|
||||
if (model != null)
|
||||
{
|
||||
model.ItemsChanged -= Model_ItemsChanged;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.CmdPal.Core.ViewModels.Messages;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Microsoft.Diagnostics.Utilities;
|
||||
using Windows.System;
|
||||
|
||||
namespace Microsoft.CmdPal.Core.ViewModels;
|
||||
@@ -50,7 +51,7 @@ public partial class ContextMenuViewModel : ObservableObject,
|
||||
|
||||
public void UpdateContextItems()
|
||||
{
|
||||
if (SelectedItem is not null)
|
||||
if (SelectedItem != null)
|
||||
{
|
||||
if (SelectedItem.MoreCommands.Count() > 1)
|
||||
{
|
||||
@@ -67,14 +68,14 @@ public partial class ContextMenuViewModel : ObservableObject,
|
||||
return;
|
||||
}
|
||||
|
||||
if (SelectedItem is null)
|
||||
if (SelectedItem == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lastSearchText = searchText;
|
||||
|
||||
if (CurrentContextMenu is null)
|
||||
if (CurrentContextMenu == null)
|
||||
{
|
||||
ListHelpers.InPlaceUpdateList(FilteredItems, []);
|
||||
return;
|
||||
@@ -123,7 +124,7 @@ public partial class ContextMenuViewModel : ObservableObject,
|
||||
/// that have a shortcut key set.</returns>
|
||||
public Dictionary<KeyChord, CommandContextItemViewModel> Keybindings()
|
||||
{
|
||||
if (CurrentContextMenu is null)
|
||||
if (CurrentContextMenu == null)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
@@ -139,7 +140,7 @@ public partial class ContextMenuViewModel : ObservableObject,
|
||||
public ContextKeybindingResult? CheckKeybinding(bool ctrl, bool alt, bool shift, bool win, VirtualKey key)
|
||||
{
|
||||
var keybindings = Keybindings();
|
||||
if (keybindings is not null)
|
||||
if (keybindings != null)
|
||||
{
|
||||
// Does the pressed key match any of the keybindings?
|
||||
var pressedKeyChord = KeyChordHelpers.FromModifiers(ctrl, alt, shift, win, key, 0);
|
||||
@@ -189,7 +190,7 @@ public partial class ContextMenuViewModel : ObservableObject,
|
||||
OnPropertyChanging(nameof(CurrentContextMenu));
|
||||
OnPropertyChanged(nameof(CurrentContextMenu));
|
||||
|
||||
if (CurrentContextMenu is not null)
|
||||
if (CurrentContextMenu != null)
|
||||
{
|
||||
ListHelpers.InPlaceUpdateList(FilteredItems, [.. CurrentContextMenu!]);
|
||||
}
|
||||
@@ -197,7 +198,7 @@ public partial class ContextMenuViewModel : ObservableObject,
|
||||
|
||||
public ContextKeybindingResult InvokeCommand(CommandItemViewModel? command)
|
||||
{
|
||||
if (command is null)
|
||||
if (command == null)
|
||||
{
|
||||
return ContextKeybindingResult.Unhandled;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ public partial class DetailsCommandsViewModel(
|
||||
{
|
||||
base.InitializeProperties();
|
||||
var model = _dataModel.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ public abstract partial class DetailsElementViewModel(IDetailsElement _detailsEl
|
||||
public override void InitializeProperties()
|
||||
{
|
||||
var model = _model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ public partial class DetailsLinkViewModel(
|
||||
|
||||
public Uri? Link { get; private set; }
|
||||
|
||||
public bool IsLink => Link is not null;
|
||||
public bool IsLink => Link != null;
|
||||
|
||||
public bool IsText => !IsLink;
|
||||
|
||||
@@ -26,14 +26,14 @@ public partial class DetailsLinkViewModel(
|
||||
{
|
||||
base.InitializeProperties();
|
||||
var model = _dataModel.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Text = model.Text ?? string.Empty;
|
||||
Link = model.Link;
|
||||
if (string.IsNullOrEmpty(Text) && Link is not null)
|
||||
if (string.IsNullOrEmpty(Text) && Link != null)
|
||||
{
|
||||
Text = Link.ToString();
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ public partial class DetailsTagsViewModel(
|
||||
{
|
||||
base.InitializeProperties();
|
||||
var model = _dataModel.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public partial class DetailsViewModel(IDetails _details, WeakReference<IPageCont
|
||||
public override void InitializeProperties()
|
||||
{
|
||||
var model = _detailsModel.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -41,7 +41,7 @@ public partial class DetailsViewModel(IDetails _details, WeakReference<IPageCont
|
||||
UpdateProperty(nameof(HeroImage));
|
||||
|
||||
var meta = model.Metadata;
|
||||
if (meta is not null)
|
||||
if (meta != null)
|
||||
{
|
||||
foreach (var element in meta)
|
||||
{
|
||||
@@ -53,7 +53,7 @@ public partial class DetailsViewModel(IDetails _details, WeakReference<IPageCont
|
||||
IDetailsTags => new DetailsTagsViewModel(element, this.PageContext),
|
||||
_ => null,
|
||||
};
|
||||
if (vm is not null)
|
||||
if (vm != null)
|
||||
{
|
||||
vm.InitializeProperties();
|
||||
Metadata.Add(vm);
|
||||
|
||||
@@ -16,7 +16,7 @@ public partial class IconDataViewModel : ObservableObject, IIconData
|
||||
// If the extension previously gave us a Data, then died, the data will
|
||||
// throw if we actually try to read it, but the pointer itself won't be
|
||||
// null, so this is relatively safe.
|
||||
public bool HasIcon => !string.IsNullOrEmpty(Icon) || Data.Unsafe is not null;
|
||||
public bool HasIcon => !string.IsNullOrEmpty(Icon) || Data.Unsafe != null;
|
||||
|
||||
// Locally cached properties from IIconData.
|
||||
public string Icon { get; private set; } = string.Empty;
|
||||
@@ -36,7 +36,7 @@ public partial class IconDataViewModel : ObservableObject, IIconData
|
||||
public void InitializeProperties()
|
||||
{
|
||||
var model = _model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public partial class IconInfoViewModel : ObservableObject, IIconInfo
|
||||
|
||||
public bool HasIcon(bool light) => IconForTheme(light).HasIcon;
|
||||
|
||||
public bool IsSet => _model.Unsafe is not null;
|
||||
public bool IsSet => _model.Unsafe != null;
|
||||
|
||||
IIconData? IIconInfo.Dark => Dark;
|
||||
|
||||
@@ -43,7 +43,7 @@ public partial class IconInfoViewModel : ObservableObject, IIconInfo
|
||||
public void InitializeProperties()
|
||||
{
|
||||
var model = _model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
|
||||
public DetailsViewModel? Details { get; private set; }
|
||||
|
||||
[MemberNotNullWhen(true, nameof(Details))]
|
||||
public bool HasDetails => Details is not null;
|
||||
public bool HasDetails => Details != null;
|
||||
|
||||
public override void InitializeProperties()
|
||||
{
|
||||
@@ -40,7 +40,7 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
|
||||
base.InitializeProperties();
|
||||
|
||||
var li = Model.Unsafe;
|
||||
if (li is null)
|
||||
if (li == null)
|
||||
{
|
||||
return; // throw?
|
||||
}
|
||||
@@ -50,7 +50,7 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
|
||||
TextToSuggest = li.TextToSuggest;
|
||||
Section = li.Section ?? string.Empty;
|
||||
var extensionDetails = li.Details;
|
||||
if (extensionDetails is not null)
|
||||
if (extensionDetails != null)
|
||||
{
|
||||
Details = new(extensionDetails, PageContext);
|
||||
Details.InitializeProperties();
|
||||
@@ -67,7 +67,7 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
|
||||
base.FetchProperty(propertyName);
|
||||
|
||||
var model = this.Model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return; // throw?
|
||||
}
|
||||
@@ -85,7 +85,7 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
|
||||
break;
|
||||
case nameof(Details):
|
||||
var extensionDetails = model.Details;
|
||||
Details = extensionDetails is not null ? new(extensionDetails, PageContext) : null;
|
||||
Details = extensionDetails != null ? new(extensionDetails, PageContext) : null;
|
||||
Details?.InitializeProperties();
|
||||
UpdateProperty(nameof(Details));
|
||||
UpdateProperty(nameof(HasDetails));
|
||||
@@ -136,7 +136,7 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
|
||||
Details?.SafeCleanup();
|
||||
|
||||
var model = Model.Unsafe;
|
||||
if (model is not null)
|
||||
if (model != null)
|
||||
{
|
||||
// We don't need to revoke the PropChanged event handler here,
|
||||
// because we are just overriding CommandItem's FetchProperty and
|
||||
|
||||
@@ -63,7 +63,6 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
|
||||
private Task? _initializeItemsTask;
|
||||
private CancellationTokenSource? _cancellationTokenSource;
|
||||
private CancellationTokenSource? _fetchItemsCancellationTokenSource;
|
||||
|
||||
private ListItemViewModel? _lastSelectedItem;
|
||||
|
||||
@@ -130,27 +129,14 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
//// Run on background thread, from InitializeAsync or Model_ItemsChanged
|
||||
private void FetchItems()
|
||||
{
|
||||
// Cancel any previous FetchItems operation
|
||||
_fetchItemsCancellationTokenSource?.Cancel();
|
||||
_fetchItemsCancellationTokenSource?.Dispose();
|
||||
_fetchItemsCancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
var cancellationToken = _fetchItemsCancellationTokenSource.Token;
|
||||
|
||||
// TEMPORARY: just plop all the items into a single group
|
||||
// see 9806fe5d8 for the last commit that had this with sections
|
||||
_isFetching = true;
|
||||
|
||||
try
|
||||
{
|
||||
// Check for cancellation before starting expensive operations
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var newItems = _model.Unsafe!.GetItems();
|
||||
|
||||
// Check for cancellation after getting items from extension
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
// Collect all the items into new viewmodels
|
||||
Collection<ListItemViewModel> newViewModels = [];
|
||||
|
||||
@@ -159,9 +145,6 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
// building new viewmodels for the ones we haven't already built.
|
||||
foreach (var item in newItems)
|
||||
{
|
||||
// Check for cancellation during item processing
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
ListItemViewModel viewModel = new(item, new(this));
|
||||
|
||||
// If an item fails to load, silently ignore it.
|
||||
@@ -171,22 +154,15 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
// Check for cancellation before initializing first twenty items
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var firstTwenty = newViewModels.Take(20);
|
||||
foreach (var item in firstTwenty)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
item?.SafeInitializeProperties();
|
||||
}
|
||||
|
||||
// Cancel any ongoing search
|
||||
_cancellationTokenSource?.Cancel();
|
||||
|
||||
// Check for cancellation before updating the list
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
lock (_listLock)
|
||||
{
|
||||
// Now that we have new ViewModels for everything from the
|
||||
@@ -197,11 +173,6 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
// TODO: Iterate over everything in Items, and prune items from the
|
||||
// cache if we don't need them anymore
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// Cancellation is expected, don't treat as error
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// TODO: Move this within the for loop, so we can catch issues with individual items
|
||||
@@ -327,11 +298,11 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
[RelayCommand]
|
||||
private void InvokeItem(ListItemViewModel? item)
|
||||
{
|
||||
if (item is not null)
|
||||
if (item != null)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(item.Command.Model, item.Model));
|
||||
}
|
||||
else if (ShowEmptyContent && EmptyContent.PrimaryCommand?.Model.Unsafe is not null)
|
||||
else if (ShowEmptyContent && EmptyContent.PrimaryCommand?.Model.Unsafe != null)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(
|
||||
EmptyContent.PrimaryCommand.Command.Model,
|
||||
@@ -343,14 +314,14 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
[RelayCommand]
|
||||
private void InvokeSecondaryCommand(ListItemViewModel? item)
|
||||
{
|
||||
if (item is not null)
|
||||
if (item != null)
|
||||
{
|
||||
if (item.SecondaryCommand is not null)
|
||||
if (item.SecondaryCommand != null)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(item.SecondaryCommand.Command.Model, item.Model));
|
||||
}
|
||||
}
|
||||
else if (ShowEmptyContent && EmptyContent.SecondaryCommand?.Model.Unsafe is not null)
|
||||
else if (ShowEmptyContent && EmptyContent.SecondaryCommand?.Model.Unsafe != null)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(
|
||||
EmptyContent.SecondaryCommand.Command.Model,
|
||||
@@ -361,12 +332,12 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
[RelayCommand]
|
||||
private void UpdateSelectedItem(ListItemViewModel? item)
|
||||
{
|
||||
if (_lastSelectedItem is not null)
|
||||
if (_lastSelectedItem != null)
|
||||
{
|
||||
_lastSelectedItem.PropertyChanged -= SelectedItemPropertyChanged;
|
||||
}
|
||||
|
||||
if (item is not null)
|
||||
if (item != null)
|
||||
{
|
||||
SetSelectedItem(item);
|
||||
}
|
||||
@@ -412,7 +383,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
private void SelectedItemPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
var item = _lastSelectedItem;
|
||||
if (item is null)
|
||||
if (item == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -467,7 +438,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
base.InitializeProperties();
|
||||
|
||||
var model = _model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return; // throw?
|
||||
}
|
||||
@@ -494,7 +465,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
public void LoadMoreIfNeeded()
|
||||
{
|
||||
var model = this._model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -538,7 +509,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
base.FetchProperty(propertyName);
|
||||
|
||||
var model = this._model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return; // throw?
|
||||
}
|
||||
@@ -569,7 +540,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
private void UpdateEmptyContent()
|
||||
{
|
||||
UpdateProperty(nameof(ShowEmptyContent));
|
||||
if (!ShowEmptyContent || EmptyContent.Model.Unsafe is null)
|
||||
if (!ShowEmptyContent || EmptyContent.Model.Unsafe == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -589,10 +560,6 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
_cancellationTokenSource?.Cancel();
|
||||
_cancellationTokenSource?.Dispose();
|
||||
_cancellationTokenSource = null;
|
||||
|
||||
_fetchItemsCancellationTokenSource?.Cancel();
|
||||
_fetchItemsCancellationTokenSource?.Dispose();
|
||||
_fetchItemsCancellationTokenSource = null;
|
||||
}
|
||||
|
||||
protected override void UnsafeCleanup()
|
||||
@@ -603,7 +570,6 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
EmptyContent = new(new(null), PageContext); // necessary?
|
||||
|
||||
_cancellationTokenSource?.Cancel();
|
||||
_fetchItemsCancellationTokenSource?.Cancel();
|
||||
|
||||
lock (_listLock)
|
||||
{
|
||||
@@ -622,7 +588,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
}
|
||||
|
||||
var model = _model.Unsafe;
|
||||
if (model is not null)
|
||||
if (model != null)
|
||||
{
|
||||
model.ItemsChanged -= Model_ItemsChanged;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ public partial class LogMessageViewModel : ExtensionObjectViewModel
|
||||
public override void InitializeProperties()
|
||||
{
|
||||
var model = _model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return; // throw?
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Microsoft.CmdPal.Common.Helpers;
|
||||
using Microsoft.CmdPal.Core.ViewModels.Models;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
|
||||
@@ -46,7 +45,7 @@ public partial class PageViewModel : ExtensionObjectViewModel, IPageContext
|
||||
[ObservableProperty]
|
||||
public partial AppExtensionHost ExtensionHost { get; private set; }
|
||||
|
||||
public bool HasStatusMessage => MostRecentStatusMessage is not null;
|
||||
public bool HasStatusMessage => MostRecentStatusMessage != null;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(HasStatusMessage))]
|
||||
@@ -133,7 +132,7 @@ public partial class PageViewModel : ExtensionObjectViewModel, IPageContext
|
||||
public override void InitializeProperties()
|
||||
{
|
||||
var page = _pageModel.Unsafe;
|
||||
if (page is null)
|
||||
if (page == null)
|
||||
{
|
||||
return; // throw?
|
||||
}
|
||||
@@ -178,7 +177,7 @@ public partial class PageViewModel : ExtensionObjectViewModel, IPageContext
|
||||
protected virtual void FetchProperty(string propertyName)
|
||||
{
|
||||
var model = this._pageModel.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return; // throw?
|
||||
}
|
||||
@@ -224,10 +223,9 @@ public partial class PageViewModel : ExtensionObjectViewModel, IPageContext
|
||||
extensionHint ??= ExtensionHost.GetExtensionDisplayName() ?? Title;
|
||||
Task.Factory.StartNew(
|
||||
() =>
|
||||
{
|
||||
var message = DiagnosticsHelper.BuildExceptionMessage(ex, extensionHint);
|
||||
ErrorMessage += message;
|
||||
},
|
||||
{
|
||||
ErrorMessage += $"A bug occurred in {$"the \"{extensionHint}\"" ?? "an unknown's"} extension's code:\n{ex.Message}\n{ex.Source}\n{ex.StackTrace}\n\n";
|
||||
},
|
||||
CancellationToken.None,
|
||||
TaskCreationOptions.None,
|
||||
Scheduler);
|
||||
@@ -242,7 +240,7 @@ public partial class PageViewModel : ExtensionObjectViewModel, IPageContext
|
||||
ExtensionHost.StatusMessages.CollectionChanged -= StatusMessages_CollectionChanged;
|
||||
|
||||
var model = _pageModel.Unsafe;
|
||||
if (model is not null)
|
||||
if (model != null)
|
||||
{
|
||||
model.PropChanged -= Model_PropChanged;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public partial class ProgressViewModel : ExtensionObjectViewModel
|
||||
public override void InitializeProperties()
|
||||
{
|
||||
var model = Model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return; // throw?
|
||||
}
|
||||
@@ -50,7 +50,7 @@ public partial class ProgressViewModel : ExtensionObjectViewModel
|
||||
protected virtual void FetchProperty(string propertyName)
|
||||
{
|
||||
var model = this.Model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return; // throw?
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ public partial class ShellViewModel : ObservableObject,
|
||||
|
||||
////LoadedState = ViewModelLoadedState.Loading;
|
||||
if (!viewModel.IsInitialized
|
||||
&& viewModel.InitializeCommand is not null)
|
||||
&& viewModel.InitializeCommand != null)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
@@ -185,7 +185,7 @@ public partial class ShellViewModel : ObservableObject,
|
||||
private void PerformCommand(PerformCommandMessage message)
|
||||
{
|
||||
var command = message.Command.Unsafe;
|
||||
if (command is null)
|
||||
if (command == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -205,7 +205,7 @@ public partial class ShellViewModel : ObservableObject,
|
||||
|
||||
// Construct our ViewModel of the appropriate type and pass it the UI Thread context.
|
||||
var pageViewModel = _pageViewModelFactory.TryCreatePageViewModel(page, _isNested, host);
|
||||
if (pageViewModel is null)
|
||||
if (pageViewModel == null)
|
||||
{
|
||||
Logger.LogError($"Failed to create ViewModel for page {page.GetType().Name}");
|
||||
throw new NotSupportedException();
|
||||
@@ -240,7 +240,7 @@ public partial class ShellViewModel : ObservableObject,
|
||||
// TODO GH #525 This needs more better locking.
|
||||
lock (_invokeLock)
|
||||
{
|
||||
if (_handleInvokeTask is not null)
|
||||
if (_handleInvokeTask != null)
|
||||
{
|
||||
// do nothing - a command is already doing a thing
|
||||
}
|
||||
@@ -280,7 +280,7 @@ public partial class ShellViewModel : ObservableObject,
|
||||
|
||||
private void UnsafeHandleCommandResult(ICommandResult? result)
|
||||
{
|
||||
if (result is null)
|
||||
if (result == null)
|
||||
{
|
||||
// No result, nothing to do.
|
||||
return;
|
||||
|
||||
@@ -17,7 +17,7 @@ public partial class StatusMessageViewModel : ExtensionObjectViewModel
|
||||
|
||||
public ProgressViewModel? Progress { get; private set; }
|
||||
|
||||
public bool HasProgress => Progress is not null;
|
||||
public bool HasProgress => Progress != null;
|
||||
|
||||
public StatusMessageViewModel(IStatusMessage message, WeakReference<IPageContext> context)
|
||||
: base(context)
|
||||
@@ -28,7 +28,7 @@ public partial class StatusMessageViewModel : ExtensionObjectViewModel
|
||||
public override void InitializeProperties()
|
||||
{
|
||||
var model = Model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return; // throw?
|
||||
}
|
||||
@@ -36,7 +36,7 @@ public partial class StatusMessageViewModel : ExtensionObjectViewModel
|
||||
Message = model.Message;
|
||||
State = model.State;
|
||||
var modelProgress = model.Progress;
|
||||
if (modelProgress is not null)
|
||||
if (modelProgress != null)
|
||||
{
|
||||
Progress = new(modelProgress, this.PageContext);
|
||||
Progress.InitializeProperties();
|
||||
@@ -61,7 +61,7 @@ public partial class StatusMessageViewModel : ExtensionObjectViewModel
|
||||
protected virtual void FetchProperty(string propertyName)
|
||||
{
|
||||
var model = this.Model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return; // throw?
|
||||
}
|
||||
@@ -76,7 +76,7 @@ public partial class StatusMessageViewModel : ExtensionObjectViewModel
|
||||
break;
|
||||
case nameof(Progress):
|
||||
var modelProgress = model.Progress;
|
||||
if (modelProgress is not null)
|
||||
if (modelProgress != null)
|
||||
{
|
||||
Progress = new(modelProgress, this.PageContext);
|
||||
Progress.InitializeProperties();
|
||||
|
||||
@@ -28,7 +28,7 @@ public partial class TagViewModel(ITag _tag, WeakReference<IPageContext> context
|
||||
public override void InitializeProperties()
|
||||
{
|
||||
var model = _tagModel.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public partial class AliasManager : ObservableObject
|
||||
try
|
||||
{
|
||||
var topLevelCommand = _topLevelCommandManager.LookupCommand(alias.CommandId);
|
||||
if (topLevelCommand is not null)
|
||||
if (topLevelCommand != null)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<ClearSearchMessage>();
|
||||
|
||||
@@ -88,7 +88,7 @@ public partial class AliasManager : ObservableObject
|
||||
}
|
||||
|
||||
// If we already have _this exact alias_, do nothing
|
||||
if (newAlias is not null &&
|
||||
if (newAlias != null &&
|
||||
_aliases.TryGetValue(newAlias.SearchPrefix, out var existingAlias))
|
||||
{
|
||||
if (existingAlias.CommandId == commandId)
|
||||
@@ -113,7 +113,7 @@ public partial class AliasManager : ObservableObject
|
||||
_aliases.Remove(alias.SearchPrefix);
|
||||
}
|
||||
|
||||
if (newAlias is not null)
|
||||
if (newAlias != null)
|
||||
{
|
||||
AddAlias(newAlias);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public partial class AppStateModel : ObservableObject
|
||||
|
||||
var loaded = JsonSerializer.Deserialize<AppStateModel>(jsonContent, JsonSerializationContext.Default.AppStateModel);
|
||||
|
||||
Debug.WriteLine(loaded is not null ? "Loaded settings file" : "Failed to parse");
|
||||
Debug.WriteLine(loaded != null ? "Loaded settings file" : "Failed to parse");
|
||||
|
||||
return loaded ?? new();
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Microsoft.CmdPal.UI.ViewModels;
|
||||
|
||||
public sealed class CommandProviderWrapper
|
||||
{
|
||||
public bool IsExtension => Extension is not null;
|
||||
public bool IsExtension => Extension != null;
|
||||
|
||||
private readonly bool isValid;
|
||||
|
||||
@@ -188,14 +188,14 @@ public sealed class CommandProviderWrapper
|
||||
|
||||
return topLevelViewModel;
|
||||
};
|
||||
if (commands is not null)
|
||||
if (commands != null)
|
||||
{
|
||||
TopLevelItems = commands
|
||||
.Select(c => makeAndAdd(c, false))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
if (fallbacks is not null)
|
||||
if (fallbacks != null)
|
||||
{
|
||||
FallbackItems = fallbacks
|
||||
.Select(c => makeAndAdd(c, true))
|
||||
|
||||
@@ -18,18 +18,18 @@ public partial class CommandSettingsViewModel(ICommandSettings? _unsafeSettings,
|
||||
public bool Initialized { get; private set; }
|
||||
|
||||
public bool HasSettings =>
|
||||
_model.Unsafe is not null && // We have a settings model AND
|
||||
(!Initialized || SettingsPage is not null); // we weren't initialized, OR we were, and we do have a settings page
|
||||
_model.Unsafe != null && // We have a settings model AND
|
||||
(!Initialized || SettingsPage != null); // we weren't initialized, OR we were, and we do have a settings page
|
||||
|
||||
private void UnsafeInitializeProperties()
|
||||
{
|
||||
var model = _model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (model.SettingsPage is not null)
|
||||
if (model.SettingsPage != null)
|
||||
{
|
||||
SettingsPage = new CommandPaletteContentPageViewModel(model.SettingsPage, mainThread, provider.ExtensionHost);
|
||||
SettingsPage.InitializeProperties();
|
||||
|
||||
@@ -30,7 +30,7 @@ internal sealed partial class CreatedExtensionForm : NewExtensionFormBase
|
||||
public override ICommandResult SubmitForm(string inputs, string data)
|
||||
{
|
||||
var dataInput = JsonNode.Parse(data)?.AsObject();
|
||||
if (dataInput is null)
|
||||
if (dataInput == null)
|
||||
{
|
||||
return CommandResult.KeepOpen();
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ public partial class LogMessagesPage : ListPage
|
||||
|
||||
private void LogMessages_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (e.Action == NotifyCollectionChangedAction.Add && e.NewItems is not null)
|
||||
if (e.Action == NotifyCollectionChangedAction.Add && e.NewItems != null)
|
||||
{
|
||||
foreach (var item in e.NewItems)
|
||||
{
|
||||
|
||||
@@ -203,7 +203,7 @@ public partial class MainListPage : DynamicListPage,
|
||||
|
||||
// If we don't have any previous filter results to work with, start
|
||||
// with a list of all our commands & apps.
|
||||
if (_filteredItems is null)
|
||||
if (_filteredItems == null)
|
||||
{
|
||||
_filteredItems = commands;
|
||||
_filteredItemsIncludesApps = _includeApps;
|
||||
|
||||
@@ -98,7 +98,7 @@ internal sealed partial class NewExtensionForm : NewExtensionFormBase
|
||||
public override CommandResult SubmitForm(string payload)
|
||||
{
|
||||
var formInput = JsonNode.Parse(payload)?.AsObject();
|
||||
if (formInput is null)
|
||||
if (formInput == null)
|
||||
{
|
||||
return CommandResult.KeepOpen();
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ public partial class NewExtensionPage : ContentPage
|
||||
|
||||
public override IContent[] GetContent()
|
||||
{
|
||||
return _resultForm is not null ? [_resultForm] : [_inputForm];
|
||||
return _resultForm != null ? [_resultForm] : [_inputForm];
|
||||
}
|
||||
|
||||
public NewExtensionPage()
|
||||
@@ -28,13 +28,13 @@ public partial class NewExtensionPage : ContentPage
|
||||
|
||||
private void FormSubmitted(NewExtensionFormBase sender, NewExtensionFormBase? args)
|
||||
{
|
||||
if (_resultForm is not null)
|
||||
if (_resultForm != null)
|
||||
{
|
||||
_resultForm.FormSubmitted -= FormSubmitted;
|
||||
}
|
||||
|
||||
_resultForm = args;
|
||||
if (_resultForm is not null)
|
||||
if (_resultForm != null)
|
||||
{
|
||||
_resultForm.FormSubmitted += FormSubmitted;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ public partial class ContentMarkdownViewModel(IMarkdownContent _markdown, WeakRe
|
||||
public override void InitializeProperties()
|
||||
{
|
||||
var model = Model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -47,7 +47,7 @@ public partial class ContentMarkdownViewModel(IMarkdownContent _markdown, WeakRe
|
||||
protected void FetchProperty(string propertyName)
|
||||
{
|
||||
var model = Model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return; // throw?
|
||||
}
|
||||
@@ -66,7 +66,7 @@ public partial class ContentMarkdownViewModel(IMarkdownContent _markdown, WeakRe
|
||||
{
|
||||
base.UnsafeCleanup();
|
||||
var model = Model.Unsafe;
|
||||
if (model is not null)
|
||||
if (model != null)
|
||||
{
|
||||
model.PropChanged -= Model_PropChanged;
|
||||
}
|
||||
|
||||
@@ -30,13 +30,13 @@ public partial class ContentTreeViewModel(ITreeContent _tree, WeakReference<IPag
|
||||
public override void InitializeProperties()
|
||||
{
|
||||
var model = Model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var root = model.RootContent;
|
||||
if (root is not null)
|
||||
if (root != null)
|
||||
{
|
||||
RootContent = ViewModelFromContent(root, PageContext);
|
||||
RootContent?.InitializeProperties();
|
||||
@@ -82,7 +82,7 @@ public partial class ContentTreeViewModel(ITreeContent _tree, WeakReference<IPag
|
||||
protected void FetchProperty(string propertyName)
|
||||
{
|
||||
var model = Model.Unsafe;
|
||||
if (model is null)
|
||||
if (model == null)
|
||||
{
|
||||
return; // throw?
|
||||
}
|
||||
@@ -91,7 +91,7 @@ public partial class ContentTreeViewModel(ITreeContent _tree, WeakReference<IPag
|
||||
{
|
||||
case nameof(RootContent):
|
||||
var root = model.RootContent;
|
||||
if (root is not null)
|
||||
if (root != null)
|
||||
{
|
||||
RootContent = ViewModelFromContent(root, PageContext);
|
||||
}
|
||||
@@ -119,7 +119,7 @@ public partial class ContentTreeViewModel(ITreeContent _tree, WeakReference<IPag
|
||||
foreach (var item in newItems)
|
||||
{
|
||||
var viewModel = ViewModelFromContent(item, PageContext);
|
||||
if (viewModel is not null)
|
||||
if (viewModel != null)
|
||||
{
|
||||
viewModel.InitializeProperties();
|
||||
newContent.Add(viewModel);
|
||||
@@ -153,7 +153,7 @@ public partial class ContentTreeViewModel(ITreeContent _tree, WeakReference<IPag
|
||||
|
||||
Children.Clear();
|
||||
var model = Model.Unsafe;
|
||||
if (model is not null)
|
||||
if (model != null)
|
||||
{
|
||||
model.PropChanged -= Model_PropChanged;
|
||||
model.ItemsChanged -= Model_ItemsChanged;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user