From 1b14bb0fe56c24330c9d38d3c19ead4da27d2281 Mon Sep 17 00:00:00 2001 From: Daniel Gidman Date: Mon, 6 Dec 2021 16:44:31 -0600 Subject: [PATCH 1/9] Convert main static references off of `Electron` into interface implementation and expose the underlying Socket for low level interaction. --- ElectronNET.API/App.cs | 3 +- ElectronNET.API/ApplicationSocket.cs | 16 + ElectronNET.API/AutoUpdater.cs | 3 +- ElectronNET.API/Clipboard.cs | 3 +- ElectronNET.API/Dialog.cs | 3 +- ElectronNET.API/Dock.cs | 3 +- ElectronNET.API/ElectronNET.API.csproj | 0 ElectronNET.API/GlobalShortcut.cs | 3 +- ElectronNET.API/HostHook.cs | 3 +- ElectronNET.API/Interfaces/IApp.cs | 713 ++++++++++++++++++ .../Interfaces/IApplicationSocket.cs | 15 + ElectronNET.API/Interfaces/IAutoUpdater.cs | 146 ++++ ElectronNET.API/Interfaces/IClipboard.cs | 122 +++ ElectronNET.API/Interfaces/IDialog.cs | 102 +++ ElectronNET.API/Interfaces/IDock.cs | 93 +++ ElectronNET.API/Interfaces/IGlobalShortcut.cs | 39 + ElectronNET.API/Interfaces/IHostHook.cs | 30 + ElectronNET.API/Interfaces/IIpcMain.cs | 65 ++ ElectronNET.API/Interfaces/IMenu.cs | 47 ++ ElectronNET.API/Interfaces/INativeTheme.cs | 101 +++ ElectronNET.API/Interfaces/INotification.cs | 23 + ElectronNET.API/Interfaces/IPowerMonitor.cs | 48 ++ ElectronNET.API/Interfaces/IScreen.cs | 66 ++ ElectronNET.API/Interfaces/IShell.cs | 70 ++ ElectronNET.API/Interfaces/ITray.cs | 141 ++++ ElectronNET.API/Interfaces/IWindowManager.cs | 68 ++ ElectronNET.API/IpcMain.cs | 3 +- ElectronNET.API/Menu.cs | 3 +- ElectronNET.API/NativeTheme.cs | 3 +- ElectronNET.API/Notification.cs | 3 +- ElectronNET.API/PowerMonitor.cs | 3 +- ElectronNET.API/Screen.cs | 3 +- .../ServiceCollectionExtensions.cs | 25 +- ElectronNET.API/Shell.cs | 3 +- ElectronNET.API/Tray.cs | 3 +- ElectronNET.API/WindowManager.cs | 3 +- 36 files changed, 1960 insertions(+), 18 deletions(-) mode change 100644 => 100755 ElectronNET.API/App.cs create mode 100755 ElectronNET.API/ApplicationSocket.cs mode change 100644 => 100755 ElectronNET.API/AutoUpdater.cs mode change 100644 => 100755 ElectronNET.API/Clipboard.cs mode change 100644 => 100755 ElectronNET.API/Dialog.cs mode change 100644 => 100755 ElectronNET.API/Dock.cs mode change 100644 => 100755 ElectronNET.API/ElectronNET.API.csproj mode change 100644 => 100755 ElectronNET.API/GlobalShortcut.cs mode change 100644 => 100755 ElectronNET.API/HostHook.cs create mode 100755 ElectronNET.API/Interfaces/IApp.cs create mode 100755 ElectronNET.API/Interfaces/IApplicationSocket.cs create mode 100755 ElectronNET.API/Interfaces/IAutoUpdater.cs create mode 100755 ElectronNET.API/Interfaces/IClipboard.cs create mode 100755 ElectronNET.API/Interfaces/IDialog.cs create mode 100755 ElectronNET.API/Interfaces/IDock.cs create mode 100755 ElectronNET.API/Interfaces/IGlobalShortcut.cs create mode 100755 ElectronNET.API/Interfaces/IHostHook.cs create mode 100755 ElectronNET.API/Interfaces/IIpcMain.cs create mode 100755 ElectronNET.API/Interfaces/IMenu.cs create mode 100755 ElectronNET.API/Interfaces/INativeTheme.cs create mode 100755 ElectronNET.API/Interfaces/INotification.cs create mode 100755 ElectronNET.API/Interfaces/IPowerMonitor.cs create mode 100755 ElectronNET.API/Interfaces/IScreen.cs create mode 100755 ElectronNET.API/Interfaces/IShell.cs create mode 100755 ElectronNET.API/Interfaces/ITray.cs create mode 100755 ElectronNET.API/Interfaces/IWindowManager.cs mode change 100644 => 100755 ElectronNET.API/IpcMain.cs mode change 100644 => 100755 ElectronNET.API/Menu.cs mode change 100644 => 100755 ElectronNET.API/NativeTheme.cs mode change 100644 => 100755 ElectronNET.API/Notification.cs mode change 100644 => 100755 ElectronNET.API/PowerMonitor.cs mode change 100644 => 100755 ElectronNET.API/Screen.cs mode change 100644 => 100755 ElectronNET.API/ServiceCollectionExtensions.cs mode change 100644 => 100755 ElectronNET.API/Shell.cs mode change 100644 => 100755 ElectronNET.API/Tray.cs mode change 100644 => 100755 ElectronNET.API/WindowManager.cs diff --git a/ElectronNET.API/App.cs b/ElectronNET.API/App.cs old mode 100644 new mode 100755 index 69d8722c..31926206 --- a/ElectronNET.API/App.cs +++ b/ElectronNET.API/App.cs @@ -7,13 +7,14 @@ using System.Threading; using System.Threading.Tasks; using ElectronNET.API.Extensions; +using ElectronNET.API.Interfaces; namespace ElectronNET.API { /// /// Control your application's event lifecycle. /// - public sealed class App + public sealed class App : IApp { /// /// Emitted when all windows have been closed. diff --git a/ElectronNET.API/ApplicationSocket.cs b/ElectronNET.API/ApplicationSocket.cs new file mode 100755 index 00000000..7480b802 --- /dev/null +++ b/ElectronNET.API/ApplicationSocket.cs @@ -0,0 +1,16 @@ +using ElectronNET.API.Interfaces; +using Quobject.SocketIoClientDotNet.Client; + +namespace ElectronNET.API +{ + /// + /// Wrapper for the underlying Socket connection + /// + public class ApplicationSocket : IApplicationSocket + { + /// + /// Socket used to communicate with main.js + /// + public Socket Socket { get; internal set; } + } +} diff --git a/ElectronNET.API/AutoUpdater.cs b/ElectronNET.API/AutoUpdater.cs old mode 100644 new mode 100755 index da1001fa..cf6a85d0 --- a/ElectronNET.API/AutoUpdater.cs +++ b/ElectronNET.API/AutoUpdater.cs @@ -5,13 +5,14 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using ElectronNET.API.Interfaces; namespace ElectronNET.API { /// /// Enable apps to automatically update themselves. Based on electron-updater. /// - public sealed class AutoUpdater + public sealed class AutoUpdater : IAutoUpdater { /// /// Whether to automatically download an update when it is found. (Default is true) diff --git a/ElectronNET.API/Clipboard.cs b/ElectronNET.API/Clipboard.cs old mode 100644 new mode 100755 index e7535378..e8a70d4e --- a/ElectronNET.API/Clipboard.cs +++ b/ElectronNET.API/Clipboard.cs @@ -3,13 +3,14 @@ using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; using System.Threading.Tasks; +using ElectronNET.API.Interfaces; namespace ElectronNET.API { /// /// Perform copy and paste operations on the system clipboard. /// - public sealed class Clipboard + public sealed class Clipboard : IClipboard { private static Clipboard _clipboard; private static object _syncRoot = new object(); diff --git a/ElectronNET.API/Dialog.cs b/ElectronNET.API/Dialog.cs old mode 100644 new mode 100755 index 7b626b4e..a68810a3 --- a/ElectronNET.API/Dialog.cs +++ b/ElectronNET.API/Dialog.cs @@ -6,13 +6,14 @@ using System.Collections.Generic; using System.Threading.Tasks; using System.Web; +using ElectronNET.API.Interfaces; namespace ElectronNET.API { /// /// Display native system dialogs for opening and saving files, alerting, etc. /// - public sealed class Dialog + public sealed class Dialog : IDialog { private static Dialog _dialog; private static object _syncRoot = new object(); diff --git a/ElectronNET.API/Dock.cs b/ElectronNET.API/Dock.cs old mode 100644 new mode 100755 index 03276842..fa25d88a --- a/ElectronNET.API/Dock.cs +++ b/ElectronNET.API/Dock.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using ElectronNET.API.Entities; using ElectronNET.API.Extensions; +using ElectronNET.API.Interfaces; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; @@ -12,7 +13,7 @@ namespace ElectronNET.API /// /// Control your app in the macOS dock. /// - public sealed class Dock + public sealed class Dock : IDock { private static Dock _dock; private static object _syncRoot = new object(); diff --git a/ElectronNET.API/ElectronNET.API.csproj b/ElectronNET.API/ElectronNET.API.csproj old mode 100644 new mode 100755 diff --git a/ElectronNET.API/GlobalShortcut.cs b/ElectronNET.API/GlobalShortcut.cs old mode 100644 new mode 100755 index d2867ecd..0f6b522f --- a/ElectronNET.API/GlobalShortcut.cs +++ b/ElectronNET.API/GlobalShortcut.cs @@ -1,13 +1,14 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using ElectronNET.API.Interfaces; namespace ElectronNET.API { /// /// Detect keyboard events when the application does not have keyboard focus. /// - public sealed class GlobalShortcut + public sealed class GlobalShortcut : IGlobalShortcut { private static GlobalShortcut _globalShortcut; private static object _syncRoot = new object(); diff --git a/ElectronNET.API/HostHook.cs b/ElectronNET.API/HostHook.cs old mode 100644 new mode 100755 index 37606250..0470dcee --- a/ElectronNET.API/HostHook.cs +++ b/ElectronNET.API/HostHook.cs @@ -3,6 +3,7 @@ using Newtonsoft.Json.Serialization; using System; using System.Threading.Tasks; +using ElectronNET.API.Interfaces; namespace ElectronNET.API { @@ -13,7 +14,7 @@ namespace ElectronNET.API /// ElectronHostHook directory: /// electronize add HostHook /// - public sealed class HostHook + public sealed class HostHook : IHostHook { private static HostHook _electronHostHook; private static object _syncRoot = new object(); diff --git a/ElectronNET.API/Interfaces/IApp.cs b/ElectronNET.API/Interfaces/IApp.cs new file mode 100755 index 00000000..abaee747 --- /dev/null +++ b/ElectronNET.API/Interfaces/IApp.cs @@ -0,0 +1,713 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using ElectronNET.API.Entities; + +namespace ElectronNET.API.Interfaces +{ + /// + /// Control your application's event lifecycle. + /// + public interface IApp + { + /// + /// Emitted when all windows have been closed. + /// + /// If you do not subscribe to this event and all windows are closed, the default behavior is to quit + /// the app; however, if you subscribe, you control whether the app quits or not.If the user pressed + /// Cmd + Q, or the developer called , Electron will first try to close all the windows + /// and then emit the event, and in this case the event + /// would not be emitted. + /// + event Action WindowAllClosed; + + /// + /// Emitted before the application starts closing its windows. + /// + /// Note: If application quit was initiated by then + /// is emitted after emitting close event on all windows and closing them. + /// + /// Note: On Windows, this event will not be emitted if the app is closed due to a shutdown/restart of the system or a user logout. + /// + event Func BeforeQuit; + + /// + /// Emitted when all windows have been closed and the application will quit. + /// + /// See the description of the event for the differences between the + /// and events. + /// + /// Note: On Windows, this event will not be emitted if the app is closed due to a shutdown/restart of the system or a user logout. + /// + event Func WillQuit; + + /// + /// Emitted when the application is quitting. + /// + /// Note: On Windows, this event will not be emitted if the app is closed due to a shutdown/restart of the system or a user logout. + /// + event Func Quitting; + + /// + /// Emitted when a blurred. + /// + event Action BrowserWindowBlur; + + /// + /// Emitted when a gets focused. + /// + event Action BrowserWindowFocus; + + /// + /// Emitted when a new is created. + /// + event Action BrowserWindowCreated; + + /// + /// Emitted when a new is created. + /// + event Action WebContentsCreated; + + /// + /// Emitted when Chrome’s 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. + /// + /// when Chrome's accessibility support is enabled, otherwise. + event Action AccessibilitySupportChanged; + + /// + /// Emitted when the application has finished basic startup. + /// + event Action Ready; + + /// + /// Application host fully started. + /// + bool IsReady { get; } + + /// + /// A property that indicates the current application's name, which is the name in the + /// application's package.json file. + /// + /// Usually the name field of package.json is a short lowercase name, according to the npm modules spec. You + /// should usually also specify a productName field, which is your application's full capitalized name, and + /// which will be preferred over name by Electron. + /// + string Name + { + [Obsolete("Use the asynchronous version NameAsync instead")] + get; + set; + } + + /// + /// A property that indicates the current application's name, which is the name in the + /// application's package.json file. + /// + /// Usually the name field of package.json is a short lowercase name, according to the npm modules spec. You + /// should usually also specify a productName field, which is your application's full capitalized name, and + /// which will be preferred over name by Electron. + /// + Task NameAsync { get; } + + /// + /// A object that allows you to read and manipulate the command line arguments that Chromium uses. + /// + CommandLine CommandLine { get; } + + /// + /// A which is the user agent string Electron will use as a global fallback. + /// + /// This is the user agent that will be used when no user agent is set at the webContents or + /// session level. It is useful for ensuring that your entire app has the same user agent. Set to a + /// custom value as early as possible in your app's initialization to ensure that your overridden value + /// is used. + /// + string UserAgentFallback + { + [Obsolete("Use the asynchronous version UserAgentFallbackAsync instead")] + get; + set; + } + + /// + /// A which is the user agent string Electron will use as a global fallback. + /// + /// This is the user agent that will be used when no user agent is set at the webContents or + /// session level. It is useful for ensuring that your entire app has the same user agent. Set to a + /// custom value as early as possible in your app's initialization to ensure that your overridden value + /// is used. + /// + Task UserAgentFallbackAsync { get; } + + /// + /// Emitted when a MacOS user wants to open a file with the application. The open-file event is usually emitted + /// when the application is already open and the OS wants to reuse the application to open the file. + /// open-file is also emitted when a file is dropped onto the dock and the application is not yet running. + /// + /// On Windows, you have to parse the arguments using App.CommandLine to get the filepath. + /// + event Action OpenFile; + + /// + /// Emitted when a MacOS user wants to open a URL with the application. Your application's Info.plist file must + /// define the URL scheme within the CFBundleURLTypes key, and set NSPrincipalClass to AtomApplication. + /// + event Action OpenUrl; + + /// + /// Try to close all windows. The event will be emitted first. If all windows are successfully + /// closed, the event will be emitted and by default the application will terminate. This method + /// guarantees that all beforeunload and unload event handlers are correctly executed. It is possible + /// that a window cancels the quitting by returning in the beforeunload event handler. + /// + void Quit(); + + /// + /// All windows will be closed immediately without asking user and the and + /// events will not be emitted. + /// + /// Exits immediately with exitCode. exitCode defaults to 0. + void Exit(int exitCode = 0); + + /// + /// Relaunches the app when current instance exits. By default the new instance will use the same working directory + /// and command line arguments with current instance. + /// + /// Note that this method does not quit the app when executed, you have to call or + /// after calling to make the app restart. + /// + /// When is called for multiple times, multiple instances will be started after current instance + /// exited. + /// + void Relaunch(); + + /// + /// Relaunches the app when current instance exits. By default the new instance will use the same working directory + /// and command line arguments with current instance. When is specified, the + /// will be passed as command line arguments instead. When + /// is specified, the will be executed for relaunch instead of current app. + /// + /// Note that this method does not quit the app when executed, you have to call or + /// after calling to make the app restart. + /// + /// When is called for multiple times, multiple instances will be started after current instance + /// exited. + /// + /// Options for the relaunch. + void Relaunch(RelaunchOptions relaunchOptions); + + /// + /// On Linux, focuses on the first visible window. On macOS, makes the application the active app. On Windows, focuses + /// on the application's first window. + /// + void Focus(); + + /// + /// On Linux, focuses on the first visible window. On macOS, makes the application the active app. On Windows, focuses + /// on the application's first window. + /// + /// You should seek to use the option as sparingly as possible. + /// + void Focus(FocusOptions focusOptions); + + /// + /// Hides all application windows without minimizing them. + /// + void Hide(); + + /// + /// Shows application windows after they were hidden. Does not automatically focus them. + /// + void Show(); + + /// + /// The current application directory. + /// + Task GetAppPathAsync(CancellationToken cancellationToken = default); + + /// + /// Sets or creates a directory your app's logs which can then be manipulated with + /// or . + /// + /// Calling without a path parameter will result in this directory being set to + /// ~/Library/Logs/YourAppName on macOS, and inside the userData directory on Linux and Windows. + /// + /// A custom path for your logs. Must be absolute. + void SetAppLogsPath(string path); + + /// + /// The path to a special directory. If is called without called + /// being called first, a default directory will be created equivalent + /// to calling without a path parameter. + /// + /// Special directory. + /// The cancellation token. + /// A path to a special directory or file associated with name. + Task GetPathAsync(PathName pathName, CancellationToken cancellationToken = default); + + /// + /// Overrides the path to a special directory or file associated with name. If the path specifies a directory + /// that does not exist, an Error is thrown. In that case, the directory should be created with fs.mkdirSync or similar. + /// + /// You can only override paths of a name defined in . + /// + /// By default, web pages' cookies and caches will be stored under the directory. If you + /// want to change this location, you have to override the path before the + /// event of the module is emitted. + /// Special directory. + /// New path to a special directory. + /// + void SetPath(PathName name, string path); + + /// + /// The version of the loaded application. If no version is found in the application’s package.json file, + /// the version of the current bundle or executable is returned. + /// + /// The version of the loaded application. + Task GetVersionAsync(CancellationToken cancellationToken = default); + + /// + /// The current application locale. Possible return values are documented here. + /// + /// Note: When distributing your packaged app, you have to also ship the locales folder. + /// + /// Note: On Windows, you have to call it after the events gets emitted. + /// + /// The current application locale. + Task GetLocaleAsync(CancellationToken cancellationToken = default); + + /// + /// Adds path to the recent documents list. This list is managed by the OS. On Windows you can visit the + /// list from the task bar, and on macOS you can visit it from dock menu. + /// + /// Path to add. + void AddRecentDocument(string path); + + /// + /// Clears the recent documents list. + /// + void ClearRecentDocuments(); + + /// + /// Sets the current executable as the default handler for a protocol (aka URI scheme). It allows you to + /// integrate your app deeper into the operating system. Once registered, all links with your-protocol:// + /// will be opened with the current executable. The whole link, including protocol, will be passed to your + /// application as a parameter. + /// + /// Note: On macOS, you can only register protocols that have been added to your app's info.plist, which + /// cannot be modified at runtime. However, you can change the file during build time via + /// Electron Forge, + /// Electron Packager, or by editing info.plist + /// with a text editor. Please refer to + /// Apple's documentation + /// for details. + /// + /// Note: In a Windows Store environment (when packaged as an appx) this API will return true for all calls but + /// the registry key it sets won't be accessible by other applications. In order to register your Windows Store + /// application as a default protocol handler you must declare the protocol in your manifest. + /// + /// The API uses the Windows Registry and LSSetDefaultHandlerForURLScheme internally. + /// + /// + /// The name of your protocol, without ://. For example, if you want your app to handle electron:// links, + /// call this method with electron as the parameter. + /// The cancellation token. + /// Whether the call succeeded. + Task SetAsDefaultProtocolClientAsync(string protocol, CancellationToken cancellationToken = default); + + /// + /// Sets the current executable as the default handler for a protocol (aka URI scheme). It allows you to + /// integrate your app deeper into the operating system. Once registered, all links with your-protocol:// + /// will be opened with the current executable. The whole link, including protocol, will be passed to your + /// application as a parameter. + /// + /// Note: On macOS, you can only register protocols that have been added to your app's info.plist, which + /// cannot be modified at runtime. However, you can change the file during build time via + /// Electron Forge, + /// Electron Packager, or by editing info.plist + /// with a text editor. Please refer to + /// Apple's documentation + /// for details. + /// + /// Note: In a Windows Store environment (when packaged as an appx) this API will return true for all calls but + /// the registry key it sets won't be accessible by other applications. In order to register your Windows Store + /// application as a default protocol handler you must declare the protocol in your manifest. + /// + /// The API uses the Windows Registry and LSSetDefaultHandlerForURLScheme internally. + /// + /// + /// The name of your protocol, without ://. For example, if you want your app to handle electron:// links, + /// call this method with electron as the parameter. + /// The path to the Electron executable. Defaults to process.execPath + /// The cancellation token. + /// Whether the call succeeded. + Task SetAsDefaultProtocolClientAsync(string protocol, string path, CancellationToken cancellationToken = default); + + /// + /// Sets the current executable as the default handler for a protocol (aka URI scheme). It allows you to + /// integrate your app deeper into the operating system. Once registered, all links with your-protocol:// + /// will be opened with the current executable. The whole link, including protocol, will be passed to your + /// application as a parameter. + /// + /// Note: On macOS, you can only register protocols that have been added to your app's info.plist, which + /// cannot be modified at runtime. However, you can change the file during build time via + /// Electron Forge, + /// Electron Packager, or by editing info.plist + /// with a text editor. Please refer to + /// Apple's documentation + /// for details. + /// + /// Note: In a Windows Store environment (when packaged as an appx) this API will return true for all calls but + /// the registry key it sets won't be accessible by other applications. In order to register your Windows Store + /// application as a default protocol handler you must declare the protocol in your manifest. + /// + /// The API uses the Windows Registry and LSSetDefaultHandlerForURLScheme internally. + /// + /// + /// The name of your protocol, without ://. For example, if you want your app to handle electron:// links, + /// call this method with electron as the parameter. + /// The path to the Electron executable. Defaults to process.execPath + /// Arguments passed to the executable. Defaults to an empty array. + /// The cancellation token. + /// Whether the call succeeded. + Task SetAsDefaultProtocolClientAsync(string protocol, string path, string[] args, CancellationToken cancellationToken = default); + + /// + /// This method checks if the current executable as the default handler for a protocol (aka URI scheme). + /// If so, it will remove the app as the default handler. + /// + /// The name of your protocol, without ://. + /// The cancellation token. + /// Whether the call succeeded. + Task RemoveAsDefaultProtocolClientAsync(string protocol, CancellationToken cancellationToken = default); + + /// + /// This method checks if the current executable as the default handler for a protocol (aka URI scheme). + /// If so, it will remove the app as the default handler. + /// + /// The name of your protocol, without ://. + /// Defaults to process.execPath. + /// The cancellation token. + /// Whether the call succeeded. + Task RemoveAsDefaultProtocolClientAsync(string protocol, string path, CancellationToken cancellationToken = default); + + /// + /// This method checks if the current executable as the default handler for a protocol (aka URI scheme). + /// If so, it will remove the app as the default handler. + /// + /// The name of your protocol, without ://. + /// Defaults to process.execPath. + /// Defaults to an empty array. + /// The cancellation token. + /// Whether the call succeeded. + Task RemoveAsDefaultProtocolClientAsync(string protocol, string path, string[] args, CancellationToken cancellationToken = default); + + /// + /// This method checks if the current executable is the default handler for a protocol (aka URI scheme). + /// + /// Note: On macOS, you can use this method to check if the app has been registered as the default protocol + /// handler for a protocol. You can also verify this by checking ~/Library/Preferences/com.apple.LaunchServices.plist + /// on the macOS machine. Please refer to Apple's documentation + /// for details. + /// + /// The API uses the Windows Registry and LSCopyDefaultHandlerForURLScheme internally. + /// + /// The name of your protocol, without ://. + /// The cancellation token. + /// Whether the current executable is the default handler for a protocol (aka URI scheme). + Task IsDefaultProtocolClientAsync(string protocol, CancellationToken cancellationToken = default); + + /// + /// This method checks if the current executable is the default handler for a protocol (aka URI scheme). + /// + /// Note: On macOS, you can use this method to check if the app has been registered as the default protocol + /// handler for a protocol. You can also verify this by checking ~/Library/Preferences/com.apple.LaunchServices.plist + /// on the macOS machine. Please refer to Apple's documentation + /// for details. + /// + /// The API uses the Windows Registry and LSCopyDefaultHandlerForURLScheme internally. + /// + /// The name of your protocol, without ://. + /// Defaults to process.execPath. + /// The cancellation token. + /// Whether the current executable is the default handler for a protocol (aka URI scheme). + Task IsDefaultProtocolClientAsync(string protocol, string path, CancellationToken cancellationToken = default); + + /// + /// This method checks if the current executable is the default handler for a protocol (aka URI scheme). + /// + /// Note: On macOS, you can use this method to check if the app has been registered as the default protocol + /// handler for a protocol. You can also verify this by checking ~/Library/Preferences/com.apple.LaunchServices.plist + /// on the macOS machine. Please refer to Apple's documentation + /// for details. + /// + /// The API uses the Windows Registry and LSCopyDefaultHandlerForURLScheme internally. + /// + /// The name of your protocol, without ://. + /// Defaults to process.execPath. + /// Defaults to an empty array. + /// The cancellation token. + /// Whether the current executable is the default handler for a protocol (aka URI scheme). + Task IsDefaultProtocolClientAsync(string protocol, string path, string[] args, CancellationToken cancellationToken = default); + + /// + /// Adds tasks to the category of the JumpList on Windows. + /// + /// Note: If you'd like to customize the Jump List even more use instead. + /// + /// Array of objects. + /// The cancellation token. + /// Whether the call succeeded. + Task SetUserTasksAsync(UserTask[] userTasks, CancellationToken cancellationToken = default); + + /// + /// Jump List settings for the application. + /// + /// The cancellation token. + /// Jump List settings. + Task GetJumpListSettingsAsync(CancellationToken cancellationToken = default); + + /// + /// Sets or removes a custom Jump List for the application. If categories is null the previously set custom + /// Jump List (if any) will be replaced by the standard Jump List for the app (managed by Windows). + /// + /// Note: If a object has neither the nor + /// the property set then its is assumed + /// to be . If the property is set but + /// the property is omitted then the is + /// assumed to be . + /// + /// Note: Users can remove items from custom categories, and Windows will not allow a removed item to be added + /// back into a custom category until after the next successful call to . Any attempt + /// to re-add a removed item to a custom category earlier than that will result in the entire custom category being + /// omitted from the Jump List. The list of removed items can be obtained using . + /// + /// Array of objects. + void SetJumpList(JumpListCategory[] categories); + + /// + /// The return value of this method indicates whether or not this instance of your application successfully obtained + /// the lock. If it failed to obtain the lock, you can assume that another instance of your application is already + /// running with the lock and exit immediately. + /// + /// I.e.This method returns if your process is the primary instance of your application and your + /// app should continue loading. It returns if your process should immediately quit as it has + /// sent its parameters to another instance that has already acquired the lock. + /// + /// On macOS, the system enforces single instance automatically when users try to open a second instance of your app + /// in Finder, and the open-file and open-url events will be emitted for that.However when users start your app in + /// command line, the system's single instance mechanism will be bypassed, and you have to use this method to ensure + /// single instance. + /// + /// Lambda with an array of the second instance’s command line arguments. + /// The second parameter is the working directory path. + /// The cancellation token. + /// This method returns false if your process is the primary instance of the application and your app + /// should continue loading. And returns true if your process has sent its parameters to another instance, and + /// you should immediately quit. + /// + Task RequestSingleInstanceLockAsync(Action newInstanceOpened, CancellationToken cancellationToken = default); + + /// + /// Releases all locks that were created by makeSingleInstance. This will allow + /// multiple instances of the application to once again run side by side. + /// + void ReleaseSingleInstanceLock(); + + /// + /// This method returns whether or not this instance of your app is currently holding the single instance lock. + /// You can request the lock with and release with + /// . + /// + /// The cancellation token. + Task HasSingleInstanceLockAsync(CancellationToken cancellationToken = default); + + /// + /// Creates an NSUserActivity and sets it as the current activity. The activity is + /// eligible for Handoff + /// to another device afterward. + /// + /// Uniquely identifies the activity. Maps to NSUserActivity.activityType. + /// App-specific state to store for use by another device. + void SetUserActivity(string type, object userInfo); + + /// + /// Creates an NSUserActivity and sets it as the current activity. The activity is + /// eligible for Handoff + /// to another device afterward. + /// + /// + /// Uniquely identifies the activity. Maps to NSUserActivity.activityType. + /// + /// App-specific state to store for use by another device. + /// + /// The webpage to load in a browser if no suitable app is installed on the resuming device. The scheme must be http or https. + /// + void SetUserActivity(string type, object userInfo, string webpageUrl); + + /// + /// The type of the currently running activity. + /// + /// The cancellation token. + Task GetCurrentActivityTypeAsync(CancellationToken cancellationToken = default); + + /// + /// Invalidates the current Handoff user activity. + /// + void InvalidateCurrentActivity(); + + /// + /// Marks the current Handoff user activity as inactive without invalidating it. + /// + void ResignCurrentActivity(); + + /// + /// Changes the Application User Model ID to id. + /// + /// Model Id. + void SetAppUserModelId(string id); + + /// TODO: Check new parameter which is a function [App.ImportCertificate] + /// + /// Imports the certificate in pkcs12 format into the platform certificate store. + /// callback is called with the result of import operation, a value of 0 indicates + /// success while any other value indicates failure according to chromium net_error_list. + /// + /// + /// The cancellation token. + /// Result of import. Value of 0 indicates success. + Task ImportCertificateAsync(ImportCertificateOptions options, CancellationToken cancellationToken = default); + + /// + /// Memory and cpu usage statistics of all the processes associated with the app. + /// + /// + /// Array of ProcessMetric objects that correspond to memory and cpu usage + /// statistics of all the processes associated with the app. + /// The cancellation token. + /// + Task GetAppMetricsAsync(CancellationToken cancellationToken = default); + + /// + /// The Graphics Feature Status from chrome://gpu/. + /// + /// Note: This information is only usable after the gpu-info-update event is emitted. + /// The cancellation token. + /// + Task GetGpuFeatureStatusAsync(CancellationToken cancellationToken = default); + + /// + /// Sets the counter badge for current app. Setting the count to 0 will hide the badge. + /// On macOS it shows on the dock icon. On Linux it only works for Unity launcher. + /// + /// Note: Unity launcher requires the existence of a .desktop file to work, for more + /// information please read Desktop Environment Integration. + /// + /// Counter badge. + /// The cancellation token. + /// Whether the call succeeded. + Task SetBadgeCountAsync(int count, CancellationToken cancellationToken = default); + + /// + /// The current value displayed in the counter badge. + /// + /// The cancellation token. + Task GetBadgeCountAsync(CancellationToken cancellationToken = default); + + /// + /// Whether the current desktop environment is Unity launcher. + /// + /// The cancellation token. + Task IsUnityRunningAsync(CancellationToken cancellationToken = default); + + /// + /// If you provided path and args options to then you need to pass the same + /// arguments here for to be set correctly. + /// + Task GetLoginItemSettingsAsync(CancellationToken cancellationToken = default); + + /// + /// If you provided path and args options to then you need to pass the same + /// arguments here for to be set correctly. + /// + /// + /// The cancellation token. + Task GetLoginItemSettingsAsync(LoginItemSettingsOptions options, CancellationToken cancellationToken = default); + + /// + /// Set the app's login item settings. + /// To work with Electron's autoUpdater on Windows, which uses Squirrel, + /// you'll want to set the launch path to Update.exe, and pass arguments that specify your application name. + /// + /// + void SetLoginItemSettings(LoginSettings loginSettings); + + /// + /// if Chrome's accessibility support is enabled, otherwise. This API will + /// return if the use of assistive technologies, such as screen readers, has been detected. + /// See Chromium's accessibility docs for more details. + /// + /// if Chrome’s accessibility support is enabled, otherwise. + Task IsAccessibilitySupportEnabledAsync(CancellationToken cancellationToken = default); + + /// + /// Manually enables Chrome's accessibility support, allowing to expose accessibility switch to users in application settings. + /// See Chromium's accessibility docs for more details. + /// Disabled () by default. + /// + /// This API must be called after the event is emitted. + /// + /// Note: Rendering accessibility tree can significantly affect the performance of your app. It should not be enabled by default. + /// + /// Enable or disable accessibility tree rendering. + void SetAccessibilitySupportEnabled(bool enabled); + + /// + /// Show the app's about panel options. These options can be overridden with + /// . + /// + void ShowAboutPanel(); + + /// + /// Set the about panel options. This will override the values defined in the app's .plist file on macOS. See the + /// Apple docs + /// for more details. On Linux, values must be set in order to be shown; there are no defaults. + /// + /// If you do not set credits but still wish to surface them in your app, AppKit will look for a file named "Credits.html", + /// "Credits.rtf", and "Credits.rtfd", in that order, in the bundle returned by the NSBundle class method main. The first file + /// found is used, and if none is found, the info area is left blank. See Apple + /// documentation for more information. + /// + /// About panel options. + void SetAboutPanelOptions(AboutPanelOptions options); + + /// + /// Subscribe to an unmapped event on the module. + /// + /// The event name + /// The handler + void On(string eventName, Action fn); + + /// + /// Subscribe to an unmapped event on the module. + /// + /// The event name + /// The handler + void On(string eventName, Action fn); + + /// + /// Subscribe to an unmapped event on the module once. + /// + /// The event name + /// The handler + void Once(string eventName, Action fn); + + /// + /// Subscribe to an unmapped event on the module once. + /// + /// The event name + /// The handler + void Once(string eventName, Action fn); + } +} \ No newline at end of file diff --git a/ElectronNET.API/Interfaces/IApplicationSocket.cs b/ElectronNET.API/Interfaces/IApplicationSocket.cs new file mode 100755 index 00000000..8d4044be --- /dev/null +++ b/ElectronNET.API/Interfaces/IApplicationSocket.cs @@ -0,0 +1,15 @@ +using Quobject.SocketIoClientDotNet.Client; + +namespace ElectronNET.API.Interfaces +{ + /// + /// Wrapper for the underlying Socket connection + /// + public interface IApplicationSocket + { + /// + /// Socket used to communicate with main.js + /// + Socket Socket { get; } + } +} \ No newline at end of file diff --git a/ElectronNET.API/Interfaces/IAutoUpdater.cs b/ElectronNET.API/Interfaces/IAutoUpdater.cs new file mode 100755 index 00000000..4ff36379 --- /dev/null +++ b/ElectronNET.API/Interfaces/IAutoUpdater.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using ElectronNET.API.Entities; + +namespace ElectronNET.API.Interfaces +{ + /// + /// Enable apps to automatically update themselves. Based on electron-updater. + /// + public interface IAutoUpdater + { + /// + /// Whether to automatically download an update when it is found. (Default is true) + /// + bool AutoDownload { get; set; } + + /// + /// Whether to automatically install a downloaded update on app quit (if `QuitAndInstall` was not called before). + /// + /// Applicable only on Windows and Linux. + /// + bool AutoInstallOnAppQuit { get; set; } + + /// + /// *GitHub provider only.* Whether to allow update to pre-release versions. + /// Defaults to "true" if application version contains prerelease components (e.g. "0.12.1-alpha.1", here "alpha" is a prerelease component), otherwise "false". + /// + /// If "true", downgrade will be allowed("allowDowngrade" will be set to "true"). + /// + bool AllowPrerelease { get; set; } + + /// + /// *GitHub provider only.* + /// Get all release notes (from current version to latest), not just the latest (Default is false). + /// + bool FullChangelog { get; set; } + + /// + /// Whether to allow version downgrade (when a user from the beta channel wants to go back to the stable channel). + /// Taken in account only if channel differs (pre-release version component in terms of semantic versioning). + /// Default is false. + /// + bool AllowDowngrade { get; set; } + + /// + /// For test only. + /// + string UpdateConfigPath { get; } + + /// + /// The current application version + /// + Task CurrentVersionAsync { get; } + + /// + /// Get the update channel. Not applicable for GitHub. + /// Doesn’t return channel from the update configuration, only if was previously set. + /// + string Channel { get; } + + /// + /// Get the update channel. Not applicable for GitHub. + /// Doesn’t return channel from the update configuration, only if was previously set. + /// + Task ChannelAsync { get; } + + /// + /// The request headers. + /// + Task> RequestHeadersAsync { get; } + + /// + /// The request headers. + /// + Dictionary RequestHeaders { set; } + + /// + /// Emitted when there is an error while updating. + /// + event Action OnError; + + /// + /// Emitted when checking if an update has started. + /// + event Action OnCheckingForUpdate; + + /// + /// Emitted when there is an available update. + /// The update is downloaded automatically if AutoDownload is true. + /// + event Action OnUpdateAvailable; + + /// + /// Emitted when there is no available update. + /// + event Action OnUpdateNotAvailable; + + /// + /// Emitted on download progress. + /// + event Action OnDownloadProgress; + + /// + /// Emitted on download complete. + /// + event Action OnUpdateDownloaded; + + /// + /// Asks the server whether there is an update. + /// + /// + Task CheckForUpdatesAsync(); + + /// + /// Asks the server whether there is an update. + /// + /// This will immediately download an update, then install when the app quits. + /// + /// + Task CheckForUpdatesAndNotifyAsync(); + + /// + /// Restarts the app and installs the update after it has been downloaded. + /// It should only be called after `update-downloaded` has been emitted. + /// + /// Note: QuitAndInstall() will close all application windows first and only emit `before-quit` event on `app` after that. + /// This is different from the normal quit event sequence. + /// + /// *windows-only* Runs the installer in silent mode. Defaults to `false`. + /// Run the app after finish even on silent install. Not applicable for macOS. Ignored if `isSilent` is set to `false`. + void QuitAndInstall(bool isSilent = false, bool isForceRunAfter = false); + + /// + /// Start downloading update manually. You can use this method if "AutoDownload" option is set to "false". + /// + /// Path to downloaded file. + Task DownloadUpdateAsync(); + + /// + /// Feed URL. + /// + /// Feed URL. + Task GetFeedURLAsync(); + } +} \ No newline at end of file diff --git a/ElectronNET.API/Interfaces/IClipboard.cs b/ElectronNET.API/Interfaces/IClipboard.cs new file mode 100755 index 00000000..607f536f --- /dev/null +++ b/ElectronNET.API/Interfaces/IClipboard.cs @@ -0,0 +1,122 @@ +using System.Threading.Tasks; +using ElectronNET.API.Entities; + +namespace ElectronNET.API.Interfaces +{ + /// + /// Perform copy and paste operations on the system clipboard. + /// + public interface IClipboard + { + /// + /// Read the content in the clipboard as plain text. + /// + /// + /// The content in the clipboard as plain text. + Task ReadTextAsync(string type = ""); + + /// + /// Writes the text into the clipboard as plain text. + /// + /// + /// + void WriteText(string text, string type = ""); + + /// + /// The content in the clipboard as markup. + /// + /// + /// + Task ReadHTMLAsync(string type = ""); + + /// + /// Writes markup to the clipboard. + /// + /// + /// + void WriteHTML(string markup, string type = ""); + + /// + /// The content in the clipboard as RTF. + /// + /// + /// + Task ReadRTFAsync(string type = ""); + + /// + /// Writes the text into the clipboard in RTF. + /// + /// + /// + void WriteRTF(string text, string type = ""); + + /// + /// Returns an Object containing title and url keys representing + /// the bookmark in the clipboard. The title and url values will + /// be empty strings when the bookmark is unavailable. + /// + /// + Task ReadBookmarkAsync(); + + /// + /// Writes the title and url into the clipboard as a bookmark. + /// + /// Note: Most apps on Windows don’t support pasting bookmarks + /// into them so you can use clipboard.write to write both a + /// bookmark and fallback text to the clipboard. + /// + /// + /// + /// + void WriteBookmark(string title, string url, string type = ""); + + /// + /// macOS: The text on the find pasteboard. This method uses synchronous IPC + /// when called from the renderer process. The cached value is reread from the + /// find pasteboard whenever the application is activated. + /// + /// + Task ReadFindTextAsync(); + + /// + /// macOS: Writes the text into the find pasteboard as plain text. This method uses + /// synchronous IPC when called from the renderer process. + /// + /// + void WriteFindText(string text); + + /// + /// Clears the clipboard content. + /// + /// + void Clear(string type = ""); + + /// + /// An array of supported formats for the clipboard type. + /// + /// + /// + Task AvailableFormatsAsync(string type = ""); + + /// + /// Writes data to the clipboard. + /// + /// + /// + void Write(Data data, string type = ""); + + /// + /// Reads an image from the clipboard. + /// + /// + /// + Task ReadImageAsync(string type = ""); + + /// + /// Writes an image to the clipboard. + /// + /// + /// + void WriteImage(NativeImage image, string type = ""); + } +} \ No newline at end of file diff --git a/ElectronNET.API/Interfaces/IDialog.cs b/ElectronNET.API/Interfaces/IDialog.cs new file mode 100755 index 00000000..eff74231 --- /dev/null +++ b/ElectronNET.API/Interfaces/IDialog.cs @@ -0,0 +1,102 @@ +using System.Threading.Tasks; +using ElectronNET.API.Entities; + +namespace ElectronNET.API.Interfaces +{ + /// + /// Display native system dialogs for opening and saving files, alerting, etc. + /// + public interface IDialog + { + /// + /// Note: On Windows and Linux an open dialog can not be both a file selector + /// and a directory selector, so if you set properties to ['openFile', 'openDirectory'] + /// on these platforms, a directory selector will be shown. + /// + /// The browserWindow argument allows the dialog to attach itself to a parent window, making it modal. + /// + /// An array of file paths chosen by the user + Task ShowOpenDialogAsync(BrowserWindow browserWindow, OpenDialogOptions options); + + /// + /// Dialog for save files. + /// + /// The browserWindow argument allows the dialog to attach itself to a parent window, making it modal. + /// + /// Returns String, the path of the file chosen by the user, if a callback is provided it returns an empty string. + Task ShowSaveDialogAsync(BrowserWindow browserWindow, SaveDialogOptions options); + + /// + /// Shows a message box, it will block the process until the message box is closed. + /// It returns the index of the clicked button. The browserWindow argument allows + /// the dialog to attach itself to a parent window, making it modal. If a callback + /// is passed, the dialog will not block the process.The API call will be + /// asynchronous and the result will be passed via callback(response). + /// + /// + /// The API call will be asynchronous and the result will be passed via MessageBoxResult. + Task ShowMessageBoxAsync(string message); + + /// + /// Shows a message box, it will block the process until the message box is closed. + /// It returns the index of the clicked button. The browserWindow argument allows + /// the dialog to attach itself to a parent window, making it modal. If a callback + /// is passed, the dialog will not block the process.The API call will be + /// asynchronous and the result will be passed via callback(response). + /// + /// + /// The API call will be asynchronous and the result will be passed via MessageBoxResult. + Task ShowMessageBoxAsync(MessageBoxOptions messageBoxOptions); + + /// + /// Shows a message box, it will block the process until the message box is closed. + /// It returns the index of the clicked button. If a callback + /// is passed, the dialog will not block the process. + /// + /// The browserWindow argument allows the dialog to attach itself to a parent window, making it modal. + /// + /// The API call will be asynchronous and the result will be passed via MessageBoxResult. + Task ShowMessageBoxAsync(BrowserWindow browserWindow, string message); + + /// + /// Shows a message box, it will block the process until the message box is closed. + /// It returns the index of the clicked button. If a callback + /// is passed, the dialog will not block the process. + /// + /// The browserWindow argument allows the dialog to attach itself to a parent window, making it modal. + /// + /// The API call will be asynchronous and the result will be passed via MessageBoxResult. + Task ShowMessageBoxAsync(BrowserWindow browserWindow, MessageBoxOptions messageBoxOptions); + + /// + /// Displays a modal dialog that shows an error message. + /// + /// This API can be called safely before the ready event the app module emits, + /// it is usually used to report errors in early stage of startup.If called + /// before the app readyevent on Linux, the message will be emitted to stderr, + /// and no GUI dialog will appear. + /// + /// The title to display in the error box. + /// The text content to display in the error box. + void ShowErrorBox(string title, string content); + + /// + /// On macOS, this displays a modal dialog that shows a message and certificate information, + /// and gives the user the option of trusting/importing the certificate. If you provide a + /// browserWindow argument the dialog will be attached to the parent window, making it modal. + /// + /// + /// + Task ShowCertificateTrustDialogAsync(CertificateTrustDialogOptions options); + + /// + /// On macOS, this displays a modal dialog that shows a message and certificate information, + /// and gives the user the option of trusting/importing the certificate. If you provide a + /// browserWindow argument the dialog will be attached to the parent window, making it modal. + /// + /// + /// + /// + Task ShowCertificateTrustDialogAsync(BrowserWindow browserWindow, CertificateTrustDialogOptions options); + } +} \ No newline at end of file diff --git a/ElectronNET.API/Interfaces/IDock.cs b/ElectronNET.API/Interfaces/IDock.cs new file mode 100755 index 00000000..0a42c491 --- /dev/null +++ b/ElectronNET.API/Interfaces/IDock.cs @@ -0,0 +1,93 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using ElectronNET.API.Entities; + +namespace ElectronNET.API.Interfaces +{ + /// + /// Control your app in the macOS dock. + /// + public interface IDock + { + /// + /// When is passed, the dock icon will bounce until either the application becomes + /// active or the request is canceled. When is passed, the dock icon will bounce + /// for one second. However, the request remains active until either the application becomes active or the request is canceled. + /// + /// Note: This method can only be used while the app is not focused; when the app is focused it will return -1. + /// + /// Can be critical or informational. The default is informational. + /// The cancellation token. + /// Return an ID representing the request. + Task BounceAsync(DockBounceType type, CancellationToken cancellationToken = default); + + /// + /// Cancel the bounce of id. + /// + /// Id of the request. + void CancelBounce(int id); + + /// + /// Bounces the Downloads stack if the filePath is inside the Downloads folder. + /// + /// + void DownloadFinished(string filePath); + + /// + /// Sets the string to be displayed in the dock’s badging area. + /// + /// + void SetBadge(string text); + + /// + /// Gets the string to be displayed in the dock’s badging area. + /// + /// The cancellation token. + /// The badge string of the dock. + Task GetBadgeAsync(CancellationToken cancellationToken = default); + + /// + /// Hides the dock icon. + /// + void Hide(); + + /// + /// Shows the dock icon. + /// + void Show(); + + /// + /// Whether the dock icon is visible. The app.dock.show() call is asynchronous + /// so this method might not return true immediately after that call. + /// + /// The cancellation token. + /// Whether the dock icon is visible. + Task IsVisibleAsync(CancellationToken cancellationToken = default); + + /// + /// Gets the dock menu items. + /// + /// + /// The menu items. + /// + IReadOnlyCollection MenuItems { get; } + + /// + /// Sets the application's dock menu. + /// + void SetMenu(MenuItem[] menuItems); + + /// + /// TODO: Menu (macOS) still to be implemented + /// Gets the application's dock menu. + /// + Task GetMenu(CancellationToken cancellationToken = default); + + /// + /// Sets the image associated with this dock icon. + /// + /// + void SetIcon(string image); + } +} \ No newline at end of file diff --git a/ElectronNET.API/Interfaces/IGlobalShortcut.cs b/ElectronNET.API/Interfaces/IGlobalShortcut.cs new file mode 100755 index 00000000..0f671c64 --- /dev/null +++ b/ElectronNET.API/Interfaces/IGlobalShortcut.cs @@ -0,0 +1,39 @@ +using System; +using System.Threading.Tasks; + +namespace ElectronNET.API.Interfaces +{ + /// + /// Detect keyboard events when the application does not have keyboard focus. + /// + public interface IGlobalShortcut + { + /// + /// Registers a global shortcut of accelerator. + /// The callback is called when the registered shortcut is pressed by the user. + /// + /// When the accelerator is already taken by other applications, this call will + /// silently fail.This behavior is intended by operating systems, since they don’t + /// want applications to fight for global shortcuts. + /// + void Register(string accelerator, Action function); + + /// + /// When the accelerator is already taken by other applications, + /// this call will still return false. This behavior is intended by operating systems, + /// since they don’t want applications to fight for global shortcuts. + /// + /// Whether this application has registered accelerator. + Task IsRegisteredAsync(string accelerator); + + /// + /// Unregisters the global shortcut of accelerator. + /// + void Unregister(string accelerator); + + /// + /// Unregisters all of the global shortcuts. + /// + void UnregisterAll(); + } +} \ No newline at end of file diff --git a/ElectronNET.API/Interfaces/IHostHook.cs b/ElectronNET.API/Interfaces/IHostHook.cs new file mode 100755 index 00000000..0a5b8dc3 --- /dev/null +++ b/ElectronNET.API/Interfaces/IHostHook.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; + +namespace ElectronNET.API.Interfaces +{ + /// + /// Allows you to execute native JavaScript/TypeScript code from the host process. + /// + /// It is only possible if the Electron.NET CLI has previously added an + /// ElectronHostHook directory: + /// electronize add HostHook + /// + public interface IHostHook + { + /// + /// Execute native JavaScript/TypeScript code. + /// + /// Socket name registered on the host. + /// Optional parameters. + void Call(string socketEventName, params dynamic[] arguments); + + /// + /// Execute native JavaScript/TypeScript code. + /// + /// Results from the executed host code. + /// Socket name registered on the host. + /// Optional parameters. + /// + Task CallAsync(string socketEventName, params dynamic[] arguments); + } +} \ No newline at end of file diff --git a/ElectronNET.API/Interfaces/IIpcMain.cs b/ElectronNET.API/Interfaces/IIpcMain.cs new file mode 100755 index 00000000..8a833e23 --- /dev/null +++ b/ElectronNET.API/Interfaces/IIpcMain.cs @@ -0,0 +1,65 @@ +using System; + +namespace ElectronNET.API.Interfaces +{ + /// + /// Communicate asynchronously from the main process to renderer processes. + /// + public interface IIpcMain + { + /// + /// Listens to channel, when a new message arrives listener would be called with + /// listener(event, args...). + /// + /// Channelname. + /// Callback Method. + void On(string channel, Action listener); + + /// + /// Send a message to the renderer process synchronously via channel, + /// you can also send arbitrary arguments. + /// + /// Note: Sending a synchronous message will block the whole renderer process, + /// unless you know what you are doing you should never use it. + /// + /// + /// + void OnSync(string channel, Func listener); + + /// + /// Adds a one time listener method for the event. This listener is invoked only + /// the next time a message is sent to channel, after which it is removed. + /// + /// Channelname. + /// Callback Method. + void Once(string channel, Action listener); + + /// + /// Removes listeners of the specified channel. + /// + /// Channelname. + void RemoveAllListeners(string channel); + + /// + /// Send a message to the renderer process asynchronously via channel, you can also send + /// arbitrary arguments. Arguments will be serialized in JSON internally and hence + /// no functions or prototype chain will be included. The renderer process handles it by + /// listening for channel with ipcRenderer module. + /// + /// BrowserWindow with channel. + /// Channelname. + /// Arguments data. + void Send(BrowserWindow browserWindow, string channel, params object[] data); + + /// + /// Send a message to the BrowserView renderer process asynchronously via channel, you can also send + /// arbitrary arguments. Arguments will be serialized in JSON internally and hence + /// no functions or prototype chain will be included. The renderer process handles it by + /// listening for channel with ipcRenderer module. + /// + /// BrowserView with channel. + /// Channelname. + /// Arguments data. + void Send(BrowserView browserView, string channel, params object[] data); + } +} \ No newline at end of file diff --git a/ElectronNET.API/Interfaces/IMenu.cs b/ElectronNET.API/Interfaces/IMenu.cs new file mode 100755 index 00000000..6dfdbd4f --- /dev/null +++ b/ElectronNET.API/Interfaces/IMenu.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using ElectronNET.API.Entities; + +namespace ElectronNET.API.Interfaces +{ + /// + /// Create native application menus and context menus. + /// + public interface IMenu + { + /// + /// Gets the menu items. + /// + /// + /// The menu items. + /// + IReadOnlyCollection MenuItems { get; } + + /// + /// Gets the context menu items. + /// + /// + /// The context menu items. + /// + IReadOnlyDictionary> ContextMenuItems { get; } + + /// + /// Sets the application menu. + /// + /// The menu items. + void SetApplicationMenu(MenuItem[] menuItems); + + /// + /// Sets the context menu. + /// + /// The browser window. + /// The menu items. + void SetContextMenu(BrowserWindow browserWindow, MenuItem[] menuItems); + + /// + /// Contexts the menu popup. + /// + /// The browser window. + void ContextMenuPopup(BrowserWindow browserWindow); + } +} \ No newline at end of file diff --git a/ElectronNET.API/Interfaces/INativeTheme.cs b/ElectronNET.API/Interfaces/INativeTheme.cs new file mode 100755 index 00000000..37f78b2a --- /dev/null +++ b/ElectronNET.API/Interfaces/INativeTheme.cs @@ -0,0 +1,101 @@ +using System; +using System.Threading.Tasks; +using ElectronNET.API.Entities; + +namespace ElectronNET.API.Interfaces +{ + /// + /// Read and respond to changes in Chromium's native color theme. + /// + public interface INativeTheme + { + /// + /// Setting this property to will remove the override and everything will be reset to the OS default. By default 'ThemeSource' is . + /// + /// Settings this property to will have the following effects: + /// + /// + /// will be when accessed + /// + /// + /// Any UI Electron renders on Linux and Windows including context menus, devtools, etc. will use the dark UI. + /// + /// + /// Any UI the OS renders on macOS including menus, window frames, etc. will use the dark UI. + /// + /// + /// The 'prefers-color-scheme' CSS query will match 'dark' mode. + /// + /// + /// The 'updated' event will be emitted + /// + /// + /// + /// Settings this property to will have the following effects: + /// + /// + /// will be when accessed + /// + /// + /// Any UI Electron renders on Linux and Windows including context menus, devtools, etc. will use the light UI. + /// + /// + /// Any UI the OS renders on macOS including menus, window frames, etc. will use the light UI. + /// + /// + /// The 'prefers-color-scheme' CSS query will match 'light' mode. + /// + /// + /// The 'updated' event will be emitted + /// + /// + /// The usage of this property should align with a classic "dark mode" state machine in your application where the user has three options. + /// + /// + /// + /// Follow OS: SetThemeSource(ThemeSourceMode.System); + /// + /// + /// Dark Mode: SetThemeSource(ThemeSourceMode.Dark); + /// + /// + /// Light Mode: SetThemeSource(ThemeSourceMode.Light); + /// + /// + /// Your application should then always use to determine what CSS to apply. + /// + /// The new ThemeSource. + void SetThemeSource(ThemeSourceMode themeSourceMode); + + /// + /// A property that can be , or . It is used to override () and + /// supercede the value that Chromium has chosen to use internally. + /// + Task GetThemeSourceAsync(); + + /// + /// A 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 . + /// + Task ShouldUseDarkColorsAsync(); + + /// + /// A for if the OS / Chromium currently has high-contrast mode enabled or is + /// being instructed to show a high-contrast UI. + /// + Task ShouldUseHighContrastColorsAsync(); + + /// + /// A for if the OS / Chromium currently has an inverted color scheme or is + /// being instructed to use an inverted color scheme. + /// + Task ShouldUseInvertedColorSchemeAsync(); + + /// + /// Emitted when something in the underlying NativeTheme has changed. This normally means that either the value of , + /// or has changed. You will have to check them to determine which one has changed. + /// + event Action Updated; + } +} \ No newline at end of file diff --git a/ElectronNET.API/Interfaces/INotification.cs b/ElectronNET.API/Interfaces/INotification.cs new file mode 100755 index 00000000..95fca190 --- /dev/null +++ b/ElectronNET.API/Interfaces/INotification.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; +using ElectronNET.API.Entities; + +namespace ElectronNET.API.Interfaces +{ + /// + /// Create OS desktop notifications + /// + public interface INotification + { + /// + /// Create OS desktop notifications + /// + /// + void Show(NotificationOptions notificationOptions); + + /// + /// Whether or not desktop notifications are supported on the current system. + /// + /// + Task IsSupportedAsync(); + } +} \ No newline at end of file diff --git a/ElectronNET.API/Interfaces/IPowerMonitor.cs b/ElectronNET.API/Interfaces/IPowerMonitor.cs new file mode 100755 index 00000000..2e3ad09c --- /dev/null +++ b/ElectronNET.API/Interfaces/IPowerMonitor.cs @@ -0,0 +1,48 @@ +using System; + +namespace ElectronNET.API.Interfaces +{ + /// + /// Monitor power state changes.. + /// + public interface IPowerMonitor + { + /// + /// Emitted when the system is about to lock the screen. + /// + event Action OnLockScreen; + + /// + /// Emitted when the system is about to unlock the screen. + /// + event Action OnUnLockScreen; + + /// + /// Emitted when the system is suspending. + /// + event Action OnSuspend; + + /// + /// Emitted when system is resuming. + /// + event Action OnResume; + + /// + /// Emitted when the system changes to AC power. + /// + event Action OnAC; + + /// + /// Emitted when system changes to battery power. + /// + event Action OnBattery; + + /// + /// 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 + /// order for the app to exit cleanly.If `e.preventDefault()` is called, the app + /// should exit as soon as possible by calling something like `app.quit()`. + /// + event Action OnShutdown; + } +} \ No newline at end of file diff --git a/ElectronNET.API/Interfaces/IScreen.cs b/ElectronNET.API/Interfaces/IScreen.cs new file mode 100755 index 00000000..cb51c360 --- /dev/null +++ b/ElectronNET.API/Interfaces/IScreen.cs @@ -0,0 +1,66 @@ +using System; +using System.Threading.Tasks; +using ElectronNET.API.Entities; + +namespace ElectronNET.API.Interfaces +{ + /// + /// Retrieve information about screen size, displays, cursor position, etc. + /// + public interface IScreen + { + /// + /// Emitted when an new Display has been added. + /// + event Action OnDisplayAdded; + + /// + /// Emitted when oldDisplay has been removed. + /// + event Action OnDisplayRemoved; + + /// + /// Emitted when one or more metrics change in a display. + /// The changedMetrics is an array of strings that describe the changes. + /// Possible changes are bounds, workArea, scaleFactor and rotation. + /// + event Action OnDisplayMetricsChanged; + + /// + /// The current absolute position of the mouse pointer. + /// + /// + Task GetCursorScreenPointAsync(); + + /// + /// macOS: The height of the menu bar in pixels. + /// + /// The height of the menu bar in pixels. + Task GetMenuBarHeightAsync(); + + /// + /// The primary display. + /// + /// + Task GetPrimaryDisplayAsync(); + + /// + /// An array of displays that are currently available. + /// + /// An array of displays that are currently available. + Task GetAllDisplaysAsync(); + + /// + /// The display nearest the specified point. + /// + /// The display nearest the specified point. + Task GetDisplayNearestPointAsync(Point point); + + /// + /// The display that most closely intersects the provided bounds. + /// + /// + /// The display that most closely intersects the provided bounds. + Task GetDisplayMatchingAsync(Rectangle rectangle); + } +} \ No newline at end of file diff --git a/ElectronNET.API/Interfaces/IShell.cs b/ElectronNET.API/Interfaces/IShell.cs new file mode 100755 index 00000000..605e3dda --- /dev/null +++ b/ElectronNET.API/Interfaces/IShell.cs @@ -0,0 +1,70 @@ +using System.Threading.Tasks; +using ElectronNET.API.Entities; + +namespace ElectronNET.API.Interfaces +{ + /// + /// Manage files and URLs using their default applications. + /// + public interface IShell + { + /// + /// Show the given file in a file manager. If possible, select the file. + /// + /// The full path to the directory / file. + Task ShowItemInFolderAsync(string fullPath); + + /// + /// Open the given file in the desktop's default manner. + /// + /// The path to the directory / file. + /// The error message corresponding to the failure if a failure occurred, otherwise . + Task OpenPathAsync(string path); + + /// + /// Open the given external protocol URL in the desktop’s default manner. + /// (For example, mailto: URLs in the user’s default mail agent). + /// + /// Max 2081 characters on windows. + /// The error message corresponding to the failure if a failure occurred, otherwise . + Task OpenExternalAsync(string url); + + /// + /// Open the given external protocol URL in the desktop’s default manner. + /// (For example, mailto: URLs in the user’s default mail agent). + /// + /// Max 2081 characters on windows. + /// Controls the behavior of OpenExternal. + /// The error message corresponding to the failure if a failure occurred, otherwise . + Task OpenExternalAsync(string url, OpenExternalOptions options); + + /// + /// Move the given file to trash and returns a status for the operation. + /// + /// The full path to the directory / file. + /// Whether the item was successfully moved to the trash. + Task TrashItemAsync(string fullPath); + + /// + /// Play the beep sound. + /// + void Beep(); + + /// + /// Creates or updates a shortcut link at shortcutPath. + /// + /// The path to the shortcut. + /// Default is + /// Structure of a shortcut. + /// Whether the shortcut was created successfully. + Task WriteShortcutLinkAsync(string shortcutPath, ShortcutLinkOperation operation, ShortcutDetails options); + + /// + /// Resolves the shortcut link at shortcutPath. + /// An exception will be thrown when any error happens. + /// + /// The path tot the shortcut. + /// of the shortcut. + Task ReadShortcutLinkAsync(string shortcutPath); + } +} \ No newline at end of file diff --git a/ElectronNET.API/Interfaces/ITray.cs b/ElectronNET.API/Interfaces/ITray.cs new file mode 100755 index 00000000..42dd4ed6 --- /dev/null +++ b/ElectronNET.API/Interfaces/ITray.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using ElectronNET.API.Entities; + +namespace ElectronNET.API.Interfaces +{ + /// + /// Add icons and context menus to the system's notification area. + /// + public interface ITray + { + /// + /// Emitted when the tray icon is clicked. + /// + event Action OnClick; + + /// + /// macOS, Windows: Emitted when the tray icon is right clicked. + /// + event Action OnRightClick; + + /// + /// macOS, Windows: Emitted when the tray icon is double clicked. + /// + event Action OnDoubleClick; + + /// + /// Windows: Emitted when the tray balloon shows. + /// + event Action OnBalloonShow; + + /// + /// Windows: Emitted when the tray balloon is clicked. + /// + event Action OnBalloonClick; + + /// + /// Windows: Emitted when the tray balloon is closed + /// because of timeout or user manually closes it. + /// + event Action OnBalloonClosed; + + /// + /// Gets the menu items. + /// + /// + /// The menu items. + /// + IReadOnlyCollection MenuItems { get; } + + /// + /// Shows the Traybar. + /// + /// The image. + /// The menu item. + void Show(string image, MenuItem menuItem); + + /// + /// Shows the Traybar. + /// + /// The image. + /// The menu items. + void Show(string image, MenuItem[] menuItems); + + /// + /// Shows the Traybar (empty). + /// + /// The image. + void Show(string image); + + /// + /// Destroys the tray icon immediately. + /// + void Destroy(); + + /// + /// Sets the image associated with this tray icon. + /// + /// + void SetImage(string image); + + /// + /// Sets the image associated with this tray icon when pressed on macOS. + /// + /// + void SetPressedImage(string image); + + /// + /// Sets the hover text for this tray icon. + /// + /// + void SetToolTip(string toolTip); + + /// + /// macOS: Sets the title displayed aside of the tray icon in the status bar. + /// + /// + void SetTitle(string title); + + /// + /// Windows: Displays a tray balloon. + /// + /// + void DisplayBalloon(DisplayBalloonOptions options); + + /// + /// Whether the tray icon is destroyed. + /// + /// + Task IsDestroyedAsync(); + + /// + /// Subscribe to an unmapped event on the module. + /// + /// The event name + /// The handler + void On(string eventName, Action fn); + + /// + /// Subscribe to an unmapped event on the module. + /// + /// The event name + /// The handler + void On(string eventName, Action fn); + + /// + /// Subscribe to an unmapped event on the module once. + /// + /// The event name + /// The handler + void Once(string eventName, Action fn); + + /// + /// Subscribe to an unmapped event on the module once. + /// + /// The event name + /// The handler + void Once(string eventName, Action fn); + } +} \ No newline at end of file diff --git a/ElectronNET.API/Interfaces/IWindowManager.cs b/ElectronNET.API/Interfaces/IWindowManager.cs new file mode 100755 index 00000000..839b1fa8 --- /dev/null +++ b/ElectronNET.API/Interfaces/IWindowManager.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using ElectronNET.API.Entities; + +namespace ElectronNET.API.Interfaces +{ + /// + /// Manage Browser Windows and Views + /// + public interface IWindowManager + { + /// + /// Quit when all windows are closed. (Default is true) + /// + /// + /// true if [quit window all closed]; otherwise, false. + /// + bool IsQuitOnWindowAllClosed { get; set; } + + /// + /// Gets the browser windows. + /// + /// + /// The browser windows. + /// + IReadOnlyCollection BrowserWindows { get; } + + /// + /// Gets the browser views. + /// + /// + /// The browser view. + /// + IReadOnlyCollection BrowserViews { get; } + + /// + /// Creates the window asynchronous. + /// + /// The load URL. + /// + Task CreateWindowAsync(string loadUrl = "http://localhost"); + + /// + /// Creates the window asynchronous. + /// + /// The options. + /// The load URL. + /// + Task CreateWindowAsync(BrowserWindowOptions options, string loadUrl = "http://localhost"); + + /// + /// A BrowserView can be used to embed additional web content into a BrowserWindow. + /// It is like a child window, except that it is positioned relative to its owning window. + /// It is meant to be an alternative to the webview tag. + /// + /// + Task CreateBrowserViewAsync(); + + /// + /// A BrowserView can be used to embed additional web content into a BrowserWindow. + /// It is like a child window, except that it is positioned relative to its owning window. + /// It is meant to be an alternative to the webview tag. + /// + /// + /// + Task CreateBrowserViewAsync(BrowserViewConstructorOptions options); + } +} \ No newline at end of file diff --git a/ElectronNET.API/IpcMain.cs b/ElectronNET.API/IpcMain.cs old mode 100644 new mode 100755 index 3e950c12..5b5732f8 --- a/ElectronNET.API/IpcMain.cs +++ b/ElectronNET.API/IpcMain.cs @@ -5,13 +5,14 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using ElectronNET.API.Interfaces; namespace ElectronNET.API { /// /// Communicate asynchronously from the main process to renderer processes. /// - public sealed class IpcMain + public sealed class IpcMain : IIpcMain { private static IpcMain _ipcMain; private static object _syncRoot = new object(); diff --git a/ElectronNET.API/Menu.cs b/ElectronNET.API/Menu.cs old mode 100644 new mode 100755 index 8397a10d..91c233fb --- a/ElectronNET.API/Menu.cs +++ b/ElectronNET.API/Menu.cs @@ -6,13 +6,14 @@ using ElectronNET.API.Extensions; using System.Linq; using System.Collections.ObjectModel; +using ElectronNET.API.Interfaces; namespace ElectronNET.API { /// /// Create native application menus and context menus. /// - public sealed class Menu + public sealed class Menu : IMenu { private static Menu _menu; private static object _syncRoot = new object(); diff --git a/ElectronNET.API/NativeTheme.cs b/ElectronNET.API/NativeTheme.cs old mode 100644 new mode 100755 index 037a97a6..ace81384 --- a/ElectronNET.API/NativeTheme.cs +++ b/ElectronNET.API/NativeTheme.cs @@ -2,13 +2,14 @@ using System.Threading.Tasks; using ElectronNET.API.Entities; using ElectronNET.API.Extensions; +using ElectronNET.API.Interfaces; namespace ElectronNET.API { /// /// Read and respond to changes in Chromium's native color theme. /// - public sealed class NativeTheme + public sealed class NativeTheme : INativeTheme { private static NativeTheme _nativeTheme; private static object _syncRoot = new object(); diff --git a/ElectronNET.API/Notification.cs b/ElectronNET.API/Notification.cs old mode 100644 new mode 100755 index 68ac4e14..cdd7eac0 --- a/ElectronNET.API/Notification.cs +++ b/ElectronNET.API/Notification.cs @@ -6,13 +6,14 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using ElectronNET.API.Interfaces; namespace ElectronNET.API { /// /// Create OS desktop notifications /// - public sealed class Notification + public sealed class Notification : INotification { private static Notification _notification; private static object _syncRoot = new object(); diff --git a/ElectronNET.API/PowerMonitor.cs b/ElectronNET.API/PowerMonitor.cs old mode 100644 new mode 100755 index 03e68748..fec049bb --- a/ElectronNET.API/PowerMonitor.cs +++ b/ElectronNET.API/PowerMonitor.cs @@ -1,12 +1,13 @@ using System; using System.Threading.Tasks; +using ElectronNET.API.Interfaces; namespace ElectronNET.API { /// /// Monitor power state changes.. /// - public sealed class PowerMonitor + public sealed class PowerMonitor : IPowerMonitor { /// /// Emitted when the system is about to lock the screen. diff --git a/ElectronNET.API/Screen.cs b/ElectronNET.API/Screen.cs old mode 100644 new mode 100755 index 31cecb5f..d7935d31 --- a/ElectronNET.API/Screen.cs +++ b/ElectronNET.API/Screen.cs @@ -4,13 +4,14 @@ using Newtonsoft.Json.Serialization; using System; using System.Threading.Tasks; +using ElectronNET.API.Interfaces; namespace ElectronNET.API { /// /// Retrieve information about screen size, displays, cursor position, etc. /// - public sealed class Screen + public sealed class Screen : IScreen { /// /// Emitted when an new Display has been added. diff --git a/ElectronNET.API/ServiceCollectionExtensions.cs b/ElectronNET.API/ServiceCollectionExtensions.cs old mode 100644 new mode 100755 index f933731b..b0c54aa5 --- a/ElectronNET.API/ServiceCollectionExtensions.cs +++ b/ElectronNET.API/ServiceCollectionExtensions.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using ElectronNET.API.Interfaces; +using Microsoft.Extensions.DependencyInjection; namespace ElectronNET.API { @@ -13,6 +14,7 @@ public static class ServiceCollectionExtensions public static IServiceCollection AddElectron(this IServiceCollection services) => services // adding in this manner to ensure late binding. + // this set for backwards compatibility .AddSingleton(provider => IpcMain.Instance) .AddSingleton(provider => App.Instance) .AddSingleton(provider => AutoUpdater.Instance) @@ -28,6 +30,25 @@ public static IServiceCollection AddElectron(this IServiceCollection services) .AddSingleton(provider => HostHook.Instance) .AddSingleton(provider => PowerMonitor.Instance) .AddSingleton(provider => NativeTheme.Instance) - .AddSingleton(provider => Dock.Instance); + .AddSingleton(provider => Dock.Instance) + .AddSingleton(provider => new ApplicationSocket { Socket = BridgeConnector.Socket, }) + // this set for proper dependency injection + .AddSingleton(provider => IpcMain.Instance) + .AddSingleton(provider => App.Instance) + .AddSingleton(provider => AutoUpdater.Instance) + .AddSingleton(provider => WindowManager.Instance) + .AddSingleton(provider => Menu.Instance) + .AddSingleton(provider => Dialog.Instance) + .AddSingleton(provider => Notification.Instance) + .AddSingleton(provider => Tray.Instance) + .AddSingleton(provider => GlobalShortcut.Instance) + .AddSingleton(provider => Shell.Instance) + .AddSingleton(provider => Screen.Instance) + .AddSingleton(provider => Clipboard.Instance) + .AddSingleton(provider => HostHook.Instance) + .AddSingleton(provider => PowerMonitor.Instance) + .AddSingleton(provider => NativeTheme.Instance) + .AddSingleton(provider => Dock.Instance) + .AddSingleton(provider => provider.GetService()); } } diff --git a/ElectronNET.API/Shell.cs b/ElectronNET.API/Shell.cs old mode 100644 new mode 100755 index 71f458e4..0228c59d --- a/ElectronNET.API/Shell.cs +++ b/ElectronNET.API/Shell.cs @@ -4,13 +4,14 @@ using Newtonsoft.Json.Serialization; using System.Threading.Tasks; using ElectronNET.API.Extensions; +using ElectronNET.API.Interfaces; namespace ElectronNET.API { /// /// Manage files and URLs using their default applications. /// - public sealed class Shell + public sealed class Shell : IShell { private static Shell _shell; private static object _syncRoot = new object(); diff --git a/ElectronNET.API/Tray.cs b/ElectronNET.API/Tray.cs old mode 100644 new mode 100755 index a5aac8a1..7c808ae9 --- a/ElectronNET.API/Tray.cs +++ b/ElectronNET.API/Tray.cs @@ -6,13 +6,14 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using ElectronNET.API.Interfaces; namespace ElectronNET.API { /// /// Add icons and context menus to the system's notification area. /// - public sealed class Tray + public sealed class Tray : ITray { /// /// Emitted when the tray icon is clicked. diff --git a/ElectronNET.API/WindowManager.cs b/ElectronNET.API/WindowManager.cs old mode 100644 new mode 100755 index 4ac85dab..e31c46b4 --- a/ElectronNET.API/WindowManager.cs +++ b/ElectronNET.API/WindowManager.cs @@ -7,13 +7,14 @@ using System.Linq; using System.Runtime.InteropServices; using System.Threading.Tasks; +using ElectronNET.API.Interfaces; namespace ElectronNET.API { /// /// /// - public sealed class WindowManager + public sealed class WindowManager : IWindowManager { private static WindowManager _windowManager; private static object _syncRoot = new object(); From 8e1e184d1e1ef4682547d2dae8c6e7820eb22d38 Mon Sep 17 00:00:00 2001 From: Todd Schavey Date: Tue, 28 Dec 2021 21:40:53 -0500 Subject: [PATCH 2/9] #647 process argv for open-file for win and linux --- ElectronNET.Host/main.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/ElectronNET.Host/main.js b/ElectronNET.Host/main.js index 37d8be8b..459c47f5 100644 --- a/ElectronNET.Host/main.js +++ b/ElectronNET.Host/main.js @@ -18,6 +18,27 @@ let launchUrl; let manifestJsonFileName = 'electron.manifest.json'; let watchable = false; + +// handle for opening the app with a file for win and linux +if (process && process.argv.length > 1) { + + let firstAppArgument = process.argv[1]; + + // With invoked via electronize, the first argument is the path to the main.js. + // Per issue #337, the /args switch can also be present. If either are present, + // we need to check the subsequent argument. + if (firstAppArgument === '..\\..\\main.js' || firstAppArgument === '../../main.js' || firstAppArgument === '/args') { + if (process.argv.length > 2) { + firstAppArgument = process.argv[2]; + } + } + + // only append the first app arg if it is not already a switch + if (!firstAppArgument.startsWith("--")) { + app.commandLine.appendSwitch("open-file", firstAppArgument); + } +} + if (app.commandLine.hasSwitch('manifest')) { manifestJsonFileName = app.commandLine.getSwitchValue('manifest'); }; From 1406fc1d798ada0d98e30bf712ce4da491d98f64 Mon Sep 17 00:00:00 2001 From: Todd Schavey Date: Sun, 2 Jan 2022 16:46:14 -0500 Subject: [PATCH 3/9] #647 add initial Process class to ElectronNET.API --- ElectronNET.API/Electron.cs | 5 ++ ElectronNET.API/Process.cs | 61 +++++++++++++++++++ .../ServiceCollectionExtensions.cs | 3 +- .../Actions/DeployEmbeddedElectronFiles.cs | 1 + ElectronNET.CLI/ElectronNET.CLI.csproj | 1 + ElectronNET.Host/api/process.js | 10 +++ ElectronNET.Host/api/process.js.map | 1 + ElectronNET.Host/api/process.ts | 11 ++++ ElectronNET.Host/main.js | 22 +------ 9 files changed, 94 insertions(+), 21 deletions(-) create mode 100644 ElectronNET.API/Process.cs create mode 100644 ElectronNET.Host/api/process.js create mode 100644 ElectronNET.Host/api/process.js.map create mode 100644 ElectronNET.Host/api/process.ts diff --git a/ElectronNET.API/Electron.cs b/ElectronNET.API/Electron.cs index 23f9902d..5c636164 100644 --- a/ElectronNET.API/Electron.cs +++ b/ElectronNET.API/Electron.cs @@ -88,5 +88,10 @@ public static class Electron /// Control your app in the macOS dock. /// public static Dock Dock { get { return Dock.Instance; } } + + /// + /// Electeon extensions to the Nodejs process object. + /// + public static Process Process { get { return Process.Instance; } } } } \ No newline at end of file diff --git a/ElectronNET.API/Process.cs b/ElectronNET.API/Process.cs new file mode 100644 index 00000000..daa692b2 --- /dev/null +++ b/ElectronNET.API/Process.cs @@ -0,0 +1,61 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace ElectronNET.API +{ + /// + /// Electron's process object is extended from the Node.js process object. It adds the + /// events, properties, and methods. + /// + public sealed class Process + { + internal Process() { } + + internal static Process Instance + { + get + { + if (_process == null) + { + lock (_syncRoot) + { + if (_process == null) + { + _process = new Process(); + } + } + } + + return _process; + } + } + + private static Process _process; + + private static readonly object _syncRoot = new(); + + /// + /// TBD + /// + /// + public async Task GetExecPathAsync(CancellationToken cancellationToken = default) + { + cancellationToken.ThrowIfCancellationRequested(); + + var taskCompletionSource = new TaskCompletionSource(); + using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) + { + BridgeConnector.Socket.On("process-execPathCompleted", (text) => + { + BridgeConnector.Socket.Off("process-execPathCompleted"); + taskCompletionSource.SetResult((string) text); + }); + + BridgeConnector.Socket.Emit("process-execPath"); + + return await taskCompletionSource.Task + .ConfigureAwait(false); + } + } + } +} diff --git a/ElectronNET.API/ServiceCollectionExtensions.cs b/ElectronNET.API/ServiceCollectionExtensions.cs index f933731b..a63aacf2 100644 --- a/ElectronNET.API/ServiceCollectionExtensions.cs +++ b/ElectronNET.API/ServiceCollectionExtensions.cs @@ -28,6 +28,7 @@ public static IServiceCollection AddElectron(this IServiceCollection services) .AddSingleton(provider => HostHook.Instance) .AddSingleton(provider => PowerMonitor.Instance) .AddSingleton(provider => NativeTheme.Instance) - .AddSingleton(provider => Dock.Instance); + .AddSingleton(provider => Dock.Instance) + .AddSingleton(provider => Process.Instance); } } diff --git a/ElectronNET.CLI/Commands/Actions/DeployEmbeddedElectronFiles.cs b/ElectronNET.CLI/Commands/Actions/DeployEmbeddedElectronFiles.cs index fcefcd45..e9a890af 100644 --- a/ElectronNET.CLI/Commands/Actions/DeployEmbeddedElectronFiles.cs +++ b/ElectronNET.CLI/Commands/Actions/DeployEmbeddedElectronFiles.cs @@ -33,6 +33,7 @@ public static void Do(string tempPath) EmbeddedFileHelper.DeployEmbeddedFile(hostApiFolder, "browserView.js", "api."); EmbeddedFileHelper.DeployEmbeddedFile(hostApiFolder, "powerMonitor.js", "api."); EmbeddedFileHelper.DeployEmbeddedFile(hostApiFolder, "nativeTheme.js", "api."); + EmbeddedFileHelper.DeployEmbeddedFile(hostApiFolder, "process.js", "api."); string splashscreenFolder = Path.Combine(tempPath, "splashscreen"); if (Directory.Exists(splashscreenFolder) == false) diff --git a/ElectronNET.CLI/ElectronNET.CLI.csproj b/ElectronNET.CLI/ElectronNET.CLI.csproj index a4bd0118..792a135d 100644 --- a/ElectronNET.CLI/ElectronNET.CLI.csproj +++ b/ElectronNET.CLI/ElectronNET.CLI.csproj @@ -74,6 +74,7 @@ + diff --git a/ElectronNET.Host/api/process.js b/ElectronNET.Host/api/process.js new file mode 100644 index 00000000..80bdaf79 --- /dev/null +++ b/ElectronNET.Host/api/process.js @@ -0,0 +1,10 @@ +"use strict"; +let electronSocket; +module.exports = (socket) => { + electronSocket = socket; + socket.on('process-execPath', () => { + const value = process.execPath; + electronSocket.emit('process-execPathCompleted', value); + }); +}; +//# sourceMappingURL=process.js.map \ No newline at end of file diff --git a/ElectronNET.Host/api/process.js.map b/ElectronNET.Host/api/process.js.map new file mode 100644 index 00000000..e2e659a4 --- /dev/null +++ b/ElectronNET.Host/api/process.js.map @@ -0,0 +1 @@ +{"version":3,"file":"process.js","sourceRoot":"","sources":["process.ts"],"names":[],"mappings":";AACA,IAAI,cAAc,CAAC;AAEnB,iBAAS,CAAC,MAAc,EAAE,EAAE;IACxB,cAAc,GAAG,MAAM,CAAC;IAExB,MAAM,CAAC,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC;QAC/B,cAAc,CAAC,IAAI,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;AACP,CAAC,CAAC"} \ No newline at end of file diff --git a/ElectronNET.Host/api/process.ts b/ElectronNET.Host/api/process.ts new file mode 100644 index 00000000..a5598698 --- /dev/null +++ b/ElectronNET.Host/api/process.ts @@ -0,0 +1,11 @@ +import { Socket } from 'net'; +let electronSocket; + +export = (socket: Socket) => { + electronSocket = socket; + + socket.on('process-execPath', () => { + const value = process.execPath; + electronSocket.emit('process-execPathCompleted', value); + }); +}; diff --git a/ElectronNET.Host/main.js b/ElectronNET.Host/main.js index 459c47f5..f984138f 100644 --- a/ElectronNET.Host/main.js +++ b/ElectronNET.Host/main.js @@ -15,30 +15,11 @@ let mainWindowId, nativeTheme; let dock; let launchFile; let launchUrl; +let processApi; let manifestJsonFileName = 'electron.manifest.json'; let watchable = false; -// handle for opening the app with a file for win and linux -if (process && process.argv.length > 1) { - - let firstAppArgument = process.argv[1]; - - // With invoked via electronize, the first argument is the path to the main.js. - // Per issue #337, the /args switch can also be present. If either are present, - // we need to check the subsequent argument. - if (firstAppArgument === '..\\..\\main.js' || firstAppArgument === '../../main.js' || firstAppArgument === '/args') { - if (process.argv.length > 2) { - firstAppArgument = process.argv[2]; - } - } - - // only append the first app arg if it is not already a switch - if (!firstAppArgument.startsWith("--")) { - app.commandLine.appendSwitch("open-file", firstAppArgument); - } -} - if (app.commandLine.hasSwitch('manifest')) { manifestJsonFileName = app.commandLine.getSwitchValue('manifest'); }; @@ -238,6 +219,7 @@ function startSocketApiBridge(port) { if (powerMonitor === undefined) powerMonitor = require('./api/powerMonitor')(socket); if (nativeTheme === undefined) nativeTheme = require('./api/nativeTheme')(socket); if (dock === undefined) dock = require('./api/dock')(socket); + if (processApi === undefined) processApi = require('./api/process')(socket); socket.on('register-app-open-file-event', (id) => { global['electronsocket'] = socket; From 562cccbfae8a9230aa19490976fb3b39bf79c294 Mon Sep 17 00:00:00 2001 From: Todd Schavey Date: Sun, 2 Jan 2022 18:28:39 -0500 Subject: [PATCH 4/9] #647 add to ElectronNET.API Process member interfaces for argv and type --- ElectronNET.API/Process.cs | 89 +++++++++++++++++++++++++---- ElectronNET.Host/api/process.js | 8 +++ ElectronNET.Host/api/process.js.map | 2 +- ElectronNET.Host/api/process.ts | 10 ++++ 4 files changed, 97 insertions(+), 12 deletions(-) diff --git a/ElectronNET.API/Process.cs b/ElectronNET.API/Process.cs index daa692b2..887eda39 100644 --- a/ElectronNET.API/Process.cs +++ b/ElectronNET.API/Process.cs @@ -1,5 +1,7 @@ using System.Threading; using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace ElectronNET.API { @@ -34,27 +36,92 @@ internal static Process Instance private static readonly object _syncRoot = new(); + /// + /// The process.execPath property returns the absolute pathname of the executable that started the Node.js process. Symbolic links, if any, are resolved. + /// + /// + /// + /// var path = await Electron.Process.ExecPathAsync; + /// + /// + public Task ExecPathAsync + { + get + { + CancellationToken cancellationToken = new(); + cancellationToken.ThrowIfCancellationRequested(); + + var taskCompletionSource = new TaskCompletionSource(); + using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) + { + BridgeConnector.Socket.On("process-execPathCompleted", (text) => + { + BridgeConnector.Socket.Off("process-execPathCompleted"); + taskCompletionSource.SetResult((string) text); + }); + + BridgeConnector.Socket.Emit("process-execPath"); + + return taskCompletionSource.Task; + } + } + } + /// /// TBD /// /// - public async Task GetExecPathAsync(CancellationToken cancellationToken = default) + public Task ArgvAsync { - cancellationToken.ThrowIfCancellationRequested(); + get + { + CancellationToken cancellationToken = new(); + cancellationToken.ThrowIfCancellationRequested(); - var taskCompletionSource = new TaskCompletionSource(); - using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) + var taskCompletionSource = new TaskCompletionSource(); + using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) + { + BridgeConnector.Socket.On("process-argvCompleted", (value) => + { + BridgeConnector.Socket.Off("process-argvCompleted"); + taskCompletionSource.SetResult( ((JArray)value).ToObject() ); + }); + + BridgeConnector.Socket.Emit("process-argv"); + + return taskCompletionSource.Task; + } + } + } + + /// + /// The process.execPath property returns the absolute pathname of the executable that started the Node.js process. Symbolic links, if any, are resolved. + /// + /// + /// + /// var path = await Electron.Process.ExecPathAsync; + /// + /// + public Task TypeAsync + { + get { - BridgeConnector.Socket.On("process-execPathCompleted", (text) => + CancellationToken cancellationToken = new(); + cancellationToken.ThrowIfCancellationRequested(); + + var taskCompletionSource = new TaskCompletionSource(); + using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) { - BridgeConnector.Socket.Off("process-execPathCompleted"); - taskCompletionSource.SetResult((string) text); - }); + BridgeConnector.Socket.On("process-typeCompleted", (text) => + { + BridgeConnector.Socket.Off("process-typeCompleted"); + taskCompletionSource.SetResult((string) text); + }); - BridgeConnector.Socket.Emit("process-execPath"); + BridgeConnector.Socket.Emit("process-type"); - return await taskCompletionSource.Task - .ConfigureAwait(false); + return taskCompletionSource.Task; + } } } } diff --git a/ElectronNET.Host/api/process.js b/ElectronNET.Host/api/process.js index 80bdaf79..00c929f4 100644 --- a/ElectronNET.Host/api/process.js +++ b/ElectronNET.Host/api/process.js @@ -6,5 +6,13 @@ module.exports = (socket) => { const value = process.execPath; electronSocket.emit('process-execPathCompleted', value); }); + socket.on('process-argv', () => { + const value = process.argv; + electronSocket.emit('process-argvCompleted', value); + }); + socket.on('process-type', () => { + const value = process.type; + electronSocket.emit('process-typeCompleted', value); + }); }; //# sourceMappingURL=process.js.map \ No newline at end of file diff --git a/ElectronNET.Host/api/process.js.map b/ElectronNET.Host/api/process.js.map index e2e659a4..1e69e30d 100644 --- a/ElectronNET.Host/api/process.js.map +++ b/ElectronNET.Host/api/process.js.map @@ -1 +1 @@ -{"version":3,"file":"process.js","sourceRoot":"","sources":["process.ts"],"names":[],"mappings":";AACA,IAAI,cAAc,CAAC;AAEnB,iBAAS,CAAC,MAAc,EAAE,EAAE;IACxB,cAAc,GAAG,MAAM,CAAC;IAExB,MAAM,CAAC,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC;QAC/B,cAAc,CAAC,IAAI,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;AACP,CAAC,CAAC"} \ No newline at end of file +{"version":3,"file":"process.js","sourceRoot":"","sources":["process.ts"],"names":[],"mappings":";AACA,IAAI,cAAc,CAAC;AAEnB,iBAAS,CAAC,MAAc,EAAE,EAAE;IACxB,cAAc,GAAG,MAAM,CAAC;IAExB,MAAM,CAAC,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC;QAC/B,cAAc,CAAC,IAAI,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,GAAG,EAAE;QAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;QAC3B,cAAc,CAAC,IAAI,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,GAAG,EAAE;QAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;QAC3B,cAAc,CAAC,IAAI,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACP,CAAC,CAAC"} \ No newline at end of file diff --git a/ElectronNET.Host/api/process.ts b/ElectronNET.Host/api/process.ts index a5598698..97c05698 100644 --- a/ElectronNET.Host/api/process.ts +++ b/ElectronNET.Host/api/process.ts @@ -8,4 +8,14 @@ export = (socket: Socket) => { const value = process.execPath; electronSocket.emit('process-execPathCompleted', value); }); + + socket.on('process-argv', () => { + const value = process.argv; + electronSocket.emit('process-argvCompleted', value); + }); + + socket.on('process-type', () => { + const value = process.type; + electronSocket.emit('process-typeCompleted', value); + }); }; From ba82b9a600ab9264584b6747af9484868c5bdb79 Mon Sep 17 00:00:00 2001 From: Todd Schavey Date: Sun, 2 Jan 2022 22:46:53 -0500 Subject: [PATCH 5/9] #647 add to ElectronNET.API Process member interfaces for various fields --- ElectronNET.API/BridgeConnector.cs | 81 ++++++++++++- ElectronNET.API/Entities/Versions.cs | 18 +++ ElectronNET.API/Process.cs | 169 ++++++++++++++++++--------- ElectronNET.Host/api/process.js | 50 +++++++- ElectronNET.Host/api/process.js.map | 2 +- ElectronNET.Host/api/process.ts | 58 ++++++++- 6 files changed, 312 insertions(+), 66 deletions(-) create mode 100644 ElectronNET.API/Entities/Versions.cs diff --git a/ElectronNET.API/BridgeConnector.cs b/ElectronNET.API/BridgeConnector.cs index 08a84745..3f37e06a 100644 --- a/ElectronNET.API/BridgeConnector.cs +++ b/ElectronNET.API/BridgeConnector.cs @@ -1,5 +1,8 @@ -using Quobject.SocketIoClientDotNet.Client; +using Newtonsoft.Json.Linq; +using Quobject.SocketIoClientDotNet.Client; using System; +using System.Threading; +using System.Threading.Tasks; namespace ElectronNET.API { @@ -40,5 +43,81 @@ public static Socket Socket return _socket; } } + + public static async Task GetValueOverSocketAsync(string eventString, string eventCompletedString) + { + CancellationToken cancellationToken = new(); + cancellationToken.ThrowIfCancellationRequested(); + + var taskCompletionSource = new TaskCompletionSource(); + using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) + { + BridgeConnector.Socket.On(eventCompletedString, (value) => + { + BridgeConnector.Socket.Off(eventCompletedString); + + if (value == null) + { + Console.WriteLine($"ERROR: BridgeConnector (event: '{eventString}') returned null. Socket loop hang."); + taskCompletionSource.SetCanceled(); + return; + } + + try + { + taskCompletionSource.SetResult( new JValue(value).ToObject() ); + } + catch (Exception e) + { + Console.WriteLine($"ERROR: BridgeConnector (event: '{eventString}') exception: {e.Message}. Socket loop hung."); + } + }); + + BridgeConnector.Socket.Emit(eventString); + + return await taskCompletionSource.Task.ConfigureAwait(false); + } + } + + public static async Task GetObjectOverSocketAsync(string eventString, string eventCompletedString) + { + CancellationToken cancellationToken = new(); + cancellationToken.ThrowIfCancellationRequested(); + + var taskCompletionSource = new TaskCompletionSource(); + using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) + { + BridgeConnector.Socket.On(eventCompletedString, (value) => + { + BridgeConnector.Socket.Off(eventCompletedString); + taskCompletionSource.SetResult( ((JObject)value).ToObject() ); + }); + + BridgeConnector.Socket.Emit(eventString); + + return await taskCompletionSource.Task.ConfigureAwait(false); + } + } + + public static async Task GetArrayOverSocketAsync(string eventString, string eventCompletedString) + { + CancellationToken cancellationToken = new(); + cancellationToken.ThrowIfCancellationRequested(); + + var taskCompletionSource = new TaskCompletionSource(); + using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) + { + BridgeConnector.Socket.On(eventCompletedString, (value) => + { + BridgeConnector.Socket.Off(eventCompletedString); + taskCompletionSource.SetResult( ((JArray)value).ToObject() ); + }); + + BridgeConnector.Socket.Emit(eventString); + + return await taskCompletionSource.Task.ConfigureAwait(false); + } + } + } } diff --git a/ElectronNET.API/Entities/Versions.cs b/ElectronNET.API/Entities/Versions.cs new file mode 100644 index 00000000..254a62c8 --- /dev/null +++ b/ElectronNET.API/Entities/Versions.cs @@ -0,0 +1,18 @@ +namespace ElectronNET.API +{ + /// + /// + /// + public class Versions + { + /// + /// Gets or sets a value representing Chrome's version string. + /// + public string Chrome { get; set; } + + /// + /// Gets or sets a value representing Electron's version string. + /// + public bool Electron { get; set; } + } +} \ No newline at end of file diff --git a/ElectronNET.API/Process.cs b/ElectronNET.API/Process.cs index 887eda39..0976d20b 100644 --- a/ElectronNET.API/Process.cs +++ b/ElectronNET.API/Process.cs @@ -37,92 +37,145 @@ internal static Process Instance private static readonly object _syncRoot = new(); /// - /// The process.execPath property returns the absolute pathname of the executable that started the Node.js process. Symbolic links, if any, are resolved. - /// - /// - /// - /// var path = await Electron.Process.ExecPathAsync; - /// - /// + /// The process.execPath property returns the absolute pathname of the executable that + /// started the Node.js process. Symbolic links, if any, are resolved. + /// public Task ExecPathAsync { get { - CancellationToken cancellationToken = new(); - cancellationToken.ThrowIfCancellationRequested(); - - var taskCompletionSource = new TaskCompletionSource(); - using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) - { - BridgeConnector.Socket.On("process-execPathCompleted", (text) => - { - BridgeConnector.Socket.Off("process-execPathCompleted"); - taskCompletionSource.SetResult((string) text); - }); - - BridgeConnector.Socket.Emit("process-execPath"); - - return taskCompletionSource.Task; - } + return BridgeConnector.GetValueOverSocketAsync( + "process-execPath", "process-execPath-Completed"); } } /// - /// TBD + /// The process.argv property returns an array containing the command-line arguments passed + /// when the Node.js process was launched. The first element will be process.execPath. See + /// process.argv0 if access to the original value of argv[0] is needed. The second element + /// will be the path to the JavaScript file being executed. The remaining elements will be + /// any additional command-line arguments /// - /// public Task ArgvAsync { get { - CancellationToken cancellationToken = new(); - cancellationToken.ThrowIfCancellationRequested(); + return BridgeConnector.GetArrayOverSocketAsync( + "process-argv", "process-argv-Completed"); + } + } - var taskCompletionSource = new TaskCompletionSource(); - using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) - { - BridgeConnector.Socket.On("process-argvCompleted", (value) => - { - BridgeConnector.Socket.Off("process-argvCompleted"); - taskCompletionSource.SetResult( ((JArray)value).ToObject() ); - }); + /// + /// The process.execPath property returns the absolute pathname of the executable that + /// started the Node.js process. Symbolic links, if any, are resolved. + /// + public Task TypeAsync + { + get + { + return BridgeConnector.GetValueOverSocketAsync( + "process-type", "process-type-Completed"); + } + } + + + /// + /// + /// + public Task VersionsAsync + { + get + { + return BridgeConnector.GetValueOverSocketAsync( + "process-versions", "process-versions-Completed"); + } + } + + + /// + /// + /// + public Task DefaultAppAsync + { + get + { + return BridgeConnector.GetValueOverSocketAsync( + "process-defaultApp", "process-defaultApp-Completed"); + } + } - BridgeConnector.Socket.Emit("process-argv"); + /// + /// + /// + public Task IsMainFrameAsync + { + get + { + return BridgeConnector.GetValueOverSocketAsync( + "process-isMainFrame", "process-isMainFrame-Completed"); + } + } - return taskCompletionSource.Task; - } + /// + /// + /// + public Task ResourcesPathAsync + { + get + { + return BridgeConnector.GetValueOverSocketAsync( + "process-resourcesPath", "process-resourcesPath-Completed"); } } /// - /// The process.execPath property returns the absolute pathname of the executable that started the Node.js process. Symbolic links, if any, are resolved. + /// /// - /// - /// - /// var path = await Electron.Process.ExecPathAsync; - /// - /// - public Task TypeAsync + public Task UpTimeAsync { get { - CancellationToken cancellationToken = new(); - cancellationToken.ThrowIfCancellationRequested(); + return BridgeConnector.GetValueOverSocketAsync( + "process-uptime", "process-uptime-Completed"); + } + } - var taskCompletionSource = new TaskCompletionSource(); - using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled())) - { - BridgeConnector.Socket.On("process-typeCompleted", (text) => - { - BridgeConnector.Socket.Off("process-typeCompleted"); - taskCompletionSource.SetResult((string) text); - }); + /// + /// + /// + public Task PidAsync + { + get + { + return BridgeConnector.GetValueOverSocketAsync( + "process-pid", "process-pid-Completed"); + } + } - BridgeConnector.Socket.Emit("process-type"); - return taskCompletionSource.Task; - } + /// + /// + /// + public Task ArchAsync + { + get + { + return BridgeConnector.GetValueOverSocketAsync( + "process-arch", "process-arch-Completed"); + } + } + + /// + /// + /// + public Task PlatformAsync + { + get + { + return BridgeConnector.GetValueOverSocketAsync( + "process-platform", "process-platform-Completed"); } } + } } diff --git a/ElectronNET.Host/api/process.js b/ElectronNET.Host/api/process.js index 00c929f4..36c08b4a 100644 --- a/ElectronNET.Host/api/process.js +++ b/ElectronNET.Host/api/process.js @@ -4,15 +4,59 @@ module.exports = (socket) => { electronSocket = socket; socket.on('process-execPath', () => { const value = process.execPath; - electronSocket.emit('process-execPathCompleted', value); + electronSocket.emit('process-execPath-Completed', value); }); socket.on('process-argv', () => { const value = process.argv; - electronSocket.emit('process-argvCompleted', value); + electronSocket.emit('process-argv-Completed', value); }); socket.on('process-type', () => { const value = process.type; - electronSocket.emit('process-typeCompleted', value); + electronSocket.emit('process-type-Completed', value); + }); + socket.on('process-versions', () => { + const value = process.versions; + electronSocket.emit('process-versions-Completed', value); + }); + socket.on('process-defaultApp', () => { + if (process.defaultApp === undefined) { + electronSocket.emit('process-defaultApp-Completed', false); + return; + } + electronSocket.emit('process-defaultApp-Completed', process.defaultApp); + }); + socket.on('process-isMainFrame', () => { + if (process.isMainFrame === undefined) { + electronSocket.emit('process-isMainFrame-Completed', false); + return; + } + electronSocket.emit('process-isMainFrame-Completed', process.isMainFrame); + }); + socket.on('process-resourcesPath', () => { + const value = process.resourcesPath; + electronSocket.emit('process-resourcesPath-Completed', value); + }); + socket.on('process-uptime', () => { + let value = process.uptime(); + if (value === undefined) { + value = -1; + } + electronSocket.emit('process-uptime-Completed', value); + }); + socket.on('process-pid', () => { + if (process.pid === undefined) { + electronSocket.emit('process-pid-Completed', -1); + return; + } + electronSocket.emit('process-pid-Completed', process.pid); + }); + socket.on('process-arch', () => { + const value = process.arch; + electronSocket.emit('process-arch-Completed', value); + }); + socket.on('process-platform', () => { + const value = process.platform; + electronSocket.emit('process-platform-Completed', value); }); }; //# sourceMappingURL=process.js.map \ No newline at end of file diff --git a/ElectronNET.Host/api/process.js.map b/ElectronNET.Host/api/process.js.map index 1e69e30d..096946ca 100644 --- a/ElectronNET.Host/api/process.js.map +++ b/ElectronNET.Host/api/process.js.map @@ -1 +1 @@ -{"version":3,"file":"process.js","sourceRoot":"","sources":["process.ts"],"names":[],"mappings":";AACA,IAAI,cAAc,CAAC;AAEnB,iBAAS,CAAC,MAAc,EAAE,EAAE;IACxB,cAAc,GAAG,MAAM,CAAC;IAExB,MAAM,CAAC,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC;QAC/B,cAAc,CAAC,IAAI,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,GAAG,EAAE;QAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;QAC3B,cAAc,CAAC,IAAI,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,GAAG,EAAE;QAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;QAC3B,cAAc,CAAC,IAAI,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACP,CAAC,CAAC"} \ No newline at end of file +{"version":3,"file":"process.js","sourceRoot":"","sources":["process.ts"],"names":[],"mappings":";AACA,IAAI,cAAc,CAAC;AAEnB,iBAAS,CAAC,MAAc,EAAE,EAAE;IACxB,cAAc,GAAG,MAAM,CAAC;IAExB,MAAM,CAAC,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC;QAC/B,cAAc,CAAC,IAAI,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,GAAG,EAAE;QAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;QAC3B,cAAc,CAAC,IAAI,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,GAAG,EAAE;QAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;QAC3B,cAAc,CAAC,IAAI,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC;QAC/B,cAAc,CAAC,IAAI,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE;QACjC,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE;YAClC,cAAc,CAAC,IAAI,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;YAC3D,OAAO;SACV;QACD,cAAc,CAAC,IAAI,CAAC,8BAA8B,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAClC,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS,EAAE;YACnC,cAAc,CAAC,IAAI,CAAC,+BAA+B,EAAE,KAAK,CAAC,CAAC;YAC5D,OAAO;SACV;QACD,cAAc,CAAC,IAAI,CAAC,+BAA+B,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QACpC,MAAM,KAAK,GAAG,OAAO,CAAC,aAAa,CAAC;QACpC,cAAc,CAAC,IAAI,CAAC,iCAAiC,EAAE,KAAK,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAC7B,IAAI,KAAK,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;QAC7B,IAAI,KAAK,KAAK,SAAS,EAAE;YACrB,KAAK,GAAG,CAAC,CAAC,CAAC;SACd;QACD,cAAc,CAAC,IAAI,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,aAAa,EAAE,GAAG,EAAE;QAC1B,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS,EAAE;YAC3B,cAAc,CAAC,IAAI,CAAC,uBAAuB,EAAE,CAAC,CAAC,CAAC,CAAC;YACjD,OAAO;SACV;QACD,cAAc,CAAC,IAAI,CAAC,uBAAuB,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,GAAG,EAAE;QAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;QAC3B,cAAc,CAAC,IAAI,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC;QAC/B,cAAc,CAAC,IAAI,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAA;AACN,CAAC,CAAC"} \ No newline at end of file diff --git a/ElectronNET.Host/api/process.ts b/ElectronNET.Host/api/process.ts index 97c05698..ad04dbf2 100644 --- a/ElectronNET.Host/api/process.ts +++ b/ElectronNET.Host/api/process.ts @@ -6,16 +6,68 @@ export = (socket: Socket) => { socket.on('process-execPath', () => { const value = process.execPath; - electronSocket.emit('process-execPathCompleted', value); + electronSocket.emit('process-execPath-Completed', value); }); socket.on('process-argv', () => { const value = process.argv; - electronSocket.emit('process-argvCompleted', value); + electronSocket.emit('process-argv-Completed', value); }); socket.on('process-type', () => { const value = process.type; - electronSocket.emit('process-typeCompleted', value); + electronSocket.emit('process-type-Completed', value); }); + + socket.on('process-versions', () => { + const value = process.versions; + electronSocket.emit('process-versions-Completed', value); + }); + + socket.on('process-defaultApp', () => { + if (process.defaultApp === undefined) { + electronSocket.emit('process-defaultApp-Completed', false); + return; + } + electronSocket.emit('process-defaultApp-Completed', process.defaultApp); + }); + + socket.on('process-isMainFrame', () => { + if (process.isMainFrame === undefined) { + electronSocket.emit('process-isMainFrame-Completed', false); + return; + } + electronSocket.emit('process-isMainFrame-Completed', process.isMainFrame); + }); + + socket.on('process-resourcesPath', () => { + const value = process.resourcesPath; + electronSocket.emit('process-resourcesPath-Completed', value); + }); + + socket.on('process-uptime', () => { + let value = process.uptime(); + if (value === undefined) { + value = -1; + } + electronSocket.emit('process-uptime-Completed', value); + }); + + socket.on('process-pid', () => { + if (process.pid === undefined) { + electronSocket.emit('process-pid-Completed', -1); + return; + } + electronSocket.emit('process-pid-Completed', process.pid); + }); + + socket.on('process-arch', () => { + const value = process.arch; + electronSocket.emit('process-arch-Completed', value); + }); + + socket.on('process-platform', () => { + const value = process.platform; + electronSocket.emit('process-platform-Completed', value); + }) }; From 592148116bcfc8aa5da2799fa74907f86ccb0d59 Mon Sep 17 00:00:00 2001 From: Todd Schavey Date: Sun, 2 Jan 2022 23:11:01 -0500 Subject: [PATCH 6/9] #647 correct to ElectronNET.API Process member for versions field --- ElectronNET.API/BridgeConnector.cs | 33 +++++++++++++++++-- .../{Versions.cs => ProcessVersions.cs} | 4 +-- ElectronNET.API/Process.cs | 4 +-- 3 files changed, 35 insertions(+), 6 deletions(-) rename ElectronNET.API/Entities/{Versions.cs => ProcessVersions.cs} (82%) diff --git a/ElectronNET.API/BridgeConnector.cs b/ElectronNET.API/BridgeConnector.cs index 3f37e06a..8c4d979d 100644 --- a/ElectronNET.API/BridgeConnector.cs +++ b/ElectronNET.API/BridgeConnector.cs @@ -90,7 +90,22 @@ public static async Task GetObjectOverSocketAsync(string eventString, stri BridgeConnector.Socket.On(eventCompletedString, (value) => { BridgeConnector.Socket.Off(eventCompletedString); - taskCompletionSource.SetResult( ((JObject)value).ToObject() ); + + if (value == null) + { + Console.WriteLine($"ERROR: BridgeConnector (event: '{eventString}') returned null. Socket loop hang."); + taskCompletionSource.SetCanceled(); + return; + } + + try + { + taskCompletionSource.SetResult( ((JObject)value).ToObject() ); + } + catch (Exception e) + { + Console.WriteLine($"ERROR: BridgeConnector (event: '{eventString}') exception: {e.Message}. Socket loop hung."); + } }); BridgeConnector.Socket.Emit(eventString); @@ -110,7 +125,21 @@ public static async Task GetArrayOverSocketAsync(string eventString, strin BridgeConnector.Socket.On(eventCompletedString, (value) => { BridgeConnector.Socket.Off(eventCompletedString); - taskCompletionSource.SetResult( ((JArray)value).ToObject() ); + if (value == null) + { + Console.WriteLine($"ERROR: BridgeConnector (event: '{eventString}') returned null. Socket loop hang."); + taskCompletionSource.SetCanceled(); + return; + } + + try + { + taskCompletionSource.SetResult( ((JArray)value).ToObject() ); + } + catch (Exception e) + { + Console.WriteLine($"ERROR: BridgeConnector (event: '{eventString}') exception: {e.Message}. Socket loop hung."); + } }); BridgeConnector.Socket.Emit(eventString); diff --git a/ElectronNET.API/Entities/Versions.cs b/ElectronNET.API/Entities/ProcessVersions.cs similarity index 82% rename from ElectronNET.API/Entities/Versions.cs rename to ElectronNET.API/Entities/ProcessVersions.cs index 254a62c8..ce61fcb1 100644 --- a/ElectronNET.API/Entities/Versions.cs +++ b/ElectronNET.API/Entities/ProcessVersions.cs @@ -3,7 +3,7 @@ namespace ElectronNET.API /// /// /// - public class Versions + public class ProcessVersions { /// /// Gets or sets a value representing Chrome's version string. @@ -13,6 +13,6 @@ public class Versions /// /// Gets or sets a value representing Electron's version string. /// - public bool Electron { get; set; } + public string Electron { get; set; } } } \ No newline at end of file diff --git a/ElectronNET.API/Process.cs b/ElectronNET.API/Process.cs index 0976d20b..3a25b44c 100644 --- a/ElectronNET.API/Process.cs +++ b/ElectronNET.API/Process.cs @@ -82,11 +82,11 @@ public Task TypeAsync /// /// /// - public Task VersionsAsync + public Task VersionsAsync { get { - return BridgeConnector.GetValueOverSocketAsync( + return BridgeConnector.GetObjectOverSocketAsync( "process-versions", "process-versions-Completed"); } } From 24a20057761b7ec8e71ccdac8d8e316f428b86e4 Mon Sep 17 00:00:00 2001 From: Todd Schavey Date: Mon, 3 Jan 2022 00:21:48 -0500 Subject: [PATCH 7/9] #647 update XML documentation to ElectronNET.API Process members --- ElectronNET.API/Process.cs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/ElectronNET.API/Process.cs b/ElectronNET.API/Process.cs index 3a25b44c..7620fa75 100644 --- a/ElectronNET.API/Process.cs +++ b/ElectronNET.API/Process.cs @@ -80,7 +80,8 @@ public Task TypeAsync /// - /// + /// The process.versions property returns an object listing the version strings of + /// chrome and electron. /// public Task VersionsAsync { @@ -93,7 +94,8 @@ public Task VersionsAsync /// - /// + /// 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. /// public Task DefaultAppAsync { @@ -105,7 +107,8 @@ public Task DefaultAppAsync } /// - /// + /// 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 /// public Task IsMainFrameAsync { @@ -117,7 +120,7 @@ public Task IsMainFrameAsync } /// - /// + /// A String representing the path to the resources directory. /// public Task ResourcesPathAsync { @@ -129,7 +132,8 @@ public Task ResourcesPathAsync } /// - /// + /// 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. /// public Task UpTimeAsync { @@ -141,7 +145,7 @@ public Task UpTimeAsync } /// - /// + /// The PID of the electron process /// public Task PidAsync { @@ -154,7 +158,7 @@ public Task PidAsync /// - /// + /// The operating system CPU architecture for which the Node.js binary was compiled /// public Task ArchAsync { @@ -166,7 +170,7 @@ public Task ArchAsync } /// - /// + /// A string identifying the operating system platform on which the Node.js process is running /// public Task PlatformAsync { From 64e058b0b59a4fbbd6c0ec9de2ee1850a66684c4 Mon Sep 17 00:00:00 2001 From: Todd Schavey Date: Tue, 4 Jan 2022 12:11:52 -0500 Subject: [PATCH 8/9] #647 make ProcessVersions Entity a record to ensure readonly access to props This is to address a PR #648 review comment to ensure that only the external users are not able to modify the instance values. --- ElectronNET.API/Entities/ProcessVersions.cs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/ElectronNET.API/Entities/ProcessVersions.cs b/ElectronNET.API/Entities/ProcessVersions.cs index ce61fcb1..df41db65 100644 --- a/ElectronNET.API/Entities/ProcessVersions.cs +++ b/ElectronNET.API/Entities/ProcessVersions.cs @@ -1,18 +1,10 @@ namespace ElectronNET.API { /// - /// + /// An object listing the version strings specific to Electron /// - public class ProcessVersions - { - /// - /// Gets or sets a value representing Chrome's version string. - /// - public string Chrome { get; set; } - - /// - /// Gets or sets a value representing Electron's version string. - /// - public string Electron { get; set; } - } -} \ No newline at end of file + /// Value representing Chrome's version string + /// Value representing Electron's version string + /// + public record ProcessVersions(string Chrome, string Electron); +} \ No newline at end of file From b8845bb4026fc3b65fa95b6c572dac4e42acad8b Mon Sep 17 00:00:00 2001 From: Daniel Gidman Date: Tue, 25 Jan 2022 10:45:49 -0600 Subject: [PATCH 9/9] Include Process into DI Mocking and interfaces --- ElectronNET.API/Interfaces/IProcess.cs | 76 +++++++++++++++++++ ElectronNET.API/Process.cs | 3 +- .../ServiceCollectionExtensions.cs | 69 ++++++++--------- 3 files changed, 113 insertions(+), 35 deletions(-) create mode 100644 ElectronNET.API/Interfaces/IProcess.cs diff --git a/ElectronNET.API/Interfaces/IProcess.cs b/ElectronNET.API/Interfaces/IProcess.cs new file mode 100644 index 00000000..dc2c3523 --- /dev/null +++ b/ElectronNET.API/Interfaces/IProcess.cs @@ -0,0 +1,76 @@ +using System.Threading.Tasks; + +namespace ElectronNET.API.Interfaces +{ + /// + /// Electron's process object is extended from the Node.js process object. It adds the + /// events, properties, and methods. + /// + public interface IProcess + { + /// + /// The process.execPath property returns the absolute pathname of the executable that + /// started the Node.js process. Symbolic links, if any, are resolved. + /// + Task ExecPathAsync { get; } + + /// + /// The process.argv property returns an array containing the command-line arguments passed + /// when the Node.js process was launched. The first element will be process.execPath. See + /// process.argv0 if access to the original value of argv[0] is needed. The second element + /// will be the path to the JavaScript file being executed. The remaining elements will be + /// any additional command-line arguments + /// + Task ArgvAsync { get; } + + /// + /// The process.execPath property returns the absolute pathname of the executable that + /// started the Node.js process. Symbolic links, if any, are resolved. + /// + Task TypeAsync { get; } + + /// + /// The process.versions property returns an object listing the version strings of + /// chrome and electron. + /// + Task VersionsAsync { get; } + + /// + /// 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. + /// + Task DefaultAppAsync { get; } + + /// + /// 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 + /// + Task IsMainFrameAsync { get; } + + /// + /// A String representing the path to the resources directory. + /// + Task ResourcesPathAsync { get; } + + /// + /// 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. + /// + Task UpTimeAsync { get; } + + /// + /// The PID of the electron process + /// + Task PidAsync { get; } + + /// + /// The operating system CPU architecture for which the Node.js binary was compiled + /// + Task ArchAsync { get; } + + /// + /// A string identifying the operating system platform on which the Node.js process is running + /// + Task PlatformAsync { get; } + } +} \ No newline at end of file diff --git a/ElectronNET.API/Process.cs b/ElectronNET.API/Process.cs index 7620fa75..34cd72af 100644 --- a/ElectronNET.API/Process.cs +++ b/ElectronNET.API/Process.cs @@ -1,5 +1,6 @@ using System.Threading; using System.Threading.Tasks; +using ElectronNET.API.Interfaces; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -9,7 +10,7 @@ namespace ElectronNET.API /// Electron's process object is extended from the Node.js process object. It adds the /// events, properties, and methods. /// - public sealed class Process + public sealed class Process : IProcess { internal Process() { } diff --git a/ElectronNET.API/ServiceCollectionExtensions.cs b/ElectronNET.API/ServiceCollectionExtensions.cs index 3592065d..c8179dd6 100755 --- a/ElectronNET.API/ServiceCollectionExtensions.cs +++ b/ElectronNET.API/ServiceCollectionExtensions.cs @@ -15,41 +15,42 @@ public static IServiceCollection AddElectron(this IServiceCollection services) => services // adding in this manner to ensure late binding. // this set for backwards compatibility - .AddSingleton(provider => IpcMain.Instance) - .AddSingleton(provider => App.Instance) - .AddSingleton(provider => AutoUpdater.Instance) - .AddSingleton(provider => WindowManager.Instance) - .AddSingleton(provider => Menu.Instance) - .AddSingleton(provider => Dialog.Instance) - .AddSingleton(provider => Notification.Instance) - .AddSingleton(provider => Tray.Instance) - .AddSingleton(provider => GlobalShortcut.Instance) - .AddSingleton(provider => Shell.Instance) - .AddSingleton(provider => Screen.Instance) - .AddSingleton(provider => Clipboard.Instance) - .AddSingleton(provider => HostHook.Instance) - .AddSingleton(provider => PowerMonitor.Instance) - .AddSingleton(provider => NativeTheme.Instance) - .AddSingleton(provider => Dock.Instance) - .AddSingleton(provider => Process.Instance) - .AddSingleton(provider => new ApplicationSocket { Socket = BridgeConnector.Socket, }) + .AddSingleton(_ => IpcMain.Instance) + .AddSingleton(_ => App.Instance) + .AddSingleton(_ => AutoUpdater.Instance) + .AddSingleton(_ => WindowManager.Instance) + .AddSingleton(_ => Menu.Instance) + .AddSingleton(_ => Dialog.Instance) + .AddSingleton(_ => Notification.Instance) + .AddSingleton(_ => Tray.Instance) + .AddSingleton(_ => GlobalShortcut.Instance) + .AddSingleton(_ => Shell.Instance) + .AddSingleton(_ => Screen.Instance) + .AddSingleton(_ => Clipboard.Instance) + .AddSingleton(_ => HostHook.Instance) + .AddSingleton(_ => PowerMonitor.Instance) + .AddSingleton(_ => NativeTheme.Instance) + .AddSingleton(_ => Dock.Instance) + .AddSingleton(_ => Process.Instance) + .AddSingleton(_ => new ApplicationSocket { Socket = BridgeConnector.Socket, }) // this set for proper dependency injection - .AddSingleton(provider => IpcMain.Instance) - .AddSingleton(provider => App.Instance) - .AddSingleton(provider => AutoUpdater.Instance) - .AddSingleton(provider => WindowManager.Instance) - .AddSingleton(provider => Menu.Instance) - .AddSingleton(provider => Dialog.Instance) - .AddSingleton(provider => Notification.Instance) - .AddSingleton(provider => Tray.Instance) - .AddSingleton(provider => GlobalShortcut.Instance) - .AddSingleton(provider => Shell.Instance) - .AddSingleton(provider => Screen.Instance) - .AddSingleton(provider => Clipboard.Instance) - .AddSingleton(provider => HostHook.Instance) - .AddSingleton(provider => PowerMonitor.Instance) - .AddSingleton(provider => NativeTheme.Instance) - .AddSingleton(provider => Dock.Instance) + .AddSingleton(_ => IpcMain.Instance) + .AddSingleton(_ => App.Instance) + .AddSingleton(_ => AutoUpdater.Instance) + .AddSingleton(_ => WindowManager.Instance) + .AddSingleton(_ => Menu.Instance) + .AddSingleton(_ => Dialog.Instance) + .AddSingleton(_ => Notification.Instance) + .AddSingleton(_ => Tray.Instance) + .AddSingleton(_ => GlobalShortcut.Instance) + .AddSingleton(_ => Shell.Instance) + .AddSingleton(_ => Screen.Instance) + .AddSingleton(_ => Clipboard.Instance) + .AddSingleton(_ => HostHook.Instance) + .AddSingleton(_ => PowerMonitor.Instance) + .AddSingleton(_ => NativeTheme.Instance) + .AddSingleton(_ => Dock.Instance) + .AddSingleton(_ => Process.Instance) .AddSingleton(provider => provider.GetService()); } }