Create a Microsoft.CmdPal.Core.ViewModels project (#40560)

_targets #40504_ 

Major refactoring for #40113

This moves a large swath of the codebase to a `.Core` project. "Core"
doesn't have any explicit dependencies on "extensions", settings or the
current `MainListPage`. It's just a filterable list of stuff. This
should let us make this component a bit more reusable.

This is half of a PR. As I did this, I noticed a particular bit of code
for TopLevelVViewModels and CommandPaletteHost that was _very rough_.
Solving it in this PR would make "move everything to a new project" much
harder to review. So I'm submitting two PRs simultaneously, so we can
see the changes separately, then merge together.
This commit is contained in:
Mike Griese
2025-07-15 12:21:44 -05:00
committed by GitHub
parent 53bb471449
commit cc16b61eb7
121 changed files with 733 additions and 571 deletions

View File

@@ -2,12 +2,16 @@
// 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.Runtime.InteropServices;
using System.Runtime.Versioning;
using ManagedCommon;
using Microsoft.CmdPal.Common.Services;
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CmdPal.UI.ViewModels;
using Microsoft.CmdPal.UI.ViewModels.MainPage;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.DependencyInjection;
using WinRT;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
@@ -16,6 +20,7 @@ namespace Microsoft.CmdPal.UI;
internal sealed class PowerToysRootPageService : IRootPageService
{
private readonly IServiceProvider _serviceProvider;
private IExtensionWrapper? _activeExtension;
private Lazy<MainListPage> _mainListPage;
public PowerToysRootPageService(IServiceProvider serviceProvider)
@@ -53,7 +58,7 @@ internal sealed class PowerToysRootPageService : IRootPageService
}
}
public void OnPerformTopLevelCommand(object? context)
private void OnPerformTopLevelCommand(object? context)
{
try
{
@@ -68,4 +73,72 @@ internal sealed class PowerToysRootPageService : IRootPageService
Logger.LogError(ex.ToString());
}
}
public void OnPerformCommand(object? context, bool topLevel, AppExtensionHost? currentHost)
{
if (topLevel)
{
OnPerformTopLevelCommand(context);
}
if (currentHost is CommandPaletteHost host)
{
SetActiveExtension(host.Extension);
}
else
{
throw new InvalidOperationException("This must be a programming error - everything in Command Palette should have a CommandPaletteHost");
}
}
public void SetActiveExtension(IExtensionWrapper? extension)
{
if (extension != _activeExtension)
{
// There's not really a CoDisallowSetForegroundWindow, so we don't
// need to handle that
_activeExtension = extension;
var extensionWinRtObject = _activeExtension?.GetExtensionObject();
if (extensionWinRtObject != null)
{
try
{
unsafe
{
var winrtObj = (IWinRTObject)extensionWinRtObject;
var intPtr = winrtObj.NativeObject.ThisPtr;
var hr = Native.CoAllowSetForegroundWindow(intPtr);
if (hr != 0)
{
Logger.LogWarning($"Error giving foreground rights: 0x{hr.Value:X8}");
}
}
}
catch (Exception ex)
{
Logger.LogError(ex.ToString());
}
}
}
}
public void GoHome()
{
SetActiveExtension(null);
}
// You may ask yourself, why aren't we using CsWin32 for this?
// The CsWin32 projected version includes some object marshalling, like so:
//
// HRESULT CoAllowSetForegroundWindow([MarshalAs(UnmanagedType.IUnknown)] object pUnk,...)
//
// And if you do it like that, then the IForegroundTransfer interface isn't marshalled correctly
internal sealed class Native
{
[DllImport("OLE32.dll", ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
[SupportedOSPlatform("windows5.0")]
internal static extern unsafe global::Windows.Win32.Foundation.HRESULT CoAllowSetForegroundWindow(nint pUnk, [Optional] void* lpvReserved);
}
}