refactoring events API, replacing task code with calls to ApiBase.

This commit is contained in:
agracio
2025-11-12 10:43:32 +00:00
parent 68feffba02
commit 546668a2c0
40 changed files with 970 additions and 1033 deletions

View File

@@ -1,37 +1,49 @@
namespace ElectronNET.API
// ReSharper disable InconsistentNaming
namespace ElectronNET.API
{
using ElectronNET.API.Serialization;
using ElectronNET.Common;
using Common;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Threading.Tasks;
public abstract class ApiBase
{
protected enum SocketEventNameTypes
protected enum SocketTaskEventNameTypes
{
DashesLowerFirst,
NoDashUpperFirst,
NoDashUpperFirst
}
protected enum SocketTaskMessageNameTypes
{
DashesLowerFirst,
NoDashUpperFirst
}
internal const int PropertyTimeout = 1000;
protected enum SocketEventNameTypes
{
DashedLower,
CamelCase,
}
private const int PropertyTimeout = 1000;
private readonly string objectName;
private readonly ConcurrentDictionary<string, PropertyGetter> propertyGetters = new ConcurrentDictionary<string, PropertyGetter>();
private readonly ConcurrentDictionary<string, string> propertyEventNames = new ConcurrentDictionary<string, string>();
private readonly ConcurrentDictionary<string, string> propertyMessageNames = new ConcurrentDictionary<string, string>();
private readonly ConcurrentDictionary<string, string> methodMessageNames = new ConcurrentDictionary<string, string>();
private readonly ConcurrentDictionary<string, PropertyGetter> propertyGetters;
private readonly ConcurrentDictionary<string, string> propertyEventNames = new();
private readonly ConcurrentDictionary<string, string> propertyMessageNames = new();
private readonly ConcurrentDictionary<string, string> methodMessageNames = new();
private static readonly ConcurrentDictionary<string, EventContainer> eventContainers = new();
private static readonly ConcurrentDictionary<string, ConcurrentDictionary<string, PropertyGetter>> AllPropertyGetters = new();
private readonly object objLock = new object();
public virtual int Id
{
get
{
return -1;
}
get => -1;
// ReSharper disable once ValueParameterNotUsed
protected set
@@ -39,11 +51,14 @@
}
}
protected abstract SocketEventNameTypes SocketEventNameType { get; }
protected abstract SocketTaskEventNameTypes SocketTaskEventNameType { get; }
protected virtual SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.NoDashUpperFirst;
protected virtual SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;
protected ApiBase()
{
this.objectName = this.GetType().Name.LowerFirst();
propertyGetters = AllPropertyGetters.GetOrAdd(objectName, _ => new ConcurrentDictionary<string, PropertyGetter>());
}
protected void CallMethod0([CallerMemberName] string callerName = null)
@@ -98,7 +113,7 @@
}
}
protected Task<T> GetPropertyAsync<T>([CallerMemberName] string callerName = null)
protected Task<T> GetPropertyAsync<T>(object arg = null, [CallerMemberName] string callerName = null)
{
Debug.Assert(callerName != null, nameof(callerName) + " != null");
@@ -106,7 +121,7 @@
{
return this.propertyGetters.GetOrAdd(callerName, _ =>
{
var getter = new PropertyGetter<T>(this, callerName, PropertyTimeout);
var getter = new PropertyGetter<T>(this, callerName, PropertyTimeout, arg);
getter.Task<T>().ContinueWith(_ =>
{
@@ -120,6 +135,98 @@
}).Task<T>();
}
}
protected void AddEvent(Action value, int? id = null, [CallerMemberName] string callerName = null)
{
Debug.Assert(callerName != null, nameof(callerName) + " != null");
var eventName = EventName(callerName);
var eventKey = EventKey(eventName, id);
lock (objLock)
{
var container = eventContainers.GetOrAdd(eventKey, _ =>
{
var container = new EventContainer();
BridgeConnector.Socket.On(eventKey, container.OnEventAction);
BridgeConnector.Socket.Emit($"register-{eventName}", id);
return container;
});
container.Register(value);
}
}
protected void RemoveEvent(Action value, int? id = null, [CallerMemberName] string callerName = null)
{
Debug.Assert(callerName != null, nameof(callerName) + " != null");
var eventName = EventName(callerName);
var eventKey = EventKey(eventName, id);
lock (objLock)
{
if (eventContainers.TryGetValue(eventKey, out var container) && !container.Unregister(value))
{
BridgeConnector.Socket.Off(eventKey);
eventContainers.TryRemove(eventKey, out _);
}
}
}
protected void AddEvent<T>(Action<T> value, int? id = null, [CallerMemberName] string callerName = null)
{
Debug.Assert(callerName != null, nameof(callerName) + " != null");
var eventName = EventName(callerName);
var eventKey = EventKey(eventName, id);
lock (objLock)
{
var container = eventContainers.GetOrAdd(eventKey, _ =>
{
var container = new EventContainer();
BridgeConnector.Socket.On<T>(eventKey, container.OnEventActionT);
BridgeConnector.Socket.Emit($"register-{eventName}", id);
return container;
});
container.Register(value);
}
}
protected void RemoveEvent<T>(Action<T> value, int? id = null, [CallerMemberName] string callerName = null)
{
Debug.Assert(callerName != null, nameof(callerName) + " != null");
var eventName = EventName(callerName);
var eventKey = EventKey(eventName, id);
lock (objLock)
{
if (eventContainers.TryGetValue(eventKey, out var container) && !container.Unregister(value))
{
BridgeConnector.Socket.Off(eventKey);
eventContainers.TryRemove(eventKey, out _);
}
}
}
private string EventName(string callerName)
{
switch (SocketEventNameType)
{
case SocketEventNameTypes.DashedLower:
return $"{objectName}-{callerName.ToDashedEventName()}";
case SocketEventNameTypes.CamelCase:
return $"{objectName}-{callerName.ToCamelCaseEventName()}";
default:
throw new ArgumentOutOfRangeException();
}
}
private string EventKey(string eventName, int? id)
{
return string.Format(CultureInfo.InvariantCulture, "{0}{1:D}", eventName, id);
}
internal abstract class PropertyGetter
{
@@ -131,26 +238,37 @@
private readonly Task<T> tcsTask;
private TaskCompletionSource<T> tcs;
public PropertyGetter(ApiBase apiBase, string callerName, int timeoutMs)
public PropertyGetter(ApiBase apiBase, string callerName, int timeoutMs, object arg = null)
{
this.tcs = new TaskCompletionSource<T>(TaskCreationOptions.RunContinuationsAsynchronously);
this.tcsTask = this.tcs.Task;
string eventName;
string messageName;
switch (apiBase.SocketEventNameType)
switch (apiBase.SocketTaskEventNameType)
{
case SocketEventNameTypes.DashesLowerFirst:
case SocketTaskEventNameTypes.DashesLowerFirst:
eventName = apiBase.propertyEventNames.GetOrAdd(callerName, s => $"{apiBase.objectName}-{s.StripAsync().LowerFirst()}-completed");
break;
case SocketEventNameTypes.NoDashUpperFirst:
case SocketTaskEventNameTypes.NoDashUpperFirst:
eventName = apiBase.propertyEventNames.GetOrAdd(callerName, s => $"{apiBase.objectName}{s.StripAsync()}Completed");
break;
default:
throw new ArgumentOutOfRangeException();
}
var messageName = apiBase.propertyMessageNames.GetOrAdd(callerName, s => apiBase.objectName + s.StripAsync());
switch (apiBase.SocketTaskMessageNameType)
{
case SocketTaskMessageNameTypes.DashesLowerFirst:
messageName = apiBase.propertyMessageNames.GetOrAdd(callerName, s => $"{apiBase.objectName}-{s.StripAsync().LowerFirst()}");
break;
case SocketTaskMessageNameTypes.NoDashUpperFirst:
messageName = apiBase.propertyMessageNames.GetOrAdd(callerName, s => apiBase.objectName + s.StripAsync());
break;
default:
throw new ArgumentOutOfRangeException();
}
BridgeConnector.Socket.Once<T>(eventName, (result) =>
{
@@ -171,14 +289,14 @@
}
}
});
if (apiBase.Id >= 0)
if (arg != null)
{
BridgeConnector.Socket.Emit(messageName, apiBase.Id);
_ = apiBase.Id >= 0 ? BridgeConnector.Socket.Emit(messageName, apiBase.Id, arg) : BridgeConnector.Socket.Emit(messageName, arg);
}
else
{
BridgeConnector.Socket.Emit(messageName);
_ = apiBase.Id >= 0 ? BridgeConnector.Socket.Emit(messageName, apiBase.Id) : BridgeConnector.Socket.Emit(messageName);
}
System.Threading.Tasks.Task.Delay(PropertyTimeout).ContinueWith(_ =>
@@ -203,5 +321,53 @@
return this.tcsTask as Task<T1>;
}
}
[SuppressMessage("ReSharper", "InconsistentlySynchronizedField")]
private class EventContainer
{
private Action eventAction;
private Delegate eventActionT;
private Action<T> GetEventActionT<T>()
{
return (Action<T>)eventActionT;
}
private void SetEventActionT<T>(Action<T> actionT)
{
eventActionT = actionT;
}
public void OnEventAction() => eventAction?.Invoke();
public void OnEventActionT<T>(T p) => GetEventActionT<T>()?.Invoke(p);
public void Register(Action receiver)
{
eventAction += receiver;
}
public void Register<T>(Action<T> receiver)
{
var actionT = GetEventActionT<T>();
actionT += receiver;
SetEventActionT(actionT);
}
public bool Unregister(Action receiver)
{
eventAction -= receiver;
return this.eventAction != null;
}
public bool Unregister<T>(Action<T> receiver)
{
var actionT = GetEventActionT<T>();
actionT -= receiver;
SetEventActionT(actionT);
return actionT != null;
}
}
}
}

View File

@@ -1,7 +1,5 @@
using ElectronNET.API.Entities;
using ElectronNET.API.Extensions;
using ElectronNET.API.Serialization;
using ElectronNET.Common;
using System;
using System.Runtime.InteropServices;
using System.Text.Json;
@@ -17,7 +15,8 @@ namespace ElectronNET.API
/// </summary>
public sealed class App : ApiBase
{
protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.NoDashUpperFirst;
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.NoDashUpperFirst;
protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;
/// <summary>
/// Emitted when all windows have been closed.
@@ -224,45 +223,37 @@ namespace ElectronNET.API
/// </summary>
public event Action BrowserWindowBlur
{
add => ApiEventManager.AddEvent("app-browser-window-blur", GetHashCode(), _browserWindowBlur, value);
remove => ApiEventManager.RemoveEvent("app-browser-window-blur", GetHashCode(), _browserWindowBlur, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action _browserWindowBlur;
/// <summary>
/// Emitted when a <see cref="BrowserWindow"/> gets focused.
/// </summary>
public event Action BrowserWindowFocus
{
add => ApiEventManager.AddEvent("app-browser-window-focus", GetHashCode(), _browserWindowFocus, value);
remove => ApiEventManager.RemoveEvent("app-browser-window-focus", GetHashCode(), _browserWindowFocus, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action _browserWindowFocus;
/// <summary>
/// Emitted when a new <see cref="BrowserWindow"/> is created.
/// </summary>
public event Action BrowserWindowCreated
{
add => ApiEventManager.AddEvent("app-browser-window-created", GetHashCode(), _browserWindowCreated, value);
remove => ApiEventManager.RemoveEvent("app-browser-window-created", GetHashCode(), _browserWindowCreated, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action _browserWindowCreated;
/// <summary>
/// Emitted when a new <see cref="WebContents"/> is created.
/// </summary>
public event Action WebContentsCreated
{
add => ApiEventManager.AddEvent("app-web-contents-created", GetHashCode(), _webContentsCreated, value);
remove => ApiEventManager.RemoveEvent("app-web-contents-created", GetHashCode(), _webContentsCreated, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action _webContentsCreated;
/// <summary>
/// Emitted when Chromes accessibility support changes. This event fires when assistive technologies, such as
/// screen readers, are enabled or disabled. See https://www.chromium.org/developers/design-documents/accessibility for more details.
@@ -270,12 +261,10 @@ namespace ElectronNET.API
/// <returns><see langword="true"/> when Chrome's accessibility support is enabled, <see langword="false"/> otherwise.</returns>
public event Action<bool> AccessibilitySupportChanged
{
add => ApiEventManager.AddEvent("app-accessibility-support-changed", GetHashCode(), _accessibilitySupportChanged, value, (args) => args.GetBoolean());
remove => ApiEventManager.RemoveEvent("app-accessibility-support-changed", GetHashCode(), _accessibilitySupportChanged, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action<bool> _accessibilitySupportChanged;
/// <summary>
/// Emitted when the application has finished basic startup.
/// </summary>
@@ -329,12 +318,10 @@ namespace ElectronNET.API
/// </summary>
public event Action<string> OpenFile
{
add => ApiEventManager.AddEvent("app-open-file", GetHashCode(), _openFile, value, (args) => args.ToString());
remove => ApiEventManager.RemoveEvent("app-open-file", GetHashCode(), _openFile, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action<string> _openFile;
/// <summary>
/// Emitted when a MacOS user wants to open a URL with the application. Your application's Info.plist file must
@@ -342,12 +329,10 @@ namespace ElectronNET.API
/// </summary>
public event Action<string> OpenUrl
{
add => ApiEventManager.AddEvent("app-open-url", GetHashCode(), _openUrl, value, (args) => args.ToString());
remove => ApiEventManager.RemoveEvent("app-open-url", GetHashCode(), _openUrl, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action<string> _openUrl;
/// <summary>
/// A <see cref="string"/> property that indicates the current application's name, which is the name in the
/// application's package.json file.

View File

@@ -1,9 +1,6 @@
using ElectronNET.API.Entities;
using ElectronNET.API.Serialization;
using ElectronNET.Common;
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Threading.Tasks;
// ReSharper disable InconsistentNaming
@@ -13,8 +10,12 @@ namespace ElectronNET.API
/// <summary>
/// Enable apps to automatically update themselves. Based on electron-updater.
/// </summary>
public sealed class AutoUpdater
public sealed class AutoUpdater: ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;
protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;
/// <summary>
/// Whether to automatically download an update when it is found. (Default is true)
/// </summary>
@@ -22,15 +23,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run(() =>
{
var tcs = new TaskCompletionSource<bool>();
BridgeConnector.Socket.Once<bool>("autoUpdater-autoDownload-get-reply", tcs.SetResult);
BridgeConnector.Socket.Emit("autoUpdater-autoDownload-get");
return tcs.Task;
}).Result;
return Task.Run(() => GetPropertyAsync<bool>()).Result;
}
set
{
@@ -47,15 +40,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run(() =>
{
var tcs = new TaskCompletionSource<bool>();
BridgeConnector.Socket.Once<bool>("autoUpdater-autoInstallOnAppQuit-get-reply", tcs.SetResult);
BridgeConnector.Socket.Emit("autoUpdater-autoInstallOnAppQuit-get");
return tcs.Task;
}).Result;
return Task.Run(() => GetPropertyAsync<bool>()).Result;
}
set
{
@@ -73,15 +58,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run(() =>
{
var tcs = new TaskCompletionSource<bool>();
BridgeConnector.Socket.Once<bool>("autoUpdater-allowPrerelease-get-reply", tcs.SetResult);
BridgeConnector.Socket.Emit("autoUpdater-allowPrerelease-get");
return tcs.Task;
}).Result;
return Task.Run(() => GetPropertyAsync<bool>()).Result;
}
set
{
@@ -97,15 +74,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run(() =>
{
var tcs = new TaskCompletionSource<bool>();
BridgeConnector.Socket.Once<bool>("autoUpdater-fullChangelog-get-reply", tcs.SetResult);
BridgeConnector.Socket.Emit("autoUpdater-fullChangelog-get");
return tcs.Task;
}).Result;
return Task.Run(() => GetPropertyAsync<bool>()).Result;
}
set
{
@@ -122,15 +91,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run(() =>
{
var tcs = new TaskCompletionSource<bool>();
BridgeConnector.Socket.Once<bool>("autoUpdater-allowDowngrade-get-reply", tcs.SetResult);
BridgeConnector.Socket.Emit("autoUpdater-allowDowngrade-get");
return tcs.Task;
}).Result;
return Task.Run(() => GetPropertyAsync<bool>()).Result;
}
set
{
@@ -145,15 +106,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run(() =>
{
var tcs = new TaskCompletionSource<string>();
BridgeConnector.Socket.Once<string>("autoUpdater-updateConfigPath-get-reply", tcs.SetResult);
BridgeConnector.Socket.Emit("autoUpdater-updateConfigPath-get");
return tcs.Task;
}).Result;
return Task.Run(() => GetPropertyAsync<string>()).Result;
}
}
@@ -164,15 +117,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run(() =>
{
var tcs = new TaskCompletionSource<SemVer>();
BridgeConnector.Socket.Once<SemVer>("autoUpdater-currentVersion-get-reply", tcs.SetResult);
BridgeConnector.Socket.Emit("autoUpdater-currentVersion-get");
return tcs.Task;
});
return Task.Run(() => GetPropertyAsync<SemVer>());
}
}
@@ -197,15 +142,18 @@ namespace ElectronNET.API
{
get
{
return Task.Run(() =>
{
var tcs = new TaskCompletionSource<string>();
return Task.Run(() => GetPropertyAsync<string>());
}
}
BridgeConnector.Socket.Once<string>("autoUpdater-channel-get-reply", tcs.SetResult);
BridgeConnector.Socket.Emit("autoUpdater-channel-get");
return tcs.Task;
});
/// <summary>
/// Set the update channel. Not applicable for GitHub.
/// </summary>
public string SetChannel
{
set
{
BridgeConnector.Socket.Emit("autoUpdater-channel-set", value);
}
}
@@ -217,15 +165,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run(() =>
{
var tcs = new TaskCompletionSource<Dictionary<string, string>>();
BridgeConnector.Socket.Once<Dictionary<string, string>>("autoUpdater-requestHeaders-get-reply", tcs.SetResult);
BridgeConnector.Socket.Emit("autoUpdater-requestHeaders-get");
return tcs.Task;
});
return Task.Run(() => GetPropertyAsync<Dictionary<string, string>>());
}
}
@@ -245,68 +185,56 @@ namespace ElectronNET.API
/// </summary>
public event Action<string> OnError
{
add => ApiEventManager.AddEvent("autoUpdater-error", GetHashCode(), _error, value, (args) => args.ToString());
remove => ApiEventManager.RemoveEvent("autoUpdater-error", GetHashCode(), _error, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action<string> _error;
/// <summary>
/// Emitted when checking if an update has started.
/// </summary>
public event Action OnCheckingForUpdate
{
add => ApiEventManager.AddEvent("autoUpdater-checking-for-update", GetHashCode(), _checkingForUpdate, value);
remove => ApiEventManager.RemoveEvent("autoUpdater-checking-for-update", GetHashCode(), _checkingForUpdate, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action _checkingForUpdate;
/// <summary>
/// Emitted when there is an available update.
/// The update is downloaded automatically if AutoDownload is true.
/// </summary>
public event Action<UpdateInfo> OnUpdateAvailable
{
add => ApiEventManager.AddEvent("autoUpdater-update-available", GetHashCode(), _updateAvailable, value, (args) => args.Deserialize(ElectronJsonContext.Default.UpdateInfo));
remove => ApiEventManager.RemoveEvent("autoUpdater-update-available", GetHashCode(), _updateAvailable, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action<UpdateInfo> _updateAvailable;
/// <summary>
/// Emitted when there is no available update.
/// </summary>
public event Action<UpdateInfo> OnUpdateNotAvailable
{
add => ApiEventManager.AddEvent("autoUpdater-update-not-available", GetHashCode(), _updateNotAvailable, value, (args) => args.Deserialize(ElectronJsonContext.Default.UpdateInfo));
remove => ApiEventManager.RemoveEvent("autoUpdater-update-not-available", GetHashCode(), _updateNotAvailable, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action<UpdateInfo> _updateNotAvailable;
/// <summary>
/// Emitted on download progress.
/// </summary>
public event Action<ProgressInfo> OnDownloadProgress
{
add => ApiEventManager.AddEvent("autoUpdater-download-progress", GetHashCode(), _downloadProgress, value, (args) => args.Deserialize(ElectronJsonContext.Default.ProgressInfo));
remove => ApiEventManager.RemoveEvent("autoUpdater-download-progress", GetHashCode(), _downloadProgress, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action<ProgressInfo> _downloadProgress;
/// <summary>
/// Emitted on download complete.
/// </summary>
public event Action<UpdateInfo> OnUpdateDownloaded
{
add => ApiEventManager.AddEvent("autoUpdater-update-downloaded", GetHashCode(), _updateDownloaded, value, (args) => args.Deserialize(ElectronJsonContext.Default.UpdateInfo));
remove => ApiEventManager.RemoveEvent("autoUpdater-update-downloaded", GetHashCode(), _updateDownloaded, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action<UpdateInfo> _updateDownloaded;
private static AutoUpdater _autoUpdater;
private static object _syncRoot = new object();
@@ -342,11 +270,11 @@ namespace ElectronNET.API
var taskCompletionSource = new TaskCompletionSource<UpdateCheckResult>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.Once<UpdateCheckResult>("autoUpdaterCheckForUpdatesComplete" + guid, (result) =>
BridgeConnector.Socket.Once<UpdateCheckResult>("autoUpdater-checkForUpdates-completed" + guid, (result) =>
{
try
{
BridgeConnector.Socket.Off("autoUpdaterCheckForUpdatesError" + guid);
BridgeConnector.Socket.Off("autoUpdater-checkForUpdatesError" + guid);
taskCompletionSource.SetResult(result);
}
catch (Exception ex)
@@ -354,15 +282,15 @@ namespace ElectronNET.API
taskCompletionSource.SetException(ex);
}
});
BridgeConnector.Socket.Once<string>("autoUpdaterCheckForUpdatesError" + guid, (result) =>
BridgeConnector.Socket.Once<string>("autoUpdater-checkForUpdatesError" + guid, (result) =>
{
BridgeConnector.Socket.Off("autoUpdaterCheckForUpdatesComplete" + guid);
BridgeConnector.Socket.Off("autoUpdater-checkForUpdates-completed" + guid);
string message = "An error occurred in CheckForUpdatesAsync";
if (!string.IsNullOrEmpty(result)) message = result;
taskCompletionSource.SetException(new Exception(message));
});
BridgeConnector.Socket.Emit("autoUpdaterCheckForUpdates", guid);
BridgeConnector.Socket.Emit("autoUpdater-checkForUpdates", guid);
return taskCompletionSource.Task;
}
@@ -378,11 +306,11 @@ namespace ElectronNET.API
var taskCompletionSource = new TaskCompletionSource<UpdateCheckResult>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.Once<UpdateCheckResult>("autoUpdaterCheckForUpdatesAndNotifyComplete" + guid, (result) =>
BridgeConnector.Socket.Once<UpdateCheckResult>("autoUpdater-checkForUpdatesAndNotify-completed" + guid, (result) =>
{
try
{
BridgeConnector.Socket.Off("autoUpdaterCheckForUpdatesAndNotifyError" + guid);
BridgeConnector.Socket.Off("autoUpdater-checkForUpdatesAndNotifyError" + guid);
taskCompletionSource.SetResult(result);
}
catch (Exception ex)
@@ -390,15 +318,15 @@ namespace ElectronNET.API
taskCompletionSource.SetException(ex);
}
});
BridgeConnector.Socket.Once<string>("autoUpdaterCheckForUpdatesAndNotifyError" + guid, (result) =>
BridgeConnector.Socket.Once<string>("autoUpdater-checkForUpdatesAndNotifyError" + guid, (result) =>
{
BridgeConnector.Socket.Off("autoUpdaterCheckForUpdatesAndNotifyComplete" + guid);
string message = "An error occurred in autoUpdaterCheckForUpdatesAndNotify";
BridgeConnector.Socket.Off("autoUpdater-checkForUpdatesAndNotify-completed" + guid);
string message = "An error occurred in CheckForUpdatesAndNotifyAsync";
if (!string.IsNullOrEmpty(result)) message = result;
taskCompletionSource.SetException(new Exception(message));
});
BridgeConnector.Socket.Emit("autoUpdaterCheckForUpdatesAndNotify", guid);
BridgeConnector.Socket.Emit("autoUpdater-checkForUpdatesAndNotify", guid);
return taskCompletionSource.Task;
}
@@ -414,7 +342,7 @@ namespace ElectronNET.API
/// <param name="isForceRunAfter">Run the app after finish even on silent install. Not applicable for macOS. Ignored if `isSilent` is set to `false`.</param>
public void QuitAndInstall(bool isSilent = false, bool isForceRunAfter = false)
{
BridgeConnector.Socket.Emit("autoUpdaterQuitAndInstall", isSilent, isForceRunAfter);
BridgeConnector.Socket.Emit("autoUpdater-quitAndInstall", isSilent, isForceRunAfter);
}
/// <summary>
@@ -426,8 +354,8 @@ namespace ElectronNET.API
var tcs = new TaskCompletionSource<string>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.Once<string>("autoUpdaterDownloadUpdateComplete" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("autoUpdaterDownloadUpdate", guid);
BridgeConnector.Socket.Once<string>("autoUpdater-downloadUpdate-completed" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("autoUpdater-downloadUpdate", guid);
return tcs.Task;
}
@@ -441,8 +369,8 @@ namespace ElectronNET.API
var tcs = new TaskCompletionSource<string>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.Once<string>("autoUpdaterGetFeedURLComplete" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("autoUpdaterGetFeedURL", guid);
BridgeConnector.Socket.Once<string>("autoUpdater-getFeedURL-completed" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("autoUpdater-getFeedURL", guid);
return tcs.Task;
}

View File

@@ -1,6 +1,4 @@
using ElectronNET.API.Entities;
using ElectronNET.API.Serialization;
using System.Text.Json;
using System.Threading.Tasks;
namespace ElectronNET.API
@@ -10,12 +8,14 @@ namespace ElectronNET.API
/// 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>
public class BrowserView
public class BrowserView: ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;
/// <summary>
/// Gets the identifier.
/// </summary>
public int Id { get; internal set; }
public override int Id { get; protected set; }
/// <summary>
/// Render and control web pages.
@@ -30,19 +30,11 @@ namespace ElectronNET.API
{
get
{
var tcs = new TaskCompletionSource<Rectangle>();
Task.Run(() =>
{
BridgeConnector.Socket.Once<Rectangle>("browserView-getBounds-reply", tcs.SetResult);
BridgeConnector.Socket.Emit("browserView-getBounds", Id);
});
return tcs.Task.GetAwaiter().GetResult();
return Task.Run(() => GetPropertyAsync<Rectangle>()).Result;
}
set
{
BridgeConnector.Socket.Emit("browserView-setBounds", Id, value);
BridgeConnector.Socket.Emit("browserView-bounds-set", Id, value);
}
}

View File

@@ -10,15 +10,13 @@ using System.Threading.Tasks;
namespace ElectronNET.API;
using ElectronNET.Common;
using System.Text.Json;
/// <summary>
/// Create and control browser windows.
/// </summary>
public class BrowserWindow : ApiBase
{
protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashesLowerFirst;
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;
/// <summary>
/// Gets the identifier.
@@ -34,34 +32,28 @@ public class BrowserWindow : ApiBase
/// </summary>
public event Action OnReadyToShow
{
add => ApiEventManager.AddEvent("browserWindow-ready-to-show", Id, _readyToShow, value);
remove => ApiEventManager.RemoveEvent("browserWindow-ready-to-show", Id, _readyToShow, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _readyToShow;
/// <summary>
/// Emitted when the document changed its title.
/// </summary>
public event Action<string> OnPageTitleUpdated
{
add => ApiEventManager.AddEvent("browserWindow-page-title-updated", Id, _pageTitleUpdated, value, (args) => args.ToString());
remove => ApiEventManager.RemoveEvent("browserWindow-page-title-updated", Id, _pageTitleUpdated, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action<string> _pageTitleUpdated;
/// <summary>
/// Emitted when the window is going to be closed.
/// </summary>
public event Action OnClose
{
add => ApiEventManager.AddEvent("browserWindow-close", Id, _close, value);
remove => ApiEventManager.RemoveEvent("browserWindow-close", Id, _close, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _close;
/// <summary>
/// Emitted when the window is closed.
/// After you have received this event you should remove the
@@ -69,144 +61,118 @@ public class BrowserWindow : ApiBase
/// </summary>
public event Action OnClosed
{
add => ApiEventManager.AddEvent("browserWindow-closed", Id, _closed, value);
remove => ApiEventManager.RemoveEvent("browserWindow-closed", Id, _closed, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _closed;
/// <summary>
/// Emitted when window session is going to end due to force shutdown or machine restart or session log off.
/// </summary>
public event Action OnSessionEnd
{
add => ApiEventManager.AddEvent("browserWindow-session-end", Id, _sessionEnd, value);
remove => ApiEventManager.RemoveEvent("browserWindow-session-end", Id, _sessionEnd, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _sessionEnd;
/// <summary>
/// Emitted when the web page becomes unresponsive.
/// </summary>
public event Action OnUnresponsive
{
add => ApiEventManager.AddEvent("browserWindow-unresponsive", Id, _unresponsive, value);
remove => ApiEventManager.RemoveEvent("browserWindow-unresponsive", Id, _unresponsive, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _unresponsive;
/// <summary>
/// Emitted when the unresponsive web page becomes responsive again.
/// </summary>
public event Action OnResponsive
{
add => ApiEventManager.AddEvent("browserWindow-responsive", Id, _responsive, value);
remove => ApiEventManager.RemoveEvent("browserWindow-responsive", Id, _responsive, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _responsive;
/// <summary>
/// Emitted when the window loses focus.
/// </summary>
public event Action OnBlur
{
add => ApiEventManager.AddEvent("browserWindow-blur", Id, _blur, value);
remove => ApiEventManager.RemoveEvent("browserWindow-blur", Id, _blur, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _blur;
/// <summary>
/// Emitted when the window gains focus.
/// </summary>
public event Action OnFocus
{
add => ApiEventManager.AddEvent("browserWindow-focus", Id, _focus, value);
remove => ApiEventManager.RemoveEvent("browserWindow-focus", Id, _focus, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _focus;
/// <summary>
/// Emitted when the window is shown.
/// </summary>
public event Action OnShow
{
add => ApiEventManager.AddEvent("browserWindow-show", Id, _show, value);
remove => ApiEventManager.RemoveEvent("browserWindow-show", Id, _show, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _show;
/// <summary>
/// Emitted when the window is hidden.
/// </summary>
public event Action OnHide
{
add => ApiEventManager.AddEvent("browserWindow-hide", Id, _hide, value);
remove => ApiEventManager.RemoveEvent("browserWindow-hide", Id, _hide, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _hide;
/// <summary>
/// Emitted when window is maximized.
/// </summary>
public event Action OnMaximize
{
add => ApiEventManager.AddEvent("browserWindow-maximize", Id, _maximize, value);
remove => ApiEventManager.RemoveEvent("browserWindow-maximize", Id, _maximize, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _maximize;
/// <summary>
/// Emitted when the window exits from a maximized state.
/// </summary>
public event Action OnUnmaximize
{
add => ApiEventManager.AddEvent("browserWindow-unmaximize", Id, _unmaximize, value);
remove => ApiEventManager.RemoveEvent("browserWindow-unmaximize", Id, _unmaximize, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _unmaximize;
/// <summary>
/// Emitted when the window is minimized.
/// </summary>
public event Action OnMinimize
{
add => ApiEventManager.AddEvent("browserWindow-minimize", Id, _minimize, value);
remove => ApiEventManager.RemoveEvent("browserWindow-minimize", Id, _minimize, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _minimize;
/// <summary>
/// Emitted when the window is restored from a minimized state.
/// </summary>
public event Action OnRestore
{
add => ApiEventManager.AddEvent("browserWindow-restore", Id, _restore, value);
remove => ApiEventManager.RemoveEvent("browserWindow-restore", Id, _restore, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _restore;
/// <summary>
/// Emitted when the window is being resized.
/// </summary>
public event Action OnResize
{
add => ApiEventManager.AddEvent("browserWindow-resize", Id, _resize, value);
remove => ApiEventManager.RemoveEvent("browserWindow-resize", Id, _resize, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _resize;
/// <summary>
/// Emitted when the window is being moved to a new position.
///
@@ -214,67 +180,55 @@ public class BrowserWindow : ApiBase
/// </summary>
public event Action OnMove
{
add => ApiEventManager.AddEvent("browserWindow-move", Id, _move, value);
remove => ApiEventManager.RemoveEvent("browserWindow-move", Id, _move, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _move;
/// <summary>
/// macOS: Emitted once when the window is moved to a new position.
/// </summary>
public event Action OnMoved
{
add => ApiEventManager.AddEvent("browserWindow-moved", Id, _moved, value);
remove => ApiEventManager.RemoveEvent("browserWindow-moved", Id, _moved, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _moved;
/// <summary>
/// Emitted when the window enters a full-screen state.
/// </summary>
public event Action OnEnterFullScreen
{
add => ApiEventManager.AddEvent("browserWindow-enter-full-screen", Id, _enterFullScreen, value);
remove => ApiEventManager.RemoveEvent("browserWindow-enter-full-screen", Id, _enterFullScreen, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _enterFullScreen;
/// <summary>
/// Emitted when the window leaves a full-screen state.
/// </summary>
public event Action OnLeaveFullScreen
{
add => ApiEventManager.AddEvent("browserWindow-leave-full-screen", Id, _leaveFullScreen, value);
remove => ApiEventManager.RemoveEvent("browserWindow-leave-full-screen", Id, _leaveFullScreen, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _leaveFullScreen;
/// <summary>
/// Emitted when the window enters a full-screen state triggered by HTML API.
/// </summary>
public event Action OnEnterHtmlFullScreen
{
add => ApiEventManager.AddEvent("browserWindow-enter-html-full-screen", Id, _enterHtmlFullScreen, value);
remove => ApiEventManager.RemoveEvent("browserWindow-enter-html-full-screen", Id, _enterHtmlFullScreen, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _enterHtmlFullScreen;
/// <summary>
/// Emitted when the window leaves a full-screen state triggered by HTML API.
/// </summary>
public event Action OnLeaveHtmlFullScreen
{
add => ApiEventManager.AddEvent("browserWindow-leave-html-full-screen", Id, _leaveHtmlFullScreen, value);
remove => ApiEventManager.RemoveEvent("browserWindow-leave-html-full-screen", Id, _leaveHtmlFullScreen, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _leaveHtmlFullScreen;
/// <summary>
/// Emitted when an App Command is invoked. These are typically related to
/// keyboard media keys or browser commands, as well as the “Back” button
@@ -286,56 +240,46 @@ public class BrowserWindow : ApiBase
/// </summary>
public event Action<string> OnAppCommand
{
add => ApiEventManager.AddEvent("browserWindow-app-command", Id, _appCommand, value, (args) => args.ToString());
remove => ApiEventManager.RemoveEvent("browserWindow-app-command", Id, _appCommand, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action<string> _appCommand;
/// <summary>
/// Emitted on 3-finger swipe. Possible directions are up, right, down, left.
/// </summary>
public event Action<string> OnSwipe
{
add => ApiEventManager.AddEvent("browserWindow-swipe", Id, _swipe, value, (args) => args.ToString());
remove => ApiEventManager.RemoveEvent("browserWindow-swipe", Id, _swipe, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action<string> _swipe;
/// <summary>
/// Emitted when the window opens a sheet.
/// </summary>
public event Action OnSheetBegin
{
add => ApiEventManager.AddEvent("browserWindow-sheet-begin", Id, _sheetBegin, value);
remove => ApiEventManager.RemoveEvent("browserWindow-sheet-begin", Id, _sheetBegin, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _sheetBegin;
/// <summary>
/// Emitted when the window has closed a sheet.
/// </summary>
public event Action OnSheetEnd
{
add => ApiEventManager.AddEvent("browserWindow-sheet-end", Id, _sheetEnd, value);
remove => ApiEventManager.RemoveEvent("browserWindow-sheet-end", Id, _sheetEnd, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _sheetEnd;
/// <summary>
/// Emitted when the native new tab button is clicked.
/// </summary>
public event Action OnNewWindowForTab
{
add => ApiEventManager.AddEvent("browserWindow-new-window-for-tab", Id, _newWindowForTab, value);
remove => ApiEventManager.RemoveEvent("browserWindow-new-window-for-tab", Id, _newWindowForTab, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _newWindowForTab;
internal BrowserWindow(int id)
{
Id = id;

View File

@@ -2,14 +2,18 @@ using ElectronNET.API.Entities;
using ElectronNET.API.Serialization;
using System.Text.Json;
using System.Threading.Tasks;
// ReSharper disable InconsistentNaming
namespace ElectronNET.API
{
/// <summary>
/// Perform copy and paste operations on the system clipboard.
/// </summary>
public sealed class Clipboard
public sealed class Clipboard: ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;
private static Clipboard _clipboard;
private static object _syncRoot = new object();
@@ -41,15 +45,7 @@ namespace ElectronNET.API
/// </summary>
/// <param name="type"></param>
/// <returns>The content in the clipboard as plain text.</returns>
public Task<string> ReadTextAsync(string type = "")
{
var tcs = new TaskCompletionSource<string>();
BridgeConnector.Socket.Once<string>("clipboard-readText-Completed", tcs.SetResult);
BridgeConnector.Socket.Emit("clipboard-readText", type);
return tcs.Task;
}
public Task<string> ReadTextAsync(string type = "") => GetPropertyAsync<string>(type);
/// <summary>
/// Writes the text into the clipboard as plain text.
@@ -66,15 +62,7 @@ namespace ElectronNET.API
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public Task<string> ReadHTMLAsync(string type = "")
{
var tcs = new TaskCompletionSource<string>();
BridgeConnector.Socket.Once<string>("clipboard-readHTML-Completed", tcs.SetResult);
BridgeConnector.Socket.Emit("clipboard-readHTML", type);
return tcs.Task;
}
public Task<string> ReadHTMLAsync(string type = "") => GetPropertyAsync<string>(type);
/// <summary>
/// Writes markup to the clipboard.
@@ -91,15 +79,7 @@ namespace ElectronNET.API
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public Task<string> ReadRTFAsync(string type = "")
{
var tcs = new TaskCompletionSource<string>();
BridgeConnector.Socket.Once<string>("clipboard-readRTF-Completed", tcs.SetResult);
BridgeConnector.Socket.Emit("clipboard-readRTF", type);
return tcs.Task;
}
public Task<string> ReadRTFAsync(string type = "") => GetPropertyAsync<string>(type);
/// <summary>
/// Writes the text into the clipboard in RTF.
@@ -108,7 +88,7 @@ namespace ElectronNET.API
/// <param name="type"></param>
public void WriteRTF(string text, string type = "")
{
BridgeConnector.Socket.Emit("clipboard-writeHTML", text, type);
BridgeConnector.Socket.Emit("clipboard-writeRTF", text, type);
}
/// <summary>
@@ -117,15 +97,7 @@ namespace ElectronNET.API
/// be empty strings when the bookmark is unavailable.
/// </summary>
/// <returns></returns>
public Task<ReadBookmark> ReadBookmarkAsync()
{
var tcs = new TaskCompletionSource<ReadBookmark>();
BridgeConnector.Socket.Once<ReadBookmark>("clipboard-readBookmark-Completed", tcs.SetResult);
BridgeConnector.Socket.Emit("clipboard-readBookmark");
return tcs.Task;
}
public Task<ReadBookmark> ReadBookmarkAsync() => GetPropertyAsync<ReadBookmark>();
/// <summary>
/// Writes the title and url into the clipboard as a bookmark.
@@ -148,15 +120,7 @@ namespace ElectronNET.API
/// find pasteboard whenever the application is activated.
/// </summary>
/// <returns></returns>
public Task<string> ReadFindTextAsync()
{
var tcs = new TaskCompletionSource<string>();
BridgeConnector.Socket.Once<string>("clipboard-readFindText-Completed", tcs.SetResult);
BridgeConnector.Socket.Emit("clipboard-readFindText");
return tcs.Task;
}
public Task<string> ReadFindTextAsync() => GetPropertyAsync<string>();
/// <summary>
/// macOS: Writes the text into the find pasteboard as plain text. This method uses
@@ -182,15 +146,7 @@ namespace ElectronNET.API
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public Task<string[]> AvailableFormatsAsync(string type = "")
{
var tcs = new TaskCompletionSource<string[]>();
BridgeConnector.Socket.Once<string[]>("clipboard-availableFormats-Completed", tcs.SetResult);
BridgeConnector.Socket.Emit("clipboard-availableFormats", type);
return tcs.Task;
}
public Task<string[]> AvailableFormatsAsync(string type = "") => GetPropertyAsync<string[]>(type);
/// <summary>
/// Writes data to the clipboard.
@@ -207,15 +163,7 @@ namespace ElectronNET.API
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public Task<NativeImage> ReadImageAsync(string type = "")
{
var tcs = new TaskCompletionSource<NativeImage>();
BridgeConnector.Socket.Once<NativeImage>("clipboard-readImage-Completed", tcs.SetResult);
BridgeConnector.Socket.Emit("clipboard-readImage", type);
return tcs.Task;
}
public Task<NativeImage> ReadImageAsync(string type = "") => GetPropertyAsync<NativeImage>(type);
/// <summary>
/// Writes an image to the clipboard.

View File

@@ -1,5 +1,4 @@
using System.Text.Json;
using System.Threading;
using System.Threading;
using System.Threading.Tasks;
namespace ElectronNET.API

View File

@@ -1,5 +1,4 @@
using ElectronNET.API.Entities;
using ElectronNET.API.Serialization;
using System;
using System.Text.Json;
using System.Threading.Tasks;

View File

@@ -1,17 +1,19 @@
using ElectronNET.API.Entities;
using ElectronNET.API.Extensions;
using ElectronNET.Common;
using System;
using System.Text.Json;
using System;
using System.Threading.Tasks;
using ElectronNET.API.Entities;
using ElectronNET.API.Extensions;
namespace ElectronNET.API
{
/// <summary>
/// Read and respond to changes in Chromium's native color theme.
/// </summary>
public sealed class NativeTheme
public sealed class NativeTheme: ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;
protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;
private static NativeTheme _nativeTheme;
private static object _syncRoot = new object();
@@ -105,58 +107,26 @@ namespace ElectronNET.API
/// A <see cref="ThemeSourceMode"/> property that can be <see cref="ThemeSourceMode.System"/>, <see cref="ThemeSourceMode.Light"/> or <see cref="ThemeSourceMode.Dark"/>. It is used to override (<seealso cref="SetThemeSource"/>) and
/// supercede the value that Chromium has chosen to use internally.
/// </summary>
public Task<ThemeSourceMode> GetThemeSourceAsync()
{
var tcs = new TaskCompletionSource<ThemeSourceMode>();
BridgeConnector.Socket.Once<ThemeSourceMode>("nativeTheme-themeSource-getCompleted", tcs.SetResult);
BridgeConnector.Socket.Emit("nativeTheme-themeSource-get");
return tcs.Task;
}
public Task<ThemeSourceMode> GetThemeSourceAsync() => GetPropertyAsync<ThemeSourceMode>();
/// <summary>
/// A <see cref="bool"/> for if the OS / Chromium currently has a dark mode enabled or is
/// being instructed to show a dark-style UI. If you want to modify this value you
/// should use <see cref="SetThemeSource"/>.
/// </summary>
public Task<bool> ShouldUseDarkColorsAsync()
{
var tcs = new TaskCompletionSource<bool>();
BridgeConnector.Socket.Once<bool>("nativeTheme-shouldUseDarkColors-completed", tcs.SetResult);
BridgeConnector.Socket.Emit("nativeTheme-shouldUseDarkColors");
return tcs.Task;
}
public Task<bool> ShouldUseDarkColorsAsync() => GetPropertyAsync<bool>();
/// <summary>
/// A <see cref="bool"/> for if the OS / Chromium currently has high-contrast mode enabled or is
/// being instructed to show a high-contrast UI.
/// </summary>
public Task<bool> ShouldUseHighContrastColorsAsync()
{
var tcs = new TaskCompletionSource<bool>();
BridgeConnector.Socket.Once<bool>("nativeTheme-shouldUseHighContrastColors-completed", tcs.SetResult);
BridgeConnector.Socket.Emit("nativeTheme-shouldUseHighContrastColors");
return tcs.Task;
}
public Task<bool> ShouldUseHighContrastColorsAsync() => GetPropertyAsync<bool>();
/// <summary>
/// A <see cref="bool"/> for if the OS / Chromium currently has an inverted color scheme or is
/// being instructed to use an inverted color scheme.
/// </summary>
public Task<bool> ShouldUseInvertedColorSchemeAsync()
{
var tcs = new TaskCompletionSource<bool>();
BridgeConnector.Socket.Once<bool>("nativeTheme-shouldUseInvertedColorScheme-completed", tcs.SetResult);
BridgeConnector.Socket.Emit("nativeTheme-shouldUseInvertedColorScheme");
return tcs.Task;
}
public Task<bool> ShouldUseInvertedColorSchemeAsync() => GetPropertyAsync<bool>();
/// <summary>
/// Emitted when something in the underlying NativeTheme has changed. This normally means that either the value of <see cref="ShouldUseDarkColorsAsync"/>,
@@ -164,10 +134,8 @@ namespace ElectronNET.API
/// </summary>
public event Action Updated
{
add => ApiEventManager.AddEvent("nativeTheme-updated", GetHashCode(), _updated, value);
remove => ApiEventManager.RemoveEvent("nativeTheme-updated", GetHashCode(), _updated, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action _updated;
}
}

View File

@@ -1,9 +1,7 @@
using ElectronNET.API.Entities;
using ElectronNET.API.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
namespace ElectronNET.API
@@ -11,8 +9,9 @@ namespace ElectronNET.API
/// <summary>
/// Create OS desktop notifications
/// </summary>
public sealed class Notification
public sealed class Notification: ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.NoDashUpperFirst;
private static Notification _notification;
private static object _syncRoot = new object();
@@ -117,16 +116,6 @@ namespace ElectronNET.API
/// Whether or not desktop notifications are supported on the current system.
/// </summary>
/// <returns></returns>
public Task<bool> IsSupportedAsync()
{
var tcs = new TaskCompletionSource<bool>();
BridgeConnector.Socket.Once<bool>("notificationIsSupportedComplete", tcs.SetResult);
BridgeConnector.Socket.Emit("notificationIsSupported");
return tcs.Task;
}
public Task<bool> IsSupportedAsync() => GetPropertyAsync<bool>();
}
}

View File

@@ -1,5 +1,4 @@
using ElectronNET.Common;
using System;
using System;
// ReSharper disable InconsistentNaming
@@ -8,74 +7,65 @@ namespace ElectronNET.API
/// <summary>
/// Monitor power state changes..
/// </summary>
public sealed class PowerMonitor
public sealed class PowerMonitor: ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;
/// <summary>
/// Emitted when the system is about to lock the screen.
/// </summary>
public event Action OnLockScreen
{
add => ApiEventManager.AddEvent("pm-lock-screen", string.Empty, _lockScreen, value);
remove => ApiEventManager.RemoveEvent("pm-lock-screen", string.Empty, _lockScreen, value);
add => AddEvent(value);
remove => RemoveEvent(value);
}
private event Action _lockScreen;
/// <summary>
/// Emitted when the system is about to unlock the screen.
/// </summary>
public event Action OnUnLockScreen
{
add => ApiEventManager.AddEvent("pm-unlock-screen", string.Empty, _unlockScreen, value);
remove => ApiEventManager.RemoveEvent("pm-unlock-screen", string.Empty, _unlockScreen, value);
add => AddEvent(value);
remove => RemoveEvent(value);
}
private event Action _unlockScreen;
/// <summary>
/// Emitted when the system is suspending.
/// </summary>
public event Action OnSuspend
{
add => ApiEventManager.AddEvent("pm-suspend", string.Empty, _suspend, value);
remove => ApiEventManager.RemoveEvent("pm-suspend", string.Empty, _suspend, value);
add => AddEvent(value);
remove => RemoveEvent(value);
}
private event Action _suspend;
/// <summary>
/// Emitted when system is resuming.
/// </summary>
public event Action OnResume
{
add => ApiEventManager.AddEvent("pm-resume", string.Empty, _resume, value);
remove => ApiEventManager.RemoveEvent("pm-resume", string.Empty, _resume, value);
add => AddEvent(value);
remove => RemoveEvent(value);
}
private event Action _resume;
/// <summary>
/// Emitted when the system changes to AC power.
/// </summary>
public event Action OnAC
{
add => ApiEventManager.AddEvent("pm-on-ac", string.Empty, _onAC, value);
remove => ApiEventManager.RemoveEvent("pm-on-ac", string.Empty, _onAC, value);
add => AddEvent(value);
remove => RemoveEvent(value);
}
private event Action _onAC;
/// <summary>
/// Emitted when system changes to battery power.
/// </summary>
public event Action OnBattery
{
add => ApiEventManager.AddEvent("pm-on-battery", string.Empty, _onBattery, value);
remove => ApiEventManager.RemoveEvent("pm-on-battery", string.Empty, _onBattery, value);
add => AddEvent(value);
remove => RemoveEvent(value);
}
private event Action _onBattery;
/// <summary>
/// Emitted when the system is about to reboot or shut down. If the event handler
/// invokes `e.preventDefault()`, Electron will attempt to delay system shutdown in
@@ -84,12 +74,10 @@ namespace ElectronNET.API
/// </summary>
public event Action OnShutdown
{
add => ApiEventManager.AddEvent("pm-shutdown", string.Empty, _shutdown, value);
remove => ApiEventManager.RemoveEvent("pm-shutdown", string.Empty, _shutdown, value);
add => AddEvent(value);
remove => RemoveEvent(value);
}
private event Action _shutdown;
private static PowerMonitor _powerMonitor;
private static object _syncRoot = new object();

View File

@@ -9,8 +9,10 @@ namespace ElectronNET.API
/// Electron's process object is extended from the Node.js process object. It adds the
/// events, properties, and methods.
/// </summary>
public sealed class Process
public sealed class Process: ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;
internal Process()
{
}
@@ -42,18 +44,7 @@ namespace ElectronNET.API
/// The process.execPath property returns the absolute pathname of the executable that
/// started the Node.js process. Symbolic links, if any, are resolved.
/// </summary>
public Task<string> ExecPathAsync
{
get
{
var tcs = new TaskCompletionSource<string>();
BridgeConnector.Socket.Once<string>("process-execPath-Completed", tcs.SetResult);
BridgeConnector.Socket.Emit("process-execPath");
return tcs.Task;
}
}
public Task<string> ExecPathAsync => GetPropertyAsync<string>();
/// <summary>
/// The process.argv property returns an array containing the command-line arguments passed
@@ -62,169 +53,56 @@ namespace ElectronNET.API
/// will be the path to the JavaScript file being executed. The remaining elements will be
/// any additional command-line arguments
/// </summary>
public Task<string[]> ArgvAsync
{
get
{
var tcs = new TaskCompletionSource<string[]>();
BridgeConnector.Socket.Once<string[]>("process-argv-Completed", tcs.SetResult);
BridgeConnector.Socket.Emit("process-argv");
return tcs.Task;
}
}
public Task<string[]> ArgvAsync => GetPropertyAsync<string[]>();
/// <summary>
/// The process.execPath property returns the absolute pathname of the executable that
/// started the Node.js process. Symbolic links, if any, are resolved.
/// </summary>
public Task<string> TypeAsync
{
get
{
var tcs = new TaskCompletionSource<string>();
BridgeConnector.Socket.Once<string>("process-type-Completed", tcs.SetResult);
BridgeConnector.Socket.Emit("process-type");
return tcs.Task;
}
}
public Task<string> TypeAsync => GetPropertyAsync<string>();
/// <summary>
/// The process.versions property returns an object listing the version strings of
/// chrome and electron.
/// </summary>
public Task<ProcessVersions> VersionsAsync
{
get
{
var tcs = new TaskCompletionSource<ProcessVersions>();
BridgeConnector.Socket.Once<ProcessVersions>("process-versions-Completed", tcs.SetResult);
BridgeConnector.Socket.Emit("process-versions");
return tcs.Task;
}
}
public Task<ProcessVersions> VersionsAsync => GetPropertyAsync<ProcessVersions>();
/// <summary>
/// A Boolean. When app is started by being passed as parameter to the default app, this
/// property is true in the main process, otherwise it is false.
/// </summary>
public Task<bool> DefaultAppAsync
{
get
{
var tcs = new TaskCompletionSource<bool>();
BridgeConnector.Socket.Once<bool>("process-defaultApp-Completed", tcs.SetResult);
BridgeConnector.Socket.Emit("process-defaultApp");
return tcs.Task;
}
}
public Task<bool> DefaultAppAsync => GetPropertyAsync<bool>();
/// <summary>
/// A Boolean, true when the current renderer context is the "main" renderer frame. If you
/// want the ID of the current frame you should use webFrame.routingId
/// </summary>
public Task<bool> IsMainFrameAsync
{
get
{
var tcs = new TaskCompletionSource<bool>();
BridgeConnector.Socket.Once<bool>("process-isMainFrame-Completed", tcs.SetResult);
BridgeConnector.Socket.Emit("process-isMainFrame");
return tcs.Task;
}
}
public Task<bool> IsMainFrameAsync => GetPropertyAsync<bool>();
/// <summary>
/// A String representing the path to the resources directory.
/// </summary>
public Task<string> ResourcesPathAsync
{
get
{
var tcs = new TaskCompletionSource<string>();
BridgeConnector.Socket.Once<string>("process-resourcesPath-Completed", tcs.SetResult);
BridgeConnector.Socket.Emit("process-resourcesPath");
return tcs.Task;
}
}
public Task<string> ResourcesPathAsync => GetPropertyAsync<string>();
/// <summary>
/// The number of seconds the current Node.js process has been running. The return value
/// includes fractions of a second. Use Math.floor() to get whole seconds.
/// </summary>
public Task<double> UpTimeAsync
{
get
{
var tcs = new TaskCompletionSource<double>();
BridgeConnector.Socket.Once<double>("process-uptime-Completed", tcs.SetResult);
BridgeConnector.Socket.Emit("process-uptime");
return tcs.Task;
}
}
public Task<double> UpTimeAsync => GetPropertyAsync<double>();
/// <summary>
/// The PID of the electron process
/// </summary>
public Task<int> PidAsync
{
get
{
var tcs = new TaskCompletionSource<int>();
BridgeConnector.Socket.Once<int>("process-pid-Completed", tcs.SetResult);
BridgeConnector.Socket.Emit("process-pid");
return tcs.Task;
}
}
public Task<int> PidAsync => GetPropertyAsync<int>();
/// <summary>
/// The operating system CPU architecture for which the Node.js binary was compiled
/// </summary>
public Task<string> ArchAsync
{
get
{
var tcs = new TaskCompletionSource<string>();
BridgeConnector.Socket.Once<string>("process-arch-Completed", tcs.SetResult);
BridgeConnector.Socket.Emit("process-arch");
return tcs.Task;
}
}
public Task<string> ArchAsync => GetPropertyAsync<string>();
/// <summary>
/// A string identifying the operating system platform on which the Node.js process is running
/// </summary>
public Task<string> PlatformAsync
{
get
{
var tcs = new TaskCompletionSource<string>();
BridgeConnector.Socket.Once<string>("process-platform-Completed", tcs.SetResult);
BridgeConnector.Socket.Emit("process-platform");
return tcs.Task;
}
}
public Task<string> PlatformAsync => GetPropertyAsync<string>();
}
}

View File

@@ -1,39 +1,39 @@
using ElectronNET.API.Entities;
using ElectronNET.API.Serialization;
using ElectronNET.Common;
using System;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using ElectronNET.API.Serialization;
namespace ElectronNET.API
{
/// <summary>
/// Retrieve information about screen size, displays, cursor position, etc.
/// </summary>
public sealed class Screen
public sealed class Screen: ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;
protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;
/// <summary>
/// Emitted when an new Display has been added.
/// </summary>
public event Action<Display> OnDisplayAdded
{
add => ApiEventManager.AddEvent("screen-display-added", GetHashCode(), _onDisplayAdded, value, (args) => args.Deserialize(ElectronJsonContext.Default.Display));
remove => ApiEventManager.RemoveEvent("screen-display-added", GetHashCode(), _onDisplayAdded, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action<Display> _onDisplayAdded;
/// <summary>
/// Emitted when oldDisplay has been removed.
/// </summary>
public event Action<Display> OnDisplayRemoved
{
add => ApiEventManager.AddEvent("screen-display-removed", GetHashCode(), _onDisplayRemoved, value, (args) => args.Deserialize(ElectronJsonContext.Default.Display));
remove => ApiEventManager.RemoveEvent("screen-display-removed", GetHashCode(), _onDisplayRemoved, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action<Display> _onDisplayRemoved;
/// <summary>
/// Emitted when one or more metrics change in a display.
/// The changedMetrics is an array of strings that describe the changes.
@@ -41,8 +41,30 @@ namespace ElectronNET.API
/// </summary>
public event Action<Display, string[]> OnDisplayMetricsChanged
{
add => ApiEventManager.AddScreenEvent("screen-display-metrics-changed", GetHashCode(), _onDisplayMetricsChanged, value);
remove => ApiEventManager.RemoveScreenEvent("screen-display-metrics-changed", GetHashCode(), _onDisplayMetricsChanged, value);
add
{
if (_onDisplayMetricsChanged == null)
{
BridgeConnector.Socket.On<JsonElement>("screen-display-metrics-changed" + GetHashCode(), (args) =>
{
var arr = args.EnumerateArray().ToArray();
var display = arr[0].Deserialize(ElectronJsonContext.Default.Display);
var metrics = arr[1].Deserialize<string[]>(ElectronJson.Options);
_onDisplayMetricsChanged(display, metrics);
});
BridgeConnector.Socket.Emit("register-screen-display-metrics-changed", GetHashCode());
}
_onDisplayMetricsChanged += value;
}
remove
{
_onDisplayMetricsChanged -= value;
if (_onDisplayMetricsChanged == null)
BridgeConnector.Socket.Off("screen-display-metrics-changed" + GetHashCode());
}
}
private event Action<Display, string[]> _onDisplayMetricsChanged;
@@ -77,87 +99,37 @@ namespace ElectronNET.API
/// The current absolute position of the mouse pointer.
/// </summary>
/// <returns></returns>
public Task<Point> GetCursorScreenPointAsync()
{
var tcs = new TaskCompletionSource<Point>();
BridgeConnector.Socket.Once<Point>("screen-getCursorScreenPointCompleted", tcs.SetResult);
BridgeConnector.Socket.Emit("screen-getCursorScreenPoint");
return tcs.Task;
}
public Task<Point> GetCursorScreenPointAsync() => GetPropertyAsync<Point>();
/// <summary>
/// macOS: The height of the menu bar in pixels.
/// </summary>
/// <returns>The height of the menu bar in pixels.</returns>
public Task<int> GetMenuBarHeightAsync()
{
var tcs = new TaskCompletionSource<int>();
BridgeConnector.Socket.Once<int>("screen-getMenuBarHeightCompleted", tcs.SetResult);
BridgeConnector.Socket.Emit("screen-getMenuBarHeight");
return tcs.Task;
}
public Task<Rectangle> GetMenuBarWorkAreaAsync() => GetPropertyAsync<Rectangle>();
/// <summary>
/// The primary display.
/// </summary>
/// <returns></returns>
public Task<Display> GetPrimaryDisplayAsync()
{
var tcs = new TaskCompletionSource<Display>();
BridgeConnector.Socket.Once<Display>("screen-getPrimaryDisplayCompleted", tcs.SetResult);
BridgeConnector.Socket.Emit("screen-getPrimaryDisplay");
return tcs.Task;
}
public Task<Display> GetPrimaryDisplayAsync() => GetPropertyAsync<Display>();
/// <summary>
/// An array of displays that are currently available.
/// </summary>
/// <returns>An array of displays that are currently available.</returns>
public Task<Display[]> GetAllDisplaysAsync()
{
var tcs = new TaskCompletionSource<Display[]>();
BridgeConnector.Socket.Once<Display[]>("screen-getAllDisplaysCompleted", tcs.SetResult);
BridgeConnector.Socket.Emit("screen-getAllDisplays");
return tcs.Task;
}
public Task<Display[]> GetAllDisplaysAsync() => GetPropertyAsync<Display[]>();
/// <summary>
/// The display nearest the specified point.
/// </summary>
/// <returns>The display nearest the specified point.</returns>
public Task<Display> GetDisplayNearestPointAsync(Point point)
{
var tcs = new TaskCompletionSource<Display>();
BridgeConnector.Socket.Once<Display>("screen-getDisplayNearestPointCompleted", tcs.SetResult);
BridgeConnector.Socket.Emit("screen-getDisplayNearestPoint", point);
return tcs.Task;
}
public Task<Display> GetDisplayNearestPointAsync(Point point) => GetPropertyAsync<Display>(point);
/// <summary>
/// The display that most closely intersects the provided bounds.
/// </summary>
/// <param name="rectangle"></param>
/// <returns>The display that most closely intersects the provided bounds.</returns>
public Task<Display> GetDisplayMatchingAsync(Rectangle rectangle)
{
var tcs = new TaskCompletionSource<Display>();
BridgeConnector.Socket.Once<Display>("screen-getDisplayMatching", tcs.SetResult);
BridgeConnector.Socket.Emit("screen-getDisplayMatching", rectangle);
return tcs.Task;
}
public Task<Display> GetDisplayMatchingAsync(Rectangle rectangle) => GetPropertyAsync<Display>(rectangle);
}
}

View File

@@ -1,7 +1,5 @@
using ElectronNET.API.Entities;
using ElectronNET.API.Serialization;
using System;
using System.Text.Json;
using System.Threading.Tasks;
namespace ElectronNET.API

View File

@@ -1,9 +1,11 @@
using ElectronNET.API.Entities;
using ElectronNET.API.Extensions;
using ElectronNET.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using ElectronNET.API.Serialization;
// ReSharper disable InconsistentNaming
@@ -12,15 +14,39 @@ namespace ElectronNET.API
/// <summary>
/// Add icons and context menus to the system's notification area.
/// </summary>
public sealed class Tray
public sealed class Tray: ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;
/// <summary>
/// Emitted when the tray icon is clicked.
/// </summary>
public event Action<TrayClickEventArgs, Rectangle> OnClick
{
add => ApiEventManager.AddTrayEvent("tray-click", GetHashCode(), _click, value);
remove => ApiEventManager.RemoveTrayEvent("tray-click", GetHashCode(), _click, value);
add
{
if (_click == null)
{
BridgeConnector.Socket.On<JsonElement>("tray-click" + GetHashCode(), (result) =>
{
var array = result.EnumerateArray().ToArray();
var trayClickEventArgs = array[0].Deserialize(ElectronJsonContext.Default.TrayClickEventArgs);
var bounds = array[1].Deserialize(ElectronJsonContext.Default.Rectangle);
_click(trayClickEventArgs, bounds);
});
BridgeConnector.Socket.Emit("register-tray-click", GetHashCode());
}
_click += value;
}
remove
{
_click -= value;
if (_click == null)
BridgeConnector.Socket.Off("tray-click" + GetHashCode());
}
}
private event Action<TrayClickEventArgs, Rectangle> _click;
@@ -30,8 +56,29 @@ namespace ElectronNET.API
/// </summary>
public event Action<TrayClickEventArgs, Rectangle> OnRightClick
{
add => ApiEventManager.AddTrayEvent("tray-right-click", GetHashCode(), _rightClick, value);
remove => ApiEventManager.RemoveTrayEvent("tray-right-click", GetHashCode(), _rightClick, value);
add
{
if (_rightClick == null)
{
BridgeConnector.Socket.On<JsonElement>("tray-right-click" + GetHashCode(), (result) =>
{
var array = result.EnumerateArray().ToArray();
var trayClickEventArgs = array[0].Deserialize(ElectronJsonContext.Default.TrayClickEventArgs);
var bounds = array[1].Deserialize(ElectronJsonContext.Default.Rectangle);
_rightClick(trayClickEventArgs, bounds);
});
BridgeConnector.Socket.Emit("register-tray-right-click", GetHashCode());
}
_rightClick += value;
}
remove
{
_rightClick -= value;
if (_rightClick == null)
BridgeConnector.Socket.Off("tray-right-click" + GetHashCode());
}
}
private event Action<TrayClickEventArgs, Rectangle> _rightClick;
@@ -41,8 +88,29 @@ namespace ElectronNET.API
/// </summary>
public event Action<TrayClickEventArgs, Rectangle> OnDoubleClick
{
add => ApiEventManager.AddTrayEvent("tray-double-click", GetHashCode(), _doubleClick, value);
remove => ApiEventManager.RemoveTrayEvent("tray-double-click", GetHashCode(), _doubleClick, value);
add
{
if (_doubleClick == null)
{
BridgeConnector.Socket.On<JsonElement>("tray-double-click" + GetHashCode(), (result) =>
{
var array = result.EnumerateArray().ToArray();
var trayClickEventArgs = array[0].Deserialize(ElectronJsonContext.Default.TrayClickEventArgs);
var bounds = array[1].Deserialize(ElectronJsonContext.Default.Rectangle);
_doubleClick(trayClickEventArgs, bounds);
});
BridgeConnector.Socket.Emit("register-tray-double-click", GetHashCode());
}
_doubleClick += value;
}
remove
{
_doubleClick -= value;
if (_doubleClick == null)
BridgeConnector.Socket.Off("tray-double-click" + GetHashCode());
}
}
private event Action<TrayClickEventArgs, Rectangle> _doubleClick;
@@ -52,35 +120,29 @@ namespace ElectronNET.API
/// </summary>
public event Action OnBalloonShow
{
add => ApiEventManager.AddEvent("tray-balloon-show", GetHashCode(), _balloonShow, value);
remove => ApiEventManager.RemoveEvent("tray-balloon-show", GetHashCode(), _balloonShow, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action _balloonShow;
/// <summary>
/// Windows: Emitted when the tray balloon is clicked.
/// </summary>
public event Action OnBalloonClick
{
add => ApiEventManager.AddEvent("tray-balloon-click", GetHashCode(), _balloonClick, value);
remove => ApiEventManager.RemoveEvent("tray-balloon-click", GetHashCode(), _balloonClick, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action _balloonClick;
/// <summary>
/// Windows: Emitted when the tray balloon is closed
/// because of timeout or user manually closes it.
/// </summary>
public event Action OnBalloonClosed
{
add => ApiEventManager.AddEvent("tray-balloon-closed", GetHashCode(), _balloonClosed, value);
remove => ApiEventManager.RemoveEvent("tray-balloon-closed", GetHashCode(), _balloonClosed, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action _balloonClosed;
// TODO: Implement macOS Events
private static Tray _tray;

View File

@@ -1,8 +1,5 @@
using ElectronNET.API.Entities;
using ElectronNET.API.Serialization;
using ElectronNET.Common;
using System;
using System.Text.Json;
using System.Threading.Tasks;
// ReSharper disable InconsistentNaming
@@ -12,15 +9,19 @@ namespace ElectronNET.API;
/// <summary>
/// Render and control web pages.
/// </summary>
public class WebContents
public class WebContents: ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;
protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.CamelCase;
/// <summary>
/// Gets the identifier.
/// </summary>
/// <value>
/// The identifier.
/// </value>
public int Id { get; private set; }
public override int Id { get; protected set; }
/// <summary>
/// Manage browser sessions, cookies, cache, proxy settings, etc.
@@ -32,103 +33,85 @@ public class WebContents
/// </summary>
public event Action<bool> OnCrashed
{
add => ApiEventManager.AddEvent("webContents-crashed", Id, _crashed, value, (args) => args.GetBoolean());
remove => ApiEventManager.RemoveEvent("webContents-crashed", Id, _crashed, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action<bool> _crashed;
/// <summary>
/// Emitted when the navigation is done, i.e. the spinner of the tab has
/// stopped spinning, and the onload event was dispatched.
/// </summary>
public event Action OnDidFinishLoad
{
add => ApiEventManager.AddEvent("webContents-didFinishLoad", Id, _didFinishLoad, value);
remove => ApiEventManager.RemoveEvent("webContents-didFinishLoad", Id, _didFinishLoad, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _didFinishLoad;
/// <summary>
/// Emitted when any frame (including main) starts navigating.
/// </summary>
public event Action<string> OnDidStartNavigation
{
add => ApiEventManager.AddEvent("webContents-didStartNavigation", Id, _didStartNavigation, value);
remove => ApiEventManager.RemoveEvent("webContents-didStartNavigation", Id, _didStartNavigation, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action<string> _didStartNavigation;
/// <summary>
/// Emitted when a main frame navigation is done.
/// This event is not emitted for in-page navigations, such as clicking anchor links or updating the window.location.hash. Use did-navigate-in-page event for this purpose.
/// </summary>
public event Action<OnDidNavigateInfo> OnDidNavigate
{
add => ApiEventManager.AddEvent("webContents-didNavigate", Id, _didNavigate, value);
remove => ApiEventManager.RemoveEvent("webContents-didNavigate", Id, _didNavigate, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action<OnDidNavigateInfo> _didNavigate;
/// <summary>
/// Emitted when a server side redirect occurs during navigation. For example a 302 redirect.
/// This event will be emitted after OnDidStartNavigation and always before the OnDidRedirectNavigation event for the same navigation.
/// </summary>
public event Action<string> OnWillRedirect
{
add => ApiEventManager.AddEvent("webContents-willRedirect", Id, _willRedirect, value);
remove => ApiEventManager.RemoveEvent("webContents-willRedirect", Id, _willRedirect, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action<string> _willRedirect;
/// <summary>
/// Emitted after a server side redirect occurs during navigation. For example a 302 redirect.
/// </summary>
public event Action<string> OnDidRedirectNavigation
{
add => ApiEventManager.AddEvent("webContents-didRedirectNavigation", Id, _didRedirectNavigation, value);
remove => ApiEventManager.RemoveEvent("webContents-didRedirectNavigation", Id, _didRedirectNavigation, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action<string> _didRedirectNavigation;
/// <summary>
/// This event is like OnDidFinishLoad but emitted when the load failed.
/// </summary>
public event Action<OnDidFailLoadInfo> OnDidFailLoad
{
add => ApiEventManager.AddEvent("webContents-didFailLoad", Id, _didFailLoad, value, (args) => args.Deserialize<OnDidFailLoadInfo>(ElectronJson.Options));
remove => ApiEventManager.RemoveEvent("webContents-didFailLoad", Id, _didFailLoad, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action<OnDidFailLoadInfo> _didFailLoad;
/// <summary>
/// Emitted when an input event is sent to the WebContents.
/// </summary>
public event Action<InputEvent> InputEvent
{
add => ApiEventManager.AddEvent("webContents-input-event", Id, _inputEvent, value, (args) => args.Deserialize<InputEvent>(ElectronJson.Options));
remove => ApiEventManager.RemoveEvent("webContents-input-event", Id, _inputEvent, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action<InputEvent> _inputEvent;
/// <summary>
/// Emitted when the document in the top-level frame is loaded.
/// </summary>
public event Action OnDomReady
{
add => ApiEventManager.AddEvent("webContents-domReady", Id, _domReady, value);
remove => ApiEventManager.RemoveEvent("webContents-domReady", Id, _domReady, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _domReady;
internal WebContents(int id)
{
Id = id;
@@ -156,38 +139,19 @@ public class WebContents
/// Get system printers.
/// </summary>
/// <returns>printers</returns>
public Task<PrinterInfo[]> GetPrintersAsync()
{
var tcs = new TaskCompletionSource<PrinterInfo[]>();
BridgeConnector.Socket.Once<PrinterInfo[]>("webContents-getPrinters-completed", tcs.SetResult);
BridgeConnector.Socket.Emit("webContents-getPrinters", Id);
return tcs.Task;
}
public Task<PrinterInfo[]> GetPrintersAsync() => GetPropertyAsync<PrinterInfo[]>();
/// <summary>
/// Prints window's web page.
/// </summary>
/// <param name="options"></param>
/// <returns>success</returns>
public Task<bool> PrintAsync(PrintOptions options = null)
{
var tcs = new TaskCompletionSource<bool>();
BridgeConnector.Socket.Once<bool>("webContents-print-completed", tcs.SetResult);
if (options == null)
{
BridgeConnector.Socket.Emit("webContents-print", Id, "");
}
else
{
BridgeConnector.Socket.Emit("webContents-print", Id, options);
}
return tcs.Task;
}
public Task<bool> PrintAsync(PrintOptions options) => GetPropertyAsync<bool>(options);
/// <summary>
/// Prints window's web page.
/// </summary>
/// <returns>success</returns>
public Task<bool> PrintAsync() => GetPropertyAsync<bool>(string.Empty);
/// <summary>
/// Prints window's web page as PDF with Chromium's preview printing custom
@@ -251,7 +215,7 @@ public class WebContents
{
var tcs = new TaskCompletionSource<string>();
BridgeConnector.Socket.Once<string>("webContents-getUrl", tcs.SetResult);
BridgeConnector.Socket.Once<string>("webContents-getUrl" + Id, tcs.SetResult);
BridgeConnector.Socket.Emit("webContents-getUrl", Id);
return tcs.Task;