mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
window reference logic
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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!);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
@@ -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=}"
|
||||
Label="退出"
|
||||
Style="{ThemeResource DefaultAppBarButtonStyle}"/>
|
||||
Label="{shcm:ResourceString Name=CoreWindowingNotifyIconExitLabel}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Snap.Hutao.Web.Bridge.Model;
|
||||
/// DS2请求
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal sealed class DynamicSecrect2Playload
|
||||
internal sealed class DataSignV2Payload
|
||||
{
|
||||
/// <summary>
|
||||
/// q
|
||||
Reference in New Issue
Block a user