diff --git a/src/ElectronNET.API/API/ApiBase.cs b/src/ElectronNET.API/API/ApiBase.cs new file mode 100644 index 00000000..73a3e9a6 --- /dev/null +++ b/src/ElectronNET.API/API/ApiBase.cs @@ -0,0 +1,177 @@ +namespace ElectronNET.API +{ + using System; + using System.Collections.Concurrent; + using System.Diagnostics; + using System.Runtime.CompilerServices; + using System.Threading.Tasks; + using ElectronNET.Common; + + public abstract class ApiBase + { + internal const int PropertyTimeout = 1000; + + private readonly string objectName; + private readonly ConcurrentDictionary propertyGetters = new ConcurrentDictionary(); + private readonly ConcurrentDictionary propertyEventNames = new ConcurrentDictionary(); + private readonly ConcurrentDictionary propertyMessageNames = new ConcurrentDictionary(); + private readonly ConcurrentDictionary methodMessageNames = new ConcurrentDictionary(); + private readonly object objLock = new object(); + + public virtual int Id + { + get + { + return -1; + } + + // ReSharper disable once ValueParameterNotUsed + protected set + { + } + } + + protected abstract string SocketEventCompleteSuffix { get; } + + protected ApiBase() + { + this.objectName = this.GetType().Name.LowerFirst(); + } + + protected void CallMethod0([CallerMemberName] string callerName = null) + { + var messageName = this.methodMessageNames.GetOrAdd(callerName, s => this.objectName + s); + if (this.Id >= 0) + { + BridgeConnector.Socket.Emit(messageName, this.Id); + } + else + { + BridgeConnector.Socket.Emit(messageName); + } + } + + protected void CallMethod1(object val1, [CallerMemberName] string callerName = null) + { + var messageName = this.methodMessageNames.GetOrAdd(callerName, s => this.objectName + s); + if (this.Id >= 0) + { + BridgeConnector.Socket.Emit(messageName, this.Id, val1); + } + else + { + BridgeConnector.Socket.Emit(messageName, val1); + } + } + + protected void CallMethod2(object val1, object val2, [CallerMemberName] string callerName = null) + { + var messageName = this.methodMessageNames.GetOrAdd(callerName, s => this.objectName + s); + if (this.Id >= 0) + { + BridgeConnector.Socket.Emit(messageName, this.Id, val1, val2); + } + else + { + BridgeConnector.Socket.Emit(messageName, val1, val2); + } + } + + protected void CallMethod3(object val1, object val2, object val3, [CallerMemberName] string callerName = null) + { + var messageName = this.methodMessageNames.GetOrAdd(callerName, s => this.objectName + s); + if (this.Id >= 0) + { + BridgeConnector.Socket.Emit(messageName, this.Id, val1, val2, val3); + } + else + { + BridgeConnector.Socket.Emit(messageName, val1, val2, val3); + } + } + + protected Task GetPropertyAsync([CallerMemberName] string callerName = null) + { + Debug.Assert(callerName != null, nameof(callerName) + " != null"); + + lock (this.objLock) + { + return this.propertyGetters.GetOrAdd(callerName, _ => + { + var getter = new PropertyGetter(this, callerName, PropertyTimeout); + + getter.Task().ContinueWith(_ => + { + lock (this.objLock) + { + return this.propertyGetters.TryRemove(callerName, out var _); + } + }); + + return getter; + }).Task(); + } + } + + internal abstract class PropertyGetter + { + public abstract Task Task(); + } + + internal class PropertyGetter : PropertyGetter + { + private readonly Task tcsTask; + private TaskCompletionSource tcs; + + public PropertyGetter(ApiBase apiBase, string callerName, int timeoutMs) + { + this.tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + this.tcsTask = this.tcs.Task; + + var eventName = apiBase.propertyEventNames.GetOrAdd(callerName, s => $"{apiBase.objectName}-{s.StripAsync().LowerFirst()}{apiBase.SocketEventCompleteSuffix}"); + var messageName = apiBase.propertyMessageNames.GetOrAdd(callerName, s => apiBase.objectName + s.StripAsync()); + + BridgeConnector.Socket.On(eventName, (result) => + { + BridgeConnector.Socket.Off(eventName); + + lock (this) + { + this.tcs?.SetResult(result); + this.tcs = null; + } + }); + + if (apiBase.Id >= 0) + { + BridgeConnector.Socket.Emit(messageName, apiBase.Id); + } + else + { + BridgeConnector.Socket.Emit(messageName); + } + + System.Threading.Tasks.Task.Delay(ApiBase.PropertyTimeout).ContinueWith(_ => + { + if (this.tcs != null) + { + lock (this) + { + if (this.tcs != null) + { + var ex = new TimeoutException($"No response after {timeoutMs:D}ms trying to retrieve value {apiBase.objectName}.{callerName}()"); + this.tcs.TrySetException(ex); + this.tcs = null; + } + } + } + }); + } + + public override Task Task() + { + return this.tcsTask as Task; + } + } + } +} diff --git a/src/ElectronNET.API/API/App.cs b/src/ElectronNET.API/API/App.cs index 81b64c89..acf87237 100644 --- a/src/ElectronNET.API/API/App.cs +++ b/src/ElectronNET.API/API/App.cs @@ -16,8 +16,10 @@ namespace ElectronNET.API /// /// Control your application's event lifecycle. /// - public sealed class App + public sealed class App : ApiBase { + protected override string SocketEventCompleteSuffix => "Completed"; + /// /// Emitted when all windows have been closed. /// @@ -372,20 +374,7 @@ public Task NameAsync { get { - return Task.Run(() => - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("appGetNameCompleted", (result) => - { - BridgeConnector.Socket.Off("appGetNameCompleted"); - taskCompletionSource.SetResult((string)result); - }); - - BridgeConnector.Socket.Emit("appGetName"); - - return taskCompletionSource.Task; - }); + return this.GetPropertyAsync(); } } @@ -430,7 +419,7 @@ internal static App Instance /// public void Quit() { - BridgeConnector.Socket.Emit("appQuit"); + this.CallMethod0(); } /// @@ -440,7 +429,7 @@ public void Quit() /// Exits immediately with exitCode. exitCode defaults to 0. public void Exit(int exitCode = 0) { - BridgeConnector.Socket.Emit("appExit", exitCode); + this.CallMethod1(exitCode); } public void DisposeSocket() @@ -460,7 +449,7 @@ public void DisposeSocket() /// public void Relaunch() { - BridgeConnector.Socket.Emit("appRelaunch"); + this.CallMethod0(); } /// @@ -478,7 +467,7 @@ public void Relaunch() /// Options for the relaunch. public void Relaunch(RelaunchOptions relaunchOptions) { - BridgeConnector.Socket.Emit("appRelaunch", JObject.FromObject(relaunchOptions, _jsonSerializer)); + this.CallMethod1(JObject.FromObject(relaunchOptions, _jsonSerializer)); } /// @@ -487,7 +476,7 @@ public void Relaunch(RelaunchOptions relaunchOptions) /// public void Focus() { - BridgeConnector.Socket.Emit("appFocus"); + this.CallMethod0(); } /// @@ -498,7 +487,7 @@ public void Focus() /// public void Focus(FocusOptions focusOptions) { - BridgeConnector.Socket.Emit("appFocus", JObject.FromObject(focusOptions, _jsonSerializer)); + this.CallMethod1(JObject.FromObject(focusOptions, _jsonSerializer)); } /// @@ -506,7 +495,7 @@ public void Focus(FocusOptions focusOptions) /// public void Hide() { - BridgeConnector.Socket.Emit("appHide"); + this.CallMethod0(); } /// @@ -514,7 +503,7 @@ public void Hide() /// public void Show() { - BridgeConnector.Socket.Emit("appShow"); + this.CallMethod0(); } /// @@ -523,21 +512,7 @@ public void Show() public async Task GetAppPathAsync(CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); - - var taskCompletionSource = new TaskCompletionSource(); - using(cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) - { - BridgeConnector.Socket.On("appGetAppPathCompleted", (path) => - { - BridgeConnector.Socket.Off("appGetAppPathCompleted"); - taskCompletionSource.SetResult(path.ToString()); - }); - - BridgeConnector.Socket.Emit("appGetAppPath"); - - return await taskCompletionSource.Task - .ConfigureAwait(false); - } + return await this.GetPropertyAsync().ConfigureAwait(false); } /// @@ -550,7 +525,7 @@ public async Task GetAppPathAsync(CancellationToken cancellationToken = /// A custom path for your logs. Must be absolute. public void SetAppLogsPath(string path) { - BridgeConnector.Socket.Emit("appSetAppLogsPath", path); + this.CallMethod1(path); } /// @@ -596,7 +571,7 @@ public async Task GetPathAsync(PathName pathName, CancellationToken canc /// public void SetPath(PathName name, string path) { - BridgeConnector.Socket.Emit("appSetPath", name.GetDescription(), path); + this.CallMethod2(name.GetDescription(), path); } /// @@ -607,21 +582,7 @@ public void SetPath(PathName name, string path) public async Task GetVersionAsync(CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); - - var taskCompletionSource = new TaskCompletionSource(); - using(cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) - { - BridgeConnector.Socket.On("appGetVersionCompleted", (version) => - { - BridgeConnector.Socket.Off("appGetVersionCompleted"); - taskCompletionSource.SetResult(version.ToString()); - }); - - BridgeConnector.Socket.Emit("appGetVersion"); - - return await taskCompletionSource.Task - .ConfigureAwait(false); - } + return await this.GetPropertyAsync().ConfigureAwait(false); } /// @@ -635,21 +596,7 @@ public async Task GetVersionAsync(CancellationToken cancellationToken = public async Task GetLocaleAsync(CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); - - var taskCompletionSource = new TaskCompletionSource(); - using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) - { - BridgeConnector.Socket.On("appGetLocaleCompleted", (local) => - { - BridgeConnector.Socket.Off("appGetLocaleCompleted"); - taskCompletionSource.SetResult(local.ToString()); - }); - - BridgeConnector.Socket.Emit("appGetLocale"); - - return await taskCompletionSource.Task - .ConfigureAwait(false); - } + return await this.GetPropertyAsync().ConfigureAwait(false); } /// @@ -659,7 +606,7 @@ public async Task GetLocaleAsync(CancellationToken cancellationToken = d /// Path to add. public void AddRecentDocument(string path) { - BridgeConnector.Socket.Emit("appAddRecentDocument", path); + this.CallMethod1(path); } /// @@ -667,7 +614,7 @@ public void AddRecentDocument(string path) /// public void ClearRecentDocuments() { - BridgeConnector.Socket.Emit("appClearRecentDocuments"); + this.CallMethod0(); } /// @@ -940,21 +887,7 @@ public async Task SetUserTasksAsync(UserTask[] userTasks, CancellationToke public async Task GetJumpListSettingsAsync(CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); - - var taskCompletionSource = new TaskCompletionSource(); - using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) - { - BridgeConnector.Socket.On("appGetJumpListSettingsCompleted", (jumpListSettings) => - { - BridgeConnector.Socket.Off("appGetJumpListSettingsCompleted"); - taskCompletionSource.SetResult(JObject.Parse(jumpListSettings.ToString()).ToObject()); - }); - - BridgeConnector.Socket.Emit("appGetJumpListSettings"); - - return await taskCompletionSource.Task - .ConfigureAwait(false); - } + return await this.GetPropertyAsync().ConfigureAwait(false); } /// @@ -975,7 +908,7 @@ public async Task GetJumpListSettingsAsync(CancellationToken c /// Array of objects. public void SetJumpList(JumpListCategory[] categories) { - BridgeConnector.Socket.Emit("appSetJumpList", JArray.FromObject(categories, _jsonSerializer)); + this.CallMethod1(JArray.FromObject(categories, _jsonSerializer)); } /// @@ -1035,7 +968,7 @@ public async Task RequestSingleInstanceLockAsync(Action /// public void ReleaseSingleInstanceLock() { - BridgeConnector.Socket.Emit("appReleaseSingleInstanceLock"); + this.CallMethod0(); } /// @@ -1047,21 +980,7 @@ public void ReleaseSingleInstanceLock() public async Task HasSingleInstanceLockAsync(CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); - - var taskCompletionSource = new TaskCompletionSource(); - using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) - { - BridgeConnector.Socket.On("appHasSingleInstanceLockCompleted", (hasLock) => - { - BridgeConnector.Socket.Off("appHasSingleInstanceLockCompleted"); - taskCompletionSource.SetResult((bool) hasLock); - }); - - BridgeConnector.Socket.Emit("appHasSingleInstanceLock"); - - return await taskCompletionSource.Task - .ConfigureAwait(false); - } + return await this.GetPropertyAsync().ConfigureAwait(false); } /// @@ -1090,7 +1009,7 @@ public void SetUserActivity(string type, object userInfo) /// public void SetUserActivity(string type, object userInfo, string webpageUrl) { - BridgeConnector.Socket.Emit("appSetUserActivity", type, userInfo, webpageUrl); + this.CallMethod3(type, userInfo, webpageUrl); } /// @@ -1100,21 +1019,7 @@ public void SetUserActivity(string type, object userInfo, string webpageUrl) public async Task GetCurrentActivityTypeAsync(CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); - - var taskCompletionSource = new TaskCompletionSource(); - using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) - { - BridgeConnector.Socket.On("appGetCurrentActivityTypeCompleted", (activityType) => - { - BridgeConnector.Socket.Off("appGetCurrentActivityTypeCompleted"); - taskCompletionSource.SetResult(activityType.ToString()); - }); - - BridgeConnector.Socket.Emit("appGetCurrentActivityType"); - - return await taskCompletionSource.Task - .ConfigureAwait(false); - } + return await this.GetPropertyAsync().ConfigureAwait(false); } /// @@ -1122,7 +1027,7 @@ public async Task GetCurrentActivityTypeAsync(CancellationToken cancella /// public void InvalidateCurrentActivity() { - BridgeConnector.Socket.Emit("appInvalidateCurrentActivity"); + this.CallMethod0(); } /// @@ -1130,7 +1035,7 @@ public void InvalidateCurrentActivity() /// public void ResignCurrentActivity() { - BridgeConnector.Socket.Emit("appResignCurrentActivity"); + this.CallMethod0(); } /// @@ -1139,7 +1044,7 @@ public void ResignCurrentActivity() /// Model Id. public void SetAppUserModelId(string id) { - BridgeConnector.Socket.Emit("appSetAppUserModelId", id); + this.CallMethod1(id); } /// TODO: Check new parameter which is a function [App.ImportCertificate] @@ -1182,23 +1087,7 @@ public async Task ImportCertificateAsync(ImportCertificateOptions options, public async Task GetAppMetricsAsync(CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); - - var taskCompletionSource = new TaskCompletionSource(); - using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) - { - BridgeConnector.Socket.On("appGetAppMetricsCompleted", (result) => - { - BridgeConnector.Socket.Off("appGetAppMetricsCompleted"); - var processMetrics = ((JArray)result).ToObject(); - - taskCompletionSource.SetResult(processMetrics); - }); - - BridgeConnector.Socket.Emit("appGetAppMetrics"); - - return await taskCompletionSource.Task - .ConfigureAwait(false); - } + return await this.GetPropertyAsync().ConfigureAwait(false); } /// @@ -1210,23 +1099,7 @@ public async Task GetAppMetricsAsync(CancellationToken cancella public async Task GetGpuFeatureStatusAsync(CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); - - var taskCompletionSource = new TaskCompletionSource(); - using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) - { - BridgeConnector.Socket.On("appGetGpuFeatureStatusCompleted", (result) => - { - BridgeConnector.Socket.Off("appGetGpuFeatureStatusCompleted"); - var gpuFeatureStatus = ((JObject)result).ToObject(); - - taskCompletionSource.SetResult(gpuFeatureStatus); - }); - - BridgeConnector.Socket.Emit("appGetGpuFeatureStatus"); - - return await taskCompletionSource.Task - .ConfigureAwait(false); - } + return await this.GetPropertyAsync().ConfigureAwait(false); } /// @@ -1266,21 +1139,7 @@ public async Task SetBadgeCountAsync(int count, CancellationToken cancella public async Task GetBadgeCountAsync(CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); - - var taskCompletionSource = new TaskCompletionSource(); - using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) - { - BridgeConnector.Socket.On("appGetBadgeCountCompleted", (count) => - { - BridgeConnector.Socket.Off("appGetBadgeCountCompleted"); - taskCompletionSource.SetResult((int)count); - }); - - BridgeConnector.Socket.Emit("appGetBadgeCount"); - - return await taskCompletionSource.Task - .ConfigureAwait(false); - } + return await this.GetPropertyAsync().ConfigureAwait(false); } /// @@ -1295,21 +1154,7 @@ public async Task GetBadgeCountAsync(CancellationToken cancellationToken = public async Task IsUnityRunningAsync(CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); - - var taskCompletionSource = new TaskCompletionSource(); - using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) - { - BridgeConnector.Socket.On("appIsUnityRunningCompleted", (isUnityRunning) => - { - BridgeConnector.Socket.Off("appIsUnityRunningCompleted"); - taskCompletionSource.SetResult((bool)isUnityRunning); - }); - - BridgeConnector.Socket.Emit("appIsUnityRunning"); - - return await taskCompletionSource.Task - .ConfigureAwait(false); - } + return await this.GetPropertyAsync().ConfigureAwait(false); } /// @@ -1365,7 +1210,7 @@ public async Task GetLoginItemSettingsAsync(LoginItemSettings /// public void SetLoginItemSettings(LoginSettings loginSettings) { - BridgeConnector.Socket.Emit("appSetLoginItemSettings", JObject.FromObject(loginSettings, _jsonSerializer)); + this.CallMethod1(JObject.FromObject(loginSettings, _jsonSerializer)); } /// @@ -1377,21 +1222,7 @@ public void SetLoginItemSettings(LoginSettings loginSettings) public async Task IsAccessibilitySupportEnabledAsync(CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); - - var taskCompletionSource = new TaskCompletionSource(); - using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) - { - BridgeConnector.Socket.On("appIsAccessibilitySupportEnabledCompleted", (isAccessibilitySupportEnabled) => - { - BridgeConnector.Socket.Off("appIsAccessibilitySupportEnabledCompleted"); - taskCompletionSource.SetResult((bool)isAccessibilitySupportEnabled); - }); - - BridgeConnector.Socket.Emit("appIsAccessibilitySupportEnabled"); - - return await taskCompletionSource.Task - .ConfigureAwait(false); - } + return await this.GetPropertyAsync().ConfigureAwait(false); } /// @@ -1406,7 +1237,7 @@ public async Task IsAccessibilitySupportEnabledAsync(CancellationToken can /// Enable or disable accessibility tree rendering. public void SetAccessibilitySupportEnabled(bool enabled) { - BridgeConnector.Socket.Emit("appSetAccessibilitySupportEnabled", enabled); + this.CallMethod1(enabled); } /// @@ -1415,7 +1246,7 @@ public void SetAccessibilitySupportEnabled(bool enabled) /// public void ShowAboutPanel() { - BridgeConnector.Socket.Emit("appShowAboutPanel"); + this.CallMethod0(); } /// @@ -1431,7 +1262,7 @@ public void ShowAboutPanel() /// About panel options. public void SetAboutPanelOptions(AboutPanelOptions options) { - BridgeConnector.Socket.Emit("appSetAboutPanelOptions", JObject.FromObject(options, _jsonSerializer)); + this.CallMethod1(JObject.FromObject(options, _jsonSerializer)); } /// @@ -1467,20 +1298,7 @@ public Task UserAgentFallbackAsync { get { - return Task.Run(() => - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("appGetUserAgentFallbackCompleted", (result) => - { - BridgeConnector.Socket.Off("appGetUserAgentFallbackCompleted"); - taskCompletionSource.SetResult((string)result); - }); - - BridgeConnector.Socket.Emit("appGetUserAgentFallback"); - - return taskCompletionSource.Task; - }); + return this.GetPropertyAsync(); } } diff --git a/src/ElectronNET.API/API/BrowserWindow.cs b/src/ElectronNET.API/API/BrowserWindow.cs index 25a0b792..6a385f82 100644 --- a/src/ElectronNET.API/API/BrowserWindow.cs +++ b/src/ElectronNET.API/API/BrowserWindow.cs @@ -13,18 +13,25 @@ namespace ElectronNET.API; +using System.Collections.Concurrent; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using ElectronNET.Common; + /// /// Create and control browser windows. /// -public class BrowserWindow +public class BrowserWindow : ApiBase { + protected override string SocketEventCompleteSuffix => "-completed"; + /// /// Gets the identifier. /// /// /// The identifier. /// - public int Id { get; private set; } + public override int Id { get; protected set; } /// /// Emitted when the web page has been rendered (while not being shown) and @@ -334,7 +341,8 @@ public event Action OnNewWindowForTab private event Action _newWindowForTab; - internal BrowserWindow(int id) { + internal BrowserWindow(int id) + { Id = id; WebContents = new WebContents(id); } @@ -344,232 +352,106 @@ internal BrowserWindow(int id) { /// emitted for the web page, and close event will also not be emitted /// for this window, but it guarantees the closed event will be emitted. /// - public void Destroy() - { - BridgeConnector.Socket.Emit("browserWindowDestroy", Id); - } + public void Destroy() => this.CallMethod0(); /// /// Try to close the window. This has the same effect as a user manually /// clicking the close button of the window. The web page may cancel the close though. /// - public void Close() - { - BridgeConnector.Socket.Emit("browserWindowClose", Id); - } + public void Close() => this.CallMethod0(); /// /// Focuses on the window. /// - public void Focus() - { - BridgeConnector.Socket.Emit("browserWindowFocus", Id); - } + public void Focus() => this.CallMethod0(); /// /// Removes focus from the window. /// - public void Blur() - { - BridgeConnector.Socket.Emit("browserWindowBlur", Id); - } + public void Blur() => this.CallMethod0(); /// /// Whether the window is focused. /// /// - public Task IsFocusedAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-isFocused-completed", (isFocused) => { - BridgeConnector.Socket.Off("browserWindow-isFocused-completed"); - - taskCompletionSource.SetResult((bool)isFocused); - }); - - BridgeConnector.Socket.Emit("browserWindowIsFocused", Id); - - return taskCompletionSource.Task; - } + public Task IsFocusedAsync() => this.GetPropertyAsync(); /// /// Whether the window is destroyed. /// /// - public Task IsDestroyedAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-isDestroyed-completed", (isDestroyed) => { - BridgeConnector.Socket.Off("browserWindow-isDestroyed-completed"); - - taskCompletionSource.SetResult((bool)isDestroyed); - }); - - BridgeConnector.Socket.Emit("browserWindowIsDestroyed", Id); - - return taskCompletionSource.Task; - } + public Task IsDestroyedAsync() => this.GetPropertyAsync(); /// /// Shows and gives focus to the window. /// - public void Show() - { - BridgeConnector.Socket.Emit("browserWindowShow", Id); - } + public void Show() => this.CallMethod0(); /// /// Shows the window but doesn’t focus on it. /// - public void ShowInactive() - { - BridgeConnector.Socket.Emit("browserWindowShowInactive", Id); - } + public void ShowInactive() => this.CallMethod0(); /// /// Hides the window. /// - public void Hide() - { - BridgeConnector.Socket.Emit("browserWindowHide", Id); - } + public void Hide() => this.CallMethod0(); /// /// Whether the window is visible to the user. /// /// - public Task IsVisibleAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-isVisible-completed", (isVisible) => { - BridgeConnector.Socket.Off("browserWindow-isVisible-completed"); - - taskCompletionSource.SetResult((bool)isVisible); - }); - - BridgeConnector.Socket.Emit("browserWindowIsVisible", Id); - - return taskCompletionSource.Task; - } + public Task IsVisibleAsync() => this.GetPropertyAsync(); /// /// Whether current window is a modal window. /// /// - public Task IsModalAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-isModal-completed", (isModal) => { - BridgeConnector.Socket.Off("browserWindow-isModal-completed"); - - taskCompletionSource.SetResult((bool)isModal); - }); - - BridgeConnector.Socket.Emit("browserWindowIsModal", Id); - - return taskCompletionSource.Task; - } + public Task IsModalAsync() => this.GetPropertyAsync(); /// /// Maximizes the window. This will also show (but not focus) the window if it isn’t being displayed already. /// - public void Maximize() - { - BridgeConnector.Socket.Emit("browserWindowMaximize", Id); - } + public void Maximize() => this.CallMethod0(); /// /// Unmaximizes the window. /// - public void Unmaximize() - { - BridgeConnector.Socket.Emit("browserWindowUnmaximize", Id); - } + public void Unmaximize() => this.CallMethod0(); /// /// Whether the window is maximized. /// /// - public Task IsMaximizedAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-isMaximized-completed", (isMaximized) => { - BridgeConnector.Socket.Off("browserWindow-isMaximized-completed"); - - taskCompletionSource.SetResult((bool)isMaximized); - }); - - BridgeConnector.Socket.Emit("browserWindowIsMaximized", Id); - - return taskCompletionSource.Task; - } + public Task IsMaximizedAsync() => this.GetPropertyAsync(); /// /// Minimizes the window. On some platforms the minimized window will be shown in the Dock. /// - public void Minimize() - { - BridgeConnector.Socket.Emit("browserWindowMinimize", Id); - } + public void Minimize() => this.CallMethod0(); /// /// Restores the window from minimized state to its previous state. /// - public void Restore() - { - BridgeConnector.Socket.Emit("browserWindowRestore", Id); - } + public void Restore() => this.CallMethod0(); /// /// Whether the window is minimized. /// /// - public Task IsMinimizedAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-isMinimized-completed", (isMinimized) => { - BridgeConnector.Socket.Off("browserWindow-isMinimized-completed"); - - taskCompletionSource.SetResult((bool)isMinimized); - }); - - BridgeConnector.Socket.Emit("browserWindowIsMinimized", Id); - - return taskCompletionSource.Task; - } + public Task IsMinimizedAsync() => this.GetPropertyAsync(); /// /// Sets whether the window should be in fullscreen mode. /// - public void SetFullScreen(bool flag) - { - BridgeConnector.Socket.Emit("browserWindowSetFullScreen", Id, flag); - } + /// + public void SetFullScreen(bool flag) => this.CallMethod1(flag); /// /// Whether the window is in fullscreen mode. /// /// - public Task IsFullScreenAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-isFullScreen-completed", (isFullScreen) => { - BridgeConnector.Socket.Off("browserWindow-isFullScreen-completed"); - - taskCompletionSource.SetResult((bool)isFullScreen); - }); - - BridgeConnector.Socket.Emit("browserWindowIsFullScreen", Id); - - return taskCompletionSource.Task; - } + public Task IsFullScreenAsync() => this.GetPropertyAsync(); /// /// This will make a window maintain an aspect ratio. The extra size allows a developer to have space, @@ -585,10 +467,8 @@ public Task IsFullScreenAsync() /// /// The aspect ratio to maintain for some portion of the content view. /// The extra size not to be included while maintaining the aspect ratio. - public void SetAspectRatio(double aspectRatio, Size extraSize) - { - BridgeConnector.Socket.Emit("browserWindowSetAspectRatio", Id, aspectRatio, JObject.FromObject(extraSize, _jsonSerializer)); - } + public void SetAspectRatio(double aspectRatio, Size extraSize) => + this.CallMethod2(aspectRatio, JObject.FromObject(extraSize, _jsonSerializer)); /// /// This will make a window maintain an aspect ratio. The extra size allows a developer to have space, @@ -604,10 +484,8 @@ public void SetAspectRatio(double aspectRatio, Size extraSize) /// /// The aspect ratio to maintain for some portion of the content view. /// The extra size not to be included while maintaining the aspect ratio. - public void SetAspectRatio(int aspectRatio, Size extraSize) - { - BridgeConnector.Socket.Emit("browserWindowSetAspectRatio", Id, aspectRatio, JObject.FromObject(extraSize, _jsonSerializer)); - } + public void SetAspectRatio(int aspectRatio, Size extraSize) => + this.CallMethod2(aspectRatio, JObject.FromObject(extraSize, _jsonSerializer)); /// /// Uses Quick Look to preview a file at a given path. @@ -615,10 +493,7 @@ public void SetAspectRatio(int aspectRatio, Size extraSize) /// The absolute path to the file to preview with QuickLook. This is important as /// Quick Look uses the file name and file extension on the path to determine the content type of the /// file to open. - public void PreviewFile(string path) - { - BridgeConnector.Socket.Emit("browserWindowPreviewFile", Id, path); - } + public void PreviewFile(string path) => this.CallMethod1(path); /// /// Uses Quick Look to preview a file at a given path. @@ -628,104 +503,57 @@ public void PreviewFile(string path) /// file to open. /// The name of the file to display on the Quick Look modal view. This is /// purely visual and does not affect the content type of the file. Defaults to path. - public void PreviewFile(string path, string displayname) - { - BridgeConnector.Socket.Emit("browserWindowPreviewFile", Id, path, displayname); - } + public void PreviewFile(string path, string displayname) => this.CallMethod2(path, displayname); /// /// Closes the currently open Quick Look panel. /// - public void CloseFilePreview() - { - BridgeConnector.Socket.Emit("browserWindowCloseFilePreview", Id); - } + public void CloseFilePreview() => this.CallMethod0(); /// /// Resizes and moves the window to the supplied bounds /// /// - public void SetBounds(Rectangle bounds) - { - BridgeConnector.Socket.Emit("browserWindowSetBounds", Id, JObject.FromObject(bounds, _jsonSerializer)); - } + public void SetBounds(Rectangle bounds) => this.CallMethod1(JObject.FromObject(bounds, _jsonSerializer)); /// /// Resizes and moves the window to the supplied bounds /// /// /// - public void SetBounds(Rectangle bounds, bool animate) - { - BridgeConnector.Socket.Emit("browserWindowSetBounds", Id, JObject.FromObject(bounds, _jsonSerializer), animate); - } + public void SetBounds(Rectangle bounds, bool animate) => this.CallMethod2(JObject.FromObject(bounds, _jsonSerializer), animate); /// /// Gets the bounds asynchronous. /// /// - public Task GetBoundsAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-getBounds-completed", (getBounds) => { - BridgeConnector.Socket.Off("browserWindow-getBounds-completed"); - - taskCompletionSource.SetResult(((JObject)getBounds).ToObject()); - }); - - BridgeConnector.Socket.Emit("browserWindowGetBounds", Id); - - return taskCompletionSource.Task; - } + public Task GetBoundsAsync() => this.GetPropertyAsync(); /// /// Resizes and moves the window’s client area (e.g. the web page) to the supplied bounds. /// /// - public void SetContentBounds(Rectangle bounds) - { - BridgeConnector.Socket.Emit("browserWindowSetContentBounds", Id, JObject.FromObject(bounds, _jsonSerializer)); - } + public void SetContentBounds(Rectangle bounds) => this.CallMethod1(JObject.FromObject(bounds, _jsonSerializer)); /// /// Resizes and moves the window’s client area (e.g. the web page) to the supplied bounds. /// /// /// - public void SetContentBounds(Rectangle bounds, bool animate) - { - BridgeConnector.Socket.Emit("browserWindowSetContentBounds", Id, JObject.FromObject(bounds, _jsonSerializer), animate); - } + public void SetContentBounds(Rectangle bounds, bool animate) => this.CallMethod2(JObject.FromObject(bounds, _jsonSerializer), animate); /// /// Gets the content bounds asynchronous. /// /// - public Task GetContentBoundsAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-getContentBounds-completed", (getContentBounds) => { - BridgeConnector.Socket.Off("browserWindow-getContentBounds-completed"); - - taskCompletionSource.SetResult(((JObject)getContentBounds).ToObject()); - }); - - BridgeConnector.Socket.Emit("browserWindowGetContentBounds", Id); - - return taskCompletionSource.Task; - } + public Task GetContentBoundsAsync() => this.GetPropertyAsync(); /// /// Resizes the window to width and height. /// /// /// - public void SetSize(int width, int height) - { - BridgeConnector.Socket.Emit("browserWindowSetSize", Id, width, height); - } + public void SetSize(int width, int height) => this.CallMethod2(width, height); /// /// Resizes the window to width and height. @@ -733,39 +561,20 @@ public void SetSize(int width, int height) /// /// /// - public void SetSize(int width, int height, bool animate) - { - BridgeConnector.Socket.Emit("browserWindowSetSize", Id, width, height, animate); - } + public void SetSize(int width, int height, bool animate) => this.CallMethod3(width, height, animate); /// /// Contains the window’s width and height. /// /// - public Task GetSizeAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-getSize-completed", (size) => { - BridgeConnector.Socket.Off("browserWindow-getSize-completed"); - - taskCompletionSource.SetResult(((JArray)size).ToObject()); - }); - - BridgeConnector.Socket.Emit("browserWindowGetSize", Id); - - return taskCompletionSource.Task; - } + public Task GetSizeAsync() => this.GetPropertyAsync(); /// /// Resizes the window’s client area (e.g. the web page) to width and height. /// /// /// - public void SetContentSize(int width, int height) - { - BridgeConnector.Socket.Emit("browserWindowSetContentSize", Id, width, height); - } + public void SetContentSize(int width, int height) => this.CallMethod2(width, height); /// /// Resizes the window’s client area (e.g. the web page) to width and height. @@ -773,124 +582,57 @@ public void SetContentSize(int width, int height) /// /// /// - public void SetContentSize(int width, int height, bool animate) - { - BridgeConnector.Socket.Emit("browserWindowSetContentSize", Id, width, height, animate); - } + public void SetContentSize(int width, int height, bool animate) => this.CallMethod3(width, height, animate); /// /// Contains the window’s client area’s width and height. /// /// - public Task GetContentSizeAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-getContentSize-completed", (size) => { - BridgeConnector.Socket.Off("browserWindow-getContentSize-completed"); - - taskCompletionSource.SetResult(((JArray)size).ToObject()); - }); - - BridgeConnector.Socket.Emit("browserWindowGetContentSize", Id); - - return taskCompletionSource.Task; - } + public Task GetContentSizeAsync() => this.GetPropertyAsync(); /// /// Sets the minimum size of window to width and height. /// /// /// - public void SetMinimumSize(int width, int height) - { - BridgeConnector.Socket.Emit("browserWindowSetMinimumSize", Id, width, height); - } + public void SetMinimumSize(int width, int height) => this.CallMethod2(width, height); /// /// Contains the window’s minimum width and height. /// /// - public Task GetMinimumSizeAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-getMinimumSize-completed", (size) => { - BridgeConnector.Socket.Off("browserWindow-getMinimumSize-completed"); - - taskCompletionSource.SetResult(((JArray)size).ToObject()); - }); - - BridgeConnector.Socket.Emit("browserWindowGetMinimumSize", Id); - - return taskCompletionSource.Task; - } + public Task GetMinimumSizeAsync() => this.GetPropertyAsync(); /// /// Sets the maximum size of window to width and height. /// /// /// - public void SetMaximumSize(int width, int height) - { - BridgeConnector.Socket.Emit("browserWindowSetMaximumSize", Id, width, height); - } + public void SetMaximumSize(int width, int height) => this.CallMethod2(width, height); /// /// Contains the window’s maximum width and height. /// /// - public Task GetMaximumSizeAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-getMaximumSize-completed", (size) => { - BridgeConnector.Socket.Off("browserWindow-getMaximumSize-completed"); - - taskCompletionSource.SetResult(((JArray)size).ToObject()); - }); - - BridgeConnector.Socket.Emit("browserWindowGetMaximumSize", Id); - - return taskCompletionSource.Task; - } + public Task GetMaximumSizeAsync() => this.GetPropertyAsync(); /// /// Sets whether the window can be manually resized by user. /// /// - public void SetResizable(bool resizable) - { - BridgeConnector.Socket.Emit("browserWindowSetResizable", Id, resizable); - } + public void SetResizable(bool resizable) => this.CallMethod1(resizable); /// /// Whether the window can be manually resized by user. /// /// - public Task IsResizableAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-isResizable-completed", (resizable) => { - BridgeConnector.Socket.Off("browserWindow-isResizable-completed"); - - taskCompletionSource.SetResult((bool)resizable); - }); - - BridgeConnector.Socket.Emit("browserWindowIsResizable", Id); - - return taskCompletionSource.Task; - } + public Task IsResizableAsync() => this.GetPropertyAsync(); /// /// Sets whether the window can be moved by user. On Linux does nothing. /// /// - public void SetMovable(bool movable) - { - BridgeConnector.Socket.Emit("browserWindowSetMovable", Id, movable); - } + public void SetMovable(bool movable) => this.CallMethod1(movable); /// /// Whether the window can be moved by user. @@ -898,29 +640,13 @@ public void SetMovable(bool movable) /// On Linux always returns true. /// /// On Linux always returns true. - public Task IsMovableAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-isMovable-completed", (movable) => { - BridgeConnector.Socket.Off("browserWindow-isMovable-completed"); - - taskCompletionSource.SetResult((bool)movable); - }); - - BridgeConnector.Socket.Emit("browserWindowIsMovable", Id); - - return taskCompletionSource.Task; - } + public Task IsMovableAsync() => this.GetPropertyAsync(); /// /// Sets whether the window can be manually minimized by user. On Linux does nothing. /// /// - public void SetMinimizable(bool minimizable) - { - BridgeConnector.Socket.Emit("browserWindowSetMinimizable", Id, minimizable); - } + public void SetMinimizable(bool minimizable) => this.CallMethod1(minimizable); /// /// Whether the window can be manually minimized by user. @@ -928,29 +654,13 @@ public void SetMinimizable(bool minimizable) /// On Linux always returns true. /// /// On Linux always returns true. - public Task IsMinimizableAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-isMinimizable-completed", (minimizable) => { - BridgeConnector.Socket.Off("browserWindow-isMinimizable-completed"); - - taskCompletionSource.SetResult((bool)minimizable); - }); - - BridgeConnector.Socket.Emit("browserWindowIsMinimizable", Id); - - return taskCompletionSource.Task; - } + public Task IsMinimizableAsync() => this.GetPropertyAsync(); /// /// Sets whether the window can be manually maximized by user. On Linux does nothing. /// /// - public void SetMaximizable(bool maximizable) - { - BridgeConnector.Socket.Emit("browserWindowSetMaximizable", Id, maximizable); - } + public void SetMaximizable(bool maximizable) => this.CallMethod1(maximizable); /// /// Whether the window can be manually maximized by user. @@ -958,57 +668,25 @@ public void SetMaximizable(bool maximizable) /// On Linux always returns true. /// /// On Linux always returns true. - public Task IsMaximizableAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-isMaximizable-completed", (maximizable) => { - BridgeConnector.Socket.Off("browserWindow-isMaximizable-completed"); - - taskCompletionSource.SetResult((bool)maximizable); - }); - - BridgeConnector.Socket.Emit("browserWindowIsMaximizable", Id); - - return taskCompletionSource.Task; - } + public Task IsMaximizableAsync() => this.GetPropertyAsync(); /// /// Sets whether the maximize/zoom window button toggles fullscreen mode or maximizes the window. /// /// - public void SetFullScreenable(bool fullscreenable) - { - BridgeConnector.Socket.Emit("browserWindowSetFullScreenable", Id, fullscreenable); - } + public void SetFullScreenable(bool fullscreenable) => this.CallMethod1(fullscreenable); /// /// Whether the maximize/zoom window button toggles fullscreen mode or maximizes the window. /// /// - public Task IsFullScreenableAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-isFullScreenable-completed", (fullscreenable) => { - BridgeConnector.Socket.Off("browserWindow-isFullScreenable-completed"); - - taskCompletionSource.SetResult((bool)fullscreenable); - }); - - BridgeConnector.Socket.Emit("browserWindowIsFullScreenable", Id); - - return taskCompletionSource.Task; - } + public Task IsFullScreenableAsync() => this.GetPropertyAsync(); /// /// Sets whether the window can be manually closed by user. On Linux does nothing. /// /// - public void SetClosable(bool closable) - { - BridgeConnector.Socket.Emit("browserWindowSetClosable", Id, closable); - } + public void SetClosable(bool closable) => this.CallMethod1(closable); /// /// Whether the window can be manually closed by user. @@ -1016,20 +694,7 @@ public void SetClosable(bool closable) /// On Linux always returns true. /// /// On Linux always returns true. - public Task IsClosableAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-isClosable-completed", (closable) => { - BridgeConnector.Socket.Off("browserWindow-isClosable-completed"); - - taskCompletionSource.SetResult((bool)closable); - }); - - BridgeConnector.Socket.Emit("browserWindowIsClosable", Id); - - return taskCompletionSource.Task; - } + public Task IsClosableAsync() => this.GetPropertyAsync(); /// /// Sets whether the window should show always on top of other windows. @@ -1037,10 +702,7 @@ public Task IsClosableAsync() /// window which can not be focused on. /// /// - public void SetAlwaysOnTop(bool flag) - { - BridgeConnector.Socket.Emit("browserWindowSetAlwaysOnTop", Id, flag); - } + public void SetAlwaysOnTop(bool flag) => this.CallMethod1(flag); /// /// Sets whether the window should show always on top of other windows. @@ -1051,10 +713,7 @@ public void SetAlwaysOnTop(bool flag) /// Values include normal, floating, torn-off-menu, modal-panel, main-menu, /// status, pop-up-menu and screen-saver. The default is floating. /// See the macOS docs - public void SetAlwaysOnTop(bool flag, OnTopLevel level) - { - BridgeConnector.Socket.Emit("browserWindowSetAlwaysOnTop", Id, flag, level.GetDescription()); - } + public void SetAlwaysOnTop(bool flag, OnTopLevel level) => this.CallMethod2(flag, level.GetDescription()); /// /// Sets whether the window should show always on top of other windows. @@ -1067,37 +726,18 @@ public void SetAlwaysOnTop(bool flag, OnTopLevel level) /// See the macOS docs /// The number of layers higher to set this window relative to the given level. /// The default is 0. Note that Apple discourages setting levels higher than 1 above screen-saver. - public void SetAlwaysOnTop(bool flag, OnTopLevel level, int relativeLevel) - { - BridgeConnector.Socket.Emit("browserWindowSetAlwaysOnTop", Id, flag, level.GetDescription(), relativeLevel); - } + public void SetAlwaysOnTop(bool flag, OnTopLevel level, int relativeLevel) => this.CallMethod3(flag, level.GetDescription(), relativeLevel); /// /// Whether the window is always on top of other windows. /// /// - public Task IsAlwaysOnTopAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-isAlwaysOnTop-completed", (isAlwaysOnTop) => { - BridgeConnector.Socket.Off("browserWindow-isAlwaysOnTop-completed"); - - taskCompletionSource.SetResult((bool)isAlwaysOnTop); - }); - - BridgeConnector.Socket.Emit("browserWindowIsAlwaysOnTop", Id); - - return taskCompletionSource.Task; - } + public Task IsAlwaysOnTopAsync() => this.GetPropertyAsync(); /// /// Moves window to the center of the screen. /// - public void Center() - { - BridgeConnector.Socket.Emit("browserWindowCenter", Id); - } + public void Center() => this.CallMethod0(); /// /// Moves window to x and y. @@ -1112,8 +752,7 @@ public void SetPosition(int x, int y) { x = x - 7; } - - BridgeConnector.Socket.Emit("browserWindowSetPosition", Id, x, y); + this.CallMethod2(x, y); } /// @@ -1130,8 +769,7 @@ public void SetPosition(int x, int y, bool animate) { x = x - 7; } - - BridgeConnector.Socket.Emit("browserWindowSetPosition", Id, x, y, animate); + this.CallMethod3(x, y, animate); } private bool isWindows10() @@ -1143,29 +781,13 @@ private bool isWindows10() /// Contains the window’s current position. /// /// - public Task GetPositionAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-getPosition-completed", (position) => { - BridgeConnector.Socket.Off("browserWindow-getPosition-completed"); - - taskCompletionSource.SetResult(((JArray)position).ToObject()); - }); - - BridgeConnector.Socket.Emit("browserWindowGetPosition", Id); - - return taskCompletionSource.Task; - } + public Task GetPositionAsync() => this.GetPropertyAsync(); /// /// Changes the title of native window to title. /// /// - public void SetTitle(string title) - { - BridgeConnector.Socket.Emit("browserWindowSetTitle", Id, title); - } + public void SetTitle(string title) => this.CallMethod1(title); /// /// The title of the native window. @@ -1173,20 +795,7 @@ public void SetTitle(string title) /// Note: The title of web page can be different from the title of the native window. /// /// - public Task GetTitleAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-getTitle-completed", (title) => { - BridgeConnector.Socket.Off("browserWindow-getTitle-completed"); - - taskCompletionSource.SetResult(title.ToString()); - }); - - BridgeConnector.Socket.Emit("browserWindowGetTitle", Id); - - return taskCompletionSource.Task; - } + public Task GetTitleAsync() => this.GetPropertyAsync(); /// /// Changes the attachment point for sheets on macOS. @@ -1194,10 +803,7 @@ public Task GetTitleAsync() /// but you may want to display them beneath a HTML-rendered toolbar. /// /// - public void SetSheetOffset(float offsetY) - { - BridgeConnector.Socket.Emit("browserWindowSetSheetOffset", Id, offsetY); - } + public void SetSheetOffset(float offsetY) => this.CallMethod1(offsetY); /// /// Changes the attachment point for sheets on macOS. @@ -1206,159 +812,80 @@ public void SetSheetOffset(float offsetY) /// /// /// - public void SetSheetOffset(float offsetY, float offsetX) - { - BridgeConnector.Socket.Emit("browserWindowSetSheetOffset", Id, offsetY, offsetX); - } + public void SetSheetOffset(float offsetY, float offsetX) => this.CallMethod2(offsetY, offsetX); /// /// Starts or stops flashing the window to attract user’s attention. /// /// - public void FlashFrame(bool flag) - { - BridgeConnector.Socket.Emit("browserWindowFlashFrame", Id, flag); - } + public void FlashFrame(bool flag) => this.CallMethod1(flag); /// /// Makes the window not show in the taskbar. /// /// - public void SetSkipTaskbar(bool skip) - { - BridgeConnector.Socket.Emit("browserWindowSetSkipTaskbar", Id, skip); - } + public void SetSkipTaskbar(bool skip) => this.CallMethod1(skip); /// /// Enters or leaves the kiosk mode. /// /// - public void SetKiosk(bool flag) - { - BridgeConnector.Socket.Emit("browserWindowSetKiosk", Id, flag); - } + public void SetKiosk(bool flag) => this.CallMethod1(flag); /// /// Whether the window is in kiosk mode. /// /// - public Task IsKioskAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-isKiosk-completed", (isKiosk) => { - BridgeConnector.Socket.Off("browserWindow-isKiosk-completed"); - - taskCompletionSource.SetResult((bool)isKiosk); - }); - - BridgeConnector.Socket.Emit("browserWindowIsKiosk", Id); - - return taskCompletionSource.Task; - } + public Task IsKioskAsync() => this.GetPropertyAsync(); /// /// Returns the native type of the handle is HWND on Windows, NSView* on macOS, and Window (unsigned long) on Linux. /// /// string of the native handle obtained, HWND on Windows, NSView* on macOS, and Window (unsigned long) on Linux. - public Task GetNativeWindowHandle() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-getNativeWindowHandle-completed", (nativeWindowHandle) => - { - BridgeConnector.Socket.Off("browserWindow-getNativeWindowHandle-completed"); - taskCompletionSource.SetResult(nativeWindowHandle.ToString()); - }); - - BridgeConnector.Socket.Emit("browserWindowGetNativeWindowHandle", Id); - - return taskCompletionSource.Task; - } + public Task GetNativeWindowHandle() => this.GetPropertyAsync(); /// /// Sets the pathname of the file the window represents, /// and the icon of the file will show in window’s title bar. /// /// - public void SetRepresentedFilename(string filename) - { - BridgeConnector.Socket.Emit("browserWindowSetRepresentedFilename", Id, filename); - } + public void SetRepresentedFilename(string filename) => this.CallMethod1(filename); /// /// The pathname of the file the window represents. /// /// - public Task GetRepresentedFilenameAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-getRepresentedFilename-completed", (pathname) => { - BridgeConnector.Socket.Off("browserWindow-getRepresentedFilename-completed"); - - taskCompletionSource.SetResult(pathname.ToString()); - }); - - BridgeConnector.Socket.Emit("browserWindowGetRepresentedFilename", Id); - - return taskCompletionSource.Task; - } + public Task GetRepresentedFilenameAsync() => this.GetPropertyAsync(); /// /// Specifies whether the window’s document has been edited, /// and the icon in title bar will become gray when set to true. /// /// - public void SetDocumentEdited(bool edited) - { - BridgeConnector.Socket.Emit("browserWindowSetDocumentEdited", Id, edited); - } + public void SetDocumentEdited(bool edited) => this.CallMethod1(edited); /// /// Whether the window’s document has been edited. /// /// - public Task IsDocumentEditedAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-isDocumentEdited-completed", (edited) => { - BridgeConnector.Socket.Off("browserWindow-isDocumentEdited-completed"); - - taskCompletionSource.SetResult((bool)edited); - }); - - BridgeConnector.Socket.Emit("browserWindowIsDocumentEdited", Id); - - return taskCompletionSource.Task; - } + public Task IsDocumentEditedAsync() => this.GetPropertyAsync(); /// /// Focuses the on web view. /// - public void FocusOnWebView() - { - BridgeConnector.Socket.Emit("browserWindowFocusOnWebView", Id); - } + public void FocusOnWebView() => this.CallMethod0(); /// /// Blurs the web view. /// - public void BlurWebView() - { - BridgeConnector.Socket.Emit("browserWindowBlurWebView", Id); - } + public void BlurWebView() => this.CallMethod0(); /// /// The url can be a remote address (e.g. http://) or /// a path to a local HTML file using the file:// protocol. /// /// - public void LoadURL(string url) - { - BridgeConnector.Socket.Emit("browserWindowLoadURL", Id, url); - } + public void LoadURL(string url) => this.CallMethod1(url); /// /// The url can be a remote address (e.g. http://) or @@ -1366,18 +893,12 @@ public void LoadURL(string url) /// /// /// - public void LoadURL(string url, LoadURLOptions options) - { - BridgeConnector.Socket.Emit("browserWindowLoadURL", Id, url, JObject.FromObject(options, _jsonSerializer)); - } + public void LoadURL(string url, LoadURLOptions options) => this.CallMethod2(url, JObject.FromObject(options, _jsonSerializer)); /// /// Same as webContents.reload. /// - public void Reload() - { - BridgeConnector.Socket.Emit("browserWindowReload", Id); - } + public void Reload() => this.CallMethod0(); /// /// Gets the menu items. @@ -1396,11 +917,12 @@ public void Reload() public void SetMenu(MenuItem[] menuItems) { menuItems.AddMenuItemsId(); - BridgeConnector.Socket.Emit("browserWindowSetMenu", Id, JArray.FromObject(menuItems, _jsonSerializer)); + this.CallMethod1(JArray.FromObject(menuItems, _jsonSerializer)); _items.AddRange(menuItems); BridgeConnector.Socket.Off("windowMenuItemClicked"); - BridgeConnector.Socket.On("windowMenuItemClicked", (id) => { + BridgeConnector.Socket.On("windowMenuItemClicked", (id) => + { MenuItem menuItem = _items.GetMenuItem(id.ToString()); menuItem?.Click(); }); @@ -1409,10 +931,7 @@ public void SetMenu(MenuItem[] menuItems) /// /// Remove the window's menu bar. /// - public void RemoveMenu() - { - BridgeConnector.Socket.Emit("browserWindowRemoveMenu", Id); - } + public void RemoveMenu() => this.CallMethod0(); /// /// Sets progress value in progress bar. Valid range is [0, 1.0]. Remove progress @@ -1425,10 +944,7 @@ public void RemoveMenu() /// assumed. /// /// - public void SetProgressBar(double progress) - { - BridgeConnector.Socket.Emit("browserWindowSetProgressBar", Id, progress); - } + public void SetProgressBar(double progress) => this.CallMethod1(progress); /// /// Sets progress value in progress bar. Valid range is [0, 1.0]. Remove progress @@ -1442,19 +958,14 @@ public void SetProgressBar(double progress) /// /// /// - public void SetProgressBar(double progress, ProgressBarOptions progressBarOptions) - { - BridgeConnector.Socket.Emit("browserWindowSetProgressBar", Id, progress, JObject.FromObject(progressBarOptions, _jsonSerializer)); - } + public void SetProgressBar(double progress, ProgressBarOptions progressBarOptions) => + this.CallMethod2(progress, JObject.FromObject(progressBarOptions, _jsonSerializer)); /// /// Sets whether the window should have a shadow. On Windows and Linux does nothing. /// /// - public void SetHasShadow(bool hasShadow) - { - BridgeConnector.Socket.Emit("browserWindowSetHasShadow", Id, hasShadow); - } + public void SetHasShadow(bool hasShadow) => this.CallMethod1(hasShadow); /// /// Whether the window has a shadow. @@ -1462,20 +973,7 @@ public void SetHasShadow(bool hasShadow) /// On Windows and Linux always returns true. /// /// - public Task HasShadowAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-hasShadow-completed", (hasShadow) => { - BridgeConnector.Socket.Off("browserWindow-hasShadow-completed"); - - taskCompletionSource.SetResult((bool)hasShadow); - }); - - BridgeConnector.Socket.Emit("browserWindowHasShadow", Id); - - return taskCompletionSource.Task; - } + public Task HasShadowAsync() => this.GetPropertyAsync(); /// /// Gets the thumbar buttons. @@ -1502,7 +1000,8 @@ public Task SetThumbarButtonsAsync(ThumbarButton[] thumbarButtons) { var taskCompletionSource = new TaskCompletionSource(); - BridgeConnector.Socket.On("browserWindowSetThumbarButtons-completed", (success) => { + BridgeConnector.Socket.On("browserWindowSetThumbarButtons-completed", (success) => + { BridgeConnector.Socket.Off("browserWindowSetThumbarButtons-completed"); taskCompletionSource.SetResult((bool)success); @@ -1514,7 +1013,8 @@ public Task SetThumbarButtonsAsync(ThumbarButton[] thumbarButtons) _thumbarButtons.AddRange(thumbarButtons); BridgeConnector.Socket.Off("thumbarButtonClicked"); - BridgeConnector.Socket.On("thumbarButtonClicked", (id) => { + BridgeConnector.Socket.On("thumbarButtonClicked", (id) => + { ThumbarButton thumbarButton = _thumbarButtons.GetThumbarButton(id.ToString()); thumbarButton?.Click(); }); @@ -1528,19 +1028,13 @@ public Task SetThumbarButtonsAsync(ThumbarButton[] thumbarButtons) /// an empty region: {x: 0, y: 0, width: 0, height: 0}. /// /// - public void SetThumbnailClip(Rectangle rectangle) - { - BridgeConnector.Socket.Emit("browserWindowSetThumbnailClip", Id, rectangle); - } + public void SetThumbnailClip(Rectangle rectangle) => this.CallMethod1(rectangle); /// /// Sets the toolTip that is displayed when hovering over the window thumbnail in the taskbar. /// /// - public void SetThumbnailToolTip(string tooltip) - { - BridgeConnector.Socket.Emit("browserWindowSetThumbnailToolTip", Id, tooltip); - } + public void SetThumbnailToolTip(string tooltip) => this.CallMethod1(tooltip); /// /// Sets the properties for the window’s taskbar button. @@ -1549,18 +1043,12 @@ public void SetThumbnailToolTip(string tooltip) /// If one of those properties is not set, then neither will be used. /// /// - public void SetAppDetails(AppDetailsOptions options) - { - BridgeConnector.Socket.Emit("browserWindowSetAppDetails", Id, JObject.FromObject(options, _jsonSerializer)); - } + public void SetAppDetails(AppDetailsOptions options) => this.CallMethod1(JObject.FromObject(options, _jsonSerializer)); /// /// Same as webContents.showDefinitionForSelection(). /// - public void ShowDefinitionForSelection() - { - BridgeConnector.Socket.Emit("browserWindowShowDefinitionForSelection", Id); - } + public void ShowDefinitionForSelection() => this.CallMethod0(); /// /// Sets whether the window menu bar should hide itself automatically. @@ -1569,58 +1057,26 @@ public void ShowDefinitionForSelection() /// If the menu bar is already visible, calling setAutoHideMenuBar(true) won’t hide it immediately. /// /// - public void SetAutoHideMenuBar(bool hide) - { - BridgeConnector.Socket.Emit("browserWindowSetAutoHideMenuBar", Id, hide); - } + public void SetAutoHideMenuBar(bool hide) => this.CallMethod1(hide); /// /// Whether menu bar automatically hides itself. /// /// - public Task IsMenuBarAutoHideAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-isMenuBarAutoHide-completed", (isMenuBarAutoHide) => { - BridgeConnector.Socket.Off("browserWindow-isMenuBarAutoHide-completed"); - - taskCompletionSource.SetResult((bool)isMenuBarAutoHide); - }); - - BridgeConnector.Socket.Emit("browserWindowIsMenuBarAutoHide", Id); - - return taskCompletionSource.Task; - } + public Task IsMenuBarAutoHideAsync() => this.GetPropertyAsync(); /// /// Sets whether the menu bar should be visible. If the menu bar is auto-hide, /// users can still bring up the menu bar by pressing the single Alt key. /// /// - public void SetMenuBarVisibility(bool visible) - { - BridgeConnector.Socket.Emit("browserWindowSetMenuBarVisibility", Id, visible); - } + public void SetMenuBarVisibility(bool visible) => this.CallMethod1(visible); /// /// Whether the menu bar is visible. /// /// - public Task IsMenuBarVisibleAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-isMenuBarVisible-completed", (isMenuBarVisible) => { - BridgeConnector.Socket.Off("browserWindow-isMenuBarVisible-completed"); - - taskCompletionSource.SetResult((bool)isMenuBarVisible); - }); - - BridgeConnector.Socket.Emit("browserWindowIsMenuBarVisible", Id); - - return taskCompletionSource.Task; - } + public Task IsMenuBarVisibleAsync() => this.GetPropertyAsync(); /// /// Sets whether the window should be visible on all workspaces. @@ -1628,10 +1084,7 @@ public Task IsMenuBarVisibleAsync() /// Note: This API does nothing on Windows. /// /// - public void SetVisibleOnAllWorkspaces(bool visible) - { - BridgeConnector.Socket.Emit("browserWindowSetVisibleOnAllWorkspaces", Id, visible); - } + public void SetVisibleOnAllWorkspaces(bool visible) => this.CallMethod1(visible); /// /// Whether the window is visible on all workspaces. @@ -1639,20 +1092,7 @@ public void SetVisibleOnAllWorkspaces(bool visible) /// Note: This API always returns false on Windows. /// /// - public Task IsVisibleOnAllWorkspacesAsync() - { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-isVisibleOnAllWorkspaces-completed", (isVisibleOnAllWorkspaces) => { - BridgeConnector.Socket.Off("browserWindow-isVisibleOnAllWorkspaces-completed"); - - taskCompletionSource.SetResult((bool)isVisibleOnAllWorkspaces); - }); - - BridgeConnector.Socket.Emit("browserWindowIsVisibleOnAllWorkspaces", Id); - - return taskCompletionSource.Task; - } + public Task IsVisibleOnAllWorkspacesAsync() => this.GetPropertyAsync(); /// /// Makes the window ignore all mouse events. @@ -1661,10 +1101,7 @@ public Task IsVisibleOnAllWorkspacesAsync() /// below this window, but if this window has focus, it will still receive keyboard events. /// /// - public void SetIgnoreMouseEvents(bool ignore) - { - BridgeConnector.Socket.Emit("browserWindowSetIgnoreMouseEvents", Id, ignore); - } + public void SetIgnoreMouseEvents(bool ignore) => this.CallMethod1(ignore); /// /// Prevents the window contents from being captured by other apps. @@ -1673,87 +1110,55 @@ public void SetIgnoreMouseEvents(bool ignore) /// On Windows it calls SetWindowDisplayAffinity with WDA_MONITOR. /// /// - public void SetContentProtection(bool enable) - { - BridgeConnector.Socket.Emit("browserWindowSetContentProtection", Id, enable); - } + public void SetContentProtection(bool enable) => this.CallMethod1(enable); /// /// Changes whether the window can be focused. /// /// - public void SetFocusable(bool focusable) - { - BridgeConnector.Socket.Emit("browserWindowSetFocusable", Id, focusable); - } + public void SetFocusable(bool focusable) => this.CallMethod1(focusable); /// /// Sets parent as current window’s parent window, /// passing null will turn current window into a top-level window. /// /// - public void SetParentWindow(BrowserWindow parent) - { - BridgeConnector.Socket.Emit("browserWindowSetParentWindow", Id, JObject.FromObject(parent, _jsonSerializer)); - } + public void SetParentWindow(BrowserWindow parent) => this.CallMethod1(JObject.FromObject(parent, _jsonSerializer)); /// /// The parent window. /// /// - public Task GetParentWindowAsync() + public async Task GetParentWindowAsync() { - var taskCompletionSource = new TaskCompletionSource(); - - BridgeConnector.Socket.On("browserWindow-getParentWindow-completed", (id) => { - BridgeConnector.Socket.Off("browserWindow-getParentWindow-completed"); - var browserWindowId = int.Parse(id.ToString()); - var browserWindow = Electron.WindowManager.BrowserWindows.ToList().Single(x => x.Id == browserWindowId); - - taskCompletionSource.SetResult(browserWindow); - }); - - BridgeConnector.Socket.Emit("browserWindowGetParentWindow", Id); - - return taskCompletionSource.Task; + var browserWindowId = await this.GetPropertyAsync().ConfigureAwait(false); + var browserWindow = Electron.WindowManager.BrowserWindows.ToList().Single(x => x.Id == browserWindowId); + return browserWindow; } /// /// All child windows. /// /// - public Task> GetChildWindowsAsync() + public async Task> GetChildWindowsAsync() { - var taskCompletionSource = new TaskCompletionSource>(); - - BridgeConnector.Socket.On("browserWindow-getChildWindows-completed", (ids) => { - BridgeConnector.Socket.Off("browserWindow-getChildWindows-completed"); - var browserWindowIds = ((JArray)ids).ToObject(); - var browserWindows = new List(); - - browserWindowIds.ToList().ForEach(id => - { - var browserWindow = Electron.WindowManager.BrowserWindows.ToList().Single(x => x.Id == id); - browserWindows.Add(browserWindow); - }); - + var browserWindowIds = await this.GetPropertyAsync().ConfigureAwait(false); + var browserWindows = new List(); - taskCompletionSource.SetResult(browserWindows); - }); - - BridgeConnector.Socket.Emit("browserWindowGetChildWindows", Id); + foreach (var id in browserWindowIds) + { + var browserWindow = Electron.WindowManager.BrowserWindows.ToList().Single(x => x.Id == id); + browserWindows.Add(browserWindow); + } - return taskCompletionSource.Task; + return browserWindows; } /// /// Controls whether to hide cursor when typing. /// /// - public void SetAutoHideCursor(bool autoHide) - { - BridgeConnector.Socket.Emit("browserWindowSetAutoHideCursor", Id, autoHide); - } + public void SetAutoHideCursor(bool autoHide) => this.CallMethod1(autoHide); /// /// Adds a vibrancy effect to the browser window. @@ -1762,10 +1167,7 @@ public void SetAutoHideCursor(bool autoHide) /// Can be appearance-based, light, dark, titlebar, selection, /// menu, popover, sidebar, medium-light or ultra-dark. /// See the macOS documentation for more details. - public void SetVibrancy(Vibrancy type) - { - BridgeConnector.Socket.Emit("browserWindowSetVibrancy", Id, type.GetDescription()); - } + public void SetVibrancy(Vibrancy type) => this.CallMethod1(type.GetDescription()); /// /// Render and control web pages. @@ -1780,6 +1182,7 @@ public void SetVibrancy(Vibrancy type) /// public void SetBrowserView(BrowserView browserView) { + // This message name does not match the default ApiBase naming convention. BridgeConnector.Socket.Emit("browserWindow-setBrowserView", Id, browserView.Id); } diff --git a/src/ElectronNET.API/Bridge/SocketIOFacade.cs b/src/ElectronNET.API/Bridge/SocketIOFacade.cs index c3815d65..64324179 100644 --- a/src/ElectronNET.API/Bridge/SocketIOFacade.cs +++ b/src/ElectronNET.API/Bridge/SocketIOFacade.cs @@ -12,6 +12,7 @@ namespace ElectronNET.API; internal class SocketIoFacade { private readonly SocketIO _socket; + private readonly object _lockObj = new object(); public SocketIoFacade(string uri) { @@ -54,53 +55,71 @@ public void Connect() public void On(string eventName, Action action) { - _socket.On(eventName, _ => + lock (_lockObj) { - Task.Run(action); - }); + _socket.On(eventName, _ => + { + Task.Run(action); + }); + } } public void On(string eventName, Action action) { - _socket.On(eventName, response => + lock (_lockObj) { - var value = response.GetValue(); - Task.Run(() => action(value)); - }); + _socket.On(eventName, response => + { + var value = response.GetValue(); + Task.Run(() => action(value)); + }); + } } // TODO: Remove this method when SocketIoClient supports object deserialization public void On(string eventName, Action action) { - _socket.On(eventName, response => + lock (_lockObj) { - var value = response.GetValue(); - ////Console.WriteLine($"Called Event {eventName} - data {value}"); - Task.Run(() => action(value)); - }); + _socket.On(eventName, response => + { + var value = response.GetValue(); + ////Console.WriteLine($"Called Event {eventName} - data {value}"); + Task.Run(() => action(value)); + }); + } } public void Once(string eventName, Action action) { - _socket.On(eventName, _ => + lock (_lockObj) { - _socket.Off(eventName); - Task.Run(action); - }); + _socket.On(eventName, _ => + { + _socket.Off(eventName); + Task.Run(action); + }); + } } public void Once(string eventName, Action action) { - _socket.On(eventName, (socketIoResponse) => + lock (_lockObj) { - _socket.Off(eventName); - Task.Run(() => action(socketIoResponse.GetValue())); - }); + _socket.On(eventName, (socketIoResponse) => + { + _socket.Off(eventName); + Task.Run(() => action(socketIoResponse.GetValue())); + }); + } } public void Off(string eventName) { - _socket.Off(eventName); + lock (_lockObj) + { + _socket.Off(eventName); + } } public async Task Emit(string eventName, params object[] args) diff --git a/src/ElectronNET.API/Common/Extensions.cs b/src/ElectronNET.API/Common/Extensions.cs index 8d9a90aa..1fcaa530 100644 --- a/src/ElectronNET.API/Common/Extensions.cs +++ b/src/ElectronNET.API/Common/Extensions.cs @@ -1,11 +1,10 @@ namespace ElectronNET.Common { using System; - using System.Collections.Immutable; using ElectronNET.Runtime.Data; using ElectronNET.Runtime.Services; - public static class Extensions + internal static class Extensions { public static bool IsUnpackaged(this StartupMethod method) { @@ -19,6 +18,38 @@ public static bool IsUnpackaged(this StartupMethod method) } } + public static string LowerFirst(this string str) + { + if (string.IsNullOrWhiteSpace(str)) + { + return str; + } + + if (str.Length == 1) + { + return str.ToLower(); + } + + return char.ToLower(str[0]) + str.Substring(1); + } + + public static string StripAsync(this string str) + { + if (string.IsNullOrWhiteSpace(str)) + { + return str; + } + + var pos = str.LastIndexOf("Async", StringComparison.Ordinal); + + if (pos > 0) + { + return str.Substring(0, pos); + } + + return str; + } + public static bool IsReady(this LifetimeServiceBase service) { return service != null && service.State == LifetimeState.Ready;