Compare commits

...

67 Commits

Author SHA1 Message Date
Florian Rappl
5b0ab76d38 Disable Linux for now 2025-11-14 09:55:30 +01:00
Florian Rappl
349762bd5e Updated changelog 2025-11-14 09:46:01 +01:00
Florian Rappl
0b49467186 Merge pull request #924 from agracio/event-task-rework
ApiEventManager Rework and refactoring of task calls
2025-11-13 14:30:31 +01:00
agracio
6fa65aa149 adding block statements to if 2025-11-12 20:20:13 +00:00
agracio
816e9c0fe9 increasing test timeout times 2025-11-12 15:56:36 +00:00
agracio
c81b0e537f increasing test timeout times 2025-11-12 15:40:04 +00:00
agracio
b89e3caa17 Merge branch 'event-task-rework' of https://github.com/agracio/Electron.NET into event-task-rework 2025-11-12 15:32:33 +00:00
agracio
e8c5de63c9 reverting Linux CI changes, skipping printer test in CI 2025-11-12 15:32:17 +00:00
agracio
d7b9174853 Merge branch 'develop' into event-task-rework 2025-11-12 15:09:44 +00:00
agracio
5ba4ab24d5 adding virtual env instructions for Linux CI 2025-11-12 15:06:14 +00:00
agracio
c6ff957d9a rebase from develop, add timeouts to tests and attempt to skip NativeImageTests on Linux 2025-11-12 14:42:43 +00:00
Florian Rappl
c37f98dcd6 Added the test logger 2025-11-12 14:27:30 +01:00
Florian Rappl
0188051d6c Updated NUKE and integrated tests in CI/CD 2025-11-12 14:21:11 +01:00
Florian Rappl
3eb8507985 Updated to target .NET 10 as well 2025-11-12 13:48:03 +01:00
agracio
546668a2c0 refactoring events API, replacing task code with calls to ApiBase. 2025-11-12 10:43:32 +00:00
Florian Rappl
68feffba02 Merge pull request #922 from softworkz/submit_fix_ipc_params
Fix sendToIpcRenderer parameter handling
2025-11-12 01:30:35 +01:00
softworkz
12d2fcb484 Fix sendToIpcRenderer parameter handling 2025-11-11 23:46:56 +01:00
Florian Rappl
979cf72d4c Merge pull request #920 from Denny09310/feature/using-once
feat: Add "Once" socket listener registration for one-time handlers
2025-11-10 22:29:01 +01:00
Florian Rappl
14bf7fdcd8 Merge pull request #921 from softworkz/submit_missing_locks
SocketIOFacade: Add missing locking on .Off calls
2025-11-10 22:27:02 +01:00
softworkz
f89f2e7591 SocketIOFacade: Add missing locking on .Off calls 2025-11-10 21:29:16 +01:00
Denny09310
9a0a494bc5 fix: missing "Once" changes, rollback to "On" on Notification 2025-11-10 11:27:32 +01:00
Florian Rappl
41a2b075c9 Merge pull request #917 from Denny09310/feature/system-text-json
refactor: Migrating from Newtonsoft.Json to System.Text.Json
2025-11-10 11:03:19 +01:00
Denny09310
adc1e81743 fix: simplified add/remove of socket listener through usage of "Once" 2025-11-10 10:40:51 +01:00
Denny09310
d8062aae00 fix: scale factor can be a double 2025-11-10 10:40:19 +01:00
Denny09310
0522bc425b fix: using correct deserialization type instead JsonElement for everyting except mixed arrays 2025-11-09 15:46:33 +01:00
Denny09310
168eceac8c fix: removed unused JsonPropertyName as ElectronJson.Options as by default camel case 2025-11-09 15:17:42 +01:00
Denny09310
4736bc640c fix: added usings, simplified imports, using JsonElement.Deserialize directly instead of JsonSerializer.Deserialize(JsonElement), removed some unused attributes 2025-11-09 15:15:52 +01:00
Denny09310
18b1317fc5 fix: ignore writing when value is null 2025-11-09 14:53:44 +01:00
Denny09310
dfe04f14d0 fix: menuItems splattering due to "params" keyword 2025-11-09 14:40:55 +01:00
Denny09310
9d6861ffcd fix: including internal properties in json 2025-11-09 14:40:55 +01:00
Denny09310
d8b0d0443d fix: removed useless attribute 2025-11-09 14:40:55 +01:00
Denny09310
71ced8db56 refactor: Migrated from Newtonsoft.Json to System.Text.Json, missing one test passing 2025-11-09 14:40:51 +01:00
Florian Rappl
fc69598b09 Merge pull request #913 from softworkz/submit_tests_fixes
Add 77 IntegrationTests and lots of fixes
2025-11-09 14:05:41 +01:00
softworkz
60a278c41f Cookie: Fix formatting 2025-11-09 12:47:56 +01:00
softworkz
9d25795b7a SocketBridgeService: Fix state transition error 2025-11-09 12:45:01 +01:00
softworkz
5b597cc12c StartupManager: Add support for running under testhost 2025-11-09 12:45:01 +01:00
softworkz
707c0f5a7b BrowserView.cs: Fix cast exception in Bounds property getter 2025-11-09 12:45:01 +01:00
softworkz
bb59bc8365 App.cs: Fix UserAgentFallbackAsync 2025-11-09 12:45:01 +01:00
softworkz
423ea57af7 ipc.ts: Add helper method for tests 2025-11-09 12:45:01 +01:00
softworkz
8dcc3721eb browserWindows.ts: Fix SetThumbarButtons 2025-11-09 12:45:01 +01:00
softworkz
dc27511aa5 browserWindows.ts: Add catch for Set/GetRepresentedFilename
It's not supported on all platforms
2025-11-09 12:45:01 +01:00
softworkz
dd465baebf notification.ts: Fix notificationIsSupported
It's a method, was used like a property
2025-11-09 12:45:01 +01:00
softworkz
04210955a3 webContents.ts: Fix clearAuthCache invocation
The options were no propagated for the overload
with RemovePassword options
2025-11-09 12:45:01 +01:00
softworkz
4129cc17a6 main.js: Load api/process import (was missing) 2025-11-09 12:45:01 +01:00
softworkz
bc0f601dd8 ProcessMetric: Fix deserialization error for CreationTime 2025-11-09 12:45:01 +01:00
softworkz
95fd7aa665 ApiBase: fix event names for App 2025-11-09 12:45:01 +01:00
softworkz
402147b8ef BrowserWindow: Disable SetPosition 'workaround'
It doesn't make sense to do this adjustment for
set only but not for get.
Neither is this done for SetBounds, so it should
be either fully consistent or left up to the
application to deal with it.
2025-11-09 12:45:01 +01:00
softworkz
ed7cc434ea browserWindowSetParentWindow: Support null parameter 2025-11-09 12:44:20 +01:00
softworkz
c5fb5f62d9 Add IntegrationTests project 2025-11-09 12:44:20 +01:00
Florian Rappl
84989cda25 Merge pull request #914 from softworkz/submit_whitespace
Fix and normalize whitespace
2025-11-09 12:25:49 +01:00
softworkz
84b3c59353 Fix and normalize whitespace 2025-11-09 03:50:24 +01:00
Florian Rappl
c1e7b84ec6 Merge pull request #911 from Denny09310/develop
feat: updated 'TitleBarOverlay' property to be passed as object
2025-11-08 16:54:35 +01:00
Denny09310
9bb7dcfa62 fix: added WriteUndefined as there is Newtonsoft.Json 2025-11-08 16:49:33 +01:00
Denny09310
c0e711940d fix: don't write anything if value is null 2025-11-08 16:45:25 +01:00
Florian Rappl
d03458094b Added converter to improve object serialization 2025-11-08 16:38:36 +01:00
Denny09310
14962e1983 chore: updated documentation 2025-11-08 11:24:36 +01:00
Denny09310
d79b73e960 fix: using newtonsoft.json instead of system.text.json for the converter 2025-11-08 11:21:39 +01:00
Denny09310
21ae89bc70 fix: missing public constructor 2025-11-08 11:15:34 +01:00
Denny09310
7927a95cb8 feat: enhance titleBarOverlay to accept both a boolean and an object 2025-11-08 11:14:33 +01:00
Florian Rappl
758e6a41e3 Added properties 2025-11-07 22:12:54 +01:00
Florian Rappl
61421ddd66 Updated changelog 2025-11-07 09:58:38 +01:00
Florian Rappl
98d085f112 Merge pull request #907 from NimbusFox/main
Removed ownjsonSerializer from WindowManager
2025-11-07 08:47:12 +01:00
Florian Rappl
cf0b12ed0a Merge pull request #908 from softworkz/submit_api_consolidation
Mitigate race conditions and simplify API invocations
2025-11-07 08:46:36 +01:00
softworkz
4c3065c64b SocketIOFacade: Synchronize un/registration of events 2025-11-07 03:49:42 +01:00
softworkz
2a6d2117e9 Mitigate race condition, introduce timeout and simplify code for property gets 2025-11-07 03:49:08 +01:00
softworkz
93f457dd0f Introduce ApiBase and simplify method invocation 2025-11-07 00:11:52 +01:00
NimbusFox
6001a3c481 Removed ownjsonSerializer from WindowManager
Removed the unneeded serializer and applied the settings to the global
this._jsonSerializer as when the X and Y values are -1 in the options
it would lead to some settings not being applied. E.g. ContextIsolation
with it now applying the default values when serializing, settings
mentioned before are correctly assigned on Electron's end
2025-11-06 18:04:06 +00:00
161 changed files with 4110 additions and 3463 deletions

View File

@@ -7,24 +7,27 @@ env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
jobs:
linux:
runs-on: ubuntu-latest
# linux:
# runs-on: ubuntu-latest
# timeout-minutes: 10
steps:
- uses: actions/checkout@v4
# steps:
# - uses: actions/checkout@v4
- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
6.0.x
8.0.x
# - name: Setup dotnet
# uses: actions/setup-dotnet@v4
# with:
# dotnet-version: |
# 6.0.x
# 8.0.x
# 10.0.x
- name: Build
run: ./build.sh
# - name: Build
# run: ./build.sh
windows:
runs-on: windows-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
@@ -35,6 +38,7 @@ jobs:
dotnet-version: |
6.0.x
8.0.x
10.0.x
- name: Build
run: |

View File

@@ -1,23 +1,54 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"$ref": "#/definitions/build",
"title": "Build Schema",
"definitions": {
"build": {
"type": "object",
"Host": {
"type": "string",
"enum": [
"AppVeyor",
"AzurePipelines",
"Bamboo",
"Bitbucket",
"Bitrise",
"GitHubActions",
"GitLab",
"Jenkins",
"Rider",
"SpaceAutomation",
"TeamCity",
"Terminal",
"TravisCI",
"VisualStudio",
"VSCode"
]
},
"ExecutableTarget": {
"type": "string",
"enum": [
"Clean",
"Compile",
"Default",
"Package",
"PrePublish",
"Publish",
"PublishPackages",
"PublishPreRelease",
"PublishRelease",
"Restore",
"RunUnitTests"
]
},
"Verbosity": {
"type": "string",
"description": "",
"enum": [
"Verbose",
"Normal",
"Minimal",
"Quiet"
]
},
"NukeBuild": {
"properties": {
"CommonPropsFilePath": {
"type": "string",
"description": "common.props file path - to determine the configured version"
},
"Configuration": {
"type": "string",
"description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)",
"enum": [
"Debug",
"Release"
]
},
"Continue": {
"type": "boolean",
"description": "Indicates to continue a previously failed build attempt"
@@ -27,25 +58,8 @@
"description": "Shows the help text for this build assembly"
},
"Host": {
"type": "string",
"description": "Host for execution. Default is 'automatic'",
"enum": [
"AppVeyor",
"AzurePipelines",
"Bamboo",
"Bitbucket",
"Bitrise",
"GitHubActions",
"GitLab",
"Jenkins",
"Rider",
"SpaceAutomation",
"TeamCity",
"Terminal",
"TravisCI",
"VisualStudio",
"VSCode"
]
"$ref": "#/definitions/Host"
},
"NoLogo": {
"type": "boolean",
@@ -66,10 +80,6 @@
"type": "string"
}
},
"ReleaseNotesFilePath": {
"type": "string",
"description": "ReleaseNotesFilePath - To determine the lates changelog version"
},
"Root": {
"type": "string",
"description": "Root directory during build execution"
@@ -78,59 +88,50 @@
"type": "array",
"description": "List of targets to be skipped. Empty list skips all dependencies",
"items": {
"type": "string",
"enum": [
"Clean",
"Compile",
"CreatePackages",
"Default",
"Package",
"PrePublish",
"Publish",
"PublishPackages",
"PublishPreRelease",
"PublishRelease",
"Restore",
"RunUnitTests"
]
"$ref": "#/definitions/ExecutableTarget"
}
},
"Solution": {
"type": "string",
"description": "Path to a solution file that is automatically loaded"
},
"Target": {
"type": "array",
"description": "List of targets to be invoked. Default is '{default_target}'",
"items": {
"type": "string",
"enum": [
"Clean",
"Compile",
"CreatePackages",
"Default",
"Package",
"PrePublish",
"Publish",
"PublishPackages",
"PublishPreRelease",
"PublishRelease",
"Restore",
"RunUnitTests"
]
"$ref": "#/definitions/ExecutableTarget"
}
},
"Verbosity": {
"type": "string",
"description": "Logging verbosity during build execution. Default is 'Normal'",
"enum": [
"Minimal",
"Normal",
"Quiet",
"Verbose"
]
"$ref": "#/definitions/Verbosity"
}
}
}
}
},
"allOf": [
{
"properties": {
"CommonPropsFilePath": {
"type": "string",
"description": "common.props file path - to determine the configured version"
},
"Configuration": {
"type": "string",
"description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)",
"enum": [
"Debug",
"Release"
]
},
"ReleaseNotesFilePath": {
"type": "string",
"description": "ReleaseNotesFilePath - To determine the lates changelog version"
},
"Solution": {
"type": "string",
"description": "Path to a solution file that is automatically loaded"
}
}
},
{
"$ref": "#/definitions/NukeBuild"
}
]
}

View File

@@ -4,9 +4,21 @@
- Updated `PrintToPDFOptions` to also allow specifying the `PageSize` with an object (#769)
- Updated splashscreen image to have 0 margin (#622)
- Updated the IPC API w.r.t. naming and consistency (#905) @agracio
- Updated the IPC bridge w.r.t. synchronization and thread-safety (#918) @agracio
- Updated serialization to use `System.Text.Json` replacing `Newtonsoft.Json` (#917) @Denny09310
- Fixed parameter handling for the `sendToIpcRenderer` function (#922) @softworkz
- Fixed synchronization on removing event handlers (#921) @softworkz
- Fixed creation of windows with `contextIsolation` enabled (#906) @NimbusFox
- Fixed single instance behavior using the `ElectronSingleInstance` property (#901)
- Fixed potential race conditions (#908) @softworkz
- Added option to use `ElectronSplashScreen` with an HTML file (#799)
- Added option to provide floating point value as aspect ratios with `SetAspectRatio` (#793)
- Added option to provide `TitleBarOverlay` as an object (#911) @Denny09310
- Added `TitleBarOverlay` property to `BrowserWindowOptions` (#909)
- Added `RoundedCorners` property to `BrowserWindowOptions`
- Added integration tests and robustness checks (#913) @softworkz
- Added .NET 10 as an explicit target
# 0.0.18

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2017-2024 Gregor Biswanger, Robert Mühsig
Copyright (c) 2017-2025 Gregor Biswanger, Robert Mühsig, Florian Rappl
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -49,12 +49,12 @@ Add the Electron.NET configuration to your `.csproj` file:
```xml
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ElectronNET.Core" Version="1.0.0" />
<PackageReference Include="ElectronNET.Core" Version="0.1.0" />
</ItemGroup>
```

View File

@@ -28,7 +28,7 @@ Add publish profiles to `Properties/PublishProfiles/`:
<Platform>Any CPU</Platform>
<PublishDir>publish\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>
@@ -48,7 +48,7 @@ Add publish profiles to `Properties/PublishProfiles/`:
<Platform>Any CPU</Platform>
<PublishDir>publish\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>
@@ -68,7 +68,7 @@ Add publish profiles to `Properties/PublishProfiles/`:
<Platform>Any CPU</Platform>
<PublishDir>publish\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>false</SelfContained>
<PublishSingleFile>false</PublishSingleFile>
@@ -89,7 +89,7 @@ Add publish profiles to `Properties/PublishProfiles/`:
<Platform>Any CPU</Platform>
<PublishDir>publish\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<SelfContained>false</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -1,6 +1,6 @@
{
"sdk": {
"version": "8.0.305",
"version": "10.0.100",
"rollForward": "feature",
"allowPrerelease": false
}

View File

@@ -3,6 +3,7 @@ using Nuke.Common;
using Nuke.Common.CI.GitHubActions;
using Nuke.Common.IO;
using Nuke.Common.ProjectModel;
using Nuke.Common.Tooling;
using Nuke.Common.Tools.DotNet;
using Nuke.Common.Tools.GitHub;
using Nuke.Common.Tools.NuGet;
@@ -15,7 +16,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using static Nuke.Common.IO.FileSystemTasks;
using static Nuke.Common.IO.PathConstruction;
using static Nuke.Common.Tools.DotNet.DotNetTasks;
// ReSharper disable ArrangeThisQualifier
@@ -116,7 +116,7 @@ class Build : NukeBuild
Target Restore => _ => _
.Executes(() =>
{
DotNetRestore(s => s.SetProjectFile(Solution.Path));
DotNetRestore(s => s.SetProjectFile(Solution));
});
Target Compile => _ => _
@@ -124,7 +124,7 @@ class Build : NukeBuild
.Executes(() =>
{
DotNetBuild(s => s
.SetProjectFile(Solution.Path)
.SetProjectFile(Solution)
.SetConfiguration(Configuration)
.SetProperty("GeneratePackageOnBuild", "True")
.SetProperty("VersionPostFix", VersionPostFix ?? string.Empty));
@@ -134,18 +134,17 @@ class Build : NukeBuild
.DependsOn(Compile)
.Executes(() =>
{
// There aren't any yet
});
var TestProject = SourceDirectory / "ElectronNET.IntegrationTests" / "ElectronNET.IntegrationTests.csproj";
Target CreatePackages => _ => _
.DependsOn(Compile)
.Executes(() =>
{
// Packages are created on build
DotNetTest(s => s
.SetProjectFile(TestProject)
.SetConfiguration(Configuration)
.When(_ => GitHubActions.Instance is not null, x => x.SetLoggers("GitHubActions"))
);
});
Target PublishPackages => _ => _
.DependsOn(CreatePackages)
.DependsOn(Compile)
.DependsOn(RunUnitTests)
.Executes(() =>
{
@@ -240,7 +239,7 @@ class Build : NukeBuild
Target Package => _ => _
.DependsOn(RunUnitTests)
.DependsOn(CreatePackages);
.DependsOn(Compile);
Target Default => _ => _
.DependsOn(Package);

View File

@@ -11,11 +11,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Nuke.Common" Version="8.0.0" />
<PackageReference Include="Nuke.Common" Version="9.0.4" />
</ItemGroup>
<ItemGroup>
<PackageDownload Include="NuGet.CommandLine" Version="[6.3.1]" />
<PackageDownload Include="NuGet.CommandLine" Version="[6.12.2]" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,373 @@
// ReSharper disable InconsistentNaming
namespace ElectronNET.API
{
using Common;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
public abstract class ApiBase
{
protected enum SocketTaskEventNameTypes
{
DashesLowerFirst,
NoDashUpperFirst
}
protected enum SocketTaskMessageNameTypes
{
DashesLowerFirst,
NoDashUpperFirst
}
protected enum SocketEventNameTypes
{
DashedLower,
CamelCase,
}
private const int PropertyTimeout = 1000;
private readonly string objectName;
private readonly ConcurrentDictionary<string, PropertyGetter> propertyGetters;
private readonly ConcurrentDictionary<string, string> propertyEventNames = new();
private readonly ConcurrentDictionary<string, string> propertyMessageNames = new();
private readonly ConcurrentDictionary<string, string> methodMessageNames = new();
private static readonly ConcurrentDictionary<string, EventContainer> eventContainers = new();
private static readonly ConcurrentDictionary<string, ConcurrentDictionary<string, PropertyGetter>> AllPropertyGetters = new();
private readonly object objLock = new object();
public virtual int Id
{
get => -1;
// ReSharper disable once ValueParameterNotUsed
protected set
{
}
}
protected abstract SocketTaskEventNameTypes SocketTaskEventNameType { get; }
protected virtual SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.NoDashUpperFirst;
protected virtual SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;
protected ApiBase()
{
this.objectName = this.GetType().Name.LowerFirst();
propertyGetters = AllPropertyGetters.GetOrAdd(objectName, _ => new ConcurrentDictionary<string, PropertyGetter>());
}
protected void CallMethod0([CallerMemberName] string callerName = null)
{
var messageName = this.methodMessageNames.GetOrAdd(callerName, s => this.objectName + s);
if (this.Id >= 0)
{
BridgeConnector.Socket.Emit(messageName, this.Id);
}
else
{
BridgeConnector.Socket.Emit(messageName);
}
}
protected void CallMethod1(object val1, [CallerMemberName] string callerName = null)
{
var messageName = this.methodMessageNames.GetOrAdd(callerName, s => this.objectName + s);
if (this.Id >= 0)
{
BridgeConnector.Socket.Emit(messageName, this.Id, val1);
}
else
{
BridgeConnector.Socket.Emit(messageName, val1);
}
}
protected void CallMethod2(object val1, object val2, [CallerMemberName] string callerName = null)
{
var messageName = this.methodMessageNames.GetOrAdd(callerName, s => this.objectName + s);
if (this.Id >= 0)
{
BridgeConnector.Socket.Emit(messageName, this.Id, val1, val2);
}
else
{
BridgeConnector.Socket.Emit(messageName, val1, val2);
}
}
protected void CallMethod3(object val1, object val2, object val3, [CallerMemberName] string callerName = null)
{
var messageName = this.methodMessageNames.GetOrAdd(callerName, s => this.objectName + s);
if (this.Id >= 0)
{
BridgeConnector.Socket.Emit(messageName, this.Id, val1, val2, val3);
}
else
{
BridgeConnector.Socket.Emit(messageName, val1, val2, val3);
}
}
protected Task<T> GetPropertyAsync<T>(object arg = null, [CallerMemberName] string callerName = null)
{
Debug.Assert(callerName != null, nameof(callerName) + " != null");
lock (this.objLock)
{
return this.propertyGetters.GetOrAdd(callerName, _ =>
{
var getter = new PropertyGetter<T>(this, callerName, PropertyTimeout, arg);
getter.Task<T>().ContinueWith(_ =>
{
lock (this.objLock)
{
return this.propertyGetters.TryRemove(callerName, out var _);
}
});
return getter;
}).Task<T>();
}
}
protected void AddEvent(Action value, int? id = null, [CallerMemberName] string callerName = null)
{
Debug.Assert(callerName != null, nameof(callerName) + " != null");
var eventName = EventName(callerName);
var eventKey = EventKey(eventName, id);
lock (objLock)
{
var container = eventContainers.GetOrAdd(eventKey, _ =>
{
var container = new EventContainer();
BridgeConnector.Socket.On(eventKey, container.OnEventAction);
BridgeConnector.Socket.Emit($"register-{eventName}", id);
return container;
});
container.Register(value);
}
}
protected void RemoveEvent(Action value, int? id = null, [CallerMemberName] string callerName = null)
{
Debug.Assert(callerName != null, nameof(callerName) + " != null");
var eventName = EventName(callerName);
var eventKey = EventKey(eventName, id);
lock (objLock)
{
if (eventContainers.TryGetValue(eventKey, out var container) && !container.Unregister(value))
{
BridgeConnector.Socket.Off(eventKey);
eventContainers.TryRemove(eventKey, out _);
}
}
}
protected void AddEvent<T>(Action<T> value, int? id = null, [CallerMemberName] string callerName = null)
{
Debug.Assert(callerName != null, nameof(callerName) + " != null");
var eventName = EventName(callerName);
var eventKey = EventKey(eventName, id);
lock (objLock)
{
var container = eventContainers.GetOrAdd(eventKey, _ =>
{
var container = new EventContainer();
BridgeConnector.Socket.On<T>(eventKey, container.OnEventActionT);
BridgeConnector.Socket.Emit($"register-{eventName}", id);
return container;
});
container.Register(value);
}
}
protected void RemoveEvent<T>(Action<T> value, int? id = null, [CallerMemberName] string callerName = null)
{
Debug.Assert(callerName != null, nameof(callerName) + " != null");
var eventName = EventName(callerName);
var eventKey = EventKey(eventName, id);
lock (objLock)
{
if (eventContainers.TryGetValue(eventKey, out var container) && !container.Unregister(value))
{
BridgeConnector.Socket.Off(eventKey);
eventContainers.TryRemove(eventKey, out _);
}
}
}
private string EventName(string callerName)
{
switch (SocketEventNameType)
{
case SocketEventNameTypes.DashedLower:
return $"{objectName}-{callerName.ToDashedEventName()}";
case SocketEventNameTypes.CamelCase:
return $"{objectName}-{callerName.ToCamelCaseEventName()}";
default:
throw new ArgumentOutOfRangeException();
}
}
private string EventKey(string eventName, int? id)
{
return string.Format(CultureInfo.InvariantCulture, "{0}{1:D}", eventName, id);
}
internal abstract class PropertyGetter
{
public abstract Task<T> Task<T>();
}
internal class PropertyGetter<T> : PropertyGetter
{
private readonly Task<T> tcsTask;
private TaskCompletionSource<T> tcs;
public PropertyGetter(ApiBase apiBase, string callerName, int timeoutMs, object arg = null)
{
this.tcs = new TaskCompletionSource<T>(TaskCreationOptions.RunContinuationsAsynchronously);
this.tcsTask = this.tcs.Task;
string eventName;
string messageName;
switch (apiBase.SocketTaskEventNameType)
{
case SocketTaskEventNameTypes.DashesLowerFirst:
eventName = apiBase.propertyEventNames.GetOrAdd(callerName, s => $"{apiBase.objectName}-{s.StripAsync().LowerFirst()}-completed");
break;
case SocketTaskEventNameTypes.NoDashUpperFirst:
eventName = apiBase.propertyEventNames.GetOrAdd(callerName, s => $"{apiBase.objectName}{s.StripAsync()}Completed");
break;
default:
throw new ArgumentOutOfRangeException();
}
switch (apiBase.SocketTaskMessageNameType)
{
case SocketTaskMessageNameTypes.DashesLowerFirst:
messageName = apiBase.propertyMessageNames.GetOrAdd(callerName, s => $"{apiBase.objectName}-{s.StripAsync().LowerFirst()}");
break;
case SocketTaskMessageNameTypes.NoDashUpperFirst:
messageName = apiBase.propertyMessageNames.GetOrAdd(callerName, s => apiBase.objectName + s.StripAsync());
break;
default:
throw new ArgumentOutOfRangeException();
}
BridgeConnector.Socket.Once<T>(eventName, (result) =>
{
lock (this)
{
try
{
var value = result;
this.tcs?.SetResult(value);
}
catch (Exception ex)
{
this.tcs?.TrySetException(ex);
}
finally
{
this.tcs = null;
}
}
});
if (arg != null)
{
_ = apiBase.Id >= 0 ? BridgeConnector.Socket.Emit(messageName, apiBase.Id, arg) : BridgeConnector.Socket.Emit(messageName, arg);
}
else
{
_ = apiBase.Id >= 0 ? BridgeConnector.Socket.Emit(messageName, apiBase.Id) : BridgeConnector.Socket.Emit(messageName);
}
System.Threading.Tasks.Task.Delay(PropertyTimeout).ContinueWith(_ =>
{
if (this.tcs != null)
{
lock (this)
{
if (this.tcs != null)
{
var ex = new TimeoutException($"No response after {timeoutMs:D}ms trying to retrieve value {apiBase.objectName}.{callerName}()");
this.tcs.TrySetException(ex);
this.tcs = null;
}
}
}
});
}
public override Task<T1> Task<T1>()
{
return this.tcsTask as Task<T1>;
}
}
[SuppressMessage("ReSharper", "InconsistentlySynchronizedField")]
private class EventContainer
{
private Action eventAction;
private Delegate eventActionT;
private Action<T> GetEventActionT<T>()
{
return (Action<T>)eventActionT;
}
private void SetEventActionT<T>(Action<T> actionT)
{
eventActionT = actionT;
}
public void OnEventAction() => eventAction?.Invoke();
public void OnEventActionT<T>(T p) => GetEventActionT<T>()?.Invoke(p);
public void Register(Action receiver)
{
eventAction += receiver;
}
public void Register<T>(Action<T> receiver)
{
var actionT = GetEventActionT<T>();
actionT += receiver;
SetEventActionT(actionT);
}
public bool Unregister(Action receiver)
{
eventAction -= receiver;
return this.eventAction != null;
}
public bool Unregister<T>(Action<T> receiver)
{
var actionT = GetEventActionT<T>();
actionT -= receiver;
SetEventActionT(actionT);
return actionT != null;
}
}
}
}

View File

@@ -1,13 +1,10 @@
using ElectronNET.API.Entities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using ElectronNET.API.Entities;
using ElectronNET.API.Extensions;
using System;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using ElectronNET.API.Extensions;
using ElectronNET.Common;
// ReSharper disable InconsistentNaming
@@ -16,8 +13,11 @@ namespace ElectronNET.API
/// <summary>
/// Control your application's event lifecycle.
/// </summary>
public sealed class App
public sealed class App : ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.NoDashUpperFirst;
protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;
/// <summary>
/// Emitted when all windows have been closed.
/// <para/>
@@ -43,13 +43,14 @@ namespace ElectronNET.API
BridgeConnector.Socket.Emit("register-app-window-all-closed", GetHashCode());
}
_windowAllClosed += value;
}
remove
{
_windowAllClosed -= value;
if(_windowAllClosed == null)
if (_windowAllClosed == null)
BridgeConnector.Socket.Off("app-window-all-closed" + GetHashCode());
}
}
@@ -115,6 +116,7 @@ namespace ElectronNET.API
BridgeConnector.Socket.Emit("register-app-before-quit", GetHashCode());
}
_beforeQuit += value;
}
remove
@@ -166,6 +168,7 @@ namespace ElectronNET.API
BridgeConnector.Socket.Emit("register-app-will-quit", GetHashCode());
}
_willQuit += value;
}
remove
@@ -192,7 +195,7 @@ namespace ElectronNET.API
{
BridgeConnector.Socket.On("app-will-quit" + GetHashCode() + "quitting", async () =>
{
if(_willQuit == null)
if (_willQuit == null)
{
await this._quitting().ConfigureAwait(false);
Exit();
@@ -201,6 +204,7 @@ namespace ElectronNET.API
BridgeConnector.Socket.Emit("register-app-will-quit", GetHashCode() + "quitting");
}
_quitting += value;
}
remove
@@ -219,45 +223,37 @@ namespace ElectronNET.API
/// </summary>
public event Action BrowserWindowBlur
{
add => ApiEventManager.AddEvent("app-browser-window-blur", GetHashCode(), _browserWindowBlur, value);
remove => ApiEventManager.RemoveEvent("app-browser-window-blur", GetHashCode(), _browserWindowBlur, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action _browserWindowBlur;
/// <summary>
/// Emitted when a <see cref="BrowserWindow"/> gets focused.
/// </summary>
public event Action BrowserWindowFocus
{
add => ApiEventManager.AddEvent("app-browser-window-focus", GetHashCode(), _browserWindowFocus, value);
remove => ApiEventManager.RemoveEvent("app-browser-window-focus", GetHashCode(), _browserWindowFocus, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action _browserWindowFocus;
/// <summary>
/// Emitted when a new <see cref="BrowserWindow"/> is created.
/// </summary>
public event Action BrowserWindowCreated
{
add => ApiEventManager.AddEvent("app-browser-window-created", GetHashCode(), _browserWindowCreated, value);
remove => ApiEventManager.RemoveEvent("app-browser-window-created", GetHashCode(), _browserWindowCreated, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action _browserWindowCreated;
/// <summary>
/// Emitted when a new <see cref="WebContents"/> is created.
/// </summary>
public event Action WebContentsCreated
{
add => ApiEventManager.AddEvent("app-web-contents-created", GetHashCode(), _webContentsCreated, value);
remove => ApiEventManager.RemoveEvent("app-web-contents-created", GetHashCode(), _webContentsCreated, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action _webContentsCreated;
/// <summary>
/// Emitted when Chromes accessibility support changes. This event fires when assistive technologies, such as
/// screen readers, are enabled or disabled. See https://www.chromium.org/developers/design-documents/accessibility for more details.
@@ -265,20 +261,18 @@ namespace ElectronNET.API
/// <returns><see langword="true"/> when Chrome's accessibility support is enabled, <see langword="false"/> otherwise.</returns>
public event Action<bool> AccessibilitySupportChanged
{
add => ApiEventManager.AddEvent("app-accessibility-support-changed", GetHashCode(), _accessibilitySupportChanged, value, (args) => (bool)args);
remove => ApiEventManager.RemoveEvent("app-accessibility-support-changed", GetHashCode(), _accessibilitySupportChanged, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action<bool> _accessibilitySupportChanged;
/// <summary>
/// Emitted when the application has finished basic startup.
/// </summary>
public event Action Ready
public event Action Ready
{
add
{
if(IsReady)
if (IsReady)
{
value();
}
@@ -296,19 +290,23 @@ namespace ElectronNET.API
/// <summary>
/// Application host fully started.
/// </summary>
public bool IsReady
{
get { return _isReady; }
public bool IsReady
{
get
{
return _isReady;
}
internal set
{
_isReady = value;
if(value)
if (value)
{
_ready?.Invoke();
}
}
}
private bool _isReady = false;
/// <summary>
@@ -320,12 +318,10 @@ namespace ElectronNET.API
/// </summary>
public event Action<string> OpenFile
{
add => ApiEventManager.AddEvent("app-open-file", GetHashCode(), _openFile, value, (args) => args.ToString());
remove => ApiEventManager.RemoveEvent("app-open-file", GetHashCode(), _openFile, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action<string> _openFile;
/// <summary>
/// Emitted when a MacOS user wants to open a URL with the application. Your application's Info.plist file must
@@ -333,12 +329,10 @@ namespace ElectronNET.API
/// </summary>
public event Action<string> OpenUrl
{
add => ApiEventManager.AddEvent("app-open-url", GetHashCode(), _openUrl, value, (args) => args.ToString());
remove => ApiEventManager.RemoveEvent("app-open-url", GetHashCode(), _openUrl, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action<string> _openUrl;
/// <summary>
/// A <see cref="string"/> property that indicates the current application's name, which is the name in the
/// application's package.json file.
@@ -372,25 +366,12 @@ namespace ElectronNET.API
{
get
{
return Task.Run<string>(() =>
{
var taskCompletionSource = new TaskCompletionSource<string>();
BridgeConnector.Socket.On("appGetNameCompleted", (result) =>
{
BridgeConnector.Socket.Off("appGetNameCompleted");
taskCompletionSource.SetResult((string)result);
});
BridgeConnector.Socket.Emit("appGetName");
return taskCompletionSource.Task;
});
return this.GetPropertyAsync<string>();
}
}
internal App()
internal App()
{
CommandLine = new CommandLine();
}
@@ -403,7 +384,7 @@ namespace ElectronNET.API
{
lock (_syncRoot)
{
if(_app == null)
if (_app == null)
{
_app = new App();
}
@@ -417,10 +398,7 @@ namespace ElectronNET.API
private static App _app;
private static object _syncRoot = new object();
private readonly JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
/// <summary>
/// Try to close all windows. The <see cref="BeforeQuit"/> event will be emitted first. If all windows are successfully
@@ -430,7 +408,7 @@ namespace ElectronNET.API
/// </summary>
public void Quit()
{
BridgeConnector.Socket.Emit("appQuit");
this.CallMethod0();
}
/// <summary>
@@ -440,7 +418,7 @@ namespace ElectronNET.API
/// <param name="exitCode">Exits immediately with exitCode. exitCode defaults to 0.</param>
public void Exit(int exitCode = 0)
{
BridgeConnector.Socket.Emit("appExit", exitCode);
this.CallMethod1(exitCode);
}
public void DisposeSocket()
@@ -460,7 +438,7 @@ namespace ElectronNET.API
/// </summary>
public void Relaunch()
{
BridgeConnector.Socket.Emit("appRelaunch");
this.CallMethod0();
}
/// <summary>
@@ -478,7 +456,7 @@ namespace ElectronNET.API
/// <param name="relaunchOptions">Options for the relaunch.</param>
public void Relaunch(RelaunchOptions relaunchOptions)
{
BridgeConnector.Socket.Emit("appRelaunch", JObject.FromObject(relaunchOptions, _jsonSerializer));
this.CallMethod1(relaunchOptions);
}
/// <summary>
@@ -487,7 +465,7 @@ namespace ElectronNET.API
/// </summary>
public void Focus()
{
BridgeConnector.Socket.Emit("appFocus");
this.CallMethod0();
}
/// <summary>
@@ -498,7 +476,7 @@ namespace ElectronNET.API
/// </summary>
public void Focus(FocusOptions focusOptions)
{
BridgeConnector.Socket.Emit("appFocus", JObject.FromObject(focusOptions, _jsonSerializer));
this.CallMethod1(focusOptions);
}
/// <summary>
@@ -506,7 +484,7 @@ namespace ElectronNET.API
/// </summary>
public void Hide()
{
BridgeConnector.Socket.Emit("appHide");
this.CallMethod0();
}
/// <summary>
@@ -514,7 +492,7 @@ namespace ElectronNET.API
/// </summary>
public void Show()
{
BridgeConnector.Socket.Emit("appShow");
this.CallMethod0();
}
/// <summary>
@@ -523,21 +501,7 @@ namespace ElectronNET.API
public async Task<string> GetAppPathAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
var taskCompletionSource = new TaskCompletionSource<string>();
using(cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
{
BridgeConnector.Socket.On("appGetAppPathCompleted", (path) =>
{
BridgeConnector.Socket.Off("appGetAppPathCompleted");
taskCompletionSource.SetResult(path.ToString());
});
BridgeConnector.Socket.Emit("appGetAppPath");
return await taskCompletionSource.Task
.ConfigureAwait(false);
}
return await this.GetPropertyAsync<string>().ConfigureAwait(false);
}
/// <summary>
@@ -550,7 +514,7 @@ namespace ElectronNET.API
/// <param name="path">A custom path for your logs. Must be absolute.</param>
public void SetAppLogsPath(string path)
{
BridgeConnector.Socket.Emit("appSetAppLogsPath", path);
this.CallMethod1(path);
}
/// <summary>
@@ -566,20 +530,14 @@ namespace ElectronNET.API
cancellationToken.ThrowIfCancellationRequested();
var taskCompletionSource = new TaskCompletionSource<string>();
using(cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
{
BridgeConnector.Socket.On("appGetPathCompleted", (path) =>
{
BridgeConnector.Socket.Off("appGetPathCompleted");
taskCompletionSource.SetResult(path.ToString());
});
BridgeConnector.Socket.Once<string>("appGetPathCompleted", taskCompletionSource.SetResult);
BridgeConnector.Socket.Emit("appGetPath", pathName.GetDescription());
return await taskCompletionSource.Task
.ConfigureAwait(false);
}
}
}
/// <summary>
@@ -596,7 +554,7 @@ namespace ElectronNET.API
/// </summary>
public void SetPath(PathName name, string path)
{
BridgeConnector.Socket.Emit("appSetPath", name.GetDescription(), path);
this.CallMethod2(name.GetDescription(), path);
}
/// <summary>
@@ -607,21 +565,7 @@ namespace ElectronNET.API
public async Task<string> GetVersionAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
var taskCompletionSource = new TaskCompletionSource<string>();
using(cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
{
BridgeConnector.Socket.On("appGetVersionCompleted", (version) =>
{
BridgeConnector.Socket.Off("appGetVersionCompleted");
taskCompletionSource.SetResult(version.ToString());
});
BridgeConnector.Socket.Emit("appGetVersion");
return await taskCompletionSource.Task
.ConfigureAwait(false);
}
return await this.GetPropertyAsync<string>().ConfigureAwait(false);
}
/// <summary>
@@ -635,21 +579,7 @@ namespace ElectronNET.API
public async Task<string> GetLocaleAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
var taskCompletionSource = new TaskCompletionSource<string>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
{
BridgeConnector.Socket.On("appGetLocaleCompleted", (local) =>
{
BridgeConnector.Socket.Off("appGetLocaleCompleted");
taskCompletionSource.SetResult(local.ToString());
});
BridgeConnector.Socket.Emit("appGetLocale");
return await taskCompletionSource.Task
.ConfigureAwait(false);
}
return await this.GetPropertyAsync<string>().ConfigureAwait(false);
}
/// <summary>
@@ -659,7 +589,7 @@ namespace ElectronNET.API
/// <param name="path">Path to add.</param>
public void AddRecentDocument(string path)
{
BridgeConnector.Socket.Emit("appAddRecentDocument", path);
this.CallMethod1(path);
}
/// <summary>
@@ -667,7 +597,7 @@ namespace ElectronNET.API
/// </summary>
public void ClearRecentDocuments()
{
BridgeConnector.Socket.Emit("appClearRecentDocuments");
this.CallMethod0();
}
/// <summary>
@@ -765,12 +695,7 @@ namespace ElectronNET.API
var taskCompletionSource = new TaskCompletionSource<bool>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
{
BridgeConnector.Socket.On("appSetAsDefaultProtocolClientCompleted", (success) =>
{
BridgeConnector.Socket.Off("appSetAsDefaultProtocolClientCompleted");
taskCompletionSource.SetResult((bool) success);
});
BridgeConnector.Socket.Once<bool>("appSetAsDefaultProtocolClientCompleted", taskCompletionSource.SetResult);
BridgeConnector.Socket.Emit("appSetAsDefaultProtocolClient", protocol, path, args);
return await taskCompletionSource.Task
@@ -813,18 +738,13 @@ namespace ElectronNET.API
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Whether the call succeeded.</returns>
public async Task<bool> RemoveAsDefaultProtocolClientAsync(string protocol, string path, string[] args, CancellationToken cancellationToken = default)
{
{
cancellationToken.ThrowIfCancellationRequested();
var taskCompletionSource = new TaskCompletionSource<bool>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
{
BridgeConnector.Socket.On("appRemoveAsDefaultProtocolClientCompleted", (success) =>
{
BridgeConnector.Socket.Off("appRemoveAsDefaultProtocolClientCompleted");
taskCompletionSource.SetResult((bool) success);
});
BridgeConnector.Socket.Once<bool>("appRemoveAsDefaultProtocolClientCompleted", taskCompletionSource.SetResult);
BridgeConnector.Socket.Emit("appRemoveAsDefaultProtocolClient", protocol, path, args);
return await taskCompletionSource.Task
@@ -891,12 +811,7 @@ namespace ElectronNET.API
var taskCompletionSource = new TaskCompletionSource<bool>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
{
BridgeConnector.Socket.On("appIsDefaultProtocolClientCompleted", (success) =>
{
BridgeConnector.Socket.Off("appIsDefaultProtocolClientCompleted");
taskCompletionSource.SetResult((bool) success);
});
BridgeConnector.Socket.Once<bool>("appIsDefaultProtocolClientCompleted", taskCompletionSource.SetResult);
BridgeConnector.Socket.Emit("appIsDefaultProtocolClient", protocol, path, args);
return await taskCompletionSource.Task
@@ -919,13 +834,8 @@ namespace ElectronNET.API
var taskCompletionSource = new TaskCompletionSource<bool>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
{
BridgeConnector.Socket.On("appSetUserTasksCompleted", (success) =>
{
BridgeConnector.Socket.Off("appSetUserTasksCompleted");
taskCompletionSource.SetResult((bool) success);
});
BridgeConnector.Socket.Emit("appSetUserTasks", JArray.FromObject(userTasks, _jsonSerializer));
BridgeConnector.Socket.Once<bool>("appSetUserTasksCompleted", taskCompletionSource.SetResult);
BridgeConnector.Socket.Emit("appSetUserTasks", userTasks);
return await taskCompletionSource.Task
.ConfigureAwait(false);
@@ -940,21 +850,7 @@ namespace ElectronNET.API
public async Task<JumpListSettings> GetJumpListSettingsAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
var taskCompletionSource = new TaskCompletionSource<JumpListSettings>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
{
BridgeConnector.Socket.On("appGetJumpListSettingsCompleted", (jumpListSettings) =>
{
BridgeConnector.Socket.Off("appGetJumpListSettingsCompleted");
taskCompletionSource.SetResult(JObject.Parse(jumpListSettings.ToString()).ToObject<JumpListSettings>());
});
BridgeConnector.Socket.Emit("appGetJumpListSettings");
return await taskCompletionSource.Task
.ConfigureAwait(false);
}
return await this.GetPropertyAsync<JumpListSettings>().ConfigureAwait(false);
}
/// <summary>
@@ -975,7 +871,7 @@ namespace ElectronNET.API
/// <param name="categories">Array of <see cref="JumpListCategory"/> objects.</param>
public void SetJumpList(JumpListCategory[] categories)
{
BridgeConnector.Socket.Emit("appSetJumpList", JArray.FromObject(categories, _jsonSerializer));
this.CallMethod1(categories);
}
/// <summary>
@@ -1006,19 +902,17 @@ namespace ElectronNET.API
var taskCompletionSource = new TaskCompletionSource<bool>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
{
BridgeConnector.Socket.On("appRequestSingleInstanceLockCompleted", (success) =>
{
BridgeConnector.Socket.Off("appRequestSingleInstanceLockCompleted");
taskCompletionSource.SetResult((bool)success);
});
BridgeConnector.Socket.Once<bool>("appRequestSingleInstanceLockCompleted", taskCompletionSource.SetResult);
BridgeConnector.Socket.Off("secondInstance");
BridgeConnector.Socket.On("secondInstance", (result) =>
BridgeConnector.Socket.On<JsonElement>("secondInstance", (result) =>
{
JArray results = (JArray)result;
string[] args = results.First.ToObject<string[]>();
string workingDirectory = results.Last.ToObject<string>();
var arr = result.EnumerateArray();
var e = arr.GetEnumerator();
e.MoveNext();
var args = e.Current.Deserialize<string[]>(JsonSerializerOptions.Default);
e.MoveNext();
var workingDirectory = e.Current.GetString();
newInstanceOpened(args, workingDirectory);
});
@@ -1035,7 +929,7 @@ namespace ElectronNET.API
/// </summary>
public void ReleaseSingleInstanceLock()
{
BridgeConnector.Socket.Emit("appReleaseSingleInstanceLock");
this.CallMethod0();
}
/// <summary>
@@ -1047,21 +941,7 @@ namespace ElectronNET.API
public async Task<bool> HasSingleInstanceLockAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
var taskCompletionSource = new TaskCompletionSource<bool>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
{
BridgeConnector.Socket.On("appHasSingleInstanceLockCompleted", (hasLock) =>
{
BridgeConnector.Socket.Off("appHasSingleInstanceLockCompleted");
taskCompletionSource.SetResult((bool) hasLock);
});
BridgeConnector.Socket.Emit("appHasSingleInstanceLock");
return await taskCompletionSource.Task
.ConfigureAwait(false);
}
return await this.GetPropertyAsync<bool>().ConfigureAwait(false);
}
/// <summary>
@@ -1090,7 +970,7 @@ namespace ElectronNET.API
/// </param>
public void SetUserActivity(string type, object userInfo, string webpageUrl)
{
BridgeConnector.Socket.Emit("appSetUserActivity", type, userInfo, webpageUrl);
this.CallMethod3(type, userInfo, webpageUrl);
}
/// <summary>
@@ -1100,21 +980,7 @@ namespace ElectronNET.API
public async Task<string> GetCurrentActivityTypeAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
var taskCompletionSource = new TaskCompletionSource<string>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
{
BridgeConnector.Socket.On("appGetCurrentActivityTypeCompleted", (activityType) =>
{
BridgeConnector.Socket.Off("appGetCurrentActivityTypeCompleted");
taskCompletionSource.SetResult(activityType.ToString());
});
BridgeConnector.Socket.Emit("appGetCurrentActivityType");
return await taskCompletionSource.Task
.ConfigureAwait(false);
}
return await this.GetPropertyAsync<string>().ConfigureAwait(false);
}
/// <summary>
@@ -1122,7 +988,7 @@ namespace ElectronNET.API
/// </summary>
public void InvalidateCurrentActivity()
{
BridgeConnector.Socket.Emit("appInvalidateCurrentActivity");
this.CallMethod0();
}
/// <summary>
@@ -1130,7 +996,7 @@ namespace ElectronNET.API
/// </summary>
public void ResignCurrentActivity()
{
BridgeConnector.Socket.Emit("appResignCurrentActivity");
this.CallMethod0();
}
/// <summary>
@@ -1139,7 +1005,7 @@ namespace ElectronNET.API
/// <param name="id">Model Id.</param>
public void SetAppUserModelId(string id)
{
BridgeConnector.Socket.Emit("appSetAppUserModelId", id);
this.CallMethod1(id);
}
/// TODO: Check new parameter which is a function [App.ImportCertificate]
@@ -1158,13 +1024,8 @@ namespace ElectronNET.API
var taskCompletionSource = new TaskCompletionSource<int>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
{
BridgeConnector.Socket.On("appImportCertificateCompleted", (result) =>
{
BridgeConnector.Socket.Off("appImportCertificateCompleted");
taskCompletionSource.SetResult((int) result);
});
BridgeConnector.Socket.Emit("appImportCertificate", JObject.FromObject(options, _jsonSerializer));
BridgeConnector.Socket.Once<int>("appImportCertificateCompleted", taskCompletionSource.SetResult);
BridgeConnector.Socket.Emit("appImportCertificate", options);
return await taskCompletionSource.Task
.ConfigureAwait(false);
@@ -1182,23 +1043,7 @@ namespace ElectronNET.API
public async Task<ProcessMetric[]> GetAppMetricsAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
var taskCompletionSource = new TaskCompletionSource<ProcessMetric[]>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
{
BridgeConnector.Socket.On("appGetAppMetricsCompleted", (result) =>
{
BridgeConnector.Socket.Off("appGetAppMetricsCompleted");
var processMetrics = ((JArray)result).ToObject<ProcessMetric[]>();
taskCompletionSource.SetResult(processMetrics);
});
BridgeConnector.Socket.Emit("appGetAppMetrics");
return await taskCompletionSource.Task
.ConfigureAwait(false);
}
return await this.GetPropertyAsync<ProcessMetric[]>().ConfigureAwait(false);
}
/// <summary>
@@ -1210,23 +1055,7 @@ namespace ElectronNET.API
public async Task<GPUFeatureStatus> GetGpuFeatureStatusAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
var taskCompletionSource = new TaskCompletionSource<GPUFeatureStatus>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
{
BridgeConnector.Socket.On("appGetGpuFeatureStatusCompleted", (result) =>
{
BridgeConnector.Socket.Off("appGetGpuFeatureStatusCompleted");
var gpuFeatureStatus = ((JObject)result).ToObject<GPUFeatureStatus>();
taskCompletionSource.SetResult(gpuFeatureStatus);
});
BridgeConnector.Socket.Emit("appGetGpuFeatureStatus");
return await taskCompletionSource.Task
.ConfigureAwait(false);
}
return await this.GetPropertyAsync<GPUFeatureStatus>().ConfigureAwait(false);
}
/// <summary>
@@ -1246,12 +1075,7 @@ namespace ElectronNET.API
var taskCompletionSource = new TaskCompletionSource<bool>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
{
BridgeConnector.Socket.On("appSetBadgeCountCompleted", (success) =>
{
BridgeConnector.Socket.Off("appSetBadgeCountCompleted");
taskCompletionSource.SetResult((bool) success);
});
BridgeConnector.Socket.Once<bool>("appSetBadgeCountCompleted", taskCompletionSource.SetResult);
BridgeConnector.Socket.Emit("appSetBadgeCount", count);
return await taskCompletionSource.Task
@@ -1266,21 +1090,7 @@ namespace ElectronNET.API
public async Task<int> GetBadgeCountAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
var taskCompletionSource = new TaskCompletionSource<int>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
{
BridgeConnector.Socket.On("appGetBadgeCountCompleted", (count) =>
{
BridgeConnector.Socket.Off("appGetBadgeCountCompleted");
taskCompletionSource.SetResult((int)count);
});
BridgeConnector.Socket.Emit("appGetBadgeCount");
return await taskCompletionSource.Task
.ConfigureAwait(false);
}
return await this.GetPropertyAsync<int>().ConfigureAwait(false);
}
/// <summary>
@@ -1295,21 +1105,7 @@ namespace ElectronNET.API
public async Task<bool> IsUnityRunningAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
var taskCompletionSource = new TaskCompletionSource<bool>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
{
BridgeConnector.Socket.On("appIsUnityRunningCompleted", (isUnityRunning) =>
{
BridgeConnector.Socket.Off("appIsUnityRunningCompleted");
taskCompletionSource.SetResult((bool)isUnityRunning);
});
BridgeConnector.Socket.Emit("appIsUnityRunning");
return await taskCompletionSource.Task
.ConfigureAwait(false);
}
return await this.GetPropertyAsync<bool>().ConfigureAwait(false);
}
/// <summary>
@@ -1334,14 +1130,7 @@ namespace ElectronNET.API
var taskCompletionSource = new TaskCompletionSource<LoginItemSettings>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
{
BridgeConnector.Socket.On("appGetLoginItemSettingsCompleted", (loginItemSettings) =>
{
BridgeConnector.Socket.Off("appGetLoginItemSettingsCompleted");
var result = ((JObject) loginItemSettings).ToObject<LoginItemSettings>();
taskCompletionSource.SetResult(result);
});
BridgeConnector.Socket.Once<LoginItemSettings>("appGetLoginItemSettingsCompleted", taskCompletionSource.SetResult);
if (options == null)
{
@@ -1349,7 +1138,7 @@ namespace ElectronNET.API
}
else
{
BridgeConnector.Socket.Emit("appGetLoginItemSettings", JObject.FromObject(options, _jsonSerializer));
BridgeConnector.Socket.Emit("appGetLoginItemSettings", options);
}
return await taskCompletionSource.Task
@@ -1365,7 +1154,7 @@ namespace ElectronNET.API
/// <param name="loginSettings"></param>
public void SetLoginItemSettings(LoginSettings loginSettings)
{
BridgeConnector.Socket.Emit("appSetLoginItemSettings", JObject.FromObject(loginSettings, _jsonSerializer));
this.CallMethod1(loginSettings);
}
/// <summary>
@@ -1377,21 +1166,7 @@ namespace ElectronNET.API
public async Task<bool> IsAccessibilitySupportEnabledAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
var taskCompletionSource = new TaskCompletionSource<bool>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
{
BridgeConnector.Socket.On("appIsAccessibilitySupportEnabledCompleted", (isAccessibilitySupportEnabled) =>
{
BridgeConnector.Socket.Off("appIsAccessibilitySupportEnabledCompleted");
taskCompletionSource.SetResult((bool)isAccessibilitySupportEnabled);
});
BridgeConnector.Socket.Emit("appIsAccessibilitySupportEnabled");
return await taskCompletionSource.Task
.ConfigureAwait(false);
}
return await this.GetPropertyAsync<bool>().ConfigureAwait(false);
}
/// <summary>
@@ -1406,7 +1181,7 @@ namespace ElectronNET.API
/// <param name="enabled">Enable or disable <see href="https://developers.google.com/web/fundamentals/accessibility/semantics-builtin/the-accessibility-tree">accessibility tree</see> rendering.</param>
public void SetAccessibilitySupportEnabled(bool enabled)
{
BridgeConnector.Socket.Emit("appSetAccessibilitySupportEnabled", enabled);
this.CallMethod1(enabled);
}
/// <summary>
@@ -1415,7 +1190,7 @@ namespace ElectronNET.API
/// </summary>
public void ShowAboutPanel()
{
BridgeConnector.Socket.Emit("appShowAboutPanel");
this.CallMethod0();
}
/// <summary>
@@ -1431,7 +1206,7 @@ namespace ElectronNET.API
/// <param name="options">About panel options.</param>
public void SetAboutPanelOptions(AboutPanelOptions options)
{
BridgeConnector.Socket.Emit("appSetAboutPanelOptions", JObject.FromObject(options, _jsonSerializer));
this.CallMethod1(options);
}
/// <summary>
@@ -1467,16 +1242,11 @@ namespace ElectronNET.API
{
get
{
return Task.Run<string>(() =>
return Task.Run(() =>
{
var taskCompletionSource = new TaskCompletionSource<string>();
BridgeConnector.Socket.On("appGetUserAgentFallbackCompleted", (result) =>
{
BridgeConnector.Socket.Off("appGetUserAgentFallbackCompleted");
taskCompletionSource.SetResult((string)result);
});
BridgeConnector.Socket.Once<string>("appGetUserAgentFallbackCompleted", taskCompletionSource.SetResult);
BridgeConnector.Socket.Emit("appGetUserAgentFallback");
return taskCompletionSource.Task;
@@ -1492,6 +1262,7 @@ namespace ElectronNET.API
private bool _preventQuit = false;
private const string ModuleName = "app";
/// <summary>
/// Subscribe to an unmapped event on the <see cref="App"/> module.
/// </summary>
@@ -1499,6 +1270,7 @@ namespace ElectronNET.API
/// <param name="action">The handler</param>
public void On(string eventName, Action action)
=> Events.Instance.On(ModuleName, eventName, action);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="App"/> module.
/// </summary>
@@ -1506,6 +1278,7 @@ namespace ElectronNET.API
/// <param name="action">The handler</param>
public async Task On(string eventName, Action<object> action)
=> await Events.Instance.On(ModuleName, eventName, action).ConfigureAwait(false);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="App"/> module once.
/// </summary>
@@ -1513,6 +1286,7 @@ namespace ElectronNET.API
/// <param name="action">The handler</param>
public void Once(string eventName, Action action)
=> Events.Instance.Once(ModuleName, eventName, action);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="App"/> module once.
/// </summary>

View File

@@ -1,11 +1,8 @@
using ElectronNET.API.Entities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using ElectronNET.API.Entities;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ElectronNET.Common;
// ReSharper disable InconsistentNaming
namespace ElectronNET.API
@@ -13,8 +10,12 @@ namespace ElectronNET.API
/// <summary>
/// Enable apps to automatically update themselves. Based on electron-updater.
/// </summary>
public sealed class AutoUpdater
public sealed class AutoUpdater: ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;
protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;
/// <summary>
/// Whether to automatically download an update when it is found. (Default is true)
/// </summary>
@@ -22,20 +23,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run<bool>(() =>
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("autoUpdater-autoDownload-get-reply", (result) =>
{
BridgeConnector.Socket.Off("autoUpdater-autoDownload-get-reply");
taskCompletionSource.SetResult((bool)result);
});
BridgeConnector.Socket.Emit("autoUpdater-autoDownload-get");
return taskCompletionSource.Task;
}).Result;
return Task.Run(() => GetPropertyAsync<bool>()).Result;
}
set
{
@@ -52,20 +40,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run<bool>(() =>
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("autoUpdater-autoInstallOnAppQuit-get-reply", (result) =>
{
BridgeConnector.Socket.Off("autoUpdater-autoInstallOnAppQuit-get-reply");
taskCompletionSource.SetResult((bool)result);
});
BridgeConnector.Socket.Emit("autoUpdater-autoInstallOnAppQuit-get");
return taskCompletionSource.Task;
}).Result;
return Task.Run(() => GetPropertyAsync<bool>()).Result;
}
set
{
@@ -83,20 +58,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run<bool>(() =>
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("autoUpdater-allowPrerelease-get-reply", (result) =>
{
BridgeConnector.Socket.Off("autoUpdater-allowPrerelease-get-reply");
taskCompletionSource.SetResult((bool)result);
});
BridgeConnector.Socket.Emit("autoUpdater-allowPrerelease-get");
return taskCompletionSource.Task;
}).Result;
return Task.Run(() => GetPropertyAsync<bool>()).Result;
}
set
{
@@ -112,20 +74,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run<bool>(() =>
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("autoUpdater-fullChangelog-get-reply", (result) =>
{
BridgeConnector.Socket.Off("autoUpdater-fullChangelog-get-reply");
taskCompletionSource.SetResult((bool)result);
});
BridgeConnector.Socket.Emit("autoUpdater-fullChangelog-get");
return taskCompletionSource.Task;
}).Result;
return Task.Run(() => GetPropertyAsync<bool>()).Result;
}
set
{
@@ -142,20 +91,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run<bool>(() =>
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("autoUpdater-allowDowngrade-get-reply", (result) =>
{
BridgeConnector.Socket.Off("autoUpdater-allowDowngrade-get-reply");
taskCompletionSource.SetResult((bool)result);
});
BridgeConnector.Socket.Emit("autoUpdater-allowDowngrade-get");
return taskCompletionSource.Task;
}).Result;
return Task.Run(() => GetPropertyAsync<bool>()).Result;
}
set
{
@@ -170,20 +106,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run<string>(() =>
{
var taskCompletionSource = new TaskCompletionSource<string>();
BridgeConnector.Socket.On("autoUpdater-updateConfigPath-get-reply", (result) =>
{
BridgeConnector.Socket.Off("autoUpdater-updateConfigPath-get-reply");
taskCompletionSource.SetResult(result.ToString());
});
BridgeConnector.Socket.Emit("autoUpdater-updateConfigPath-get");
return taskCompletionSource.Task;
}).Result;
return Task.Run(() => GetPropertyAsync<string>()).Result;
}
}
@@ -194,20 +117,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run<SemVer>(() =>
{
var taskCompletionSource = new TaskCompletionSource<SemVer>();
BridgeConnector.Socket.On("autoUpdater-currentVersion-get-reply", (result) =>
{
BridgeConnector.Socket.Off("autoUpdater-currentVersion-get-reply");
SemVer version = ((JObject)result).ToObject<SemVer>();
taskCompletionSource.SetResult(version);
});
BridgeConnector.Socket.Emit("autoUpdater-currentVersion-get");
return taskCompletionSource.Task;
});
return Task.Run(() => GetPropertyAsync<SemVer>());
}
}
@@ -232,22 +142,20 @@ namespace ElectronNET.API
{
get
{
return Task.Run<string>(() =>
{
var taskCompletionSource = new TaskCompletionSource<string>();
BridgeConnector.Socket.On("autoUpdater-channel-get-reply", (result) =>
{
BridgeConnector.Socket.Off("autoUpdater-channel-get-reply");
taskCompletionSource.SetResult(result.ToString());
});
BridgeConnector.Socket.Emit("autoUpdater-channel-get");
return taskCompletionSource.Task;
});
return Task.Run(() => GetPropertyAsync<string>());
}
}
/// <summary>
/// Set the update channel. Not applicable for GitHub.
/// </summary>
public string SetChannel
{
set
{
BridgeConnector.Socket.Emit("autoUpdater-channel-set", value);
}
}
/// <summary>
@@ -257,18 +165,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run(() =>
{
var taskCompletionSource = new TaskCompletionSource<Dictionary<string, string>>();
BridgeConnector.Socket.On("autoUpdater-requestHeaders-get-reply", (headers) =>
{
BridgeConnector.Socket.Off("autoUpdater-requestHeaders-get-reply");
Dictionary<string, string> result = ((JObject)headers).ToObject<Dictionary<string, string>>();
taskCompletionSource.SetResult(result);
});
BridgeConnector.Socket.Emit("autoUpdater-requestHeaders-get");
return taskCompletionSource.Task;
});
return Task.Run(() => GetPropertyAsync<Dictionary<string, string>>());
}
}
@@ -279,7 +176,7 @@ namespace ElectronNET.API
{
set
{
BridgeConnector.Socket.Emit("autoUpdater-requestHeaders-set", JObject.FromObject(value, _jsonSerializer));
BridgeConnector.Socket.Emit("autoUpdater-requestHeaders-set", value);
}
}
@@ -288,72 +185,62 @@ namespace ElectronNET.API
/// </summary>
public event Action<string> OnError
{
add => ApiEventManager.AddEvent("autoUpdater-error", GetHashCode(), _error, value, (args) => args.ToString());
remove => ApiEventManager.RemoveEvent("autoUpdater-error", GetHashCode(), _error, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action<string> _error;
/// <summary>
/// Emitted when checking if an update has started.
/// </summary>
public event Action OnCheckingForUpdate
{
add => ApiEventManager.AddEvent("autoUpdater-checking-for-update", GetHashCode(), _checkingForUpdate, value);
remove => ApiEventManager.RemoveEvent("autoUpdater-checking-for-update", GetHashCode(), _checkingForUpdate, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action _checkingForUpdate;
/// <summary>
/// Emitted when there is an available update.
/// The update is downloaded automatically if AutoDownload is true.
/// </summary>
public event Action<UpdateInfo> OnUpdateAvailable
{
add => ApiEventManager.AddEvent("autoUpdater-update-available", GetHashCode(), _updateAvailable, value, (args) => JObject.Parse(args.ToString()).ToObject<UpdateInfo>());
remove => ApiEventManager.RemoveEvent("autoUpdater-update-available", GetHashCode(), _updateAvailable, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action<UpdateInfo> _updateAvailable;
/// <summary>
/// Emitted when there is no available update.
/// </summary>
public event Action<UpdateInfo> OnUpdateNotAvailable
{
add => ApiEventManager.AddEvent("autoUpdater-update-not-available", GetHashCode(), _updateNotAvailable, value, (args) => JObject.Parse(args.ToString()).ToObject<UpdateInfo>());
remove => ApiEventManager.RemoveEvent("autoUpdater-update-not-available", GetHashCode(), _updateNotAvailable, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action<UpdateInfo> _updateNotAvailable;
/// <summary>
/// Emitted on download progress.
/// </summary>
public event Action<ProgressInfo> OnDownloadProgress
{
add => ApiEventManager.AddEvent("autoUpdater-download-progress", GetHashCode(), _downloadProgress, value, (args) => JObject.Parse(args.ToString()).ToObject<ProgressInfo>());
remove => ApiEventManager.RemoveEvent("autoUpdater-download-progress", GetHashCode(), _downloadProgress, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action<ProgressInfo> _downloadProgress;
/// <summary>
/// Emitted on download complete.
/// </summary>
public event Action<UpdateInfo> OnUpdateDownloaded
{
add => ApiEventManager.AddEvent("autoUpdater-update-downloaded", GetHashCode(), _updateDownloaded, value, (args) => JObject.Parse(args.ToString()).ToObject<UpdateInfo>());
remove => ApiEventManager.RemoveEvent("autoUpdater-update-downloaded", GetHashCode(), _updateDownloaded, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action<UpdateInfo> _updateDownloaded;
private static AutoUpdater _autoUpdater;
private static object _syncRoot = new object();
internal AutoUpdater() { }
internal AutoUpdater()
{
}
internal static AutoUpdater Instance
{
@@ -383,30 +270,27 @@ namespace ElectronNET.API
var taskCompletionSource = new TaskCompletionSource<UpdateCheckResult>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("autoUpdaterCheckForUpdatesComplete" + guid, (updateCheckResult) =>
BridgeConnector.Socket.Once<UpdateCheckResult>("autoUpdater-checkForUpdates-completed" + guid, (result) =>
{
try
{
BridgeConnector.Socket.Off("autoUpdaterCheckForUpdatesComplete" + guid);
BridgeConnector.Socket.Off("autoUpdaterCheckForUpdatesError" + guid);
taskCompletionSource.SetResult(JObject.Parse(updateCheckResult.ToString()).ToObject<UpdateCheckResult>());
BridgeConnector.Socket.Off("autoUpdater-checkForUpdatesError" + guid);
taskCompletionSource.SetResult(result);
}
catch (Exception ex)
{
taskCompletionSource.SetException(ex);
}
});
BridgeConnector.Socket.On("autoUpdaterCheckForUpdatesError" + guid, (error) =>
BridgeConnector.Socket.Once<string>("autoUpdater-checkForUpdatesError" + guid, (result) =>
{
BridgeConnector.Socket.Off("autoUpdaterCheckForUpdatesComplete" + guid);
BridgeConnector.Socket.Off("autoUpdaterCheckForUpdatesError" + guid);
BridgeConnector.Socket.Off("autoUpdater-checkForUpdates-completed" + guid);
string message = "An error occurred in CheckForUpdatesAsync";
if (error != null && !string.IsNullOrEmpty(error.ToString()))
message = JsonConvert.SerializeObject(error);
if (!string.IsNullOrEmpty(result)) message = result;
taskCompletionSource.SetException(new Exception(message));
});
BridgeConnector.Socket.Emit("autoUpdaterCheckForUpdates", guid);
BridgeConnector.Socket.Emit("autoUpdater-checkForUpdates", guid);
return taskCompletionSource.Task;
}
@@ -422,33 +306,27 @@ namespace ElectronNET.API
var taskCompletionSource = new TaskCompletionSource<UpdateCheckResult>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("autoUpdaterCheckForUpdatesAndNotifyComplete" + guid, (updateCheckResult) =>
BridgeConnector.Socket.Once<UpdateCheckResult>("autoUpdater-checkForUpdatesAndNotify-completed" + guid, (result) =>
{
try
{
BridgeConnector.Socket.Off("autoUpdaterCheckForUpdatesAndNotifyComplete" + guid);
BridgeConnector.Socket.Off("autoUpdaterCheckForUpdatesAndNotifyError" + guid);
if (updateCheckResult == null)
taskCompletionSource.SetResult(null);
else
taskCompletionSource.SetResult(JObject.Parse(updateCheckResult.ToString()).ToObject<UpdateCheckResult>());
BridgeConnector.Socket.Off("autoUpdater-checkForUpdatesAndNotifyError" + guid);
taskCompletionSource.SetResult(result);
}
catch (Exception ex)
{
taskCompletionSource.SetException(ex);
}
});
BridgeConnector.Socket.On("autoUpdaterCheckForUpdatesAndNotifyError" + guid, (error) =>
BridgeConnector.Socket.Once<string>("autoUpdater-checkForUpdatesAndNotifyError" + guid, (result) =>
{
BridgeConnector.Socket.Off("autoUpdaterCheckForUpdatesAndNotifyComplete" + guid);
BridgeConnector.Socket.Off("autoUpdaterCheckForUpdatesAndNotifyError" + guid);
string message = "An error occurred in autoUpdaterCheckForUpdatesAndNotify";
if (error != null)
message = JsonConvert.SerializeObject(error);
BridgeConnector.Socket.Off("autoUpdater-checkForUpdatesAndNotify-completed" + guid);
string message = "An error occurred in CheckForUpdatesAndNotifyAsync";
if (!string.IsNullOrEmpty(result)) message = result;
taskCompletionSource.SetException(new Exception(message));
});
BridgeConnector.Socket.Emit("autoUpdaterCheckForUpdatesAndNotify", guid);
BridgeConnector.Socket.Emit("autoUpdater-checkForUpdatesAndNotify", guid);
return taskCompletionSource.Task;
}
@@ -464,7 +342,7 @@ namespace ElectronNET.API
/// <param name="isForceRunAfter">Run the app after finish even on silent install. Not applicable for macOS. Ignored if `isSilent` is set to `false`.</param>
public void QuitAndInstall(bool isSilent = false, bool isForceRunAfter = false)
{
BridgeConnector.Socket.Emit("autoUpdaterQuitAndInstall", isSilent, isForceRunAfter);
BridgeConnector.Socket.Emit("autoUpdater-quitAndInstall", isSilent, isForceRunAfter);
}
/// <summary>
@@ -473,18 +351,13 @@ namespace ElectronNET.API
/// <returns>Path to downloaded file.</returns>
public Task<string> DownloadUpdateAsync()
{
var taskCompletionSource = new TaskCompletionSource<string>();
var tcs = new TaskCompletionSource<string>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("autoUpdaterDownloadUpdateComplete" + guid, (downloadedPath) =>
{
BridgeConnector.Socket.Off("autoUpdaterDownloadUpdateComplete" + guid);
taskCompletionSource.SetResult(downloadedPath.ToString());
});
BridgeConnector.Socket.Once<string>("autoUpdater-downloadUpdate-completed" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("autoUpdater-downloadUpdate", guid);
BridgeConnector.Socket.Emit("autoUpdaterDownloadUpdate", guid);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -493,23 +366,17 @@ namespace ElectronNET.API
/// <returns>Feed URL.</returns>
public Task<string> GetFeedURLAsync()
{
var taskCompletionSource = new TaskCompletionSource<string>();
var tcs = new TaskCompletionSource<string>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("autoUpdaterGetFeedURLComplete" + guid, (downloadedPath) =>
{
BridgeConnector.Socket.Off("autoUpdaterGetFeedURLComplete" + guid);
taskCompletionSource.SetResult(downloadedPath.ToString());
});
BridgeConnector.Socket.Once<string>("autoUpdater-getFeedURL-completed" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("autoUpdater-getFeedURL", guid);
BridgeConnector.Socket.Emit("autoUpdaterGetFeedURL", guid);
return taskCompletionSource.Task;
return tcs.Task;
}
private readonly JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
}
}

View File

@@ -1,25 +1,21 @@
using ElectronNET.API.Entities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using ElectronNET.API.Entities;
using System.Threading.Tasks;
namespace ElectronNET.API
{
/// <summary>
/// A BrowserView can be used to embed additional web content into a BrowserWindow.
/// It is like a child window, except that it is positioned relative to its owning window.
/// A BrowserView can be used to embed additional web content into a BrowserWindow.
/// It is like a child window, except that it is positioned relative to its owning window.
/// It is meant to be an alternative to the webview tag.
/// </summary>
public class BrowserView
public class BrowserView: ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;
/// <summary>
/// Gets the identifier.
/// </summary>
/// <value>
/// The identifier.
/// </value>
public int Id { get; internal set; }
public override int Id { get; protected set; }
/// <summary>
/// Render and control web pages.
@@ -28,38 +24,24 @@ namespace ElectronNET.API
/// <summary>
/// Resizes and moves the view to the supplied bounds relative to the window.
///
/// (experimental)
/// </summary>
public Rectangle Bounds
{
get
{
return Task.Run<Rectangle>(() =>
{
var taskCompletionSource = new TaskCompletionSource<Rectangle>();
BridgeConnector.Socket.On("browserView-getBounds-reply", (result) =>
{
BridgeConnector.Socket.Off("browserView-getBounds-reply");
taskCompletionSource.SetResult((Rectangle)result);
});
BridgeConnector.Socket.Emit("browserView-getBounds", Id);
return taskCompletionSource.Task;
}).Result;
return Task.Run(() => GetPropertyAsync<Rectangle>()).Result;
}
set
{
BridgeConnector.Socket.Emit("browserView-setBounds", Id, JObject.FromObject(value, _jsonSerializer));
BridgeConnector.Socket.Emit("browserView-bounds-set", Id, value);
}
}
/// <summary>
/// BrowserView
/// </summary>
internal BrowserView(int id)
internal BrowserView(int id)
{
Id = id;
@@ -74,12 +56,11 @@ namespace ElectronNET.API
/// <param name="options"></param>
public void SetAutoResize(AutoResizeOptions options)
{
BridgeConnector.Socket.Emit("browserView-setAutoResize", Id, JObject.FromObject(options, _jsonSerializer));
BridgeConnector.Socket.Emit("browserView-setAutoResize", Id, options);
}
/// <summary>
/// Color in #aarrggbb or #argb form. The alpha channel is optional.
///
/// (experimental)
/// </summary>
/// <param name="color">Color in #aarrggbb or #argb form. The alpha channel is optional.</param>
@@ -87,11 +68,6 @@ namespace ElectronNET.API
{
BridgeConnector.Socket.Emit("browserView-setBackgroundColor", Id, color);
}
private JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
};
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +1,25 @@
using ElectronNET.API.Entities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using ElectronNET.API.Entities;
using ElectronNET.API.Serialization;
using System.Text.Json;
using System.Threading.Tasks;
// ReSharper disable InconsistentNaming
namespace ElectronNET.API
{
/// <summary>
/// Perform copy and paste operations on the system clipboard.
/// </summary>
public sealed class Clipboard
public sealed class Clipboard: ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;
private static Clipboard _clipboard;
private static object _syncRoot = new object();
internal Clipboard() { }
internal Clipboard()
{
}
internal static Clipboard Instance
{
@@ -40,21 +45,7 @@ namespace ElectronNET.API
/// </summary>
/// <param name="type"></param>
/// <returns>The content in the clipboard as plain text.</returns>
public Task<string> ReadTextAsync(string type = "")
{
var taskCompletionSource = new TaskCompletionSource<string>();
BridgeConnector.Socket.On("clipboard-readText-Completed", (text) =>
{
BridgeConnector.Socket.Off("clipboard-readText-Completed");
taskCompletionSource.SetResult(text.ToString());
});
BridgeConnector.Socket.Emit("clipboard-readText", type);
return taskCompletionSource.Task;
}
public Task<string> ReadTextAsync(string type = "") => GetPropertyAsync<string>(type);
/// <summary>
/// Writes the text into the clipboard as plain text.
@@ -71,21 +62,7 @@ namespace ElectronNET.API
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public Task<string> ReadHTMLAsync(string type = "")
{
var taskCompletionSource = new TaskCompletionSource<string>();
BridgeConnector.Socket.On("clipboard-readHTML-Completed", (text) =>
{
BridgeConnector.Socket.Off("clipboard-readHTML-Completed");
taskCompletionSource.SetResult(text.ToString());
});
BridgeConnector.Socket.Emit("clipboard-readHTML", type);
return taskCompletionSource.Task;
}
public Task<string> ReadHTMLAsync(string type = "") => GetPropertyAsync<string>(type);
/// <summary>
/// Writes markup to the clipboard.
@@ -102,21 +79,7 @@ namespace ElectronNET.API
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public Task<string> ReadRTFAsync(string type = "")
{
var taskCompletionSource = new TaskCompletionSource<string>();
BridgeConnector.Socket.On("clipboard-readRTF-Completed", (text) =>
{
BridgeConnector.Socket.Off("clipboard-readRTF-Completed");
taskCompletionSource.SetResult(text.ToString());
});
BridgeConnector.Socket.Emit("clipboard-readRTF", type);
return taskCompletionSource.Task;
}
public Task<string> ReadRTFAsync(string type = "") => GetPropertyAsync<string>(type);
/// <summary>
/// Writes the text into the clipboard in RTF.
@@ -125,7 +88,7 @@ namespace ElectronNET.API
/// <param name="type"></param>
public void WriteRTF(string text, string type = "")
{
BridgeConnector.Socket.Emit("clipboard-writeHTML", text, type);
BridgeConnector.Socket.Emit("clipboard-writeRTF", text, type);
}
/// <summary>
@@ -134,21 +97,7 @@ namespace ElectronNET.API
/// be empty strings when the bookmark is unavailable.
/// </summary>
/// <returns></returns>
public Task<ReadBookmark> ReadBookmarkAsync()
{
var taskCompletionSource = new TaskCompletionSource<ReadBookmark>();
BridgeConnector.Socket.On("clipboard-readBookmark-Completed", (bookmark) =>
{
BridgeConnector.Socket.Off("clipboard-readBookmark-Completed");
taskCompletionSource.SetResult(((JObject)bookmark).ToObject<ReadBookmark>());
});
BridgeConnector.Socket.Emit("clipboard-readBookmark");
return taskCompletionSource.Task;
}
public Task<ReadBookmark> ReadBookmarkAsync() => GetPropertyAsync<ReadBookmark>();
/// <summary>
/// Writes the title and url into the clipboard as a bookmark.
@@ -171,21 +120,7 @@ namespace ElectronNET.API
/// find pasteboard whenever the application is activated.
/// </summary>
/// <returns></returns>
public Task<string> ReadFindTextAsync()
{
var taskCompletionSource = new TaskCompletionSource<string>();
BridgeConnector.Socket.On("clipboard-readFindText-Completed", (text) =>
{
BridgeConnector.Socket.Off("clipboard-readFindText-Completed");
taskCompletionSource.SetResult(text.ToString());
});
BridgeConnector.Socket.Emit("clipboard-readFindText");
return taskCompletionSource.Task;
}
public Task<string> ReadFindTextAsync() => GetPropertyAsync<string>();
/// <summary>
/// macOS: Writes the text into the find pasteboard as plain text. This method uses
@@ -211,21 +146,7 @@ namespace ElectronNET.API
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public Task<string[]> AvailableFormatsAsync(string type = "")
{
var taskCompletionSource = new TaskCompletionSource<string[]>();
BridgeConnector.Socket.On("clipboard-availableFormats-Completed", (formats) =>
{
BridgeConnector.Socket.Off("clipboard-availableFormats-Completed");
taskCompletionSource.SetResult(((JArray)formats).ToObject<string[]>());
});
BridgeConnector.Socket.Emit("clipboard-availableFormats", type);
return taskCompletionSource.Task;
}
public Task<string[]> AvailableFormatsAsync(string type = "") => GetPropertyAsync<string[]>(type);
/// <summary>
/// Writes data to the clipboard.
@@ -234,7 +155,7 @@ namespace ElectronNET.API
/// <param name="type"></param>
public void Write(Data data, string type = "")
{
BridgeConnector.Socket.Emit("clipboard-write", JObject.FromObject(data, _jsonSerializer), type);
BridgeConnector.Socket.Emit("clipboard-write", data, type);
}
/// <summary>
@@ -242,25 +163,8 @@ namespace ElectronNET.API
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public Task<NativeImage> ReadImageAsync(string type = "")
{
var taskCompletionSource = new TaskCompletionSource<NativeImage>();
public Task<NativeImage> ReadImageAsync(string type = "") => GetPropertyAsync<NativeImage>(type);
BridgeConnector.Socket.On("clipboard-readImage-Completed", (image) =>
{
BridgeConnector.Socket.Off("clipboard-readImage-Completed");
var nativeImage = ((JObject)image).ToObject<NativeImage>();
taskCompletionSource.SetResult(nativeImage);
});
BridgeConnector.Socket.Emit("clipboard-readImage", type);
return taskCompletionSource.Task;
}
/// <summary>
/// Writes an image to the clipboard.
/// </summary>
@@ -268,14 +172,7 @@ namespace ElectronNET.API
/// <param name="type"></param>
public void WriteImage(NativeImage image, string type = "")
{
BridgeConnector.Socket.Emit("clipboard-writeImage", JsonConvert.SerializeObject(image), type);
BridgeConnector.Socket.Emit("clipboard-writeImage", JsonSerializer.Serialize(image, ElectronJson.Options), type);
}
private JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
}
}
}

View File

@@ -8,7 +8,9 @@ namespace ElectronNET.API
/// </summary>
public sealed class CommandLine
{
internal CommandLine() { }
internal CommandLine()
{
}
internal static CommandLine Instance
{
@@ -66,22 +68,17 @@ namespace ElectronNET.API
/// <param name="switchName">A command-line switch</param>
/// <param name="cancellationToken"></param>
/// <returns>Whether the command-line switch is present.</returns>
public async Task<bool> HasSwitchAsync(string switchName, CancellationToken cancellationToken = default(CancellationToken))
public async Task<bool> HasSwitchAsync(string switchName, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
var taskCompletionSource = new TaskCompletionSource<bool>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
var tcs = new TaskCompletionSource<bool>();
using (cancellationToken.Register(() => tcs.TrySetCanceled()))
{
BridgeConnector.Socket.On("appCommandLineHasSwitchCompleted", (result) =>
{
BridgeConnector.Socket.Off("appCommandLineHasSwitchCompleted");
taskCompletionSource.SetResult((bool)result);
});
BridgeConnector.Socket.Once<bool>("appCommandLineHasSwitchCompleted", tcs.SetResult);
BridgeConnector.Socket.Emit("appCommandLineHasSwitch", switchName);
return await taskCompletionSource.Task.ConfigureAwait(false);
return await tcs.Task.ConfigureAwait(false);
}
}
@@ -94,23 +91,18 @@ namespace ElectronNET.API
/// <remarks>
/// Note: When the switch is not present or has no value, it returns empty string.
/// </remarks>
public async Task<string> GetSwitchValueAsync(string switchName, CancellationToken cancellationToken = default(CancellationToken))
public async Task<string> GetSwitchValueAsync(string switchName, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
var taskCompletionSource = new TaskCompletionSource<string>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
var tcs = new TaskCompletionSource<string>();
using (cancellationToken.Register(() => tcs.TrySetCanceled()))
{
BridgeConnector.Socket.On("appCommandLineGetSwitchValueCompleted", (result) =>
{
BridgeConnector.Socket.Off("appCommandLineGetSwitchValueCompleted");
taskCompletionSource.SetResult((string)result);
});
BridgeConnector.Socket.Once<string>("appCommandLineGetSwitchValueCompleted", tcs.SetResult);
BridgeConnector.Socket.Emit("appCommandLineGetSwitchValue", switchName);
return await taskCompletionSource.Task.ConfigureAwait(false);
return await tcs.Task.ConfigureAwait(false);
}
}
}
}
}

View File

@@ -1,9 +1,7 @@
using System;
using System.Threading.Tasks;
using ElectronNET.API.Entities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using ElectronNET.API.Serialization;
using System;
using System.Text.Json;
namespace ElectronNET.API
{
@@ -34,16 +32,21 @@ namespace ElectronNET.API
{
if (_changed == null)
{
BridgeConnector.Socket.On("webContents-session-cookies-changed" + Id, (args) =>
BridgeConnector.Socket.On<JsonElement>("webContents-session-cookies-changed" + Id, (args) =>
{
Cookie cookie = ((JArray)args)[0].ToObject<Cookie>();
CookieChangedCause cause = ((JArray)args)[1].ToObject<CookieChangedCause>();
bool removed = ((JArray)args)[2].ToObject<bool>();
var e = args.EnumerateArray().GetEnumerator();
e.MoveNext();
var cookie = e.Current.Deserialize<Cookie>(ElectronJson.Options);
e.MoveNext();
var cause = e.Current.Deserialize<CookieChangedCause>(ElectronJson.Options);
e.MoveNext();
var removed = e.Current.GetBoolean();
_changed(cookie, cause, removed);
});
BridgeConnector.Socket.Emit("register-webContents-session-cookies-changed", Id);
}
_changed += value;
}
remove
@@ -57,11 +60,6 @@ namespace ElectronNET.API
private event Action<Cookie, CookieChangedCause, bool> _changed;
private JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
}
}
}

View File

@@ -1,9 +1,6 @@
using ElectronNET.API.Entities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using ElectronNET.API.Entities;
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Threading.Tasks;
namespace ElectronNET.API
@@ -16,7 +13,9 @@ namespace ElectronNET.API
private static Dialog _dialog;
private static object _syncRoot = new object();
internal Dialog() { }
internal Dialog()
{
}
internal static Dialog Instance
{
@@ -26,7 +25,7 @@ namespace ElectronNET.API
{
lock (_syncRoot)
{
if(_dialog == null)
if (_dialog == null)
{
_dialog = new Dialog();
}
@@ -47,23 +46,16 @@ namespace ElectronNET.API
/// <returns>An array of file paths chosen by the user</returns>
public Task<string[]> ShowOpenDialogAsync(BrowserWindow browserWindow, OpenDialogOptions options)
{
var taskCompletionSource = new TaskCompletionSource<string[]>();
var tcs = new TaskCompletionSource<string[]>();
var guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("showOpenDialogComplete" + guid, (filePaths) =>
{
BridgeConnector.Socket.Off("showOpenDialogComplete" + guid);
BridgeConnector.Socket.Once<string[]>("showOpenDialogComplete" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("showOpenDialog",
browserWindow,
options,
guid);
var result = ((JArray)filePaths).ToObject<string[]>();
taskCompletionSource.SetResult(result);
});
BridgeConnector.Socket.Emit("showOpenDialog",
JObject.FromObject(browserWindow, _jsonSerializer),
JObject.FromObject(options, _jsonSerializer), guid);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -74,22 +66,16 @@ namespace ElectronNET.API
/// <returns>Returns String, the path of the file chosen by the user, if a callback is provided it returns an empty string.</returns>
public Task<string> ShowSaveDialogAsync(BrowserWindow browserWindow, SaveDialogOptions options)
{
var taskCompletionSource = new TaskCompletionSource<string>();
var tcs = new TaskCompletionSource<string>();
var guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("showSaveDialogComplete" + guid, (filename) =>
{
BridgeConnector.Socket.Off("showSaveDialogComplete" + guid);
taskCompletionSource.SetResult(filename.ToString());
});
BridgeConnector.Socket.Once<string>("showSaveDialogComplete" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("showSaveDialog",
JObject.FromObject(browserWindow, _jsonSerializer),
JObject.FromObject(options, _jsonSerializer),
guid);
browserWindow,
options,
guid);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -143,35 +129,39 @@ namespace ElectronNET.API
/// <returns>The API call will be asynchronous and the result will be passed via MessageBoxResult.</returns>
public Task<MessageBoxResult> ShowMessageBoxAsync(BrowserWindow browserWindow, MessageBoxOptions messageBoxOptions)
{
var taskCompletionSource = new TaskCompletionSource<MessageBoxResult>();
var tcs = new TaskCompletionSource<MessageBoxResult>();
var guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("showMessageBoxComplete" + guid, (args) =>
BridgeConnector.Socket.Once<JsonElement>("showMessageBoxComplete" + guid, (args) =>
{
BridgeConnector.Socket.Off("showMessageBoxComplete" + guid);
// args is [response:int, checkboxChecked:boolean]
var arr = args.EnumerateArray();
var e = arr.GetEnumerator();
e.MoveNext();
var response = e.Current.GetInt32();
e.MoveNext();
var checkbox = e.Current.GetBoolean();
var result = ((JArray)args);
taskCompletionSource.SetResult(new MessageBoxResult
tcs.SetResult(new MessageBoxResult
{
Response = (int)result.First,
CheckboxChecked = (bool)result.Last
Response = response,
CheckboxChecked = checkbox
});
});
if (browserWindow == null)
{
BridgeConnector.Socket.Emit("showMessageBox", JObject.FromObject(messageBoxOptions, _jsonSerializer), guid);
} else
BridgeConnector.Socket.Emit("showMessageBox", messageBoxOptions, guid);
}
else
{
BridgeConnector.Socket.Emit("showMessageBox",
JObject.FromObject(browserWindow, _jsonSerializer),
JObject.FromObject(messageBoxOptions, _jsonSerializer),
BridgeConnector.Socket.Emit("showMessageBox",
browserWindow,
messageBoxOptions,
guid);
}
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -211,28 +201,18 @@ namespace ElectronNET.API
/// <returns></returns>
public Task ShowCertificateTrustDialogAsync(BrowserWindow browserWindow, CertificateTrustDialogOptions options)
{
var taskCompletionSource = new TaskCompletionSource<object>();
var tcs = new TaskCompletionSource<object>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("showCertificateTrustDialogComplete" + guid, () =>
{
BridgeConnector.Socket.Off("showCertificateTrustDialogComplete" + guid);
taskCompletionSource.SetResult(null);
});
BridgeConnector.Socket.Once("showCertificateTrustDialogComplete" + guid, () => tcs.SetResult(null));
BridgeConnector.Socket.Emit("showCertificateTrustDialog",
JObject.FromObject(browserWindow, _jsonSerializer),
JObject.FromObject(options, _jsonSerializer),
browserWindow,
options,
guid);
return taskCompletionSource.Task;
return tcs.Task;
}
private JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
}
}

View File

@@ -1,11 +1,10 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using ElectronNET.API.Entities;
using ElectronNET.API.Extensions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using ElectronNET.API.Serialization;
using System.Collections.Generic;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
namespace ElectronNET.API
{
@@ -54,18 +53,13 @@ namespace ElectronNET.API
{
cancellationToken.ThrowIfCancellationRequested();
var taskCompletionSource = new TaskCompletionSource<int>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
var tcs = new TaskCompletionSource<int>();
using (cancellationToken.Register(() => tcs.TrySetCanceled()))
{
BridgeConnector.Socket.On("dock-bounce-completed", (id) =>
{
BridgeConnector.Socket.Off("dock-bounce-completed");
taskCompletionSource.SetResult((int) id);
});
BridgeConnector.Socket.Once<int>("dock-bounce-completed", tcs.SetResult);
BridgeConnector.Socket.Emit("dock-bounce", type.GetDescription());
return await taskCompletionSource.Task
return await tcs.Task
.ConfigureAwait(false);
}
}
@@ -106,18 +100,13 @@ namespace ElectronNET.API
{
cancellationToken.ThrowIfCancellationRequested();
var taskCompletionSource = new TaskCompletionSource<string>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
var tcs = new TaskCompletionSource<string>();
using (cancellationToken.Register(() => tcs.TrySetCanceled()))
{
BridgeConnector.Socket.On("dock-getBadge-completed", (text) =>
{
BridgeConnector.Socket.Off("dock-getBadge-completed");
taskCompletionSource.SetResult((string) text);
});
BridgeConnector.Socket.Once<string>("dock-getBadge-completed", tcs.SetResult);
BridgeConnector.Socket.Emit("dock-getBadge");
return await taskCompletionSource.Task
return await tcs.Task
.ConfigureAwait(false);
}
}
@@ -148,18 +137,13 @@ namespace ElectronNET.API
{
cancellationToken.ThrowIfCancellationRequested();
var taskCompletionSource = new TaskCompletionSource<bool>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
var tcs = new TaskCompletionSource<bool>();
using (cancellationToken.Register(() => tcs.TrySetCanceled()))
{
BridgeConnector.Socket.On("dock-isVisible-completed", (isVisible) =>
{
BridgeConnector.Socket.Off("dock-isVisible-completed");
taskCompletionSource.SetResult((bool) isVisible);
});
BridgeConnector.Socket.Once<bool>("dock-isVisible-completed", tcs.SetResult);
BridgeConnector.Socket.Emit("dock-isVisible");
return await taskCompletionSource.Task
return await tcs.Task
.ConfigureAwait(false);
}
}
@@ -170,7 +154,14 @@ namespace ElectronNET.API
/// <value>
/// The menu items.
/// </value>
public IReadOnlyCollection<MenuItem> MenuItems { get { return _items.AsReadOnly(); } }
public IReadOnlyCollection<MenuItem> MenuItems
{
get
{
return _items.AsReadOnly();
}
}
private List<MenuItem> _items = new List<MenuItem>();
/// <summary>
@@ -179,15 +170,15 @@ namespace ElectronNET.API
public void SetMenu(MenuItem[] menuItems)
{
menuItems.AddMenuItemsId();
BridgeConnector.Socket.Emit("dock-setMenu", JArray.FromObject(menuItems, _jsonSerializer));
BridgeConnector.Socket.Emit("dock-setMenu", new[] { menuItems });
_items.AddRange(menuItems);
BridgeConnector.Socket.Off("dockMenuItemClicked");
BridgeConnector.Socket.On("dockMenuItemClicked", (id) => {
MenuItem menuItem = _items.GetMenuItem(id.ToString());
BridgeConnector.Socket.On<string>("dockMenuItemClicked", (id) =>
{
MenuItem menuItem = _items.GetMenuItem(id);
menuItem?.Click();
});
}
/// <summary>
@@ -198,18 +189,13 @@ namespace ElectronNET.API
{
cancellationToken.ThrowIfCancellationRequested();
var taskCompletionSource = new TaskCompletionSource<Menu>();
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
var tcs = new TaskCompletionSource<Menu>();
using (cancellationToken.Register(() => tcs.TrySetCanceled()))
{
BridgeConnector.Socket.On("dock-getMenu-completed", (menu) =>
{
BridgeConnector.Socket.Off("dock-getMenu-completed");
taskCompletionSource.SetResult(((JObject)menu).ToObject<Menu>());
});
BridgeConnector.Socket.Once<Menu>("dock-getMenu-completed", tcs.SetResult);
BridgeConnector.Socket.Emit("dock-getMenu");
return await taskCompletionSource.Task
return await tcs.Task
.ConfigureAwait(false);
}
}
@@ -223,10 +209,6 @@ namespace ElectronNET.API
BridgeConnector.Socket.Emit("dock-setIcon", image);
}
private JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
};
}
}
}

View File

@@ -8,62 +8,134 @@
/// <summary>
/// Communicate asynchronously from the main process to renderer processes.
/// </summary>
public static IpcMain IpcMain { get { return IpcMain.Instance; } }
public static IpcMain IpcMain
{
get
{
return IpcMain.Instance;
}
}
/// <summary>
/// Control your application's event lifecycle.
/// </summary>
public static App App { get { return App.Instance; } }
public static App App
{
get
{
return App.Instance;
}
}
/// <summary>
/// Enable apps to automatically update themselves. Based on electron-updater.
/// </summary>
public static AutoUpdater AutoUpdater { get { return AutoUpdater.Instance; } }
public static AutoUpdater AutoUpdater
{
get
{
return AutoUpdater.Instance;
}
}
/// <summary>
/// Control your windows.
/// </summary>
public static WindowManager WindowManager { get { return WindowManager.Instance; } }
public static WindowManager WindowManager
{
get
{
return WindowManager.Instance;
}
}
/// <summary>
/// Create native application menus and context menus.
/// </summary>
public static Menu Menu { get { return Menu.Instance; } }
public static Menu Menu
{
get
{
return Menu.Instance;
}
}
/// <summary>
/// Display native system dialogs for opening and saving files, alerting, etc.
/// </summary>
public static Dialog Dialog { get { return Dialog.Instance; } }
public static Dialog Dialog
{
get
{
return Dialog.Instance;
}
}
/// <summary>
/// Create OS desktop notifications
/// </summary>
public static Notification Notification { get { return Notification.Instance; } }
public static Notification Notification
{
get
{
return Notification.Instance;
}
}
/// <summary>
/// Add icons and context menus to the systems notification area.
/// </summary>
public static Tray Tray { get { return Tray.Instance; } }
public static Tray Tray
{
get
{
return Tray.Instance;
}
}
/// <summary>
/// Detect keyboard events when the application does not have keyboard focus.
/// </summary>
public static GlobalShortcut GlobalShortcut { get { return GlobalShortcut.Instance; } }
public static GlobalShortcut GlobalShortcut
{
get
{
return GlobalShortcut.Instance;
}
}
/// <summary>
/// Manage files and URLs using their default applications.
/// </summary>
public static Shell Shell { get { return Shell.Instance; } }
public static Shell Shell
{
get
{
return Shell.Instance;
}
}
/// <summary>
/// Retrieve information about screen size, displays, cursor position, etc.
/// </summary>
public static Screen Screen { get { return Screen.Instance; } }
public static Screen Screen
{
get
{
return Screen.Instance;
}
}
/// <summary>
/// Perform copy and paste operations on the system clipboard.
/// </summary>
public static Clipboard Clipboard { get { return Clipboard.Instance; } }
public static Clipboard Clipboard
{
get
{
return Clipboard.Instance;
}
}
/// <summary>
/// Allows you to execute native JavaScript/TypeScript code from the host process.
@@ -72,26 +144,56 @@
/// ElectronHostHook directory:
/// <c>electronize add HostHook</c>
/// </summary>
public static HostHook HostHook { get { return HostHook.Instance; } }
public static HostHook HostHook
{
get
{
return HostHook.Instance;
}
}
/// <summary>
/// Allows you to execute native Lock and Unlock process.
/// </summary>
public static PowerMonitor PowerMonitor { get { return PowerMonitor.Instance; } }
public static PowerMonitor PowerMonitor
{
get
{
return PowerMonitor.Instance;
}
}
/// <summary>
/// Read and respond to changes in Chromium's native color theme.
/// </summary>
public static NativeTheme NativeTheme { get { return NativeTheme.Instance; } }
public static NativeTheme NativeTheme
{
get
{
return NativeTheme.Instance;
}
}
/// <summary>
/// Control your app in the macOS dock.
/// </summary>
public static Dock Dock { get { return Dock.Instance; } }
public static Dock Dock
{
get
{
return Dock.Instance;
}
}
/// <summary>
/// Electeon extensions to the Nodejs process object.
/// </summary>
public static Process Process { get { return Process.Instance; } }
public static Process Process
{
get
{
return Process.Instance;
}
}
}
}

View File

@@ -28,6 +28,6 @@ namespace ElectronNET.API.Entities
/// <summary>
/// Gets or sets the dataURL
/// </summary>
public string DataUrl { get; set; }
public string DataUrl { get; set; }
}
}

View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ElectronNET.API.Entities
namespace ElectronNET.API.Entities
{
/// <summary>
///

View File

@@ -1,6 +1,7 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using ElectronNET.Converter;
using System.ComponentModel;
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
{
@@ -199,7 +200,7 @@ namespace ElectronNET.API.Entities
public bool DarkTheme { get; set; }
/// <summary>
/// Makes the window . Default is false.
/// Makes the window transparent. Default is false.
/// </summary>
public bool Transparent { get; set; }
@@ -212,9 +213,20 @@ namespace ElectronNET.API.Entities
/// The style of window title bar. Default is default. Possible values are:
/// 'default' | 'hidden' | 'hiddenInset' | 'customButtonsOnHover'
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public TitleBarStyle TitleBarStyle { get; set; }
/// <summary>
/// Configures the window's title bar overlay when using a frameless window.
/// Can be either:
/// - false: No title bar overlay.
/// - true: Enables the default title bar overlay.
/// - An object defining custom overlay options (such as height, color, etc.).
///
/// Default is false.
/// </summary>
[JsonConverter(typeof(TitleBarOverlayConverter))]
public TitleBarOverlay TitleBarOverlay { get; set; }
/// <summary>
/// Shows the title in the tile bar in full screen mode on macOS for all
/// titleBarStyle options.Default is false.
@@ -229,12 +241,20 @@ namespace ElectronNET.API.Entities
[DefaultValue(true)]
public bool ThickFrame { get; set; } = true;
/// <summary>
/// Whether frameless window should have rounded corners. Default is true. Setting this
/// property to false will prevent the window from being fullscreenable on macOS. On
/// Windows versions older than Windows 11 Build 22000 this property has no effect, and
/// frameless windows will not have rounded corners.
/// </summary>
[DefaultValue(true)]
public bool RoundedCorners { get; set; } = true;
/// <summary>
/// Add a type of vibrancy effect to the window, only on macOS. Can be
/// appearance-based, light, dark, titlebar, selection, menu, popover, sidebar,
/// medium-light or ultra-dark.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public Vibrancy Vibrancy { get; set; }
/// <summary>
@@ -272,3 +292,7 @@ namespace ElectronNET.API.Entities
public string ProxyCredentials { get; set; }
}
}

View File

@@ -8,7 +8,7 @@
/// <summary>
/// Percentage of CPU used since the last call to getCPUUsage. First call returns 0.
/// </summary>
public int PercentCPUUsage { get; set; }
public double PercentCPUUsage { get; set; }
/// <summary>
/// The number of average idle cpu wakeups per second since the last call to

View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ElectronNET.API.Entities
namespace ElectronNET.API.Entities
{
/// <summary>
/// Provide metadata about the current loaded Chrome extension

View File

@@ -1,12 +1,14 @@
namespace ElectronNET.API.Entities {
namespace ElectronNET.API.Entities
{
/// <summary>
///
/// </summary>
public class Cookie {
public class Cookie
{
/// <summary>
/// The name of the cookie.
/// </summary>
public string Name { get; set;}
public string Name { get; set; }
/// <summary>
/// The value of the cookie.
@@ -26,7 +28,7 @@
/// <summary>
/// (optional) - The path of the cookie.
/// </summary>
public string Path { get; set; }
public string Path { get; set; }
/// <summary>
/// (optional) - Whether the cookie is marked as secure.
@@ -36,7 +38,7 @@
/// <summary>
/// (optional) - Whether the cookie is marked as HTTP only.
/// </summary>
public bool HttpOnly { get; set; }
public bool HttpOnly { get; set; }
/// <summary>
/// (optional) - Whether the cookie is a session cookie or a persistent cookie with an expiration date.
@@ -48,4 +50,4 @@
/// </summary>
public long ExpirationDate { get; set; }
}
}
}

View File

@@ -1,17 +1,17 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace ElectronNET.API.Entities {
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
{
/// <summary>
/// The cause of the change
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum CookieChangedCause
public enum CookieChangedCause
{
/// <summary>
///The cookie was changed directly by a consumer's action.
/// </summary>
[JsonProperty("explicit")]
[JsonPropertyName("explicit")]
@explicit,
/// <summary>
@@ -32,7 +32,7 @@ namespace ElectronNET.API.Entities {
/// <summary>
/// The cookie was overwritten with an already-expired expiration date.
/// </summary>
[JsonProperty("expired_overwrite")]
[JsonPropertyName("expired_overwrite")]
expiredOverwrite
}
}
}

View File

@@ -1,10 +1,12 @@
using System.ComponentModel;
namespace ElectronNET.API.Entities {
namespace ElectronNET.API.Entities
{
/// <summary>
///
/// </summary>
public class CookieDetails {
public class CookieDetails
{
/// <summary>
/// The URL to associate the cookie with. The callback will be rejected if the URL is invalid.
/// </summary>
@@ -19,7 +21,7 @@ namespace ElectronNET.API.Entities {
/// <summary>
/// (optional) - The value of the cookie. Empty by default if omitted.
/// </summary>
[DefaultValue("")]
[DefaultValue("")]
public string Value { get; set; }
/// <summary>
@@ -31,13 +33,13 @@ namespace ElectronNET.API.Entities {
/// <summary>
/// (optional) - The path of the cookie. Empty by default if omitted.
/// </summary>
[DefaultValue("")]
[DefaultValue("")]
public string Path { get; set; }
/// <summary>
/// (optional) - Whether the cookie is marked as secure. Defaults to false.
/// </summary>
[DefaultValue(false)]
[DefaultValue(false)]
public bool Secure { get; set; }
/// <summary>
@@ -53,4 +55,4 @@ namespace ElectronNET.API.Entities {
[DefaultValue(0)]
public long ExpirationDate { get; set; }
}
}
}

View File

@@ -1,13 +1,9 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ElectronNET.API.Entities
namespace ElectronNET.API.Entities
{
/// <summary>
///
/// </summary>
public class CookieFilter
public class CookieFilter
{
/// <summary>
/// (optional) - Retrieves cookies which are associated with url.Empty implies retrieving cookies of all URLs.
@@ -38,6 +34,5 @@ namespace ElectronNET.API.Entities
/// (optional) - Filters out session or persistent cookies.
/// </summary>
public bool Session { get; set; }
}
}
}

View File

@@ -41,7 +41,7 @@
/// <summary>
/// Unique identifier associated with the display.
/// </summary>
public string Id { get; set; }
public long Id { get; set; }
/// <summary>
/// true for an internal display and false for an external display.
@@ -61,7 +61,7 @@
/// <summary>
/// Output device's pixel scale factor.
/// </summary>
public int ScaleFactor { get; set; }
public double ScaleFactor { get; set; }
/// <summary>
/// Can be available, unavailable, unknown.

View File

@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ElectronNET.API.Entities
namespace ElectronNET.API.Entities
{
/// <summary>
/// Docs: https://electronjs.org/docs/api/structures/extension

View File

@@ -1,4 +1,5 @@
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
{
@@ -10,43 +11,43 @@ namespace ElectronNET.API.Entities
/// <summary>
/// Canvas.
/// </summary>
[JsonProperty("2d_canvas")]
[JsonPropertyName("2d_canvas")]
public string Canvas { get; set; }
/// <summary>
/// Flash.
/// </summary>
[JsonProperty("flash_3d")]
[JsonPropertyName("flash_3d")]
public string Flash3D { get; set; }
/// <summary>
/// Flash Stage3D.
/// </summary>
[JsonProperty("flash_stage3d")]
[JsonPropertyName("flash_stage3d")]
public string FlashStage3D { get; set; }
/// <summary>
/// Flash Stage3D Baseline profile.
/// </summary>
[JsonProperty("flash_stage3d_baseline")]
[JsonPropertyName("flash_stage3d_baseline")]
public string FlashStage3dBaseline { get; set; }
/// <summary>
/// Compositing.
/// </summary>
[JsonProperty("gpu_compositing")]
[JsonPropertyName("gpu_compositing")]
public string GpuCompositing { get; set; }
/// <summary>
/// Multiple Raster Threads.
/// </summary>
[JsonProperty("multiple_raster_threads")]
[JsonPropertyName("multiple_raster_threads")]
public string MultipleRasterThreads { get; set; }
/// <summary>
/// Native GpuMemoryBuffers.
/// </summary>
[JsonProperty("native_gpu_memory_buffers")]
[JsonPropertyName("native_gpu_memory_buffers")]
public string NativeGpuMemoryBuffers { get; set; }
/// <summary>
@@ -57,19 +58,19 @@ namespace ElectronNET.API.Entities
/// <summary>
/// Video Decode.
/// </summary>
[JsonProperty("video_decode")]
[JsonPropertyName("video_decode")]
public string VideoDecode { get; set; }
/// <summary>
/// Video Encode.
/// </summary>
[JsonProperty("video_encode")]
[JsonPropertyName("video_encode")]
public string VideoEncode { get; set; }
/// <summary>
/// VPx Video Decode.
/// </summary>
[JsonProperty("vpx_decode")]
[JsonPropertyName("vpx_decode")]
public string VpxDecode { get; set; }
/// <summary>

View File

@@ -9,10 +9,10 @@
/// Path for the pkcs12 file.
/// </summary>
public string Certificate { get; set; }
/// <summary>
/// Passphrase for the certificate.
/// </summary>
public string Password {get; set; }
public string Password { get; set; }
}
}
}

View File

@@ -1,10 +1,9 @@
using Newtonsoft.Json.Converters;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace ElectronNET.API.Entities
{
using ElectronNET.Converter;
using System.Text.Json.Serialization;
/// <summary>
///
@@ -76,7 +75,8 @@ namespace ElectronNET.API.Entities
/// `touchScrollStarted`, `pointerDown`, `pointerUp`, `pointerMove`,
/// `pointerRawUpdate`, `pointerCancel` or `pointerCausedUaAction`.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public InputEventType Type { get; set; }
}
}

View File

@@ -9,26 +9,32 @@ public enum InputEventType
///
/// </summary>
undefined,
/// <summary>
///
/// </summary>
mouseDown,
/// <summary>
///
/// </summary>
mouseUp,
/// <summary>
///
/// </summary>
mouseMove,
/// <summary>
///
/// </summary>
mouseEnter,
/// <summary>
///
/// </summary>
mouseLeave,
/// <summary>
///
/// </summary>

View File

@@ -1,5 +1,5 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
{
@@ -21,7 +21,7 @@ namespace ElectronNET.API.Entities
/// <summary>
/// One of the following: "tasks" | "frequent" | "recent" | "custom"
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public JumpListCategoryType Type { get; set; }
}
}
}

View File

@@ -1,5 +1,5 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
{
@@ -52,7 +52,8 @@ namespace ElectronNET.API.Entities
/// <summary>
/// One of the following: "task" | "separator" | "file"
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public JumpListItemType Type { get; set; }
}
}

View File

@@ -1,7 +1,5 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.ComponentModel;
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
{
@@ -21,13 +19,11 @@ namespace ElectronNET.API.Entities
/// Define the action of the menu item, when specified the click property will be
/// ignored.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public MenuRole Role { get; set; }
/// <summary>
/// Can be normal, separator, submenu, checkbox or radio.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public MenuType Type { get; set; }
@@ -101,3 +97,5 @@ namespace ElectronNET.API.Entities
public string Position { get; set; }
}
}

View File

@@ -1,5 +1,5 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
{
@@ -13,7 +13,6 @@ namespace ElectronNET.API.Entities
/// displays the same icon as "info", unless you set an icon using the "icon"
/// option. On macOS, both "warning" and "error" display the same warning icon.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public MessageBoxType Type { get; set; }
/// <summary>
@@ -99,3 +98,5 @@ namespace ElectronNET.API.Entities
}
}
}

View File

@@ -1,12 +1,12 @@
using System;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
namespace ElectronNET.API.Entities
{
@@ -21,9 +21,9 @@ namespace ElectronNET.API.Entities
private static readonly Dictionary<string, float> ScaleFactorPairs = new Dictionary<string, float>
{
{"@2x", 2.0f}, {"@3x", 3.0f}, {"@1x", 1.0f}, {"@4x", 4.0f},
{"@5x", 5.0f}, {"@1.25x", 1.25f}, {"@1.33x", 1.33f}, {"@1.4x", 1.4f},
{"@1.5x", 1.5f}, {"@1.8x", 1.8f}, {"@2.5x", 2.5f}
{ "@2x", 2.0f }, { "@3x", 3.0f }, { "@1x", 1.0f }, { "@4x", 4.0f },
{ "@5x", 5.0f }, { "@1.25x", 1.25f }, { "@1.33x", 1.33f }, { "@1.4x", 1.4f },
{ "@1.5x", 1.5f }, { "@1.8x", 1.8f }, { "@2.5x", 2.5f }
};
private static float? ExtractDpiFromFilePath(string filePath)
@@ -34,6 +34,7 @@ namespace ElectronNET.API.Entities
.Select(p => p.Value)
.FirstOrDefault();
}
private static Image BytesToImage(byte[] bytes)
{
var ms = new MemoryStream(bytes);
@@ -83,7 +84,7 @@ namespace ElectronNET.API.Entities
/// <param name="dataUrl">A data URL with a base64 encoded image.</param>
public static NativeImage CreateFromDataURL(string dataUrl)
{
var images = new Dictionary<float,Image>();
var images = new Dictionary<float, Image>();
var parsedDataUrl = Regex.Match(dataUrl, @"data:image/(?<type>.+?),(?<data>.+)");
var actualData = parsedDataUrl.Groups["data"].Value;
var binData = Convert.FromBase64String(actualData);
@@ -101,7 +102,7 @@ namespace ElectronNET.API.Entities
/// <param name="path">The path of the image</param>
public static NativeImage CreateFromPath(string path)
{
var images = new Dictionary<float,Image>();
var images = new Dictionary<float, Image>();
if (Regex.IsMatch(path, "(@.+?x)"))
{
var dpi = ExtractDpiFromFilePath(path);
@@ -164,7 +165,7 @@ namespace ElectronNET.API.Entities
/// </summary>
public NativeImage Crop(Rectangle rect)
{
var images = new Dictionary<float,Image>();
var images = new Dictionary<float, Image>();
foreach (var image in _images)
{
images.Add(image.Key, Crop(rect.X, rect.Y, rect.Width, rect.Height, image.Key));
@@ -196,7 +197,7 @@ namespace ElectronNET.API.Entities
if (options.Buffer.Length > 0)
{
_images[options.ScaleFactor] =
CreateFromBuffer(options.Buffer, new CreateFromBufferOptions {ScaleFactor = options.ScaleFactor})
CreateFromBuffer(options.Buffer, new CreateFromBufferOptions { ScaleFactor = options.ScaleFactor })
.GetScale(options.ScaleFactor);
}
else if (!string.IsNullOrEmpty(options.DataUrl))
@@ -225,7 +226,7 @@ namespace ElectronNET.API.Entities
/// </summary>
public byte[] GetBitmap(BitmapOptions options)
{
return ToBitmap(new ToBitmapOptions{ ScaleFactor = options.ScaleFactor });
return ToBitmap(new ToBitmapOptions { ScaleFactor = options.ScaleFactor });
}
/// <summary>
@@ -419,12 +420,13 @@ namespace ElectronNET.API.Entities
return codec;
}
}
return null;
}
internal Dictionary<float,string> GetAllScaledImages()
internal Dictionary<float, string> GetAllScaledImages()
{
var dict = new Dictionary<float,string>();
var dict = new Dictionary<float, string>();
try
{
foreach (var (scale, image) in _images)
@@ -436,7 +438,7 @@ namespace ElectronNET.API.Entities
{
Console.WriteLine(ex);
}
return dict;
}
@@ -450,4 +452,4 @@ namespace ElectronNET.API.Entities
return null;
}
}
}
}

View File

@@ -1,34 +1,39 @@
using System;
using ElectronNET.API.Serialization;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using Newtonsoft.Json;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
{
internal class NativeImageJsonConverter : JsonConverter
internal class NativeImageJsonConverter : JsonConverter<NativeImage>
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
public override void Write(Utf8JsonWriter writer, NativeImage value, JsonSerializerOptions options)
{
if (value is NativeImage nativeImage)
if (value is null)
{
var scaledImages = nativeImage.GetAllScaledImages();
serializer.Serialize(writer, scaledImages);
writer.WriteNullValue();
return;
}
var scaledImages = value.GetAllScaledImages();
JsonSerializer.Serialize(writer, scaledImages, ElectronJson.Options);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
public override NativeImage Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var dict = serializer.Deserialize<Dictionary<float, string>>(reader);
var dict = JsonSerializer.Deserialize<Dictionary<float, string>>(ref reader, ElectronJson.Options);
var newDictionary = new Dictionary<float, Image>();
foreach (var item in dict)
{
var bytes = Convert.FromBase64String(item.Value);
newDictionary.Add(item.Key, Image.FromStream(new MemoryStream(bytes)));
}
return new NativeImage(newDictionary);
}
public override bool CanConvert(Type objectType) => objectType == typeof(NativeImage);
}
}

View File

@@ -1,5 +1,5 @@
using Newtonsoft.Json;
using System;
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
{
@@ -86,7 +86,7 @@ namespace ElectronNET.API.Entities
/// <value>
/// The show identifier.
/// </value>
[JsonProperty]
[JsonInclude]
internal string ShowID { get; set; }
/// <summary>
@@ -101,7 +101,7 @@ namespace ElectronNET.API.Entities
/// <value>
/// The click identifier.
/// </value>
[JsonProperty]
[JsonInclude]
internal string ClickID { get; set; }
/// <summary>
@@ -118,7 +118,7 @@ namespace ElectronNET.API.Entities
/// <value>
/// The close identifier.
/// </value>
[JsonProperty]
[JsonInclude]
internal string CloseID { get; set; }
/// <summary>
@@ -135,7 +135,7 @@ namespace ElectronNET.API.Entities
/// <value>
/// The reply identifier.
/// </value>
[JsonProperty]
[JsonInclude]
internal string ReplyID { get; set; }
/// <summary>
@@ -150,7 +150,7 @@ namespace ElectronNET.API.Entities
/// <value>
/// The action identifier.
/// </value>
[JsonProperty]
[JsonInclude]
internal string ActionID { get; set; }
/// <summary>

View File

@@ -1,5 +1,5 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
{
@@ -13,7 +13,7 @@ namespace ElectronNET.API.Entities
/// detach.Defaults to last used dock state.In undocked mode it's possible to dock
/// back.In detach mode it's not.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public DevToolsMode Mode { get; set; }
}
}
}

View File

@@ -1,5 +1,5 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
{
@@ -33,7 +33,6 @@ namespace ElectronNET.API.Entities
/// Contains which features the dialog should use. The following values are supported:
/// 'openFile' | 'openDirectory' | 'multiSelections' | 'showHiddenFiles' | 'createDirectory' | 'promptToCreate' | 'noResolveAliases' | 'treatPackageAsDirectory'
/// </summary>
[JsonProperty("properties", ItemConverterType = typeof(StringEnumConverter))]
public OpenDialogProperty[] Properties { get; set; }
/// <summary>
@@ -58,4 +57,5 @@ namespace ElectronNET.API.Entities
/// </example>
public FileFilter[] Filters { get; set; }
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.ComponentModel;
using System.ComponentModel;
namespace ElectronNET.API.Entities
{

View File

@@ -0,0 +1,20 @@
namespace ElectronNET.API.Entities;
public class PageSize
{
private readonly string _value;
public PageSize()
{
}
private PageSize(string value) : this() => _value = value;
public double Height { get; set; }
public double Width { get; set; }
public static implicit operator string(PageSize pageSize) => pageSize?._value;
public static implicit operator PageSize(string value) => new(value);
}

View File

@@ -67,7 +67,7 @@ namespace ElectronNET.API.Entities
/// true for landscape, false for portrait.
/// </summary>
public bool Landscape { get; set; }
/// <summary>
/// The scale factor of the web page
/// </summary>
@@ -102,6 +102,5 @@ namespace ElectronNET.API.Entities
/// Dpi
/// </summary>
public PrintDpi Dpi { get; set; }
}
}

View File

@@ -1,4 +1,7 @@
namespace ElectronNET.API.Entities;
using ElectronNET.Converter;
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities;
/// <summary>
///
@@ -30,7 +33,8 @@ public class PrintToPDFOptions
/// `A5`, `A6`, `Legal`, `Letter`, `Tabloid`, `Ledger`, or an Object containing
/// `height` and `width` in inches. Defaults to `Letter`.
/// </summary>
public object PageSize { get; set; } = "Letter";
[JsonConverter(typeof(PageSizeConverter))]
public PageSize PageSize { get; set; } = "Letter";
/// <summary>
/// Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string,

View File

@@ -14,7 +14,7 @@ namespace ElectronNET.API.Entities
/// Name
/// </summary>
public string Description { get; set; }
/// <summary>
/// Status
/// </summary>
@@ -24,6 +24,5 @@ namespace ElectronNET.API.Entities
/// Is default
/// </summary>
public bool IsDefault { get; set; }
}
}

View File

@@ -1,7 +1,7 @@
namespace ElectronNET.API.Entities
{
/// <summary>
///
/// Process metrics information.
/// </summary>
public class ProcessMetric
{
@@ -21,11 +21,9 @@
public CPUUsage Cpu { get; set; }
/// <summary>
/// Creation time for this process. The time is represented as number of milliseconds since epoch.
/// Since the <see cref="PId"/> can be reused after a process dies, it is useful to use both the <see cref="PId"/>
/// and the <see cref="CreationTime"/> to uniquely identify a process.
/// Creation time for this process in milliseconds since Unix epoch. Can exceed Int32 range and may contain fractional milliseconds.
/// </summary>
public int CreationTime { get; set; }
public double CreationTime { get; set; }
/// <summary>
/// Memory information for the process.

View File

@@ -1,5 +1,5 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
{
@@ -11,7 +11,7 @@ namespace ElectronNET.API.Entities
/// <summary>
/// Mode for the progress bar. Can be 'none' | 'normal' | 'indeterminate' | 'error' | 'paused'.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public ProgressBarMode Mode { get; set; }
}
}
}

View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ElectronNET.API.Entities
namespace ElectronNET.API.Entities
{
/// <summary>
///

View File

@@ -1,5 +1,5 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
{
@@ -28,7 +28,6 @@ namespace ElectronNET.API.Entities
/// Scheme of the authentication. Can be basic, digest, ntlm, negotiate.
/// Must be provided if removing by origin.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public Scheme Scheme { get; set; }
/// <summary>
@@ -51,3 +50,5 @@ namespace ElectronNET.API.Entities
}
}
}

View File

@@ -8,35 +8,43 @@
/// <summary>
///
/// </summary>
public string Raw { get; set; }
public string Raw { get; set; }
/// <summary>
///
/// </summary>
public bool Loose { get; set; }
/// <summary>
///
/// </summary>
public SemVerOptions Options { get; set; }
/// <summary>
///
/// </summary>
public int Major { get; set; }
/// <summary>
///
/// </summary>
public int Minor { get; set; }
/// <summary>
///
/// </summary>
public int Patch { get; set; }
/// <summary>
///
/// </summary>
public string Version { get; set; }
/// <summary>
///
/// </summary>
public string[] Build { get; set; }
/// <summary>
///
/// </summary>
@@ -46,14 +54,16 @@
/// <summary>
///
/// </summary>
public class SemVerOptions {
public class SemVerOptions
{
/// <summary>
///
/// </summary>
public bool? Loose { get; set; }
/// <summary>
///
/// </summary>
public bool? IncludePrerelease { get; set; }
}
}
}

View File

@@ -1,6 +1,5 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
{
@@ -36,7 +35,6 @@ namespace ElectronNET.API.Entities
/// hidden - The button is not shown to the user.
/// noninteractive - The button is enabled but not interactive; no pressed button state is drawn.This value is intended for instances where the button is used in a notification.
/// </summary>
[JsonProperty("flags", ItemConverterType = typeof(StringEnumConverter))]
public ThumbarButtonFlag[] Flags { get; set; }
/// <summary>
@@ -58,4 +56,5 @@ namespace ElectronNET.API.Entities
Icon = icon;
}
}
}
}

View File

@@ -0,0 +1,22 @@
namespace ElectronNET.API.Entities;
public class TitleBarOverlay
{
private readonly bool? _value;
public TitleBarOverlay()
{
}
private TitleBarOverlay(bool value) : this() => _value = value;
public string Color { get; set; }
public double Height { get; set; }
public string SymbolColor { get; set; }
public static implicit operator bool?(TitleBarOverlay titleBarOverlay) => titleBarOverlay?._value;
public static implicit operator TitleBarOverlay(bool value) => new(value);
}

View File

@@ -1,4 +1,5 @@
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
{
@@ -10,7 +11,7 @@ namespace ElectronNET.API.Entities
/// <summary>
/// The default style
/// </summary>
[JsonProperty("default")]
[JsonPropertyName("default")]
defaultStyle,
/// <summary>

View File

@@ -15,7 +15,6 @@
/// </summary>
public void Cancel()
{
}
/// <summary>
@@ -23,7 +22,6 @@
/// </summary>
public void Dispose()
{
}
}
}
}

View File

@@ -9,7 +9,7 @@
/// The data is available as a Buffer, in the rawData field.
/// </summary>
public string Type { get; } = "rawData";
/// <summary>
/// The raw bytes of the post data in a Buffer.
/// </summary>

View File

@@ -27,8 +27,9 @@ namespace ElectronNET.API.Extensions
return ((DescriptionAttribute)attrs[0]).Description;
}
}
//If we have no description attribute, just return the ToString of the enum
return enumerationValue.ToString();
}
}
}
}

View File

@@ -56,7 +56,7 @@ namespace ElectronNET.API.Extensions
var menuItem = menuItems[index];
if (menuItem?.Submenu?.Length > 0)
{
if(menuItem.Type == MenuType.normal)
if (menuItem.Type == MenuType.normal)
{
menuItem.Type = MenuType.submenu;
}
@@ -68,4 +68,4 @@ namespace ElectronNET.API.Extensions
return menuItems;
}
}
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Threading.Tasks;
namespace ElectronNET.API
@@ -12,7 +13,9 @@ namespace ElectronNET.API
private static GlobalShortcut _globalShortcut;
private static object _syncRoot = new object();
internal GlobalShortcut() { }
internal GlobalShortcut()
{
}
internal static GlobalShortcut Instance
{
@@ -50,11 +53,11 @@ namespace ElectronNET.API
_shortcuts.Add(accelerator, function);
BridgeConnector.Socket.Off("globalShortcut-pressed");
BridgeConnector.Socket.On("globalShortcut-pressed", (shortcut) =>
BridgeConnector.Socket.On<string>("globalShortcut-pressed", (shortcut) =>
{
if (_shortcuts.ContainsKey(shortcut.ToString()))
if (_shortcuts.TryGetValue(shortcut, out var action))
{
_shortcuts[shortcut.ToString()]();
action();
}
});
@@ -70,18 +73,12 @@ namespace ElectronNET.API
/// <returns>Whether this application has registered accelerator.</returns>
public Task<bool> IsRegisteredAsync(string accelerator)
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("globalShortcut-isRegisteredCompleted", (isRegistered) =>
{
BridgeConnector.Socket.Off("globalShortcut-isRegisteredCompleted");
taskCompletionSource.SetResult((bool)isRegistered);
});
var tcs = new TaskCompletionSource<bool>();
BridgeConnector.Socket.Once<bool>("globalShortcut-isRegisteredCompleted", tcs.SetResult);
BridgeConnector.Socket.Emit("globalShortcut-isRegistered", accelerator);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>

View File

@@ -1,7 +1,6 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using ElectronNET.API.Serialization;
using System;
using System.Text.Json;
using System.Threading.Tasks;
namespace ElectronNET.API
@@ -17,9 +16,11 @@ namespace ElectronNET.API
{
private static HostHook _electronHostHook;
private static object _syncRoot = new object();
string oneCallguid = Guid.NewGuid().ToString();
private string oneCallguid = Guid.NewGuid().ToString();
internal HostHook() { }
internal HostHook()
{
}
internal static HostHook Instance
{
@@ -47,10 +48,9 @@ namespace ElectronNET.API
/// <param name="arguments">Optional parameters.</param>
public void Call(string socketEventName, params dynamic[] arguments)
{
BridgeConnector.Socket.On(socketEventName + "Error" + oneCallguid, (result) =>
BridgeConnector.Socket.Once<string>(socketEventName + "Error" + oneCallguid, (result) =>
{
BridgeConnector.Socket.Off(socketEventName + "Error" + oneCallguid);
Electron.Dialog.ShowErrorBox("Host Hook Exception", result.ToString());
Electron.Dialog.ShowErrorBox("Host Hook Exception", result);
});
BridgeConnector.Socket.Emit(socketEventName, arguments, oneCallguid);
@@ -65,64 +65,37 @@ namespace ElectronNET.API
/// <returns></returns>
public Task<T> CallAsync<T>(string socketEventName, params dynamic[] arguments)
{
var taskCompletionSource = new TaskCompletionSource<T>();
var tcs = new TaskCompletionSource<T>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On(socketEventName + "Error" + guid, (result) =>
BridgeConnector.Socket.Once<string>(socketEventName + "Error" + guid, (result) =>
{
BridgeConnector.Socket.Off(socketEventName + "Error" + guid);
Electron.Dialog.ShowErrorBox("Host Hook Exception", result.ToString());
taskCompletionSource.SetException(new Exception($"Host Hook Exception {result}"));
Electron.Dialog.ShowErrorBox("Host Hook Exception", result);
tcs.SetException(new Exception($"Host Hook Exception {result}"));
});
BridgeConnector.Socket.On(socketEventName + "Complete" + guid, (result) =>
BridgeConnector.Socket.Once<JsonElement>(socketEventName + "Complete" + guid, (result) =>
{
BridgeConnector.Socket.Off(socketEventName + "Error" + guid);
BridgeConnector.Socket.Off(socketEventName + "Complete" + guid);
T data = default;
try
{
if (result.GetType().IsValueType || result is string)
{
data = (T)result;
}
else
{
var token = JToken.Parse(result.ToString());
if (token is JArray)
{
data = token.ToObject<T>();
}
else if (token is JObject)
{
data = token.ToObject<T>();
}
else
{
data = (T)result;
}
}
data = result.Deserialize<T>(ElectronJson.Options);
}
catch (Exception exception)
{
taskCompletionSource.SetException(exception);
//throw new InvalidCastException("Return value does not match with the generic type.", exception);
tcs.SetException(exception);
}
taskCompletionSource.SetResult(data);
tcs.SetResult(data);
});
BridgeConnector.Socket.Emit(socketEventName, arguments, guid);
return taskCompletionSource.Task;
return tcs.Task;
}
private JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
}
}

View File

@@ -1,10 +1,8 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using ElectronNET.API.Serialization;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
namespace ElectronNET.API
@@ -17,17 +15,19 @@ namespace ElectronNET.API
private static IpcMain _ipcMain;
private static object _syncRoot = new object();
internal IpcMain() { }
internal IpcMain()
{
}
internal static IpcMain Instance
{
get
{
if(_ipcMain == null)
if (_ipcMain == null)
{
lock (_syncRoot)
{
if(_ipcMain == null)
if (_ipcMain == null)
{
_ipcMain = new IpcMain();
}
@@ -48,11 +48,11 @@ namespace ElectronNET.API
{
await BridgeConnector.Socket.Emit("registerIpcMainChannel", channel).ConfigureAwait(false);
BridgeConnector.Socket.Off(channel);
BridgeConnector.Socket.On(channel, (args) =>
BridgeConnector.Socket.On<JsonElement>(channel, (args) =>
{
List<object> objectArray = FormatArguments(args);
if(objectArray.Count == 1)
if (objectArray.Count == 1)
{
listener(objectArray.First());
}
@@ -63,19 +63,10 @@ namespace ElectronNET.API
});
}
private List<object> FormatArguments(object args)
private static List<object> FormatArguments(JsonElement args)
{
List<object> objectArray = ((JArray)args).ToObject<object[]>().ToList();
for (int index = 0; index < objectArray.Count; index++)
{
var item = objectArray[index];
if (item == null)
{
objectArray.Remove(item);
}
}
var objectArray = args.Deserialize<object[]>(ElectronJson.Options).ToList();
objectArray.RemoveAll(item => item is null);
return objectArray;
}
@@ -91,7 +82,8 @@ namespace ElectronNET.API
public void OnSync(string channel, Func<object, object> listener)
{
BridgeConnector.Socket.Emit("registerSyncIpcMainChannel", channel);
BridgeConnector.Socket.On(channel, (args) => {
BridgeConnector.Socket.On<JsonElement>(channel, (args) =>
{
List<object> objectArray = FormatArguments(args);
object parameter;
if (objectArray.Count == 1)
@@ -117,7 +109,7 @@ namespace ElectronNET.API
public void Once(string channel, Action<object> listener)
{
BridgeConnector.Socket.Emit("registerOnceIpcMainChannel", channel);
BridgeConnector.Socket.Once<object>(channel, (args) =>
BridgeConnector.Socket.Once<JsonElement>(channel, (args) =>
{
List<object> objectArray = FormatArguments(args);
@@ -152,32 +144,7 @@ namespace ElectronNET.API
/// <param name="data">Arguments data.</param>
public void Send(BrowserWindow browserWindow, string channel, params object[] data)
{
List<JObject> jobjects = new List<JObject>();
List<JArray> jarrays = new List<JArray>();
List<object> objects = new List<object>();
foreach (var parameterObject in data)
{
if(parameterObject.GetType().IsArray || parameterObject.GetType().IsGenericType && parameterObject is IEnumerable)
{
jarrays.Add(JArray.FromObject(parameterObject, _jsonSerializer));
} else if(parameterObject.GetType().IsClass && !parameterObject.GetType().IsPrimitive && !(parameterObject is string))
{
jobjects.Add(JObject.FromObject(parameterObject, _jsonSerializer));
} else if(parameterObject.GetType().IsPrimitive || (parameterObject is string))
{
objects.Add(parameterObject);
}
}
if(jobjects.Count > 0 || jarrays.Count > 0)
{
BridgeConnector.Socket.Emit("sendToIpcRenderer", JObject.FromObject(browserWindow, _jsonSerializer), channel, jarrays.ToArray(), jobjects.ToArray(), objects.ToArray());
}
else
{
BridgeConnector.Socket.Emit("sendToIpcRenderer", JObject.FromObject(browserWindow, _jsonSerializer), channel, data);
}
BridgeConnector.Socket.Emit("sendToIpcRenderer", browserWindow, channel, data);
}
/// <summary>
@@ -191,39 +158,9 @@ namespace ElectronNET.API
/// <param name="data">Arguments data.</param>
public void Send(BrowserView browserView, string channel, params object[] data)
{
List<JObject> jobjects = new List<JObject>();
List<JArray> jarrays = new List<JArray>();
List<object> objects = new List<object>();
foreach (var parameterObject in data)
{
if(parameterObject.GetType().IsArray || parameterObject.GetType().IsGenericType && parameterObject is IEnumerable)
{
jarrays.Add(JArray.FromObject(parameterObject, _jsonSerializer));
} else if(parameterObject.GetType().IsClass && !parameterObject.GetType().IsPrimitive && !(parameterObject is string))
{
jobjects.Add(JObject.FromObject(parameterObject, _jsonSerializer));
} else if(parameterObject.GetType().IsPrimitive || (parameterObject is string))
{
objects.Add(parameterObject);
}
}
if(jobjects.Count > 0 || jarrays.Count > 0)
{
BridgeConnector.Socket.Emit("sendToIpcRendererBrowserView", browserView.Id, channel, jarrays.ToArray(), jobjects.ToArray(), objects.ToArray());
}
else
{
BridgeConnector.Socket.Emit("sendToIpcRendererBrowserView", browserView.Id, channel, data);
}
BridgeConnector.Socket.Emit("sendToIpcRendererBrowserView", browserView.Id, channel, data);
}
private JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
}
}
}

View File

@@ -1,11 +1,10 @@
using ElectronNET.API.Entities;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Collections.Generic;
using ElectronNET.API.Entities;
using ElectronNET.API.Extensions;
using System.Linq;
using ElectronNET.API.Serialization;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text.Json;
namespace ElectronNET.API
{
@@ -17,7 +16,9 @@ namespace ElectronNET.API
private static Menu _menu;
private static object _syncRoot = new object();
internal Menu() { }
internal Menu()
{
}
internal static Menu Instance
{
@@ -27,7 +28,7 @@ namespace ElectronNET.API
{
lock (_syncRoot)
{
if(_menu == null)
if (_menu == null)
{
_menu = new Menu();
}
@@ -44,7 +45,14 @@ namespace ElectronNET.API
/// <value>
/// The menu items.
/// </value>
public IReadOnlyCollection<MenuItem> MenuItems { get { return _menuItems.AsReadOnly(); } }
public IReadOnlyCollection<MenuItem> MenuItems
{
get
{
return _menuItems.AsReadOnly();
}
}
private List<MenuItem> _menuItems = new List<MenuItem>();
/// <summary>
@@ -58,12 +66,13 @@ namespace ElectronNET.API
menuItems.AddMenuItemsId();
menuItems.AddSubmenuTypes();
BridgeConnector.Socket.Emit("menu-setApplicationMenu", JArray.FromObject(menuItems, _jsonSerializer));
BridgeConnector.Socket.Emit("menu-setApplicationMenu", new[] { menuItems });
_menuItems.AddRange(menuItems);
BridgeConnector.Socket.Off("menuItemClicked");
BridgeConnector.Socket.On("menuItemClicked", (id) => {
MenuItem menuItem = _menuItems.GetMenuItem(id.ToString());
BridgeConnector.Socket.On<string>("menuItemClicked", (id) =>
{
MenuItem menuItem = _menuItems.GetMenuItem(id);
menuItem.Click?.Invoke();
});
}
@@ -75,6 +84,7 @@ namespace ElectronNET.API
/// The context menu items.
/// </value>
public IReadOnlyDictionary<int, ReadOnlyCollection<MenuItem>> ContextMenuItems { get; internal set; }
private Dictionary<int, List<MenuItem>> _contextMenuItems = new Dictionary<int, List<MenuItem>>();
/// <summary>
@@ -87,7 +97,7 @@ namespace ElectronNET.API
menuItems.AddMenuItemsId();
menuItems.AddSubmenuTypes();
BridgeConnector.Socket.Emit("menu-setContextMenu", browserWindow.Id, JArray.FromObject(menuItems, _jsonSerializer));
BridgeConnector.Socket.Emit("menu-setContextMenu", browserWindow.Id, menuItems);
if (!_contextMenuItems.ContainsKey(browserWindow.Id))
{
@@ -97,10 +107,14 @@ namespace ElectronNET.API
}
BridgeConnector.Socket.Off("contextMenuItemClicked");
BridgeConnector.Socket.On("contextMenuItemClicked", (results) =>
BridgeConnector.Socket.On<JsonElement>("contextMenuItemClicked", (results) =>
{
var id = ((JArray)results).First.ToString();
var browserWindowId = (int)((JArray)results).Last;
var arr = results.EnumerateArray();
var e = arr.GetEnumerator();
e.MoveNext();
var id = e.Current.GetString();
e.MoveNext();
var browserWindowId = e.Current.GetInt32();
MenuItem menuItem = _contextMenuItems[browserWindowId].GetMenuItem(id);
menuItem.Click?.Invoke();
@@ -116,10 +130,6 @@ namespace ElectronNET.API
BridgeConnector.Socket.Emit("menu-contextMenuPopup", browserWindow.Id);
}
private JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
};
}
}

View File

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

View File

@@ -1,7 +1,4 @@
using ElectronNET.API.Entities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using ElectronNET.API.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -12,12 +9,15 @@ namespace ElectronNET.API
/// <summary>
/// Create OS desktop notifications
/// </summary>
public sealed class Notification
public sealed class Notification: ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.NoDashUpperFirst;
private static Notification _notification;
private static object _syncRoot = new object();
internal Notification() { }
internal Notification()
{
}
internal static Notification Instance
{
@@ -48,7 +48,7 @@ namespace ElectronNET.API
{
GenerateIDsForDefinedActions(notificationOptions);
BridgeConnector.Socket.Emit("createNotification", JObject.FromObject(notificationOptions, _jsonSerializer));
BridgeConnector.Socket.Emit("createNotification", notificationOptions);
}
private static void GenerateIDsForDefinedActions(NotificationOptions notificationOptions)
@@ -61,9 +61,7 @@ namespace ElectronNET.API
isActionDefined = true;
BridgeConnector.Socket.Off("NotificationEventShow");
BridgeConnector.Socket.On("NotificationEventShow", (id) => {
_notificationOptions.Single(x => x.ShowID == id.ToString()).OnShow();
});
BridgeConnector.Socket.On<string>("NotificationEventShow", (id) => { _notificationOptions.Single(x => x.ShowID == id).OnShow(); });
}
if (notificationOptions.OnClick != null)
@@ -72,9 +70,7 @@ namespace ElectronNET.API
isActionDefined = true;
BridgeConnector.Socket.Off("NotificationEventClick");
BridgeConnector.Socket.On("NotificationEventClick", (id) => {
_notificationOptions.Single(x => x.ClickID == id.ToString()).OnClick();
});
BridgeConnector.Socket.On<string>("NotificationEventClick", (id) => { _notificationOptions.Single(x => x.ClickID == id).OnClick(); });
}
if (notificationOptions.OnClose != null)
@@ -83,9 +79,7 @@ namespace ElectronNET.API
isActionDefined = true;
BridgeConnector.Socket.Off("NotificationEventClose");
BridgeConnector.Socket.On("NotificationEventClose", (id) => {
_notificationOptions.Single(x => x.CloseID == id.ToString()).OnClose();
});
BridgeConnector.Socket.On<string>("NotificationEventClose", (id) => { _notificationOptions.Single(x => x.CloseID == id).OnClose(); });
}
if (notificationOptions.OnReply != null)
@@ -94,9 +88,9 @@ namespace ElectronNET.API
isActionDefined = true;
BridgeConnector.Socket.Off("NotificationEventReply");
BridgeConnector.Socket.On("NotificationEventReply", (args) => {
var arguments = ((JArray)args).ToObject<string[]>();
_notificationOptions.Single(x => x.ReplyID == arguments[0].ToString()).OnReply(arguments[1].ToString());
BridgeConnector.Socket.On<string[]>("NotificationEventReply", (args) =>
{
_notificationOptions.Single(x => x.ReplyID == args[0]).OnReply(args[1]);
});
}
@@ -106,9 +100,9 @@ namespace ElectronNET.API
isActionDefined = true;
BridgeConnector.Socket.Off("NotificationEventAction");
BridgeConnector.Socket.On("NotificationEventAction", (args) => {
var arguments = ((JArray)args).ToObject<string[]>();
_notificationOptions.Single(x => x.ReplyID == arguments[0].ToString()).OnAction(arguments[1].ToString());
BridgeConnector.Socket.On<string[]>("NotificationEventAction", (args) =>
{
_notificationOptions.Single(x => x.ActionID == args[0]).OnAction(args[1]);
});
}
@@ -122,26 +116,6 @@ namespace ElectronNET.API
/// Whether or not desktop notifications are supported on the current system.
/// </summary>
/// <returns></returns>
public Task<bool> IsSupportedAsync()
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("notificationIsSupportedComplete", (isSupported) =>
{
BridgeConnector.Socket.Off("notificationIsSupportedComplete");
taskCompletionSource.SetResult((bool)isSupported);
});
BridgeConnector.Socket.Emit("notificationIsSupported");
return taskCompletionSource.Task;
}
private JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
public Task<bool> IsSupportedAsync() => GetPropertyAsync<bool>();
}
}

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,4 @@
using ElectronNET.API.Entities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using ElectronNET.API.Entities;
using System;
using System.Threading.Tasks;
@@ -50,18 +47,13 @@ namespace ElectronNET.API
/// <returns></returns>
public Task ClearAuthCacheAsync(RemovePassword options)
{
var taskCompletionSource = new TaskCompletionSource<object>();
var tcs = new TaskCompletionSource<object>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-clearAuthCache-completed" + guid, () =>
{
BridgeConnector.Socket.Off("webContents-session-clearAuthCache-completed" + guid);
taskCompletionSource.SetResult(null);
});
BridgeConnector.Socket.Once("webContents-session-clearAuthCache-completed" + guid, () => tcs.SetResult(null));
BridgeConnector.Socket.Emit("webContents-session-clearAuthCache", Id, options, guid);
BridgeConnector.Socket.Emit("webContents-session-clearAuthCache", Id, JObject.FromObject(options, _jsonSerializer), guid);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -69,18 +61,13 @@ namespace ElectronNET.API
/// </summary>
public Task ClearAuthCacheAsync()
{
var taskCompletionSource = new TaskCompletionSource<object>();
var tcs = new TaskCompletionSource<object>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-clearAuthCache-completed" + guid, () =>
{
BridgeConnector.Socket.Off("webContents-session-clearAuthCache-completed" + guid);
taskCompletionSource.SetResult(null);
});
BridgeConnector.Socket.Once("webContents-session-clearAuthCache-completed" + guid, () => tcs.SetResult(null));
BridgeConnector.Socket.Emit("webContents-session-clearAuthCache", Id, guid);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -89,18 +76,13 @@ namespace ElectronNET.API
/// <returns></returns>
public Task ClearCacheAsync()
{
var taskCompletionSource = new TaskCompletionSource<object>();
var tcs = new TaskCompletionSource<object>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-clearCache-completed" + guid, () =>
{
BridgeConnector.Socket.Off("webContents-session-clearCache-completed" + guid);
taskCompletionSource.SetResult(null);
});
BridgeConnector.Socket.Once("webContents-session-clearCache-completed" + guid, () => tcs.SetResult(null));
BridgeConnector.Socket.Emit("webContents-session-clearCache", Id, guid);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -109,18 +91,13 @@ namespace ElectronNET.API
/// <returns></returns>
public Task ClearHostResolverCacheAsync()
{
var taskCompletionSource = new TaskCompletionSource<object>();
var tcs = new TaskCompletionSource<object>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-clearHostResolverCache-completed" + guid, () =>
{
BridgeConnector.Socket.Off("webContents-session-clearHostResolverCache-completed" + guid);
taskCompletionSource.SetResult(null);
});
BridgeConnector.Socket.Once("webContents-session-clearHostResolverCache-completed" + guid, () => tcs.SetResult(null));
BridgeConnector.Socket.Emit("webContents-session-clearHostResolverCache", Id, guid);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -129,18 +106,13 @@ namespace ElectronNET.API
/// <returns></returns>
public Task ClearStorageDataAsync()
{
var taskCompletionSource = new TaskCompletionSource<object>();
var tcs = new TaskCompletionSource<object>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-clearStorageData-completed" + guid, () =>
{
BridgeConnector.Socket.Off("webContents-session-clearStorageData-completed" + guid);
taskCompletionSource.SetResult(null);
});
BridgeConnector.Socket.Once("webContents-session-clearStorageData-completed" + guid, () => tcs.SetResult(null));
BridgeConnector.Socket.Emit("webContents-session-clearStorageData", Id, guid);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -150,18 +122,13 @@ namespace ElectronNET.API
/// <returns></returns>
public Task ClearStorageDataAsync(ClearStorageDataOptions options)
{
var taskCompletionSource = new TaskCompletionSource<object>();
var tcs = new TaskCompletionSource<object>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-clearStorageData-options-completed" + guid, () =>
{
BridgeConnector.Socket.Off("webContents-session-clearStorageData-options-completed" + guid);
taskCompletionSource.SetResult(null);
});
BridgeConnector.Socket.Once("webContents-session-clearStorageData-options-completed" + guid, () => tcs.SetResult(null));
BridgeConnector.Socket.Emit("webContents-session-clearStorageData-options", Id, options, guid);
BridgeConnector.Socket.Emit("webContents-session-clearStorageData-options", Id, JObject.FromObject(options, _jsonSerializer), guid);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -174,7 +141,7 @@ namespace ElectronNET.API
/// <param name="options"></param>
public void CreateInterruptedDownload(CreateInterruptedDownloadOptions options)
{
BridgeConnector.Socket.Emit("webContents-session-createInterruptedDownload", Id, JObject.FromObject(options, _jsonSerializer));
BridgeConnector.Socket.Emit("webContents-session-createInterruptedDownload", Id, options);
}
/// <summary>
@@ -192,7 +159,7 @@ namespace ElectronNET.API
/// <param name="options"></param>
public void EnableNetworkEmulation(EnableNetworkEmulationOptions options)
{
BridgeConnector.Socket.Emit("webContents-session-enableNetworkEmulation", Id, JObject.FromObject(options, _jsonSerializer));
BridgeConnector.Socket.Emit("webContents-session-enableNetworkEmulation", Id, options);
}
/// <summary>
@@ -210,20 +177,13 @@ namespace ElectronNET.API
/// <returns></returns>
public Task<int[]> GetBlobDataAsync(string identifier)
{
var taskCompletionSource = new TaskCompletionSource<int[]>();
var tcs = new TaskCompletionSource<int[]>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-getBlobData-completed" + guid, (buffer) =>
{
var result = ((JArray)buffer).ToObject<int[]>();
BridgeConnector.Socket.Off("webContents-session-getBlobData-completed" + guid);
taskCompletionSource.SetResult(result);
});
BridgeConnector.Socket.Once<int[]>("webContents-session-getBlobData-completed" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("webContents-session-getBlobData", Id, identifier, guid);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -232,18 +192,13 @@ namespace ElectronNET.API
/// <returns>Callback is invoked with the session's current cache size.</returns>
public Task<int> GetCacheSizeAsync()
{
var taskCompletionSource = new TaskCompletionSource<int>();
var tcs = new TaskCompletionSource<int>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-getCacheSize-completed" + guid, (size) =>
{
BridgeConnector.Socket.Off("webContents-session-getCacheSize-completed" + guid);
taskCompletionSource.SetResult((int)size);
});
BridgeConnector.Socket.Once<int>("webContents-session-getCacheSize-completed" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("webContents-session-getCacheSize", Id, guid);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -252,19 +207,13 @@ namespace ElectronNET.API
/// <returns></returns>
public Task<string[]> GetPreloadsAsync()
{
var taskCompletionSource = new TaskCompletionSource<string[]>();
var tcs = new TaskCompletionSource<string[]>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-getPreloads-completed" + guid, (preloads) =>
{
var result = ((JArray)preloads).ToObject<string[]>();
BridgeConnector.Socket.Off("webContents-session-getPreloads-completed" + guid);
taskCompletionSource.SetResult(result);
});
BridgeConnector.Socket.Once<string[]>("webContents-session-getPreloads-completed" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("webContents-session-getPreloads", Id, guid);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -273,18 +222,13 @@ namespace ElectronNET.API
/// <returns></returns>
public Task<string> GetUserAgent()
{
var taskCompletionSource = new TaskCompletionSource<string>();
var tcs = new TaskCompletionSource<string>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-getUserAgent-completed" + guid, (userAgent) =>
{
BridgeConnector.Socket.Off("webContents-session-getUserAgent-completed" + guid);
taskCompletionSource.SetResult(userAgent.ToString());
});
BridgeConnector.Socket.Once<string>("webContents-session-getUserAgent-completed" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("webContents-session-getUserAgent", Id, guid);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -295,18 +239,13 @@ namespace ElectronNET.API
/// <returns></returns>
public Task<string> ResolveProxyAsync(string url)
{
var taskCompletionSource = new TaskCompletionSource<string>();
var tcs = new TaskCompletionSource<string>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-resolveProxy-completed" + guid, (proxy) =>
{
BridgeConnector.Socket.Off("webContents-session-resolveProxy-completed" + guid);
taskCompletionSource.SetResult(proxy.ToString());
});
BridgeConnector.Socket.Once<string>("webContents-session-resolveProxy-completed" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("webContents-session-resolveProxy", Id, url, guid);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -337,18 +276,13 @@ namespace ElectronNET.API
/// <returns></returns>
public Task SetProxyAsync(ProxyConfig config)
{
var taskCompletionSource = new TaskCompletionSource<object>();
var tcs = new TaskCompletionSource<object>();
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-setProxy-completed" + guid, () =>
{
BridgeConnector.Socket.Off("webContents-session-setProxy-completed" + guid);
taskCompletionSource.SetResult(null);
});
BridgeConnector.Socket.Once("webContents-session-setProxy-completed" + guid, () => tcs.SetResult(null));
BridgeConnector.Socket.Emit("webContents-session-setProxy", Id, config, guid);
BridgeConnector.Socket.Emit("webContents-session-setProxy", Id, JObject.FromObject(config, _jsonSerializer), guid);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -385,19 +319,12 @@ namespace ElectronNET.API
/// <returns></returns>
public Task<ChromeExtensionInfo[]> GetAllExtensionsAsync()
{
var taskCompletionSource = new TaskCompletionSource<ChromeExtensionInfo[]>();
BridgeConnector.Socket.On("webContents-session-getAllExtensions-completed", (extensionslist) =>
{
BridgeConnector.Socket.Off("webContents-session-getAllExtensions-completed");
var chromeExtensionInfos = ((JArray)extensionslist).ToObject<ChromeExtensionInfo[]>();
taskCompletionSource.SetResult(chromeExtensionInfos);
});
var tcs = new TaskCompletionSource<ChromeExtensionInfo[]>();
BridgeConnector.Socket.Once<ChromeExtensionInfo[]>("webContents-session-getAllExtensions-completed", tcs.SetResult);
BridgeConnector.Socket.Emit("webContents-session-getAllExtensions", Id);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -439,25 +366,14 @@ namespace ElectronNET.API
/// <returns></returns>
public Task<Extension> LoadExtensionAsync(string path, bool allowFileAccess = false)
{
var taskCompletionSource = new TaskCompletionSource<Extension>();
BridgeConnector.Socket.On("webContents-session-loadExtension-completed", (extension) =>
{
BridgeConnector.Socket.Off("webContents-session-loadExtension-completed");
taskCompletionSource.SetResult(((JObject)extension).ToObject<Extension>());
});
var tcs = new TaskCompletionSource<Extension>();
BridgeConnector.Socket.Once<Extension>("webContents-session-loadExtension-completed", tcs.SetResult);
BridgeConnector.Socket.Emit("webContents-session-loadExtension", Id, path, allowFileAccess);
return taskCompletionSource.Task;
return tcs.Task;
}
private JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
}
}

View File

@@ -1,9 +1,8 @@
using ElectronNET.API.Entities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System.Threading.Tasks;
using ElectronNET.API.Entities;
using ElectronNET.API.Extensions;
using ElectronNET.API.Serialization;
using System.Text.Json;
using System.Threading.Tasks;
namespace ElectronNET.API
{
@@ -15,7 +14,9 @@ namespace ElectronNET.API
private static Shell _shell;
private static object _syncRoot = new object();
internal Shell() { }
internal Shell()
{
}
internal static Shell Instance
{
@@ -42,16 +43,13 @@ namespace ElectronNET.API
/// <param name="fullPath">The full path to the directory / file.</param>
public Task ShowItemInFolderAsync(string fullPath)
{
var taskCompletionSource = new TaskCompletionSource<object>();
BridgeConnector.Socket.On("shell-showItemInFolderCompleted", () =>
{
BridgeConnector.Socket.Off("shell-showItemInFolderCompleted");
});
var tcs = new TaskCompletionSource<object>();
// Is this really useful?
BridgeConnector.Socket.Once("shell-showItemInFolderCompleted", () => { });
BridgeConnector.Socket.Emit("shell-showItemInFolder", fullPath);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -61,18 +59,12 @@ namespace ElectronNET.API
/// <returns>The error message corresponding to the failure if a failure occurred, otherwise <see cref="string.Empty"/>.</returns>
public Task<string> OpenPathAsync(string path)
{
var taskCompletionSource = new TaskCompletionSource<string>();
BridgeConnector.Socket.On("shell-openPathCompleted", (errorMessage) =>
{
BridgeConnector.Socket.Off("shell-openPathCompleted");
taskCompletionSource.SetResult((string) errorMessage);
});
var tcs = new TaskCompletionSource<string>();
BridgeConnector.Socket.Once<string>("shell-openPathCompleted", tcs.SetResult);
BridgeConnector.Socket.Emit("shell-openPath", path);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -95,14 +87,9 @@ namespace ElectronNET.API
/// <returns>The error message corresponding to the failure if a failure occurred, otherwise <see cref="string.Empty"/>.</returns>
public Task<string> OpenExternalAsync(string url, OpenExternalOptions options)
{
var taskCompletionSource = new TaskCompletionSource<string>();
var tcs = new TaskCompletionSource<string>();
BridgeConnector.Socket.On("shell-openExternalCompleted", (error) =>
{
BridgeConnector.Socket.Off("shell-openExternalCompleted");
taskCompletionSource.SetResult((string) error);
});
BridgeConnector.Socket.Once<string>("shell-openExternalCompleted", tcs.SetResult);
if (options == null)
{
@@ -110,10 +97,10 @@ namespace ElectronNET.API
}
else
{
BridgeConnector.Socket.Emit("shell-openExternal", url, JObject.FromObject(options, _jsonSerializer));
BridgeConnector.Socket.Emit("shell-openExternal", url, options);
}
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -123,18 +110,12 @@ namespace ElectronNET.API
/// <returns> Whether the item was successfully moved to the trash.</returns>
public Task<bool> TrashItemAsync(string fullPath)
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("shell-trashItem-completed", (success) =>
{
BridgeConnector.Socket.Off("shell-trashItem-completed");
taskCompletionSource.SetResult((bool) success);
});
var tcs = new TaskCompletionSource<bool>();
BridgeConnector.Socket.Once<bool>("shell-trashItem-completed", tcs.SetResult);
BridgeConnector.Socket.Emit("shell-trashItem", fullPath);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -154,18 +135,12 @@ namespace ElectronNET.API
/// <returns>Whether the shortcut was created successfully.</returns>
public Task<bool> WriteShortcutLinkAsync(string shortcutPath, ShortcutLinkOperation operation, ShortcutDetails options)
{
var taskCompletionSource = new TaskCompletionSource<bool>();
var tcs = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("shell-writeShortcutLinkCompleted", (success) =>
{
BridgeConnector.Socket.Off("shell-writeShortcutLinkCompleted");
BridgeConnector.Socket.Once<bool>("shell-writeShortcutLinkCompleted", tcs.SetResult);
BridgeConnector.Socket.Emit("shell-writeShortcutLink", shortcutPath, operation.GetDescription(), options);
taskCompletionSource.SetResult((bool) success);
});
BridgeConnector.Socket.Emit("shell-writeShortcutLink", shortcutPath, operation.GetDescription(), JObject.FromObject(options, _jsonSerializer));
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -176,28 +151,14 @@ namespace ElectronNET.API
/// <returns><see cref="ShortcutDetails"/> of the shortcut.</returns>
public Task<ShortcutDetails> ReadShortcutLinkAsync(string shortcutPath)
{
var taskCompletionSource = new TaskCompletionSource<ShortcutDetails>();
BridgeConnector.Socket.On("shell-readShortcutLinkCompleted", (shortcutDetails) =>
{
BridgeConnector.Socket.Off("shell-readShortcutLinkCompleted");
var shortcutObject = shortcutDetails as JObject;
var details = shortcutObject?.ToObject<ShortcutDetails>();
taskCompletionSource.SetResult(details);
});
var tcs = new TaskCompletionSource<ShortcutDetails>();
BridgeConnector.Socket.Once<ShortcutDetails>("shell-readShortcutLinkCompleted", tcs.SetResult);
BridgeConnector.Socket.Emit("shell-readShortcutLink", shortcutPath);
return taskCompletionSource.Task;
return tcs.Task;
}
private readonly JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
}
}

View File

@@ -1,12 +1,12 @@
using ElectronNET.API.Entities;
using ElectronNET.API.Entities;
using ElectronNET.API.Extensions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using ElectronNET.Common;
using ElectronNET.API.Serialization;
// ReSharper disable InconsistentNaming
namespace ElectronNET.API
@@ -14,15 +14,41 @@ namespace ElectronNET.API
/// <summary>
/// Add icons and context menus to the system's notification area.
/// </summary>
public sealed class Tray
public sealed class Tray: ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;
/// <summary>
/// Emitted when the tray icon is clicked.
/// </summary>
public event Action<TrayClickEventArgs, Rectangle> OnClick
{
add => ApiEventManager.AddTrayEvent("tray-click", GetHashCode(), _click, value);
remove => ApiEventManager.RemoveTrayEvent("tray-click", GetHashCode(), _click, value);
add
{
if (_click == null)
{
BridgeConnector.Socket.On<JsonElement>("tray-click" + GetHashCode(), (result) =>
{
var array = result.EnumerateArray().ToArray();
var trayClickEventArgs = array[0].Deserialize(ElectronJsonContext.Default.TrayClickEventArgs);
var bounds = array[1].Deserialize(ElectronJsonContext.Default.Rectangle);
_click(trayClickEventArgs, bounds);
});
BridgeConnector.Socket.Emit("register-tray-click", GetHashCode());
}
_click += value;
}
remove
{
_click -= value;
if (_click == null)
{
BridgeConnector.Socket.Off("tray-click" + GetHashCode());
}
}
}
private event Action<TrayClickEventArgs, Rectangle> _click;
@@ -32,8 +58,31 @@ namespace ElectronNET.API
/// </summary>
public event Action<TrayClickEventArgs, Rectangle> OnRightClick
{
add => ApiEventManager.AddTrayEvent("tray-right-click", GetHashCode(), _rightClick, value);
remove => ApiEventManager.RemoveTrayEvent("tray-right-click", GetHashCode(), _rightClick, value);
add
{
if (_rightClick == null)
{
BridgeConnector.Socket.On<JsonElement>("tray-right-click" + GetHashCode(), (result) =>
{
var array = result.EnumerateArray().ToArray();
var trayClickEventArgs = array[0].Deserialize(ElectronJsonContext.Default.TrayClickEventArgs);
var bounds = array[1].Deserialize(ElectronJsonContext.Default.Rectangle);
_rightClick(trayClickEventArgs, bounds);
});
BridgeConnector.Socket.Emit("register-tray-right-click", GetHashCode());
}
_rightClick += value;
}
remove
{
_rightClick -= value;
if (_rightClick == null)
{
BridgeConnector.Socket.Off("tray-right-click" + GetHashCode());
}
}
}
private event Action<TrayClickEventArgs, Rectangle> _rightClick;
@@ -43,8 +92,31 @@ namespace ElectronNET.API
/// </summary>
public event Action<TrayClickEventArgs, Rectangle> OnDoubleClick
{
add => ApiEventManager.AddTrayEvent("tray-double-click", GetHashCode(), _doubleClick, value);
remove => ApiEventManager.RemoveTrayEvent("tray-double-click", GetHashCode(), _doubleClick, value);
add
{
if (_doubleClick == null)
{
BridgeConnector.Socket.On<JsonElement>("tray-double-click" + GetHashCode(), (result) =>
{
var array = result.EnumerateArray().ToArray();
var trayClickEventArgs = array[0].Deserialize(ElectronJsonContext.Default.TrayClickEventArgs);
var bounds = array[1].Deserialize(ElectronJsonContext.Default.Rectangle);
_doubleClick(trayClickEventArgs, bounds);
});
BridgeConnector.Socket.Emit("register-tray-double-click", GetHashCode());
}
_doubleClick += value;
}
remove
{
_doubleClick -= value;
if (_doubleClick == null)
{
BridgeConnector.Socket.Off("tray-double-click" + GetHashCode());
}
}
}
private event Action<TrayClickEventArgs, Rectangle> _doubleClick;
@@ -54,41 +126,37 @@ namespace ElectronNET.API
/// </summary>
public event Action OnBalloonShow
{
add => ApiEventManager.AddEvent("tray-balloon-show", GetHashCode(), _balloonShow, value);
remove => ApiEventManager.RemoveEvent("tray-balloon-show", GetHashCode(), _balloonShow, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action _balloonShow;
/// <summary>
/// Windows: Emitted when the tray balloon is clicked.
/// </summary>
public event Action OnBalloonClick
{
add => ApiEventManager.AddEvent("tray-balloon-click", GetHashCode(), _balloonClick, value);
remove => ApiEventManager.RemoveEvent("tray-balloon-click", GetHashCode(), _balloonClick, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action _balloonClick;
/// <summary>
/// Windows: Emitted when the tray balloon is closed
/// because of timeout or user manually closes it.
/// </summary>
public event Action OnBalloonClosed
{
add => ApiEventManager.AddEvent("tray-balloon-closed", GetHashCode(), _balloonClosed, value);
remove => ApiEventManager.RemoveEvent("tray-balloon-closed", GetHashCode(), _balloonClosed, value);
add => AddEvent(value, GetHashCode());
remove => RemoveEvent(value, GetHashCode());
}
private event Action _balloonClosed;
// TODO: Implement macOS Events
private static Tray _tray;
private static readonly object _syncRoot = new();
internal Tray() { }
internal Tray()
{
}
internal static Tray Instance
{
@@ -137,7 +205,7 @@ namespace ElectronNET.API
public async Task Show(string image, MenuItem[] menuItems)
{
menuItems.AddMenuItemsId();
await BridgeConnector.Socket.Emit("create-tray", image, JArray.FromObject(menuItems, this._jsonSerializer)).ConfigureAwait(false);
await BridgeConnector.Socket.Emit("create-tray", image, menuItems).ConfigureAwait(false);
_items.Clear();
_items.AddRange(menuItems);
@@ -209,7 +277,7 @@ namespace ElectronNET.API
/// <param name="options"></param>
public async Task DisplayBalloon(DisplayBalloonOptions options)
{
await BridgeConnector.Socket.Emit("tray-displayBalloon", JObject.FromObject(options, this._jsonSerializer)).ConfigureAwait(false);
await BridgeConnector.Socket.Emit("tray-displayBalloon", options).ConfigureAwait(false);
}
/// <summary>
@@ -218,27 +286,18 @@ namespace ElectronNET.API
/// <returns></returns>
public async Task<bool> IsDestroyedAsync()
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On<bool>("tray-isDestroyedCompleted", (isDestroyed) =>
{
BridgeConnector.Socket.Off("tray-isDestroyedCompleted");
taskCompletionSource.SetResult(isDestroyed);
});
var tcs = new TaskCompletionSource<bool>();
BridgeConnector.Socket.Once<bool>("tray-isDestroyedCompleted", tcs.SetResult);
await BridgeConnector.Socket.Emit("tray-isDestroyed").ConfigureAwait(false);
return await taskCompletionSource.Task.ConfigureAwait(false);
return await tcs.Task.ConfigureAwait(false);
}
private readonly JsonSerializer _jsonSerializer = new()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
};
private const string ModuleName = "tray";
/// <summary>
/// Subscribe to an unmapped event on the <see cref="Tray"/> module.
/// </summary>
@@ -246,6 +305,7 @@ namespace ElectronNET.API
/// <param name="action">The handler</param>
public void On(string eventName, Action action)
=> Events.Instance.On(ModuleName, eventName, action);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="Tray"/> module.
/// </summary>
@@ -253,6 +313,7 @@ namespace ElectronNET.API
/// <param name="action">The handler</param>
public async Task On<T>(string eventName, Action<T> action)
=> await Events.Instance.On(ModuleName, eventName, action).ConfigureAwait(false);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="Tray"/> module once.
/// </summary>
@@ -260,6 +321,7 @@ namespace ElectronNET.API
/// <param name="action">The handler</param>
public void Once(string eventName, Action action)
=> Events.Instance.Once(ModuleName, eventName, action);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="Tray"/> module once.
/// </summary>

View File

@@ -1,10 +1,7 @@
using ElectronNET.API.Entities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using ElectronNET.API.Entities;
using System;
using System.Threading.Tasks;
using ElectronNET.Common;
// ReSharper disable InconsistentNaming
namespace ElectronNET.API;
@@ -12,15 +9,19 @@ namespace ElectronNET.API;
/// <summary>
/// Render and control web pages.
/// </summary>
public class WebContents
public class WebContents: ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;
protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.CamelCase;
/// <summary>
/// Gets the identifier.
/// </summary>
/// <value>
/// The identifier.
/// </value>
public int Id { get; private set; }
public override int Id { get; protected set; }
/// <summary>
/// Manage browser sessions, cookies, cache, proxy settings, etc.
@@ -32,103 +33,85 @@ public class WebContents
/// </summary>
public event Action<bool> OnCrashed
{
add => ApiEventManager.AddEvent("webContents-crashed", Id, _crashed, value, (args) => (bool)args);
remove => ApiEventManager.RemoveEvent("webContents-crashed", Id, _crashed, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action<bool> _crashed;
/// <summary>
/// Emitted when the navigation is done, i.e. the spinner of the tab has
/// stopped spinning, and the onload event was dispatched.
/// </summary>
public event Action OnDidFinishLoad
{
add => ApiEventManager.AddEvent("webContents-didFinishLoad", Id, _didFinishLoad, value);
remove => ApiEventManager.RemoveEvent("webContents-didFinishLoad", Id, _didFinishLoad, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _didFinishLoad;
/// <summary>
/// Emitted when any frame (including main) starts navigating.
/// </summary>
public event Action<string> OnDidStartNavigation
{
add => ApiEventManager.AddEvent("webContents-didStartNavigation", Id, _didStartNavigation, value);
remove => ApiEventManager.RemoveEvent("webContents-didStartNavigation", Id, _didStartNavigation, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action<string> _didStartNavigation;
/// <summary>
/// Emitted when a main frame navigation is done.
/// This event is not emitted for in-page navigations, such as clicking anchor links or updating the window.location.hash. Use did-navigate-in-page event for this purpose.
/// </summary>
public event Action<OnDidNavigateInfo> OnDidNavigate
{
add => ApiEventManager.AddEvent("webContents-didNavigate", Id, _didNavigate, value);
remove => ApiEventManager.RemoveEvent("webContents-didNavigate", Id, _didNavigate, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action<OnDidNavigateInfo> _didNavigate;
/// <summary>
/// Emitted when a server side redirect occurs during navigation. For example a 302 redirect.
/// This event will be emitted after OnDidStartNavigation and always before the OnDidRedirectNavigation event for the same navigation.
/// </summary>
public event Action<string> OnWillRedirect
{
add => ApiEventManager.AddEvent("webContents-willRedirect", Id, _willRedirect, value);
remove => ApiEventManager.RemoveEvent("webContents-willRedirect", Id, _willRedirect, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action<string> _willRedirect;
/// <summary>
/// Emitted after a server side redirect occurs during navigation. For example a 302 redirect.
/// </summary>
public event Action<string> OnDidRedirectNavigation
{
add => ApiEventManager.AddEvent("webContents-didRedirectNavigation", Id, _didRedirectNavigation, value);
remove => ApiEventManager.RemoveEvent("webContents-didRedirectNavigation", Id, _didRedirectNavigation, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action<string> _didRedirectNavigation;
/// <summary>
/// This event is like OnDidFinishLoad but emitted when the load failed.
/// </summary>
public event Action<OnDidFailLoadInfo> OnDidFailLoad
{
add => ApiEventManager.AddEvent("webContents-didFailLoad", Id, _didFailLoad, value, (args) => ((JObject)args).ToObject<OnDidFailLoadInfo>());
remove => ApiEventManager.RemoveEvent("webContents-didFailLoad", Id, _didFailLoad, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action<OnDidFailLoadInfo> _didFailLoad;
/// <summary>
/// Emitted when an input event is sent to the WebContents.
/// </summary>
public event Action<InputEvent> InputEvent
{
add => ApiEventManager.AddEvent("webContents-input-event", Id, _inputEvent, value, (args) => ((JObject)args).ToObject<InputEvent>());
remove => ApiEventManager.RemoveEvent("webContents-input-event", Id, _inputEvent, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action<InputEvent> _inputEvent;
/// <summary>
/// Emitted when the document in the top-level frame is loaded.
/// </summary>
public event Action OnDomReady
{
add => ApiEventManager.AddEvent("webContents-domReady", Id, _domReady, value);
remove => ApiEventManager.RemoveEvent("webContents-domReady", Id, _domReady, value);
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
private event Action _domReady;
internal WebContents(int id)
{
Id = id;
@@ -149,55 +132,26 @@ public class WebContents
/// <param name="openDevToolsOptions"></param>
public void OpenDevTools(OpenDevToolsOptions openDevToolsOptions)
{
BridgeConnector.Socket.Emit("webContentsOpenDevTools", Id, JObject.FromObject(openDevToolsOptions, _jsonSerializer));
BridgeConnector.Socket.Emit("webContentsOpenDevTools", Id, openDevToolsOptions);
}
/// <summary>
/// Get system printers.
/// </summary>
/// <returns>printers</returns>
public Task<PrinterInfo[]> GetPrintersAsync()
{
var taskCompletionSource = new TaskCompletionSource<PrinterInfo[]>();
BridgeConnector.Socket.On("webContents-getPrinters-completed", (printers) =>
{
BridgeConnector.Socket.Off("webContents-getPrinters-completed");
taskCompletionSource.SetResult(((Newtonsoft.Json.Linq.JArray)printers).ToObject<PrinterInfo[]>());
});
BridgeConnector.Socket.Emit("webContents-getPrinters", Id);
return taskCompletionSource.Task;
}
public Task<PrinterInfo[]> GetPrintersAsync() => GetPropertyAsync<PrinterInfo[]>();
/// <summary>
/// Prints window's web page.
/// </summary>
/// <param name="options"></param>
/// <returns>success</returns>
public Task<bool> PrintAsync(PrintOptions options = null)
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("webContents-print-completed", (success) =>
{
BridgeConnector.Socket.Off("webContents-print-completed");
taskCompletionSource.SetResult((bool)success);
});
if(options == null)
{
BridgeConnector.Socket.Emit("webContents-print", Id, "");
}
else
{
BridgeConnector.Socket.Emit("webContents-print", Id, JObject.FromObject(options, _jsonSerializer));
}
return taskCompletionSource.Task;
}
public Task<bool> PrintAsync(PrintOptions options) => GetPropertyAsync<bool>(options);
/// <summary>
/// Prints window's web page.
/// </summary>
/// <returns>success</returns>
public Task<bool> PrintAsync() => GetPropertyAsync<bool>(string.Empty);
/// <summary>
/// Prints window's web page as PDF with Chromium's preview printing custom
@@ -210,24 +164,20 @@ public class WebContents
/// <returns>success</returns>
public Task<bool> PrintToPDFAsync(string path, PrintToPDFOptions options = null)
{
var taskCompletionSource = new TaskCompletionSource<bool>();
var tcs = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("webContents-printToPDF-completed", (success) =>
{
BridgeConnector.Socket.Off("webContents-printToPDF-completed");
taskCompletionSource.SetResult((bool)success);
});
BridgeConnector.Socket.Once<bool>("webContents-printToPDF-completed", tcs.SetResult);
if(options == null)
if (options == null)
{
BridgeConnector.Socket.Emit("webContents-printToPDF", Id, "", path);
}
else
{
BridgeConnector.Socket.Emit("webContents-printToPDF", Id, JObject.FromObject(options, _jsonSerializer), path);
BridgeConnector.Socket.Emit("webContents-printToPDF", Id, options, path);
}
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -246,19 +196,14 @@ public class WebContents
/// Code execution will be suspended until web page stop loading.
/// </para>
/// </remarks>
public Task<object> ExecuteJavaScriptAsync(string code, bool userGesture = false)
public Task<T> ExecuteJavaScriptAsync<T>(string code, bool userGesture = false)
{
var taskCompletionSource = new TaskCompletionSource<object>();
BridgeConnector.Socket.On("webContents-executeJavaScript-completed", (result) =>
{
BridgeConnector.Socket.Off("webContents-executeJavaScript-completed");
taskCompletionSource.SetResult(result);
});
var tcs = new TaskCompletionSource<T>();
BridgeConnector.Socket.Once<T>("webContents-executeJavaScript-completed", tcs.SetResult);
BridgeConnector.Socket.Emit("webContents-executeJavaScript", Id, code, userGesture);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -268,18 +213,12 @@ public class WebContents
/// <returns>URL of the loaded page</returns>
public Task<string> GetUrl()
{
var taskCompletionSource = new TaskCompletionSource<string>();
var eventString = "webContents-getUrl" + Id;
BridgeConnector.Socket.On(eventString, (url) =>
{
BridgeConnector.Socket.Off(eventString);
taskCompletionSource.SetResult((string)url);
});
var tcs = new TaskCompletionSource<string>();
BridgeConnector.Socket.Once<string>("webContents-getUrl" + Id, tcs.SetResult);
BridgeConnector.Socket.Emit("webContents-getUrl", Id);
return taskCompletionSource.Task;
return tcs.Task;
}
/// <summary>
@@ -314,24 +253,22 @@ public class WebContents
/// <param name="options"></param>
public Task LoadURLAsync(string url, LoadURLOptions options)
{
var taskCompletionSource = new TaskCompletionSource<object>();
var tcs = new TaskCompletionSource<object>();
BridgeConnector.Socket.On("webContents-loadURL-complete" + Id, () =>
{
BridgeConnector.Socket.Off("webContents-loadURL-complete" + Id);
BridgeConnector.Socket.Off("webContents-loadURL-error" + Id);
taskCompletionSource.SetResult(null);
});
BridgeConnector.Socket.On("webContents-loadURL-error" + Id, (error) =>
BridgeConnector.Socket.Once("webContents-loadURL-complete" + Id, () =>
{
BridgeConnector.Socket.Off("webContents-loadURL-error" + Id);
taskCompletionSource.SetException(new InvalidOperationException(error.ToString()));
tcs.SetResult(null);
});
BridgeConnector.Socket.Emit("webContents-loadURL", Id, url, JObject.FromObject(options, _jsonSerializer));
BridgeConnector.Socket.Once<string>("webContents-loadURL-error" + Id, (error) =>
{
tcs.SetException(new InvalidOperationException(error));
});
return taskCompletionSource.Task;
BridgeConnector.Socket.Emit("webContents-loadURL", Id, url, options);
return tcs.Task;
}
/// <summary>
@@ -345,11 +282,4 @@ public class WebContents
{
BridgeConnector.Socket.Emit("webContents-insertCSS", Id, isBrowserWindow, path);
}
private readonly JsonSerializer _jsonSerializer = new()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
}
}

View File

@@ -1,5 +1,6 @@
using Newtonsoft.Json.Linq;
using ElectronNET.API.Serialization;
using System;
using System.Text.Json;
namespace ElectronNET.API.Entities
{
@@ -8,6 +9,7 @@ namespace ElectronNET.API.Entities
public int Id { get; set; }
public string Url { get; set; }
public string Method { get; set; }
public int? WebContentsId { get; set; }
// Ensure all necessary properties are included as per Electron documentation
}
@@ -32,18 +34,17 @@ namespace ElectronNET.API.Entities
{
if (_onBeforeRequest == null)
{
BridgeConnector.Socket.On($"webContents-session-webRequest-onBeforeRequest{Id}",
BridgeConnector.Socket.On<JsonElement>($"webContents-session-webRequest-onBeforeRequest{Id}",
(args) =>
{
////var details = ((JObject)args[0]).ToObject<OnBeforeRequestDetails>();
////var callback = args.Length > 1 ? (Action<object>)((response) => { BridgeConnector.Socket.Emit($"webContents-session-webRequest-onBeforeRequest-response{Id}", response); }) : null;
var details = ((JObject)args).ToObject<OnBeforeRequestDetails>();
var callback = (Action<object>)((response) => { BridgeConnector.Socket.Emit($"webContents-session-webRequest-onBeforeRequest-response{Id}", response); });
{
//// var details0 = args[0].Deserialize<OnBeforeRequestDetails>(ElectronNET.ElectronJson.Options);
var details = args.Deserialize<OnBeforeRequestDetails>(ElectronJson.Options);
var callback = (Action<object>)((response) => { BridgeConnector.Socket.Emit($"webContents-session-webRequest-onBeforeRequest-response{Id}", response); });
_onBeforeRequest?.Invoke(details, callback);
});
_onBeforeRequest?.Invoke(details, callback);
});
BridgeConnector.Socket.Emit("register-webContents-session-webRequest-onBeforeRequest", Id, JObject.FromObject(filter));
BridgeConnector.Socket.Emit("register-webContents-session-webRequest-onBeforeRequest", Id, filter);
}
_onBeforeRequest += listener;
@@ -58,4 +59,4 @@ namespace ElectronNET.API.Entities
}
}
}
}
}

View File

@@ -1,12 +1,10 @@
using ElectronNET.API.Entities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using ElectronNET.API.Entities;
using ElectronNET.API.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Threading.Tasks;
namespace ElectronNET.API
@@ -19,7 +17,9 @@ namespace ElectronNET.API
private static WindowManager _windowManager;
private static readonly object SyncRoot = new();
internal WindowManager() { }
internal WindowManager()
{
}
internal static WindowManager Instance
{
@@ -55,6 +55,7 @@ namespace ElectronNET.API
_isQuitOnWindowAllClosed = value;
}
}
private bool _isQuitOnWindowAllClosed = true;
/// <summary>
@@ -95,36 +96,28 @@ namespace ElectronNET.API
/// <returns></returns>
public async Task<BrowserWindow> CreateWindowAsync(BrowserWindowOptions options, string loadUrl = "http://localhost")
{
var taskCompletionSource = new TaskCompletionSource<BrowserWindow>();
var tcs = new TaskCompletionSource<BrowserWindow>();
BridgeConnector.Socket.On("BrowserWindowCreated", (id) =>
BridgeConnector.Socket.Once<int>("BrowserWindowCreated", (id) =>
{
BridgeConnector.Socket.Off("BrowserWindowCreated");
var browserWindowId = int.Parse(id.ToString()!);
var browserWindow = new BrowserWindow(browserWindowId);
var browserWindow = new BrowserWindow(id);
_browserWindows.Add(browserWindow);
taskCompletionSource.SetResult(browserWindow);
tcs.SetResult(browserWindow);
});
BridgeConnector.Socket.On<object>("BrowserWindowClosed", (ids) =>
BridgeConnector.Socket.Once<int[]>("BrowserWindowClosed", (ids) =>
{
BridgeConnector.Socket.Off("BrowserWindowClosed");
var browserWindowIds = ((JArray)ids).ToObject<int[]>();
for (int index = 0; index < _browserWindows.Count; index++)
{
if (!browserWindowIds.Contains(_browserWindows[index].Id))
if (!ids.Contains(_browserWindows[index].Id))
{
_browserWindows.RemoveAt(index);
}
}
});
if (loadUrl.ToUpper() == "HTTP://LOCALHOST" && ElectronNetRuntime.AspNetWebPort.HasValue)
if (loadUrl.Equals("http://localhost", StringComparison.OrdinalIgnoreCase) && ElectronNetRuntime.AspNetWebPort.HasValue)
{
loadUrl = $"{loadUrl}:{ElectronNetRuntime.AspNetWebPort}";
}
@@ -142,7 +135,7 @@ namespace ElectronNET.API
options.X = 0;
options.Y = 0;
await BridgeConnector.Socket.Emit("createBrowserWindow", JObject.FromObject(options, this._jsonSerializer), loadUrl).ConfigureAwait(false);
await BridgeConnector.Socket.Emit("createBrowserWindow", options, loadUrl).ConfigureAwait(false);
}
else
{
@@ -153,15 +146,10 @@ namespace ElectronNET.API
options.X -= 7;
}
var ownjsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
};
await BridgeConnector.Socket.Emit("createBrowserWindow", JObject.FromObject(options, ownjsonSerializer), loadUrl).ConfigureAwait(false);
await BridgeConnector.Socket.Emit("createBrowserWindow", options, loadUrl).ConfigureAwait(false);
}
return await taskCompletionSource.Task.ConfigureAwait(false);
return await tcs.Task.ConfigureAwait(false);
}
private bool IsWindows10()
@@ -189,35 +177,21 @@ namespace ElectronNET.API
/// <returns></returns>
public async Task<BrowserView> CreateBrowserViewAsync(BrowserViewConstructorOptions options)
{
var taskCompletionSource = new TaskCompletionSource<BrowserView>();
var tcs = new TaskCompletionSource<BrowserView>();
BridgeConnector.Socket.On("BrowserViewCreated", (id) =>
BridgeConnector.Socket.Once<int>("BrowserViewCreated", (id) =>
{
BridgeConnector.Socket.Off("BrowserViewCreated");
string browserViewId = id.ToString();
BrowserView browserView = new BrowserView(int.Parse(browserViewId));
BrowserView browserView = new(id);
_browserViews.Add(browserView);
taskCompletionSource.SetResult(browserView);
tcs.SetResult(browserView);
});
var ownjsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
};
await BridgeConnector.Socket.Emit("createBrowserView", JObject.FromObject(options, ownjsonSerializer)).ConfigureAwait(false);
await BridgeConnector.Socket.Emit("createBrowserView", options).ConfigureAwait(false);
return await taskCompletionSource.Task.ConfigureAwait(false);
return await tcs.Task.ConfigureAwait(false);
}
private readonly JsonSerializer _jsonSerializer = new()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
}
}
}

View File

@@ -16,7 +16,8 @@ namespace ElectronNET.API
private readonly TextInfo _textInfo = new CultureInfo("en-US", false).TextInfo;
private Events()
{ }
{
}
public static Events Instance
{
@@ -94,6 +95,5 @@ namespace ElectronNET.API
BridgeConnector.Socket.Once(listener, action);
await BridgeConnector.Socket.Emit(subscriber, eventName, listener).ConfigureAwait(false);
}
}
}
}

View File

@@ -2,28 +2,25 @@
// ReSharper disable once CheckNamespace
namespace ElectronNET.API;
using ElectronNET.API.Serialization;
using SocketIO.Serializer.SystemTextJson;
using System;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using SocketIO.Serializer.NewtonsoftJson;
using SocketIO = SocketIOClient.SocketIO;
internal class SocketIoFacade
{
private readonly SocketIO _socket;
private readonly object _lockObj = new object();
public SocketIoFacade(string uri)
{
_socket = new SocketIO(uri);
var jsonSerializer = new NewtonsoftJsonSerializer(new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
});
_socket.Serializer = jsonSerializer;
_socket.Serializer = new SystemTextJsonSerializer(ElectronJson.Options);
// Use default System.Text.Json serializer from SocketIOClient.
// Outgoing args are normalized to camelCase via SerializeArg in Emit.
}
public event EventHandler BridgeDisconnected;
@@ -32,10 +29,7 @@ internal class SocketIoFacade
public void Connect()
{
_socket.OnError += (sender, e) =>
{
Console.WriteLine($"BridgeConnector Error: {sender} {e}");
};
_socket.OnError += (sender, e) => { Console.WriteLine($"BridgeConnector Error: {sender} {e}"); };
_socket.OnConnected += (_, _) =>
{
@@ -54,53 +48,68 @@ internal class SocketIoFacade
public void On(string eventName, Action action)
{
_socket.On(eventName, _ =>
lock (_lockObj)
{
Task.Run(action);
});
_socket.On(eventName, _ => { Task.Run(action); });
}
}
public void On<T>(string eventName, Action<T> action)
{
_socket.On(eventName, response =>
lock (_lockObj)
{
var value = response.GetValue<T>();
Task.Run(() => action(value));
});
_socket.On(eventName, response =>
{
var value = response.GetValue<T>();
Task.Run(() => action(value));
});
}
}
// TODO: Remove this method when SocketIoClient supports object deserialization
// Keep object overload for compatibility; value will be a JsonElement boxed as object.
public void On(string eventName, Action<object> action)
{
_socket.On(eventName, response =>
lock (_lockObj)
{
var value = response.GetValue<object>();
////Console.WriteLine($"Called Event {eventName} - data {value}");
Task.Run(() => action(value));
});
_socket.On(eventName, response =>
{
var value = (object)response.GetValue<JsonElement>();
////Console.WriteLine($"Called Event {eventName} - data {value}");
Task.Run(() => action(value));
});
}
}
public void Once(string eventName, Action action)
{
_socket.On(eventName, _ =>
lock (_lockObj)
{
_socket.Off(eventName);
Task.Run(action);
});
_socket.On(eventName, _ =>
{
this.Off(eventName);
Task.Run(action);
});
}
}
public void Once<T>(string eventName, Action<T> action)
{
_socket.On(eventName, (socketIoResponse) =>
lock (_lockObj)
{
_socket.Off(eventName);
Task.Run(() => action(socketIoResponse.GetValue<T>()));
});
_socket.On(eventName, (socketIoResponse) =>
{
this.Off(eventName);
Task.Run(() => action(socketIoResponse.GetValue<T>()));
});
}
}
public void Off(string eventName)
{
_socket.Off(eventName);
lock (_lockObj)
{
_socket.Off(eventName);
}
}
public async Task Emit(string eventName, params object[] args)
@@ -112,4 +121,4 @@ internal class SocketIoFacade
{
_socket.Dispose();
}
}
}

View File

@@ -1,99 +0,0 @@
using System;
using ElectronNET.API;
using ElectronNET.API.Entities;
using Newtonsoft.Json.Linq;
namespace ElectronNET.Common;
internal static class ApiEventManager
{
internal static void AddEvent(string eventName, object id, Action callback, Action value, string suffix = "")
{
if (callback == null)
{
BridgeConnector.Socket.On(eventName + id, () => { callback(); });
BridgeConnector.Socket.Emit($"register-{eventName}{suffix}", id);
}
callback += value;
}
internal static void RemoveEvent(string eventName, object id, Action callback, Action value)
{
callback -= value;
if (callback == null) BridgeConnector.Socket.Off(eventName + id);
}
internal static void AddEvent<T>(string eventName, object id, Action<T> callback, Action<T> value, Func<object, T> converter, string suffix = "")
{
if (callback == null)
{
BridgeConnector.Socket.On(eventName + id, (args) =>
{
var converted = converter.Invoke(args);
callback(converted);
});
BridgeConnector.Socket.Emit($"register-{eventName}{suffix}", id);
}
callback += value;
}
internal static void AddEvent<T>(string eventName, object id, Action<T> callback, Action<T> value)
{
if (callback == null)
{
BridgeConnector.Socket.On<T>(eventName + id, (args) => callback(args));
BridgeConnector.Socket.Emit($"register-{eventName}", id);
}
callback += value;
}
internal static void RemoveEvent<T>(string eventName, object id, Action<T> callback, Action<T> value)
{
callback -= value;
if (callback == null) BridgeConnector.Socket.Off(eventName + id);
}
internal static void AddTrayEvent(string eventName, object id, Action<TrayClickEventArgs, Rectangle> callback, Action<TrayClickEventArgs, Rectangle> value)
{
if (callback == null)
{
BridgeConnector.Socket.On<dynamic>(eventName + id, (result) =>
{
var args = ((JArray)result).ToObject<object[]>();
var trayClickEventArgs = ((JObject)args[0]).ToObject<TrayClickEventArgs>();
var bounds = ((JObject)args[1]).ToObject<Rectangle>();
callback(trayClickEventArgs, bounds);
});
BridgeConnector.Socket.Emit($"register-{eventName}", id);
callback += value;
}
}
internal static void RemoveTrayEvent(string eventName, object id, Action<TrayClickEventArgs, Rectangle> callback, Action<TrayClickEventArgs, Rectangle> value)
{
callback -= value;
if (callback == null) BridgeConnector.Socket.Off(eventName + id);
}
internal static void AddScreenEvent(string eventName, object id, Action<Display, string[]> callback, Action<Display, string[]> value)
{
if (callback == null)
{
BridgeConnector.Socket.On(eventName + id, (args) =>
{
var display = ((JArray)args).First.ToObject<Display>();
var metrics = ((JArray)args).Last.ToObject<string[]>();
callback(display, metrics);
});
BridgeConnector.Socket.Emit($"register-{eventName}", id);
callback += value;
}
}
internal static void RemoveScreenEvent(string eventName, object id, Action<Display, string[]> callback, Action<Display, string[]> value)
{
callback -= value;
if (callback == null) BridgeConnector.Socket.Off(eventName + id);
}
}

View File

@@ -1,11 +1,12 @@
namespace ElectronNET.Common
{
using System;
using System.Collections.Immutable;
using ElectronNET.Runtime.Data;
using ElectronNET.Runtime.Services;
using System.Globalization;
using System.Text.RegularExpressions;
using System;
using ElectronNET.Runtime.Data;
using ElectronNET.Runtime.Services;
public static class Extensions
namespace ElectronNET.Common
{
internal static class Extensions
{
public static bool IsUnpackaged(this StartupMethod method)
{
@@ -19,6 +20,58 @@
}
}
public static string LowerFirst(this string str)
{
if (string.IsNullOrWhiteSpace(str))
{
return str;
}
if (str.Length == 1)
{
return str.ToLower();
}
return char.ToLower(str[0]) + str.Substring(1);
}
public static string StripAsync(this string str)
{
if (string.IsNullOrWhiteSpace(str))
{
return str;
}
var pos = str.LastIndexOf("Async", StringComparison.Ordinal);
if (pos > 0)
{
return str.Substring(0, pos);
}
return str;
}
public static string StripOn(this string str)
{
if (string.IsNullOrWhiteSpace(str) || !str.StartsWith("On", StringComparison.Ordinal))
{
return str;
}
return str.Substring(2);
}
public static string ToDashedEventName(this string str)
{
return string.Join("-", Regex.Split(str.StripOn(), "(?<!^)(?=[A-Z])")).ToLower(CultureInfo.InvariantCulture);
}
public static string ToCamelCaseEventName(this string str)
{
return str.StripOn().LowerFirst();
}
public static bool IsReady(this LifetimeServiceBase service)
{
return service != null && service.State == LifetimeState.Ready;

View File

@@ -18,7 +18,7 @@
/// and .net versions and on every platform where .net runs. This is just the innermost core, that's why
/// there are many dead ends, but it has all the crucial parts.
/// </remarks>
/// <seealso cref="System.IDisposable" />
/// <seealso cref="IDisposable" />
[SuppressMessage("ReSharper", "SuspiciousLockOverSynchronizationPrimitive")]
public class ProcessRunner : IDisposable
{
@@ -322,7 +322,7 @@
/// <paramref name="cancellationToken"/> has been triggered.
/// This method does not end the process itself.</remarks>
/// <returns>true, if the process has exited, false if the process is still running.</returns>
public async Task<bool> WaitForExitAsync(CancellationToken cancellationToken = default(CancellationToken))
public async Task<bool> WaitForExitAsync(CancellationToken cancellationToken = default)
{
var proc = this.process;

View File

@@ -16,7 +16,7 @@
private ProcessWindowStyle windowStyle;
/// <summary>
/// Default constructor. At least the <see cref='System.Diagnostics.ProcessStartInfo.FileName'/>
/// Default constructor. At least the <see cref='ProcessStartInfo.FileName'/>
/// property must be set before starting the process.
/// </summary>
public RunnerParams()

View File

@@ -1,54 +1,45 @@
namespace ElectronNET.Converter;
using ElectronNET.API.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using ElectronNET.API.Entities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
/// <summary>
///
/// </summary>
public class ModifierTypeListConverter : JsonConverter<List<ModifierType>>
{
/// <summary>
///
/// </summary>
/// <param name="reader"></param>
/// <param name="objectType"></param>
/// <param name="existingValue"></param>
/// <param name="hasExistingValue"></param>
/// <param name="serializer"></param>
/// <returns></returns>
public override List<ModifierType> ReadJson(JsonReader reader, Type objectType, List<ModifierType> existingValue, bool hasExistingValue, JsonSerializer serializer)
public override List<ModifierType> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var token = JToken.Load(reader);
if (token.Type == JTokenType.Null)
if (reader.TokenType == JsonTokenType.Null)
{
return null;
}
return token.ToObject<List<string>>().Select(m => (ModifierType)Enum.Parse(typeof(ModifierType), m)).ToList();
var list = new List<ModifierType>();
if (reader.TokenType != JsonTokenType.StartArray)
{
throw new JsonException("Expected array for ModifierType list");
}
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndArray) break;
if (reader.TokenType != JsonTokenType.String) throw new JsonException("Expected string enum value");
var s = reader.GetString();
list.Add((ModifierType)Enum.Parse(typeof(ModifierType), s, ignoreCase: true));
}
return list;
}
/// <summary>
///
/// </summary>
/// <param name="writer"></param>
/// <param name="value"></param>
/// <param name="serializer"></param>
public override void WriteJson(JsonWriter writer, List<ModifierType> value, JsonSerializer serializer)
public override void Write(Utf8JsonWriter writer, List<ModifierType> value, JsonSerializerOptions options)
{
writer.WriteStartArray();
foreach (var modifier in value)
{
writer.WriteValue(modifier.ToString());
writer.WriteStringValue(modifier.ToString());
}
writer.WriteEndArray();
}
}
}

View File

@@ -0,0 +1,46 @@
using ElectronNET.API.Entities;
using ElectronNET.API.Serialization;
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace ElectronNET.Converter;
public class PageSizeConverter : JsonConverter<PageSize>
{
public override PageSize Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.String)
{
return reader.GetString();
}
else if (reader.TokenType == JsonTokenType.StartObject)
{
return JsonSerializer.Deserialize<PageSize>(ref reader, ElectronJson.Options);
}
else
{
throw new JsonException("Invalid value for PageSize. Expected string or an object.");
}
}
public override void Write(Utf8JsonWriter writer, PageSize value, JsonSerializerOptions options)
{
if (value is null)
{
return;
}
var str = (string)value;
if (str is not null)
{
writer.WriteStringValue(str);
}
else
{
JsonSerializer.Serialize(writer, value, ElectronJson.Options);
}
}
}

View File

@@ -0,0 +1,46 @@
using ElectronNET.API.Entities;
using ElectronNET.API.Serialization;
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace ElectronNET.Converter;
public class TitleBarOverlayConverter : JsonConverter<TitleBarOverlay>
{
public override TitleBarOverlay Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.True || reader.TokenType == JsonTokenType.False)
{
return (bool)reader.GetBoolean();
}
else if (reader.TokenType == JsonTokenType.StartObject)
{
using var doc = JsonDocument.ParseValue(ref reader);
return doc.RootElement.Deserialize<TitleBarOverlay>(ElectronJson.Options);
}
else
{
throw new JsonException("Invalid value for TitleBarOverlay. Expected boolean or an object.");
}
}
public override void Write(Utf8JsonWriter writer, TitleBarOverlay value, JsonSerializerOptions options)
{
if (value is null)
{
return;
}
var @bool = (bool?)value;
if (@bool.HasValue)
{
writer.WriteBooleanValue(@bool.Value);
}
else
{
JsonSerializer.Serialize(writer, value, ElectronJson.Options);
}
}
}

View File

@@ -3,7 +3,7 @@
<Import Project="..\common.props" />
<PropertyGroup>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
<TargetFrameworks>net6.0;net8.0;net10.0</TargetFrameworks>
<PackageOutputPath>..\..\artifacts</PackageOutputPath>
<PackageId>$(PackageNamePrefix).API</PackageId>
<Title>$(PackageId)</Title>
@@ -27,8 +27,6 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SocketIO.Serializer.NewtonsoftJson" Version="3.1.2" />
<PackageReference Include="SocketIOClient" Version="3.1.2" />
<PackageReference Include="System.Drawing.Common" Version="8.0.16" />
<PackageReference Include="System.Text.Json" Version="8.0.5" />
@@ -38,4 +36,4 @@
<InternalsVisibleTo Include="ElectronNET.AspNet" />
<InternalsVisibleTo Include="ElectronNET.Core.AspNet" />
</ItemGroup>
</Project>
</Project>

View File

@@ -1,12 +1,12 @@
namespace ElectronNET
{
using System;
using System.Collections.Immutable;
using System.Threading.Tasks;
using ElectronNET.API;
using ElectronNET.Runtime;
using ElectronNET.Runtime.Controllers;
using ElectronNET.Runtime.Data;
using System;
using System.Collections.Immutable;
using System.Threading.Tasks;
public static class ElectronNetRuntime
{

View File

@@ -1,10 +1,10 @@
namespace ElectronNET.Runtime.Controllers
{
using System.Threading.Tasks;
using ElectronNET.API;
using ElectronNET.Runtime.Services;
using ElectronNET.Runtime.Services.ElectronProcess;
using ElectronNET.Runtime.Services.SocketBridge;
using System.Threading.Tasks;
internal abstract class RuntimeControllerBase : LifetimeServiceBase, IElectronNetRuntimeController
{
@@ -20,7 +20,6 @@
protected override Task StartCore()
{
return Task.CompletedTask;
}
@@ -28,6 +27,5 @@
{
return Task.CompletedTask;
}
}
}
}

View File

@@ -1,13 +1,13 @@
namespace ElectronNET.Runtime.Controllers
{
using System;
using System.Threading.Tasks;
using ElectronNET.API;
using ElectronNET.Common;
using ElectronNET.Runtime.Data;
using ElectronNET.Runtime.Helpers;
using ElectronNET.Runtime.Services.ElectronProcess;
using ElectronNET.Runtime.Services.SocketBridge;
using System;
using System.Threading.Tasks;
internal class RuntimeControllerDotNetFirst : RuntimeControllerBase
{
@@ -68,7 +68,6 @@
private void SocketBridge_Ready(object sender, EventArgs e)
{
this.TransitionState(LifetimeState.Ready);
}
private void SocketBridge_Stopped(object sender, EventArgs e)
@@ -102,6 +101,5 @@
this.electronProcess.Stop();
return Task.CompletedTask;
}
}
}
}

View File

@@ -1,11 +1,11 @@
namespace ElectronNET.Runtime.Controllers
{
using System;
using System.Threading.Tasks;
using ElectronNET.API;
using ElectronNET.Runtime.Data;
using ElectronNET.Runtime.Services.ElectronProcess;
using ElectronNET.Runtime.Services.SocketBridge;
using System;
using System.Threading.Tasks;
internal class RuntimeControllerElectronFirst : RuntimeControllerBase
{
@@ -103,6 +103,5 @@
this.socketBridge.Stop();
return Task.CompletedTask;
}
}
}
}

View File

@@ -1,8 +1,8 @@
namespace ElectronNET.Runtime
{
using ElectronNET.Runtime.Data;
using System;
using System.Threading.Tasks;
using ElectronNET.Runtime.Data;
public interface IElectronNetRuntimeController
{

View File

@@ -1,11 +1,11 @@
namespace ElectronNET.Runtime.Services.ElectronProcess
{
using ElectronNET.Common;
using ElectronNET.Runtime.Data;
using System;
using System.ComponentModel;
using System.IO;
using System.Threading.Tasks;
using ElectronNET.Common;
using ElectronNET.Runtime.Data;
/// <summary>
/// Launches and manages the Electron app process.

View File

@@ -1,10 +1,10 @@
namespace ElectronNET.Runtime.Services.ElectronProcess
{
using ElectronNET.Runtime.Data;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading.Tasks;
using ElectronNET.Runtime.Data;
/// <summary>
/// Launches and manages the Electron app process.

View File

@@ -1,9 +1,9 @@
namespace ElectronNET.Runtime.Services
{
using ElectronNET.Runtime.Data;
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using ElectronNET.Runtime.Data;
public abstract class LifetimeServiceBase
{
@@ -14,7 +14,9 @@
private LifetimeState state = LifetimeState.Uninitialized;
protected LifetimeServiceBase() { }
protected LifetimeServiceBase()
{
}
public event EventHandler Starting;
@@ -132,4 +134,4 @@
}
}
}
}
}

View File

@@ -1,11 +1,11 @@
namespace ElectronNET.Runtime.Services.SocketBridge
{
using System;
using System.Threading.Tasks;
using ElectronNET.API;
using ElectronNET.Runtime.Data;
using System;
using System.Threading.Tasks;
internal class SocketBridgeService : LifetimeServiceBase
internal class SocketBridgeService : LifetimeServiceBase
{
private readonly int socketPort;
private readonly string socketUrl;
@@ -40,7 +40,10 @@
private void Connect()
{
this.socket.Connect();
this.TransitionState(LifetimeState.Started);
if (this.State < LifetimeState.Started)
{
this.TransitionState(LifetimeState.Started);
}
}
private void Socket_BridgeDisconnected(object sender, EventArgs e)
@@ -53,4 +56,4 @@
this.TransitionState(LifetimeState.Ready);
}
}
}
}

View File

@@ -103,7 +103,7 @@
{
ElectronNetRuntime.ElectronProcessId = result;
Console.WriteLine("Electron Process ID: " + result);
Console.WriteLine("Electron Process ID: " + result);
}
}
}
@@ -122,16 +122,27 @@
}
ElectronNetRuntime.ElectronExecutable = executable;
}
private BuildInfo GatherBuildInfo()
{
var buildInfo = new BuildInfo();
var attributes = Assembly.GetEntryAssembly()?.GetCustomAttributes<AssemblyMetadataAttribute>().ToList();
var electronAssembly = Assembly.GetEntryAssembly();
if (attributes?.Count > 0)
if (electronAssembly == null)
{
return buildInfo;
}
if (electronAssembly.GetName().Name == "testhost" || electronAssembly.GetName().Name == "ReSharperTestRunner")
{
electronAssembly = AppDomain.CurrentDomain.GetData("ElectronTestAssembly") as Assembly ?? electronAssembly;
}
var attributes = electronAssembly.GetCustomAttributes<AssemblyMetadataAttribute>().ToList();
if (attributes.Count > 0)
{
buildInfo.ElectronExecutable = attributes.FirstOrDefault(e => e.Key == nameof(buildInfo.ElectronExecutable))?.Value;
buildInfo.ElectronVersion = attributes.FirstOrDefault(e => e.Key == nameof(buildInfo.ElectronVersion))?.Value;
@@ -166,4 +177,4 @@
return buildInfo;
}
}
}
}

View File

@@ -0,0 +1,34 @@
using ElectronNET.API.Entities;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace ElectronNET.API.Serialization
{
internal static class ElectronJson
{
public static readonly JsonSerializerOptions Options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
WriteIndented = false,
Converters =
{
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
}
};
}
// Use source generation where feasible for hot paths
[JsonSourceGenerationOptions(WriteIndented = false, PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
[JsonSerializable(typeof(TrayClickEventArgs))]
[JsonSerializable(typeof(Rectangle))]
[JsonSerializable(typeof(Display))]
[JsonSerializable(typeof(UpdateInfo))]
[JsonSerializable(typeof(ProgressInfo))]
[JsonSerializable(typeof(UpdateCheckResult))]
[JsonSerializable(typeof(SemVer))]
internal partial class ElectronJsonContext : JsonSerializerContext
{
}
}

View File

@@ -3,7 +3,7 @@
<Import Project="..\common.props" />
<PropertyGroup>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
<TargetFrameworks>net6.0;net8.0;net10.0</TargetFrameworks>
<PackageOutputPath>..\..\artifacts</PackageOutputPath>
<PackageId>$(PackageNamePrefix).AspNet</PackageId>
<Title>$(PackageId)</Title>
@@ -20,12 +20,18 @@
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0|AnyCPU'">
<NoWarn>1701;1702;4014;CS4014;CA1416;CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net10.0|AnyCPU'">
<NoWarn>1701;1702;4014;CS4014;CA1416;CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net6.0|AnyCPU'">
<NoWarn>1701;1702;4014;CS4014;CA1416;CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0|AnyCPU'">
<NoWarn>1701;1702;4014;CS4014;CA1416;CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net10.0|AnyCPU'">
<NoWarn>1701;1702;4014;CS4014;CA1416;CS1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>

View File

@@ -5,7 +5,7 @@
using ElectronNET.Runtime.Services;
using Microsoft.Extensions.Hosting;
internal class AspNetLifetimeAdapter : LifetimeServiceBase
internal class AspNetLifetimeAdapter : LifetimeServiceBase
{
private readonly IHostApplicationLifetime lifetimeService;
@@ -24,4 +24,4 @@
return Task.CompletedTask;
}
}
}
}

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More