Files
cursor-lang/CursorLang.Settings/App.xaml.cs
T
alex 81587988f2
Pull request / build (pull_request) Successful in 39s
added sending closing event message to settings windows
2026-08-14 02:18:47 +05:00

146 lines
4.7 KiB
C#

using System.Windows;
using CursorLang.Core.Services;
using CursorLang.Settings.Services;
using CursorLang.Settings.ViewModels;
using CursorLang.Settings.Views;
using Microsoft.Extensions.DependencyInjection;
namespace CursorLang.Settings;
/// <summary>
/// The settings window as a process of its own.
/// </summary>
/// <remarks>
/// It is started by the agent — from the tray menu, or straight away when the user
/// launches the application themselves — and it ends when the window is closed. That
/// is the whole point of the split: WPF costs around a hundred megabytes, and this way
/// the system gets all of it back the moment the user is done, instead of the
/// background process carrying it until sign-out.
///
/// Nothing here talks to the agent directly. Every edit goes into settings.json, and
/// <see cref="SettingsService"/> nudges the agent to re-read it once the file is
/// written. An agent that is not running is a normal case: the window works the same.
/// </remarks>
// ReSharper disable once RedundantExtendsListEntry
public partial class App : Application
{
private ServiceProvider? _services;
private SingleInstanceGate? _instanceGate;
private SettingsCloseSignal? _closeSignal;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var gate = new SingleInstanceGate(SingleInstanceGate.SettingsName);
if (!gate.TryAcquire(showRunningInstance: true))
{
gate.Dispose();
Shutdown();
return;
}
_instanceGate = gate;
_instanceGate.ActivationRequested += OnActivationRequested;
_closeSignal = new SettingsCloseSignal();
_closeSignal.CloseRequested += OnCloseRequested;
_closeSignal.Listen();
var services = new ServiceCollection();
ConfigureServices(services);
_services = services.BuildServiceProvider();
_services.GetRequiredService<SettingsService>().TrackChanges();
_services.GetRequiredService<ThemeService>();
MainWindow = _services.GetRequiredService<MainWindow>();
ShutdownMode = ShutdownMode.OnMainWindowClose;
MainWindow.Show();
_ = _services.GetRequiredService<SettingsViewModel>().InitializeAsync();
}
protected override void OnExit(ExitEventArgs e)
{
_services?.Dispose();
if (_closeSignal is not null)
{
_closeSignal.CloseRequested -= OnCloseRequested;
_closeSignal.Dispose();
}
if (_instanceGate is not null)
{
_instanceGate.ActivationRequested -= OnActivationRequested;
_instanceGate.Dispose();
}
base.OnExit(e);
}
internal static void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(AppVersion.Current);
services.AddSingleton<SettingsService>();
services.AddSingleton(provider => provider.GetRequiredService<SettingsService>().Load());
services.AddSingleton<ThemeService>();
services.AddSingleton<IThemeService>(provider => provider.GetRequiredService<ThemeService>());
services.AddSingleton<MainWindowPlacement>();
services.AddSingleton<ILocalizationService, LocalizationService>();
services.AddSingleton<IStartupService, StartupService>();
services.AddSingleton<SettingsViewModel>();
services.AddSingleton<MainWindow>();
}
// A second launch — another click on "Settings" in the tray menu, say. The gate
// answers on a thread pool thread, and a window obeys only its own
private void OnActivationRequested(object? sender, EventArgs e) =>
Dispatcher.BeginInvoke(ShowMainWindow);
// The agent is quitting. Answered on a thread pool thread, and the window is closed
// on its own one
private void OnCloseRequested(object? sender, EventArgs e) =>
Dispatcher.BeginInvoke(CloseMainWindow);
/// <summary>
/// Closes the window the way the title bar button does, so that everything hanging
/// off closing happens; <see cref="ShutdownMode.OnMainWindowClose"/> ends the process
/// after it. Without a window there is nothing to close and the process simply ends.
/// </summary>
private void CloseMainWindow()
{
if (MainWindow is { } window)
{
window.Close();
return;
}
Shutdown();
}
private void ShowMainWindow()
{
if (MainWindow is not { } window)
{
return;
}
if (window.WindowState == WindowState.Minimized)
{
window.WindowState = WindowState.Normal;
}
window.Show();
window.Activate();
}
}