window reference logic

This commit is contained in:
Lightczx
2024-05-13 15:36:48 +08:00
parent 0f767f7e77
commit 38e152befd
19 changed files with 156 additions and 68 deletions

View File

@@ -38,7 +38,7 @@ internal sealed partial class Activation : IActivation, IDisposable
private const string UrlActionRefresh = "/REFRESH";
private readonly IServiceProvider serviceProvider;
private readonly ICurrentWindowReference currentWindowReference;
private readonly ICurrentXamlWindowReference currentWindowReference;
private readonly ITaskContext taskContext;
private readonly SemaphoreSlim activateSemaphore = new(1);

View File

@@ -1,24 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Snap.Hutao.Core.Windowing;
using Snap.Hutao.Win32.Foundation;
using WinRT.Interop;
namespace Snap.Hutao.Core.LifeCycle;
internal static class CurrentWindowReferenceExtension
{
public static XamlRoot GetXamlRoot(this ICurrentWindowReference reference)
{
return reference.Window.Content.XamlRoot;
}
public static HWND GetWindowHandle(this ICurrentWindowReference reference)
{
return reference.Window is IXamlWindowOptionsSource optionsSource
? optionsSource.WindowOptions.Hwnd
: WindowNative.GetWindowHandle(reference.Window);
}
}

View File

@@ -5,19 +5,19 @@ using Microsoft.UI.Xaml;
namespace Snap.Hutao.Core.LifeCycle;
[Injection(InjectAs.Singleton, typeof(ICurrentWindowReference))]
internal sealed class CurrentWindowReference : ICurrentWindowReference
[Injection(InjectAs.Singleton, typeof(ICurrentXamlWindowReference))]
internal sealed class CurrentXamlWindowReference : ICurrentXamlWindowReference
{
private readonly WeakReference<Window> reference = new(default!);
[SuppressMessage("", "SH007")]
public Window Window
public Window? Window
{
get
{
reference.TryGetTarget(out Window? window);
return window!;
}
set => reference.SetTarget(value);
set => reference.SetTarget(value!);
}
}

View File

@@ -0,0 +1,23 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Snap.Hutao.Core.Windowing;
using Snap.Hutao.Win32.Foundation;
using WinRT.Interop;
namespace Snap.Hutao.Core.LifeCycle;
internal static class CurrentXamlWindowReferenceExtension
{
public static XamlRoot GetXamlRoot(this ICurrentXamlWindowReference reference)
{
ArgumentNullException.ThrowIfNull(reference.Window);
return reference.Window.Content.XamlRoot;
}
public static HWND GetWindowHandle(this ICurrentXamlWindowReference reference)
{
return WindowExtension.GetWindowHandle(reference.Window);
}
}

View File

@@ -5,10 +5,10 @@ using Microsoft.UI.Xaml;
namespace Snap.Hutao.Core.LifeCycle;
internal interface ICurrentWindowReference
internal interface ICurrentXamlWindowReference
{
/// <summary>
/// Only set in WindowController
/// </summary>
public Window Window { get; set; }
public Window? Window { get; set; }
}

View File

@@ -32,13 +32,19 @@
</Grid.RowDefinitions>
<TextBlock Margin="8" Text="{Binding Title}"/>
<Grid Grid.Row="1" Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}">
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<StackPanel
Margin="4,0"
HorizontalAlignment="Right"
Orientation="Horizontal"
Spacing="2">
<AppBarButton
Command="{Binding ShowMainWindowCommand}"
Icon="{shcm:BitmapIcon Source=ms-appx:///Assets/Logo.ico}"
Label="{shcm:ResourceString Name=CoreWindowingNotifyIconViewLabel}"/>
<AppBarButton
Margin="4,0"
Command="{Binding ExitCommand}"
Icon="{shcm:FontIcon Glyph=&#xE7E8;}"
Label="退出"
Style="{ThemeResource DefaultAppBarButtonStyle}"/>
Label="{shcm:ResourceString Name=CoreWindowingNotifyIconExitLabel}"/>
</StackPanel>
</Grid>
</Grid>

View File

@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.Win32.Foundation;
@@ -40,9 +39,8 @@ internal sealed class NotifyIconController : IDisposable
},
ContextMenuRequested = (window, point) =>
{
Flyout flyout = lazyMenu.Value;
RECT iconRect = NotifyIconMethods.GetRect(Id, window.HWND);
xamlHostWindow.ShowFlyoutAt(flyout, new Windows.Foundation.Point(point.X, point.Y), iconRect);
xamlHostWindow.ShowFlyoutAt(lazyMenu.Value, new Windows.Foundation.Point(point.X, point.Y), iconRect);
},
};

View File

@@ -1,16 +1,9 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using Snap.Hutao.Core.Windowing.Backdrop;
using Snap.Hutao.Win32.Foundation;
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using static Snap.Hutao.Win32.ConstValues;
@@ -129,10 +122,8 @@ internal sealed class NotifyIconMessageWindow : IDisposable
break;
case WM_CONTEXTMENU:
window.ContextMenuRequested?.Invoke(window, wParam2);
Debug.WriteLine($"[uMsg: 0x{uMsg:X8}] [X: {wParam2.X} Y: {wParam2.Y}] [Low: WM_CONTEXTMENU High: 0x{lParam2.High:X8}]");
break;
default:
Debug.WriteLine($"[uMsg: 0x{uMsg:X8}] [X: {wParam2.X} Y: {wParam2.Y}] [Low: 0x{lParam2.Low:X8} High: 0x{lParam2.High:X8}]");
break;
}
}
@@ -145,7 +136,6 @@ internal sealed class NotifyIconMessageWindow : IDisposable
case WM_DWMNCRENDERINGCHANGED:
break;
default:
Debug.WriteLine($"[uMsg: 0x{uMsg:X8}] [wParam: 0x{wParam.Value:X8}] [lParam: 0x{lParam.Value:X8}]");
break;
}
}

View File

@@ -1,12 +1,10 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Media;
using Snap.Hutao.Core.Windowing.Backdrop;
using Snap.Hutao.Win32;
using Snap.Hutao.Win32.Foundation;

View File

@@ -22,6 +22,12 @@ internal static class WindowExtension
WindowControllers.Add(window, windowController);
}
public static bool IsControllerInitialized<TWindow>(this TWindow window)
where TWindow : Window
{
return WindowControllers.TryGetValue(window, out _);
}
public static void SetLayeredWindow(this Window window)
{
HWND hwnd = (HWND)WindowNative.GetWindowHandle(window);
@@ -30,4 +36,21 @@ internal static class WindowExtension
SetWindowLongPtrW(hwnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, style);
SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 0, LAYERED_WINDOW_ATTRIBUTES_FLAGS.LWA_COLORKEY | LAYERED_WINDOW_ATTRIBUTES_FLAGS.LWA_ALPHA);
}
public static void Show(this Window window)
{
ShowWindow(GetWindowHandle(window), SHOW_WINDOW_CMD.SW_NORMAL);
}
public static void Hide(this Window window)
{
ShowWindow(GetWindowHandle(window), SHOW_WINDOW_CMD.SW_HIDE);
}
public static HWND GetWindowHandle(this Window? window)
{
return window is IXamlWindowOptionsSource optionsSource
? optionsSource.WindowOptions.Hwnd
: WindowNative.GetWindowHandle(window);
}
}

View File

@@ -36,8 +36,7 @@ internal sealed class XamlWindowController
this.options = options;
this.serviceProvider = serviceProvider;
// Window reference must be set before Window Subclass created
serviceProvider.GetRequiredService<ICurrentWindowReference>().Window = window;
serviceProvider.GetRequiredService<ICurrentXamlWindowReference>().Window = window;
subclass = new(window, options);
windowNonRudeHWND = new(options.Hwnd);
@@ -137,9 +136,23 @@ internal sealed class XamlWindowController
private void OnWindowClosed(object sender, WindowEventArgs args)
{
SaveOrSkipWindowSize();
subclass?.Dispose();
windowNonRudeHWND?.Dispose();
if (LocalSetting.Get(SettingKeys.IsNotifyIconEnabled, true))
{
args.Handled = true;
window.Hide();
}
else
{
SaveOrSkipWindowSize();
subclass?.Dispose();
windowNonRudeHWND?.Dispose();
ICurrentXamlWindowReference currentXamlWindowReference = serviceProvider.GetRequiredService<ICurrentXamlWindowReference>();
if (currentXamlWindowReference.Window == window)
{
currentXamlWindowReference.Window = default!;
}
}
}
private void ExtendsContentIntoTitleBar()

View File

@@ -13,7 +13,7 @@ namespace Snap.Hutao.Factory.ContentDialog;
[Injection(InjectAs.Singleton, typeof(IContentDialogFactory))]
internal sealed partial class ContentDialogFactory : IContentDialogFactory
{
private readonly ICurrentWindowReference currentWindowReference;
private readonly ICurrentXamlWindowReference currentWindowReference;
private readonly IServiceProvider serviceProvider;
private readonly ITaskContext taskContext;
private readonly AppOptions appOptions;

View File

@@ -18,7 +18,7 @@ namespace Snap.Hutao.Factory.Picker;
[Injection(InjectAs.Transient, typeof(IFileSystemPickerInteraction))]
internal sealed partial class FileSystemPickerInteraction : IFileSystemPickerInteraction
{
private readonly ICurrentWindowReference currentWindowReference;
private readonly ICurrentXamlWindowReference currentWindowReference;
public unsafe ValueResult<bool, ValueFile> PickFile(string? title, string? defaultFileName, (string Name, string Type)[]? filters)
{

View File

@@ -13,7 +13,6 @@ namespace Snap.Hutao;
/// </summary>
[HighQuality]
[Injection(InjectAs.Singleton)]
[SuppressMessage("", "CA1001")]
internal sealed partial class MainWindow : Window, IXamlWindowOptionsSource, IMinMaxInfoHandler
{
private const int MinWidth = 1000;
@@ -30,6 +29,8 @@ internal sealed partial class MainWindow : Window, IXamlWindowOptionsSource, IMi
InitializeComponent();
windowOptions = new(this, TitleBarView.DragArea, new(1200, 741), SettingKeys.WindowRect);
this.InitializeController(serviceProvider);
Closed += OnClosed;
}
/// <inheritdoc/>
@@ -41,4 +42,13 @@ internal sealed partial class MainWindow : Window, IXamlWindowOptionsSource, IMi
pInfo.ptMinTrackSize.x = (int)Math.Max(MinWidth * scalingFactor, pInfo.ptMinTrackSize.x);
pInfo.ptMinTrackSize.y = (int)Math.Max(MinHeight * scalingFactor, pInfo.ptMinTrackSize.y);
}
private void OnClosed(object sender, WindowEventArgs args)
{
if (LocalSetting.Get(SettingKeys.IsNotifyIconEnabled, true))
{
args.Handled = true;
this.Hide();
}
}
}

View File

@@ -192,6 +192,12 @@
<data name="CoreWindowHotkeyCombinationRegisterFailed" xml:space="preserve">
<value>[{0}] 热键 [{1}] 注册失败</value>
</data>
<data name="CoreWindowingNotifyIconExitLabel" xml:space="preserve">
<value>退出</value>
</data>
<data name="CoreWindowingNotifyIconViewLabel" xml:space="preserve">
<value>主界面</value>
</data>
<data name="CoreWindowThemeDark" xml:space="preserve">
<value>深色</value>
</data>

View File

@@ -2,7 +2,10 @@
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.UI.Xaml;
using Snap.Hutao.Core;
using Snap.Hutao.Core.LifeCycle;
using Snap.Hutao.Core.Windowing;
using System.Globalization;
using System.Text;
@@ -13,6 +16,8 @@ namespace Snap.Hutao.ViewModel;
internal sealed partial class NotifyIconViewModel : ObservableObject
{
private readonly RuntimeOptions runtimeOptions;
private readonly ICurrentXamlWindowReference currentXamlWindowReference;
private readonly IServiceProvider serviceProvider;
private readonly App app;
public string Title
@@ -35,6 +40,43 @@ internal sealed partial class NotifyIconViewModel : ObservableObject
}
}
[Command("ShowMainWindowCommand")]
private void ShowMainWindow()
{
switch (currentXamlWindowReference.Window)
{
case MainWindow mainWindow:
{
// MainWindow is activated, bring to foreground
mainWindow.Show();
mainWindow.WindowOptions.BringToForeground();
return;
}
case null:
{
// MainWindow is hided, show it
MainWindow mainWindow = serviceProvider.GetRequiredService<MainWindow>();
currentXamlWindowReference.Window = mainWindow;
// TODO: Can actually be no any window is initialized
mainWindow.Show();
break;
}
case Window otherWindow:
{
if (otherWindow is IXamlWindowOptionsSource optionsSource)
{
otherWindow.Show();
optionsSource.WindowOptions.BringToForeground();
}
return;
}
}
}
[Command("ExitCommand")]
private void Exit()
{

View File

@@ -4,6 +4,7 @@
using Microsoft.Extensions.Caching.Memory;
using Snap.Hutao.Core;
using Snap.Hutao.Core.Caching;
using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.Core.LifeCycle;
using Snap.Hutao.Core.Setting;
using Snap.Hutao.Service.Notification;
@@ -46,7 +47,6 @@ internal sealed partial class TestViewModel : Abstraction.ViewModel
private readonly ILogger<TestViewModel> logger;
private readonly IMemoryCache memoryCache;
private readonly ITaskContext taskContext;
private readonly MainWindow mainWindow;
private UploadAnnouncement announcement = new();
@@ -117,14 +117,17 @@ internal sealed partial class TestViewModel : Abstraction.ViewModel
[Command("ExceptionCommand")]
private static void ThrowTestException()
{
Must.NeverHappen();
HutaoException.Throw("Test Exception");
}
[Command("ResetMainWindowSizeCommand")]
private void ResetMainWindowSize()
{
double scale = mainWindow.WindowOptions.GetRasterizationScale();
mainWindow.AppWindow.Resize(new Windows.Graphics.SizeInt32(1372, 772).Scale(scale));
if (serviceProvider.GetRequiredService<ICurrentXamlWindowReference>().Window is MainWindow mainWindow)
{
double scale = mainWindow.WindowOptions.GetRasterizationScale();
mainWindow.AppWindow.Resize(new Windows.Graphics.SizeInt32(1372, 772).Scale(scale));
}
}
[Command("UploadAnnouncementCommand")]
@@ -186,7 +189,7 @@ internal sealed partial class TestViewModel : Abstraction.ViewModel
{
IDirect3DDevice direct3DDevice = WinRT.IInspectable.FromAbi((nint)inspectable).ObjRef.AsInterface<IDirect3DDevice>();
HWND hwnd = serviceProvider.GetRequiredService<ICurrentWindowReference>().GetWindowHandle();
HWND hwnd = serviceProvider.GetRequiredService<ICurrentXamlWindowReference>().GetWindowHandle();
GraphicsCaptureItem.As<IGraphicsCaptureItemInterop>().CreateForWindow(hwnd, out GraphicsCaptureItem item);
using (Direct3D11CaptureFramePool framePool = Direct3D11CaptureFramePool.CreateFreeThreaded(direct3DDevice, DirectXPixelFormat.B8G8R8A8UIntNormalized, 2, item.Size))

View File

@@ -195,7 +195,7 @@ internal class MiHoYoJSBridge
};
}
protected virtual JsResult<Dictionary<string, string>> GetDynamicSecrectV1(JsParam param)
protected virtual JsResult<Dictionary<string, string>> GetDataSignV1(JsParam param)
{
DataSignOptions options = DataSignOptions.CreateForGeneration1(SaltType.LK2, true);
return new()
@@ -207,7 +207,7 @@ internal class MiHoYoJSBridge
};
}
protected virtual JsResult<Dictionary<string, string>> GetDynamicSecrectV2(JsParam<DynamicSecrect2Playload> param)
protected virtual JsResult<Dictionary<string, string>> GetDataSignV2(JsParam<DataSignV2Payload> param)
{
DataSignOptions options = DataSignOptions.CreateForGeneration2(SaltType.X4, false, param.Payload.Body, param.Payload.GetQueryParam());
return new()
@@ -451,8 +451,8 @@ internal class MiHoYoJSBridge
"getCookieInfo" => GetCookieInfo(param),
"getCookieToken" => await GetCookieTokenAsync(param).ConfigureAwait(false),
"getCurrentLocale" => GetCurrentLocale(param),
"getDS" => GetDynamicSecrectV1(param),
"getDS2" => GetDynamicSecrectV2(param),
"getDS" => GetDataSignV1(param),
"getDS2" => GetDataSignV2(param),
"getHTTPRequestHeaders" => GetHttpRequestHeader(param),
"getStatusBarHeight" => GetStatusBarHeight(param),
"getUserInfo" => await GetUserInfoAsync(param).ConfigureAwait(false),

View File

@@ -7,7 +7,7 @@ namespace Snap.Hutao.Web.Bridge.Model;
/// DS2请求
/// </summary>
[HighQuality]
internal sealed class DynamicSecrect2Playload
internal sealed class DataSignV2Payload
{
/// <summary>
/// q