Skip to content

Commit

Permalink
♻️ Fix graceful shutdown and add reconnection logic in overlay.
Browse files Browse the repository at this point in the history
Settings UI code is refactored to accomodate the refactoring for improved lifecycle management, but doesn't reconnect at all.
  • Loading branch information
hexawyz committed Apr 29, 2024
1 parent 98d833d commit 335d226
Show file tree
Hide file tree
Showing 24 changed files with 565 additions and 226 deletions.
1 change: 1 addition & 0 deletions Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<PackageReference Update="Serilog.AspNetCore" Version="8.0.0" />
<PackageReference Update="SixLabors.ImageSharp" Version="3.1.3" />
<PackageReference Update="SixLabors.ImageSharp.Drawing" Version="2.1.2" />
<PackageReference Update="System.ServiceModel.Primitives" Version="8.0.0" />
<PackageReference Update="xunit" Version="2.6.4" />
<PackageReference Update="xunit.runner.console" Version="2.6.4" />
<PackageReference Update="xunit.runner.visualstudio" Version="2.5.6" />
Expand Down
4 changes: 4 additions & 0 deletions Exo.Contracts.Ui/Exo.Contracts.Ui.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.ServiceModel.Primitives" />
</ItemGroup>

</Project>
20 changes: 20 additions & 0 deletions Exo.Contracts.Ui/IServiceLifetimeService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.ServiceModel;

namespace Exo.Contracts.Ui;

[ServiceContract(Name = "ServiceLifetime")]
public interface IServiceLifetimeService
{
/// <summary>Tries to get the SHA1 service version.</summary>
/// <remarks>This call is guaranteed to return a value is the service is started and not shutting down.</remarks>
/// <param name="cancellationToken"></param>
/// <returns>The service version as an SHA1 commit id, or <see langword="null"/> if the service is stopped.</returns>
[OperationContract(Name = "TryGetVersion")]
ValueTask<string?> TryGetVersionAsync(CancellationToken cancellationToken);

/// <summary>Waits for the service to stop.</summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[OperationContract(Name = "WaitForStop")]
Task WaitForStopAsync(CancellationToken cancellationToken);
}
2 changes: 1 addition & 1 deletion Exo.Core/AsyncGlobalMutex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public static AsyncGlobalMutex Get(string name)
private AsyncGlobalMutex(string mutexName)
{
_mutex = new(false, mutexName);
_thread = new(MutexThread) { IsBackground = true };
_thread = new(MutexThread) { Name = mutexName, IsBackground = true };
_pendingTaskList = new();
_waitQueue = new();
_manualResetEvent = new(false);
Expand Down
6 changes: 3 additions & 3 deletions Exo.Overlay/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ internal partial class App : Application

public static readonly string? SettingsUiExecutablePath = LocateSettingsUi();

private readonly ServiceConnectionManager _connectionManager = new("Local\\Exo.Service.Overlay");
private readonly ServiceConnectionManager _connectionManager = new("Local\\Exo.Service.Overlay", 100);

private OverlayViewModel? _overlayViewModel;
private NotifyIconService? _notifyIconService;
Expand All @@ -31,9 +31,9 @@ protected override async void OnStartup(System.Windows.StartupEventArgs e)
// Use this undocumented uxtheme API (always… why!) to allow system dark mode for classical UI.
NativeMethods.SetPreferredAppMode(1);

_overlayViewModel = new(_connectionManager.Channel.CreateGrpcService<IOverlayNotificationService>());
_overlayViewModel = new(_connectionManager);

_notifyIconService = await NotifyIconService.CreateAsync(_connectionManager.Channel.CreateGrpcService<IOverlayCustomMenuService>()).ConfigureAwait(false);
_notifyIconService = await NotifyIconService.CreateAsync(_connectionManager).ConfigureAwait(false);
}

private static string? LocateSettingsUi()
Expand Down
9 changes: 8 additions & 1 deletion Exo.Overlay/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ public static unsafe nint LoadIconMetric(nint instanceHandle, nint resourceId, I
public static extern unsafe int SetMenuItemInfo(nint menuHandle, uint item, int isByPosition, MenuItemInfo* menuItemInfo);

[DllImport("user32", ExactSpelling = true, CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true)]
public static extern unsafe int RemoveMenu(nint menuHandle, uint position, int isByPosition);
public static extern unsafe int RemoveMenu(nint menuHandle, uint position, RemoveMenuOptions options);

[DllImport("user32", ExactSpelling = true, CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true)]
public static extern unsafe int TrackPopupMenuEx(nint menuHandle, TrackPopupMenuOptions options, int x, int y, nint windowHandle, TrackPopupMenuParameters* parameters);
Expand Down Expand Up @@ -373,6 +373,13 @@ public static class MenuItemBitmap
public const nint PopupMinimize = 11;
}

[Flags]
public enum RemoveMenuOptions : uint
{
ByCommand = 0x00000000,
ByPosition = 0x00000400,
}

[Flags]
public enum TrackPopupMenuOptions : uint
{
Expand Down
4 changes: 2 additions & 2 deletions Exo.Overlay/NotificationWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ public static ValueTask<NotificationWindow> GetOrCreateAsync()
}
}

private readonly Thread _messageThread = new(MessageLoopThreadProcedure);
private readonly Thread _messageThread;
private readonly ConcurrentQueue<RegisteredCallback> _pendingCallbacks;
private readonly Dictionary<ushort, WeakReference<NotifyIcon>> _registeredIcons;
private readonly Dictionary<nint, WeakReference<PopupMenu>> _registeredMenus;
Expand All @@ -227,7 +227,7 @@ public static ValueTask<NotificationWindow> GetOrCreateAsync()

private NotificationWindow()
{
_messageThread = new(MessageLoopThreadProcedure) { IsBackground = true };
_messageThread = new(MessageLoopThreadProcedure) { Name = "NotificationWindow", IsBackground = true };
_pendingCallbacks = new();
_registeredIcons = new();
_registeredMenus = new();
Expand Down
Loading

0 comments on commit 335d226

Please sign in to comment.