Files
Electron.NET/src/ElectronNET.API/API/WindowManager.cs
2025-12-22 12:32:52 +01:00

193 lines
6.3 KiB
C#

using ElectronNET.API.Entities;
using ElectronNET.API.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Threading.Tasks;
namespace ElectronNET.API
{
/// <summary>
///
/// </summary>
public sealed class WindowManager
{
private static WindowManager _windowManager;
private static readonly object SyncRoot = new();
internal WindowManager()
{
}
internal static WindowManager Instance
{
get
{
if (_windowManager == null)
{
lock (SyncRoot)
{
if (_windowManager == null)
{
_windowManager = new WindowManager();
}
}
}
return _windowManager;
}
}
/// <summary>
/// Quit when all windows are closed. (Default is true)
/// </summary>
/// <value>
/// <c>true</c> if [quit window all closed]; otherwise, <c>false</c>.
/// </value>
public bool IsQuitOnWindowAllClosed
{
get => _isQuitOnWindowAllClosed;
set
{
BridgeConnector.Socket.Emit("quit-app-window-all-closed", value);
_isQuitOnWindowAllClosed = value;
}
}
private bool _isQuitOnWindowAllClosed = true;
/// <summary>
/// Gets the browser windows.
/// </summary>
/// <value>
/// The browser windows.
/// </value>
public IReadOnlyCollection<BrowserWindow> BrowserWindows => _browserWindows.AsReadOnly();
private readonly List<BrowserWindow> _browserWindows = new();
/// <summary>
/// Gets the browser views.
/// </summary>
/// <value>
/// The browser view.
/// </value>
public IReadOnlyCollection<BrowserView> BrowserViews => _browserViews.AsReadOnly();
private readonly List<BrowserView> _browserViews = new();
/// <summary>
/// Creates the window asynchronous.
/// </summary>
/// <param name="loadUrl">The load URL.</param>
/// <returns></returns>
public async Task<BrowserWindow> CreateWindowAsync(string loadUrl = "http://localhost")
{
return await this.CreateWindowAsync(new BrowserWindowOptions(), loadUrl).ConfigureAwait(false);
}
/// <summary>
/// Creates the window asynchronous.
/// </summary>
/// <param name="options">The options.</param>
/// <param name="loadUrl">The load URL.</param>
/// <returns></returns>
public async Task<BrowserWindow> CreateWindowAsync(BrowserWindowOptions options, string loadUrl = "http://localhost")
{
var tcs = new TaskCompletionSource<BrowserWindow>();
BridgeConnector.Socket.Once<int>("BrowserWindowCreated", (id) =>
{
var browserWindow = new BrowserWindow(id);
_browserWindows.Add(browserWindow);
tcs.SetResult(browserWindow);
});
BridgeConnector.Socket.Once<int[]>("BrowserWindowClosed", (ids) =>
{
for (int index = 0; index < _browserWindows.Count; index++)
{
if (!ids.Contains(_browserWindows[index].Id))
{
_browserWindows.RemoveAt(index);
}
}
});
if (loadUrl.Equals("http://localhost", StringComparison.OrdinalIgnoreCase) && ElectronNetRuntime.AspNetWebPort.HasValue)
{
loadUrl = $"{loadUrl}:{ElectronNetRuntime.AspNetWebPort}";
}
// Workaround Windows 10 / Electron Bug
// https://github.com/electron/electron/issues/4045
if (IsWindows10())
{
options.Width += 14;
options.Height += 7;
}
if (!options.X.HasValue && !options.Y.HasValue)
{
await BridgeConnector.Socket.Emit("createBrowserWindow", options, loadUrl).ConfigureAwait(false);
}
else
{
// Workaround Windows 10 / Electron Bug
// https://github.com/electron/electron/issues/4045
if (IsWindows10())
{
options.X -= 7;
}
await BridgeConnector.Socket.Emit("createBrowserWindow", options, loadUrl).ConfigureAwait(false);
}
return await tcs.Task.ConfigureAwait(false);
}
private bool IsWindows10()
{
return RuntimeInformation.OSDescription.Contains("Windows 10");
}
/// <summary>
/// A BrowserView can be used to embed additional web content into a BrowserWindow.
/// It is like a child window, except that it is positioned relative to its owning window.
/// It is meant to be an alternative to the webview tag.
/// </summary>
/// <returns></returns>
public Task<BrowserView> CreateBrowserViewAsync()
{
return CreateBrowserViewAsync(new BrowserViewConstructorOptions());
}
/// <summary>
/// A BrowserView can be used to embed additional web content into a BrowserWindow.
/// It is like a child window, except that it is positioned relative to its owning window.
/// It is meant to be an alternative to the webview tag.
/// </summary>
/// <param name="options"></param>
/// <returns></returns>
public async Task<BrowserView> CreateBrowserViewAsync(BrowserViewConstructorOptions options)
{
var tcs = new TaskCompletionSource<BrowserView>();
BridgeConnector.Socket.Once<int>("BrowserViewCreated", (id) =>
{
BrowserView browserView = new(id);
_browserViews.Add(browserView);
tcs.SetResult(browserView);
});
await BridgeConnector.Socket.Emit("createBrowserView", options).ConfigureAwait(false);
return await tcs.Task.ConfigureAwait(false);
}
}
}