Compare commits

...

39 Commits

Author SHA1 Message Date
Florian Rappl
20acd31f1a Updated changelog 2025-11-16 09:59:46 +01:00
Florian Rappl
f53d071bd9 Merge pull request #929 from softworkz/submit_platform_annotations
ElectronNET.API: Add platform support attributes
2025-11-16 09:38:31 +01:00
softworkz
2cf3095450 BrowserWindowTests: Add delays everywhere 2025-11-16 03:05:33 +01:00
softworkz
0ec791da9d Improve test Progress_bar_and_always_on_top_toggle 2025-11-16 02:59:50 +01:00
softworkz
0580942a59 ElectronNET API: Add platform support attributes 2025-11-16 02:53:28 +01:00
Florian Rappl
8e8d88c48f Merge pull request #931 from softworkz/submit_update_tests
Integration Tests Everywhere!
2025-11-16 02:42:22 +01:00
softworkz
61476e3ca4 Try fix remaining tests 2025-11-16 01:04:58 +01:00
softworkz
9488576d8f Add integration-tests workflow 2025-11-16 00:30:07 +01:00
softworkz
ff1b802838 Update ElectronFixture 2025-11-16 00:30:07 +01:00
softworkz
c98ad58290 Add xunit.runner.json 2025-11-16 00:30:07 +01:00
softworkz
a30239e3a6 Update electron start 2025-11-16 00:30:07 +01:00
softworkz
17f24749cd Project defaults: Make RuntimeIdentifier overrideable 2025-11-16 00:30:07 +01:00
softworkz
7558037b91 ElectronNET.IntegrationTests: Add platform support attributes 2025-11-16 00:30:07 +01:00
softworkz
e4485fd483 Remove Can_set_app_logs_path test
It's pointless because it doesn't ever throw
2025-11-16 00:24:17 +01:00
softworkz
1a964b405e BrowserWindow tests: use about:blank as url 2025-11-16 00:24:17 +01:00
softworkz
dfcb2345f3 Test project: Update to .net10 2025-11-16 00:24:17 +01:00
softworkz
3f10d6b5dd Remove tests for app badgecount
These require a full-blown desktop environment which is hardly ever available where these tests are run
2025-11-16 00:24:17 +01:00
Florian Rappl
90c3eb2c88 Merge pull request #935 from softworkz/submit_ts_project
ElectronNET.Host: Replace website by a real ts project
2025-11-15 16:02:02 +01:00
Florian Rappl
dbf76a1d6d Merge pull request #927 from softworkz/submit_whitespace2
Fix formatting and add GitHub Action to check trailing whitespace
2025-11-15 16:00:36 +01:00
softworkz
8e7892ebd4 Fix whitespace formatting 2025-11-15 13:52:19 +01:00
softworkz
30b547b8d3 Add R# settings 2025-11-15 13:41:25 +01:00
softworkz
30b4d92291 Add GitHub Action to check trailing whitespace on PRs 2025-11-15 13:41:25 +01:00
softworkz
6c9027faf3 WebApp: Do not compiled TS on build
(it's sufficient on save)
2025-11-15 13:14:27 +01:00
softworkz
c712027ea3 ElectronNET.Host: Replace website by a real ts project 2025-11-15 13:13:35 +01:00
Florian Rappl
7889057022 Merge pull request #933 from softworkz/submit_invocation_rename
Rename PropertyGet to more generic Invocator
2025-11-15 12:38:48 +01:00
Florian Rappl
68c50f1c1e Merge pull request #928 from softworkz/submit_remove_priv
Remove softworkz' special sauce
2025-11-15 12:37:24 +01:00
Florian Rappl
1006355bb7 Merge pull request #930 from softworkz/submit_pkg_update
build project: Update packages (due to vulnerabilities)
2025-11-15 12:35:34 +01:00
Florian Rappl
12c5391164 Merge pull request #932 from softworkz/submit_platform_specific
Webb app: add platform guards and promote analyzer severity
2025-11-15 12:34:57 +01:00
Florian Rappl
8ba24c0f2f Merge pull request #934 from ElectronNET/dependabot/npm_and_yarn/src/ElectronNET.WebApp/ElectronHostHook/js-yaml-4.1.1
Bump js-yaml from 4.1.0 to 4.1.1 in /src/ElectronNET.WebApp/ElectronHostHook
2025-11-15 12:25:28 +01:00
dependabot[bot]
bb7ae8d711 Bump js-yaml in /src/ElectronNET.WebApp/ElectronHostHook
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.1.0 to 4.1.1.
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.1.0...4.1.1)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 4.1.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-15 10:40:05 +00:00
softworkz
385dcfbf52 ApiBase: Code style and whitespace 2025-11-15 10:21:18 +01:00
softworkz
515430ff96 ApiBase: Rename PropertyGet to more generic Invocator 2025-11-15 10:21:18 +01:00
softworkz
a6d67a4dfe Make CA1416 and error (platform-depended reachabílitiy of code 2025-11-15 09:50:00 +01:00
softworkz
946b2af81a Webb app: add platform conditions 2025-11-15 09:50:00 +01:00
softworkz
1e483e9cc4 build project: Update packages (due to vulnerabilities) 2025-11-15 09:35:42 +01:00
softworkz
5305e17ba9 MSBuild props/targets: Adapt demo/test projects for change 2025-11-15 08:44:50 +01:00
softworkz
442084a3e5 MSBuild props/targets: Remove wrapped files 2025-11-15 08:44:50 +01:00
softworkz
cd205edabb common.props: Remove personal extras 2025-11-15 08:27:34 +01:00
Florian Rappl
10bf461b51 Prepare for Blazor support 2025-11-14 17:38:55 +01:00
166 changed files with 3225 additions and 2154 deletions

209
.github/workflows/integration-tests.yml vendored Normal file
View File

@@ -0,0 +1,209 @@
name: Tests
on:
push:
branches: [ develop, main ]
pull_request:
branches: [ develop, main ]
concurrency:
group: integration-tests-${{ github.ref }}
cancel-in-progress: true
jobs:
tests:
name: Integration Tests (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
rid: linux-x64
- os: windows-2022
rid: win-x64
- os: macos-14
rid: osx-arm64
env:
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
DOTNET_NOLOGO: 1
CI: true
ELECTRON_ENABLE_LOGGING: 1
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Restore
run: dotnet restore -r ${{ matrix.rid }} -p:RuntimeIdentifier=${{ matrix.rid }} src/ElectronNET.IntegrationTests/ElectronNET.IntegrationTests.csproj
- name: Build
run: dotnet build --no-restore -c Release -r ${{ matrix.rid }} -p:RuntimeIdentifier=${{ matrix.rid }} src/ElectronNET.IntegrationTests/ElectronNET.IntegrationTests.csproj
- name: Install Linux GUI dependencies
if: runner.os == 'Linux'
run: |
set -e
sudo apt-get update
# Core Electron dependencies
sudo apt-get install -y xvfb \
libgtk-3-0 libnss3 libgdk-pixbuf-2.0-0 libdrm2 libgbm1 libxss1 libxtst6 libatk-bridge2.0-0 libatk1.0-0 libatspi2.0-0 libx11-xcb1 libasound2t64
- name: Run tests (Linux)
if: runner.os == 'Linux'
continue-on-error: true
run: |
mkdir -p test-results/Ubuntu
xvfb-run -a dotnet test src/ElectronNET.IntegrationTests/ElectronNET.IntegrationTests.csproj \
-c Release --no-build -r ${{ matrix.rid }} -p:RuntimeIdentifier=${{ matrix.rid }} \
--logger "trx;LogFileName=Ubuntu.trx" \
--logger "console;verbosity=detailed" \
--results-directory test-results
- name: Run tests (Windows)
if: runner.os == 'Windows'
continue-on-error: true
run: |
New-Item -ItemType Directory -Force -Path test-results/Windows | Out-Null
dotnet test src/ElectronNET.IntegrationTests/ElectronNET.IntegrationTests.csproj -c Release --no-build -r ${{ matrix.rid }} -p:RuntimeIdentifier=${{ matrix.rid }} --logger "trx;LogFileName=Windows.trx" --logger "console;verbosity=detailed" --results-directory test-results
- name: Run tests (macOS)
if: runner.os == 'macOS'
continue-on-error: true
run: |
mkdir -p test-results/macOS
dotnet test src/ElectronNET.IntegrationTests/ElectronNET.IntegrationTests.csproj -c Release --no-build -r ${{ matrix.rid }} -p:RuntimeIdentifier=${{ matrix.rid }} --logger "trx;LogFileName=macOS.trx" --logger "console;verbosity=detailed" --results-directory test-results
- name: Upload raw test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.os }}
path: test-results/*.trx
retention-days: 7
summary:
name: Test Results
runs-on: ubuntu-24.04
if: always()
needs: [tests]
permissions:
actions: read
contents: read
checks: write
pull-requests: write
steps:
- name: Download all test results
uses: actions/download-artifact@v4
with:
path: test-results
- name: Setup .NET (for CTRF conversion)
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- name: Install CTRF TRX→CTRF converter (dotnet tool)
run: |
dotnet new tool-manifest
dotnet tool install DotnetCtrfJsonReporter --local
- name: Convert TRX → CTRF and clean names (keep suites; set filePath=OS)
shell: bash
run: |
set -euo pipefail
mkdir -p ctrf
shopt -s globstar nullglob
conv=0
for trx in test-results/**/*.trx; do
fname="$(basename "$trx")"
os="${fname%.trx}"
outdir="ctrf/${os}"
mkdir -p "$outdir"
out="${outdir}/ctrf-report.json"
dotnet tool run DotnetCtrfJsonReporter -p "$trx" -d "$outdir" -f "ctrf-report.json"
jq --arg os "$os" '.results.tests |= map(.filePath = $os)' "$out" > "${out}.tmp" && mv "${out}.tmp" "$out"
echo "Converted & normalized $trx -> $out"
conv=$((conv+1))
done
echo "Processed $conv TRX file(s)"
- name: Publish Test Report
if: always()
uses: ctrf-io/github-test-reporter@v1
with:
report-path: 'ctrf/**/*.json'
summary: true
pull-request: false
status-check: false
status-check-name: 'Integration Tests'
use-suite-name: true
update-comment: true
always-group-by: true
overwrite-comment: true
exit-on-fail: true
group-by: 'suite'
upload-artifact: true
fetch-previous-results: true
summary-report: false
summary-delta-report: true
github-report: true
test-report: false
test-list-report: false
failed-report: true
failed-folded-report: false
skipped-report: true
suite-folded-report: true
suite-list-report: false
file-report: true
previous-results-report: true
insights-report: true
flaky-report: true
flaky-rate-report: true
fail-rate-report: false
slowest-report: false
report-order: 'summary-delta-report,failed-report,skipped-report,suite-folded-report,file-report,previous-results-report,github-report'
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Create PR Comment
if: always()
uses: ctrf-io/github-test-reporter@v1
with:
report-path: 'ctrf/**/*.json'
summary: true
pull-request: true
use-suite-name: true
update-comment: true
always-group-by: true
overwrite-comment: true
upload-artifact: false
pull-request-report: true
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Summary
run: echo "All matrix test jobs completed."

View File

@@ -0,0 +1,85 @@
name: Trailing Whitespace Check
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
check-trailing-whitespace:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check for trailing whitespace
run: |
echo "Checking for trailing whitespace in changed files..."
# Get the base branch
BASE_SHA="${{ github.event.pull_request.base.sha }}"
HEAD_SHA="${{ github.event.pull_request.head.sha }}"
# Get list of changed files (excluding deleted files)
CHANGED_FILES=$(git diff --name-only --diff-filter=d "$BASE_SHA" "$HEAD_SHA")
if [ -z "$CHANGED_FILES" ]; then
echo "No files to check."
exit 0
fi
# File patterns to check (text files)
PATTERNS="\.cs$|\.csproj$|\.sln$|\.ts$|\.html$|\.css$|\.scss$"
# Directories and file patterns to exclude
EXCLUDE_PATTERNS="(^|\/)(\.|node_modules|bin|obj|artifacts|packages|\.vs|\.nuke\/temp)($|\/)"
ERRORS_FOUND=0
TEMP_FILE=$(mktemp)
while IFS= read -r file; do
# Skip if file doesn't exist (shouldn't happen with --diff-filter=d, but just in case)
if [ ! -f "$file" ]; then
continue
fi
# Check if file matches patterns to check
if ! echo "$file" | grep -qE "$PATTERNS"; then
continue
fi
# Check if file should be excluded
if echo "$file" | grep -qE "$EXCLUDE_PATTERNS"; then
continue
fi
# Find trailing whitespace lines, excluding XML doc placeholder lines that are exactly "/// " (one space)
MATCHES=$(grep -n '[[:space:]]$' "$file" | grep -vE '^[0-9]+:[[:space:]]*/// $' || true)
if [ -n "$MATCHES" ]; then
echo "❌ Trailing whitespace found in: $file"
echo "$MATCHES" | head -10
TOTAL=$(echo "$MATCHES" | wc -l)
if [ "$TOTAL" -gt 10 ]; then
echo " ... and $(($TOTAL - 10)) more lines"
fi
echo "1" >> "$TEMP_FILE"
fi
done <<< "$CHANGED_FILES"
ERRORS_FOUND=$(wc -l < "$TEMP_FILE" 2>/dev/null || echo "0")
rm -f "$TEMP_FILE"
if [ "$ERRORS_FOUND" -gt 0 ]; then
echo ""
echo "❌ Found trailing whitespace in $ERRORS_FOUND file(s)."
echo "Please remove trailing whitespace from the files listed above."
exit 1
else
echo "✅ No trailing whitespace found in changed files."
exit 0
fi

View File

@@ -1,3 +1,14 @@
# 0.2.0
## ElectronNET.Core
- Updated dependencies (#930) @softworkz
- Updated integration tests (#931) @softworkz
- Updated `ElectronNET.Host` (#935) @softworkz
- Removed transition period specific build configuration (#928) @softworkz
- Added `IsRunningBlazor` option to `BrowserWindowOptions` (#926)
- Added platform support attributes (#929) @softworkz
# 0.1.0
## ElectronNET.Core

View File

@@ -58,22 +58,22 @@ To do so, use the `UseElectron` extension method on a `WebApplicationBuilder`, a
using ElectronNET.API;
using ElectronNET.API.Entities;
public static void Main(string[] args)
{
WebHost.CreateDefaultBuilder(args)
.UseElectron(args, ElectronAppReady)
.UseStartup<Startup>()
.Build()
.Run();
}
public static void Main(string[] args)
{
WebHost.CreateDefaultBuilder(args)
.UseElectron(args, ElectronAppReady)
.UseStartup<Startup>()
.Build()
.Run();
}
public static async Task ElectronAppReady()
{
var browserWindow = await Electron.WindowManager.CreateWindowAsync(
new BrowserWindowOptions { Show = false });
public static async Task ElectronAppReady()
{
var browserWindow = await Electron.WindowManager.CreateWindowAsync(
new BrowserWindowOptions { Show = false });
browserWindow.OnReadyToShow += () => browserWindow.Show();
}
browserWindow.OnReadyToShow += () => browserWindow.Show();
}
```
### Minimal API Example
@@ -113,6 +113,56 @@ app.MapRazorPages();
app.Run();
```
### Blazor
For a project with Blazor you can use:
```cs
using ElectronNET.API;
using ElectronNET.API.Entities;
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddRazorComponents()
.AddInteractiveWebAssemblyComponents();
builder.Services.AddElectron(); // <-- might be useful to set up DI
builder.UseElectron(args, async () =>
{
var options = new BrowserWindowOptions {
Show = false,
AutoHideMenuBar = true,
IsRunningBlazor = true, // <-- crucial
};
var browserWindow = await Electron.WindowManager.CreateWindowAsync(options);
browserWindow.OnReadyToShow += () => browserWindow.Show();
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseWebAssemblyDebugging();
}
else
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
}
app.UseStaticFiles();
app.UseAntiforgery();
app.MapRazorComponents<BlazorApp.Components.App>()
.AddInteractiveWebAssemblyRenderMode();
app.Run();
```
The `IsRunningBlazor` option makes sure to set up the renderer in a way that Blazor can just run without any interference. This includes things such as HMR for development.
## 🚀 Starting and Debugging the Application
Just press `F5` in Visual Studio or use dotnet for debugging.

View File

@@ -54,7 +54,7 @@ Add the Electron.NET configuration to your `.csproj` file:
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ElectronNET.Core" Version="0.1.0" />
<PackageReference Include="ElectronNET.Core" Version="0.2.0" />
</ItemGroup>
```

View File

@@ -85,7 +85,7 @@ public sealed class ReleaseNotesParser
// Parse content.
var notes = new List<string>();
while (true)
{
// Sanity checks.

View File

@@ -11,6 +11,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="17.11.48" />
<PackageReference Include="Microsoft.Build.Tasks.Core" Version="17.11.48" />
<PackageReference Include="Nuke.Common" Version="9.0.4" />
</ItemGroup>

4
src/.editorconfig Normal file
View File

@@ -0,0 +1,4 @@
[*.cs]
# CA1416: Validate platform compatibility
dotnet_diagnostic.CA1416.severity = error

View File

@@ -1,4 +1,5 @@
// ReSharper disable InconsistentNaming
namespace ElectronNET.API
{
using Common;
@@ -17,6 +18,7 @@ namespace ElectronNET.API
DashesLowerFirst,
NoDashUpperFirst
}
protected enum SocketTaskMessageNameTypes
{
DashesLowerFirst,
@@ -29,15 +31,15 @@ namespace ElectronNET.API
CamelCase,
}
private const int PropertyTimeout = 1000;
private const int InvocationTimeout = 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, Invocator> invocators;
private readonly ConcurrentDictionary<string, string> invocationEventNames = new();
private readonly ConcurrentDictionary<string, string> invocationMessageNames = 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 static readonly ConcurrentDictionary<string, ConcurrentDictionary<string, Invocator>> AllInvocators = new();
private readonly object objLock = new object();
@@ -58,7 +60,7 @@ namespace ElectronNET.API
protected ApiBase()
{
this.objectName = this.GetType().Name.LowerFirst();
propertyGetters = AllPropertyGetters.GetOrAdd(objectName, _ => new ConcurrentDictionary<string, PropertyGetter>());
this.invocators = AllInvocators.GetOrAdd(this.objectName, _ => new ConcurrentDictionary<string, Invocator>());
}
protected void CallMethod0([CallerMemberName] string callerName = null)
@@ -113,21 +115,21 @@ namespace ElectronNET.API
}
}
protected Task<T> GetPropertyAsync<T>(object arg = null, [CallerMemberName] string callerName = null)
protected Task<T> InvokeAsync<T>(object arg = null, [CallerMemberName] string callerName = null)
{
Debug.Assert(callerName != null, nameof(callerName) + " != null");
lock (this.objLock)
{
return this.propertyGetters.GetOrAdd(callerName, _ =>
return this.invocators.GetOrAdd(callerName, _ =>
{
var getter = new PropertyGetter<T>(this, callerName, PropertyTimeout, arg);
var getter = new Invocator<T>(this, callerName, InvocationTimeout, arg);
getter.Task<T>().ContinueWith(_ =>
{
lock (this.objLock)
{
return this.propertyGetters.TryRemove(callerName, out var _);
return this.invocators.TryRemove(callerName, out var _);
}
});
@@ -135,15 +137,15 @@ namespace ElectronNET.API
}).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);
var eventName = this.EventName(callerName);
lock (objLock)
var eventKey = this.EventKey(eventName, id);
lock (this.objLock)
{
var container = eventContainers.GetOrAdd(eventKey, _ =>
{
@@ -156,14 +158,14 @@ namespace ElectronNET.API
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);
var eventName = this.EventName(callerName);
var eventKey = this.EventKey(eventName, id);
lock (objLock)
lock (this.objLock)
{
if (eventContainers.TryGetValue(eventKey, out var container) && !container.Unregister(value))
{
@@ -172,15 +174,15 @@ namespace ElectronNET.API
}
}
}
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 eventName = this.EventName(callerName);
var eventKey = this.EventKey(eventName, id);
lock (this.objLock)
{
var container = eventContainers.GetOrAdd(eventKey, _ =>
{
@@ -197,10 +199,10 @@ namespace ElectronNET.API
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);
var eventName = this.EventName(callerName);
var eventKey = this.EventKey(eventName, id);
lock (objLock)
lock (this.objLock)
{
if (eventContainers.TryGetValue(eventKey, out var container) && !container.Unregister(value))
{
@@ -212,33 +214,33 @@ namespace ElectronNET.API
private string EventName(string callerName)
{
switch (SocketEventNameType)
switch (this.SocketEventNameType)
{
case SocketEventNameTypes.DashedLower:
return $"{objectName}-{callerName.ToDashedEventName()}";
return $"{this.objectName}-{callerName.ToDashedEventName()}";
case SocketEventNameTypes.CamelCase:
return $"{objectName}-{callerName.ToCamelCaseEventName()}";
return $"{this.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
internal abstract class Invocator
{
public abstract Task<T> Task<T>();
}
internal class PropertyGetter<T> : PropertyGetter
internal class Invocator<T> : Invocator
{
private readonly Task<T> tcsTask;
private TaskCompletionSource<T> tcs;
public PropertyGetter(ApiBase apiBase, string callerName, int timeoutMs, object arg = null)
public Invocator(ApiBase apiBase, string callerName, int timeoutMs, object arg = null)
{
this.tcs = new TaskCompletionSource<T>(TaskCreationOptions.RunContinuationsAsynchronously);
this.tcsTask = this.tcs.Task;
@@ -249,22 +251,22 @@ namespace ElectronNET.API
switch (apiBase.SocketTaskEventNameType)
{
case SocketTaskEventNameTypes.DashesLowerFirst:
eventName = apiBase.propertyEventNames.GetOrAdd(callerName, s => $"{apiBase.objectName}-{s.StripAsync().LowerFirst()}-completed");
eventName = apiBase.invocationEventNames.GetOrAdd(callerName, s => $"{apiBase.objectName}-{s.StripAsync().LowerFirst()}-completed");
break;
case SocketTaskEventNameTypes.NoDashUpperFirst:
eventName = apiBase.propertyEventNames.GetOrAdd(callerName, s => $"{apiBase.objectName}{s.StripAsync()}Completed");
eventName = apiBase.invocationEventNames.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()}");
messageName = apiBase.invocationMessageNames.GetOrAdd(callerName, s => $"{apiBase.objectName}-{s.StripAsync().LowerFirst()}");
break;
case SocketTaskMessageNameTypes.NoDashUpperFirst:
messageName = apiBase.propertyMessageNames.GetOrAdd(callerName, s => apiBase.objectName + s.StripAsync());
messageName = apiBase.invocationMessageNames.GetOrAdd(callerName, s => apiBase.objectName + s.StripAsync());
break;
default:
throw new ArgumentOutOfRangeException();
@@ -289,17 +291,17 @@ namespace ElectronNET.API
}
}
});
if (arg != null)
{
_ = apiBase.Id >= 0 ? BridgeConnector.Socket.Emit(messageName, apiBase.Id, arg) : BridgeConnector.Socket.Emit(messageName, arg);
_ = 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);
_ = apiBase.Id >= 0 ? BridgeConnector.Socket.Emit(messageName, apiBase.Id) : BridgeConnector.Socket.Emit(messageName);
}
System.Threading.Tasks.Task.Delay(PropertyTimeout).ContinueWith(_ =>
System.Threading.Tasks.Task.Delay(InvocationTimeout).ContinueWith(_ =>
{
if (this.tcs != null)
{
@@ -321,7 +323,7 @@ namespace ElectronNET.API
return this.tcsTask as Task<T1>;
}
}
[SuppressMessage("ReSharper", "InconsistentlySynchronizedField")]
private class EventContainer
{
@@ -330,44 +332,44 @@ namespace ElectronNET.API
private Action<T> GetEventActionT<T>()
{
return (Action<T>)eventActionT;
return (Action<T>)this.eventActionT;
}
private void SetEventActionT<T>(Action<T> actionT)
{
eventActionT = actionT;
this.eventActionT = actionT;
}
public void OnEventAction() => eventAction?.Invoke();
public void OnEventAction() => this.eventAction?.Invoke();
public void OnEventActionT<T>(T p) => GetEventActionT<T>()?.Invoke(p);
public void OnEventActionT<T>(T p) => this.GetEventActionT<T>()?.Invoke(p);
public void Register(Action receiver)
{
eventAction += receiver;
this.eventAction += receiver;
}
public void Register<T>(Action<T> receiver)
{
var actionT = GetEventActionT<T>();
var actionT = this.GetEventActionT<T>();
actionT += receiver;
SetEventActionT(actionT);
this.SetEventActionT(actionT);
}
public bool Unregister(Action receiver)
{
eventAction -= receiver;
this.eventAction -= receiver;
return this.eventAction != null;
}
public bool Unregister<T>(Action<T> receiver)
{
var actionT = GetEventActionT<T>();
var actionT = this.GetEventActionT<T>();
actionT -= receiver;
SetEventActionT(actionT);
this.SetEventActionT(actionT);
return actionT != null;
}
}
}
}
}

View File

@@ -2,6 +2,7 @@ using ElectronNET.API.Entities;
using ElectronNET.API.Extensions;
using System;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
@@ -58,7 +59,7 @@ namespace ElectronNET.API
private event Action _windowAllClosed;
/// <summary>
/// Emitted before the application starts closing its windows.
/// Emitted before the application starts closing its windows.
/// <para/>
/// Note: If application quit was initiated by <see cref="AutoUpdater.QuitAndInstall"/> then <see cref="BeforeQuit"/>
/// is emitted after emitting close event on all windows and closing them.
@@ -259,6 +260,8 @@ namespace ElectronNET.API
/// screen readers, are enabled or disabled. See https://www.chromium.org/developers/design-documents/accessibility for more details.
/// </summary>
/// <returns><see langword="true"/> when Chrome's accessibility support is enabled, <see langword="false"/> otherwise.</returns>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public event Action<bool> AccessibilitySupportChanged
{
add => AddEvent(value, GetHashCode());
@@ -316,6 +319,7 @@ namespace ElectronNET.API
/// <para/>
/// On Windows, you have to parse the arguments using App.CommandLine to get the filepath.
/// </summary>
[SupportedOSPlatform("macOS")]
public event Action<string> OpenFile
{
add => AddEvent(value, GetHashCode());
@@ -327,6 +331,7 @@ namespace ElectronNET.API
/// Emitted when a MacOS user wants to open a URL with the application. Your application's Info.plist file must
/// define the URL scheme within the CFBundleURLTypes key, and set NSPrincipalClass to AtomApplication.
/// </summary>
[SupportedOSPlatform("macOS")]
public event Action<string> OpenUrl
{
add => AddEvent(value, GetHashCode());
@@ -366,7 +371,7 @@ namespace ElectronNET.API
{
get
{
return this.GetPropertyAsync<string>();
return this.InvokeAsync<string>();
}
}
@@ -399,7 +404,6 @@ namespace ElectronNET.API
private static object _syncRoot = new object();
/// <summary>
/// Try to close all windows. The <see cref="BeforeQuit"/> event will be emitted first. If all windows are successfully
/// closed, the <see cref="WillQuit"/> event will be emitted and by default the application will terminate. This method
@@ -482,6 +486,7 @@ namespace ElectronNET.API
/// <summary>
/// Hides all application windows without minimizing them.
/// </summary>
[SupportedOSPlatform("macOS")]
public void Hide()
{
this.CallMethod0();
@@ -490,6 +495,7 @@ namespace ElectronNET.API
/// <summary>
/// Shows application windows after they were hidden. Does not automatically focus them.
/// </summary>
[SupportedOSPlatform("macOS")]
public void Show()
{
this.CallMethod0();
@@ -501,7 +507,7 @@ namespace ElectronNET.API
public async Task<string> GetAppPathAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
return await this.GetPropertyAsync<string>().ConfigureAwait(false);
return await this.InvokeAsync<string>().ConfigureAwait(false);
}
/// <summary>
@@ -558,14 +564,14 @@ namespace ElectronNET.API
}
/// <summary>
/// The version of the loaded application. If no version is found in the applications package.json file,
/// The version of the loaded application. If no version is found in the applications package.json file,
/// the version of the current bundle or executable is returned.
/// </summary>
/// <returns>The version of the loaded application.</returns>
public async Task<string> GetVersionAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
return await this.GetPropertyAsync<string>().ConfigureAwait(false);
return await this.InvokeAsync<string>().ConfigureAwait(false);
}
/// <summary>
@@ -579,7 +585,7 @@ namespace ElectronNET.API
public async Task<string> GetLocaleAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
return await this.GetPropertyAsync<string>().ConfigureAwait(false);
return await this.InvokeAsync<string>().ConfigureAwait(false);
}
/// <summary>
@@ -587,6 +593,8 @@ namespace ElectronNET.API
/// list from the task bar, and on macOS you can visit it from dock menu.
/// </summary>
/// <param name="path">Path to add.</param>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public void AddRecentDocument(string path)
{
this.CallMethod1(path);
@@ -595,6 +603,8 @@ namespace ElectronNET.API
/// <summary>
/// Clears the recent documents list.
/// </summary>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public void ClearRecentDocuments()
{
this.CallMethod0();
@@ -710,6 +720,8 @@ namespace ElectronNET.API
/// <param name="protocol">The name of your protocol, without ://.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Whether the call succeeded.</returns>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public async Task<bool> RemoveAsDefaultProtocolClientAsync(string protocol, CancellationToken cancellationToken = default)
{
return await this.RemoveAsDefaultProtocolClientAsync(protocol, null, null, cancellationToken).ConfigureAwait(false);
@@ -723,6 +735,8 @@ namespace ElectronNET.API
/// <param name="path">Defaults to process.execPath.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Whether the call succeeded.</returns>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public async Task<bool> RemoveAsDefaultProtocolClientAsync(string protocol, string path, CancellationToken cancellationToken = default)
{
return await this.RemoveAsDefaultProtocolClientAsync(protocol, path, null, cancellationToken).ConfigureAwait(false);
@@ -737,6 +751,8 @@ namespace ElectronNET.API
/// <param name="args">Defaults to an empty array.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Whether the call succeeded.</returns>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public async Task<bool> RemoveAsDefaultProtocolClientAsync(string protocol, string path, string[] args, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -827,6 +843,7 @@ namespace ElectronNET.API
/// <param name="userTasks">Array of <see cref="UserTask"/> objects.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Whether the call succeeded.</returns>
[SupportedOSPlatform("Windows")]
public async Task<bool> SetUserTasksAsync(UserTask[] userTasks, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -847,10 +864,11 @@ namespace ElectronNET.API
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Jump List settings.</returns>
[SupportedOSPlatform("Windows")]
public async Task<JumpListSettings> GetJumpListSettingsAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
return await this.GetPropertyAsync<JumpListSettings>().ConfigureAwait(false);
return await this.InvokeAsync<JumpListSettings>().ConfigureAwait(false);
}
/// <summary>
@@ -869,6 +887,7 @@ namespace ElectronNET.API
/// omitted from the Jump List. The list of removed items can be obtained using <see cref="GetJumpListSettingsAsync"/>.
/// </summary>
/// <param name="categories">Array of <see cref="JumpListCategory"/> objects.</param>
[SupportedOSPlatform("Windows")]
public void SetJumpList(JumpListCategory[] categories)
{
this.CallMethod1(categories);
@@ -941,7 +960,7 @@ namespace ElectronNET.API
public async Task<bool> HasSingleInstanceLockAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
return await this.GetPropertyAsync<bool>().ConfigureAwait(false);
return await this.InvokeAsync<bool>().ConfigureAwait(false);
}
/// <summary>
@@ -951,6 +970,7 @@ namespace ElectronNET.API
/// </summary>
/// <param name="type">Uniquely identifies the activity. Maps to <see href="https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSUserActivity_Class/index.html#//apple_ref/occ/instp/NSUserActivity/activityType">NSUserActivity.activityType</see>.</param>
/// <param name="userInfo">App-specific state to store for use by another device.</param>
[SupportedOSPlatform("macOS")]
public void SetUserActivity(string type, object userInfo)
{
SetUserActivity(type, userInfo, null);
@@ -968,6 +988,7 @@ namespace ElectronNET.API
/// <param name="webpageUrl">
/// The webpage to load in a browser if no suitable app is installed on the resuming device. The scheme must be http or https.
/// </param>
[SupportedOSPlatform("macOS")]
public void SetUserActivity(string type, object userInfo, string webpageUrl)
{
this.CallMethod3(type, userInfo, webpageUrl);
@@ -977,15 +998,17 @@ namespace ElectronNET.API
/// The type of the currently running activity.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
[SupportedOSPlatform("macOS")]
public async Task<string> GetCurrentActivityTypeAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
return await this.GetPropertyAsync<string>().ConfigureAwait(false);
return await this.InvokeAsync<string>().ConfigureAwait(false);
}
/// <summary>
/// Invalidates the current <see href="https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/Handoff/HandoffFundamentals/HandoffFundamentals.html">Handoff</see> user activity.
/// </summary>
[SupportedOSPlatform("macOS")]
public void InvalidateCurrentActivity()
{
this.CallMethod0();
@@ -994,6 +1017,7 @@ namespace ElectronNET.API
/// <summary>
/// Marks the current <see href="https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/Handoff/HandoffFundamentals/HandoffFundamentals.html">Handoff</see> user activity as inactive without invalidating it.
/// </summary>
[SupportedOSPlatform("macOS")]
public void ResignCurrentActivity()
{
this.CallMethod0();
@@ -1003,6 +1027,7 @@ namespace ElectronNET.API
/// Changes the <see href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx">Application User Model ID</see> to id.
/// </summary>
/// <param name="id">Model Id.</param>
[SupportedOSPlatform("Windows")]
public void SetAppUserModelId(string id)
{
this.CallMethod1(id);
@@ -1017,6 +1042,7 @@ namespace ElectronNET.API
/// <param name="options"></param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Result of import. Value of 0 indicates success.</returns>
[SupportedOSPlatform("Linux")]
public async Task<int> ImportCertificateAsync(ImportCertificateOptions options, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -1043,7 +1069,7 @@ namespace ElectronNET.API
public async Task<ProcessMetric[]> GetAppMetricsAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
return await this.GetPropertyAsync<ProcessMetric[]>().ConfigureAwait(false);
return await this.InvokeAsync<ProcessMetric[]>().ConfigureAwait(false);
}
/// <summary>
@@ -1055,7 +1081,7 @@ namespace ElectronNET.API
public async Task<GPUFeatureStatus> GetGpuFeatureStatusAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
return await this.GetPropertyAsync<GPUFeatureStatus>().ConfigureAwait(false);
return await this.InvokeAsync<GPUFeatureStatus>().ConfigureAwait(false);
}
/// <summary>
@@ -1068,6 +1094,8 @@ namespace ElectronNET.API
/// <param name="count">Counter badge.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Whether the call succeeded.</returns>
[SupportedOSPlatform("Linux")]
[SupportedOSPlatform("macOS")]
public async Task<bool> SetBadgeCountAsync(int count, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -1087,10 +1115,12 @@ namespace ElectronNET.API
/// The current value displayed in the counter badge.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
[SupportedOSPlatform("Linux")]
[SupportedOSPlatform("macOS")]
public async Task<int> GetBadgeCountAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
return await this.GetPropertyAsync<int>().ConfigureAwait(false);
return await this.InvokeAsync<int>().ConfigureAwait(false);
}
/// <summary>
@@ -1102,16 +1132,19 @@ namespace ElectronNET.API
/// Whether the current desktop environment is Unity launcher.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
[SupportedOSPlatform("Linux")]
public async Task<bool> IsUnityRunningAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
return await this.GetPropertyAsync<bool>().ConfigureAwait(false);
return await this.InvokeAsync<bool>().ConfigureAwait(false);
}
/// <summary>
/// If you provided path and args options to <see cref="SetLoginItemSettings"/> then you need to pass the same
/// arguments here for <see cref="LoginItemSettings.OpenAtLogin"/> to be set correctly.
/// </summary>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public async Task<LoginItemSettings> GetLoginItemSettingsAsync(CancellationToken cancellationToken = default)
{
return await this.GetLoginItemSettingsAsync(null, cancellationToken).ConfigureAwait(false);
@@ -1123,6 +1156,8 @@ namespace ElectronNET.API
/// </summary>
/// <param name="options"></param>
/// <param name="cancellationToken">The cancellation token.</param>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public async Task<LoginItemSettings> GetLoginItemSettingsAsync(LoginItemSettingsOptions options, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -1152,6 +1187,8 @@ namespace ElectronNET.API
/// you'll want to set the launch path to Update.exe, and pass arguments that specify your application name.
/// </summary>
/// <param name="loginSettings"></param>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public void SetLoginItemSettings(LoginSettings loginSettings)
{
this.CallMethod1(loginSettings);
@@ -1163,10 +1200,12 @@ namespace ElectronNET.API
/// See <see href="chromium.org/developers/design-documents/accessibility">Chromium's accessibility docs</see> for more details.
/// </summary>
/// <returns><see langword="true"/> if Chromes accessibility support is enabled, <see langword="false"/> otherwise.</returns>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public async Task<bool> IsAccessibilitySupportEnabledAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
return await this.GetPropertyAsync<bool>().ConfigureAwait(false);
return await this.InvokeAsync<bool>().ConfigureAwait(false);
}
/// <summary>
@@ -1179,6 +1218,8 @@ namespace ElectronNET.API
/// Note: Rendering accessibility tree can significantly affect the performance of your app. It should not be enabled by default.
/// </summary>
/// <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>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public void SetAccessibilitySupportEnabled(bool enabled)
{
this.CallMethod1(enabled);
@@ -1245,7 +1286,7 @@ namespace ElectronNET.API
return Task.Run(() =>
{
var taskCompletionSource = new TaskCompletionSource<string>();
BridgeConnector.Socket.Once<string>("appGetUserAgentFallbackCompleted", taskCompletionSource.SetResult);
BridgeConnector.Socket.Emit("appGetUserAgentFallback");
@@ -1295,4 +1336,4 @@ namespace ElectronNET.API
public async Task Once(string eventName, Action<object> action)
=> await Events.Instance.Once(ModuleName, eventName, action).ConfigureAwait(false);
}
}
}

View File

@@ -10,7 +10,7 @@ namespace ElectronNET.API
/// <summary>
/// Enable apps to automatically update themselves. Based on electron-updater.
/// </summary>
public sealed class AutoUpdater: ApiBase
public sealed class AutoUpdater : ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;
@@ -23,7 +23,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run(() => GetPropertyAsync<bool>()).Result;
return Task.Run(() => this.InvokeAsync<bool>()).Result;
}
set
{
@@ -40,7 +40,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run(() => GetPropertyAsync<bool>()).Result;
return Task.Run(() => this.InvokeAsync<bool>()).Result;
}
set
{
@@ -49,7 +49,7 @@ namespace ElectronNET.API
}
/// <summary>
/// *GitHub provider only.* Whether to allow update to pre-release versions.
/// *GitHub provider only.* Whether to allow update to pre-release versions.
/// Defaults to "true" if application version contains prerelease components (e.g. "0.12.1-alpha.1", here "alpha" is a prerelease component), otherwise "false".
///
/// If "true", downgrade will be allowed("allowDowngrade" will be set to "true").
@@ -58,7 +58,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run(() => GetPropertyAsync<bool>()).Result;
return Task.Run(() => this.InvokeAsync<bool>()).Result;
}
set
{
@@ -67,14 +67,14 @@ namespace ElectronNET.API
}
/// <summary>
/// *GitHub provider only.*
/// *GitHub provider only.*
/// Get all release notes (from current version to latest), not just the latest (Default is false).
/// </summary>
public bool FullChangelog
{
get
{
return Task.Run(() => GetPropertyAsync<bool>()).Result;
return Task.Run(() => this.InvokeAsync<bool>()).Result;
}
set
{
@@ -91,7 +91,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run(() => GetPropertyAsync<bool>()).Result;
return Task.Run(() => this.InvokeAsync<bool>()).Result;
}
set
{
@@ -106,7 +106,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run(() => GetPropertyAsync<string>()).Result;
return Task.Run(() => this.InvokeAsync<string>()).Result;
}
}
@@ -117,12 +117,12 @@ namespace ElectronNET.API
{
get
{
return Task.Run(() => GetPropertyAsync<SemVer>());
return Task.Run(() => this.InvokeAsync<SemVer>());
}
}
/// <summary>
/// Get the update channel. Not applicable for GitHub.
/// Get the update channel. Not applicable for GitHub.
/// Doesnt return channel from the update configuration, only if was previously set.
/// </summary>
[Obsolete("Use the asynchronous version ChannelAsync instead")]
@@ -135,19 +135,19 @@ namespace ElectronNET.API
}
/// <summary>
/// Get the update channel. Not applicable for GitHub.
/// Get the update channel. Not applicable for GitHub.
/// Doesnt return channel from the update configuration, only if was previously set.
/// </summary>
public Task<string> ChannelAsync
{
get
{
return Task.Run(() => GetPropertyAsync<string>());
return Task.Run(() => this.InvokeAsync<string>());
}
}
/// <summary>
/// Set the update channel. Not applicable for GitHub.
/// Set the update channel. Not applicable for GitHub.
/// </summary>
public string SetChannel
{
@@ -165,7 +165,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run(() => GetPropertyAsync<Dictionary<string, string>>());
return Task.Run(() => this.InvokeAsync<Dictionary<string, string>>());
}
}
@@ -199,7 +199,7 @@ namespace ElectronNET.API
}
/// <summary>
/// Emitted when there is an available update.
/// Emitted when there is an available update.
/// The update is downloaded automatically if AutoDownload is true.
/// </summary>
public event Action<UpdateInfo> OnUpdateAvailable
@@ -332,11 +332,11 @@ namespace ElectronNET.API
}
/// <summary>
/// Restarts the app and installs the update after it has been downloaded.
/// It should only be called after `update-downloaded` has been emitted.
///
/// Note: QuitAndInstall() will close all application windows first and only emit `before-quit` event on `app` after that.
/// This is different from the normal quit event sequence.
/// Restarts the app and installs the update after it has been downloaded.
/// It should only be called after `update-downloaded` has been emitted.
///
/// Note: QuitAndInstall() will close all application windows first and only emit `before-quit` event on `app` after that.
/// This is different from the normal quit event sequence.
/// </summary>
/// <param name="isSilent">*windows-only* Runs the installer in silent mode. Defaults to `false`.</param>
/// <param name="isForceRunAfter">Run the app after finish even on silent install. Not applicable for macOS. Ignored if `isSilent` is set to `false`.</param>
@@ -374,9 +374,5 @@ namespace ElectronNET.API
return tcs.Task;
}
}
}
}

View File

@@ -8,10 +8,11 @@ namespace ElectronNET.API
/// It is like a child window, except that it is positioned relative to its owning window.
/// It is meant to be an alternative to the webview tag.
/// </summary>
public class BrowserView: ApiBase
public class BrowserView : ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;
/// <summary>
/// Gets the identifier.
/// </summary>
@@ -30,7 +31,7 @@ namespace ElectronNET.API
{
get
{
return Task.Run(() => GetPropertyAsync<Rectangle>()).Result;
return Task.Run(() => this.InvokeAsync<Rectangle>()).Result;
}
set
{
@@ -69,5 +70,4 @@ namespace ElectronNET.API
BridgeConnector.Socket.Emit("browserView-setBackgroundColor", Id, color);
}
}
}
}

View File

@@ -1,10 +1,11 @@
using ElectronNET.API.Entities;
using ElectronNET.API.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using ElectronNET.API.Entities;
using ElectronNET.API.Extensions;
// ReSharper disable InconsistentNaming
@@ -27,7 +28,7 @@ public class BrowserWindow : ApiBase
public override int Id { get; protected set; }
/// <summary>
/// Emitted when the web page has been rendered (while not being shown) and
/// Emitted when the web page has been rendered (while not being shown) and
/// window can be displayed without a visual flash.
/// </summary>
public event Action OnReadyToShow
@@ -55,8 +56,8 @@ public class BrowserWindow : ApiBase
}
/// <summary>
/// Emitted when the window is closed.
/// After you have received this event you should remove the
/// Emitted when the window is closed.
/// After you have received this event you should remove the
/// reference to the window and avoid using it any more.
/// </summary>
public event Action OnClosed
@@ -68,6 +69,7 @@ public class BrowserWindow : ApiBase
/// <summary>
/// Emitted when window session is going to end due to force shutdown or machine restart or session log off.
/// </summary>
[SupportedOSPlatform("Windows")]
public event Action OnSessionEnd
{
add => AddEvent(value, Id);
@@ -187,6 +189,8 @@ public class BrowserWindow : ApiBase
/// <summary>
/// macOS: Emitted once when the window is moved to a new position.
/// </summary>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public event Action OnMoved
{
add => AddEvent(value, Id);
@@ -230,14 +234,16 @@ public class BrowserWindow : ApiBase
}
/// <summary>
/// Emitted when an App Command is invoked. These are typically related to
/// keyboard media keys or browser commands, as well as the “Back” button
/// Emitted when an App Command is invoked. These are typically related to
/// keyboard media keys or browser commands, as well as the “Back” button
/// built into some mice on Windows.
///
/// Commands are lowercased, underscores are replaced with hyphens,
/// and the APPCOMMAND_ prefix is stripped off.e.g.APPCOMMAND_BROWSER_BACKWARD
/// Commands are lowercased, underscores are replaced with hyphens,
/// and the APPCOMMAND_ prefix is stripped off.e.g.APPCOMMAND_BROWSER_BACKWARD
/// is emitted as browser-backward.
/// </summary>
[SupportedOSPlatform("Windows")]
[SupportedOSPlatform("Linux")]
public event Action<string> OnAppCommand
{
add => AddEvent(value, Id);
@@ -247,6 +253,7 @@ public class BrowserWindow : ApiBase
/// <summary>
/// Emitted on 3-finger swipe. Possible directions are up, right, down, left.
/// </summary>
[SupportedOSPlatform("macOS")]
public event Action<string> OnSwipe
{
add => AddEvent(value, Id);
@@ -256,6 +263,7 @@ public class BrowserWindow : ApiBase
/// <summary>
/// Emitted when the window opens a sheet.
/// </summary>
[SupportedOSPlatform("macOS")]
public event Action OnSheetBegin
{
add => AddEvent(value, Id);
@@ -265,6 +273,7 @@ public class BrowserWindow : ApiBase
/// <summary>
/// Emitted when the window has closed a sheet.
/// </summary>
[SupportedOSPlatform("macOS")]
public event Action OnSheetEnd
{
add => AddEvent(value, Id);
@@ -274,6 +283,7 @@ public class BrowserWindow : ApiBase
/// <summary>
/// Emitted when the native new tab button is clicked.
/// </summary>
[SupportedOSPlatform("macOS")]
public event Action OnNewWindowForTab
{
add => AddEvent(value, Id);
@@ -287,15 +297,15 @@ public class BrowserWindow : ApiBase
}
/// <summary>
/// Force closing the window, the unload and beforeunload event wont be
/// emitted for the web page, and close event will also not be emitted
/// Force closing the window, the unload and beforeunload event wont be
/// emitted for the web page, and close event will also not be emitted
/// for this window, but it guarantees the closed event will be emitted.
/// </summary>
public void Destroy() => this.CallMethod0();
/// <summary>
/// Try to close the window. This has the same effect as a user manually
/// clicking the close button of the window. The web page may cancel the close though.
/// Try to close the window. This has the same effect as a user manually
/// clicking the close button of the window. The web page may cancel the close though.
/// </summary>
public void Close() => this.CallMethod0();
@@ -313,13 +323,13 @@ public class BrowserWindow : ApiBase
/// Whether the window is focused.
/// </summary>
/// <returns></returns>
public Task<bool> IsFocusedAsync() => this.GetPropertyAsync<bool>();
public Task<bool> IsFocusedAsync() => this.InvokeAsync<bool>();
/// <summary>
/// Whether the window is destroyed.
/// </summary>
/// <returns></returns>
public Task<bool> IsDestroyedAsync() => this.GetPropertyAsync<bool>();
public Task<bool> IsDestroyedAsync() => this.InvokeAsync<bool>();
/// <summary>
/// Shows and gives focus to the window.
@@ -340,13 +350,13 @@ public class BrowserWindow : ApiBase
/// Whether the window is visible to the user.
/// </summary>
/// <returns></returns>
public Task<bool> IsVisibleAsync() => this.GetPropertyAsync<bool>();
public Task<bool> IsVisibleAsync() => this.InvokeAsync<bool>();
/// <summary>
/// Whether current window is a modal window.
/// </summary>
/// <returns></returns>
public Task<bool> IsModalAsync() => this.GetPropertyAsync<bool>();
public Task<bool> IsModalAsync() => this.InvokeAsync<bool>();
/// <summary>
/// Maximizes the window. This will also show (but not focus) the window if it isnt being displayed already.
@@ -362,7 +372,7 @@ public class BrowserWindow : ApiBase
/// Whether the window is maximized.
/// </summary>
/// <returns></returns>
public Task<bool> IsMaximizedAsync() => this.GetPropertyAsync<bool>();
public Task<bool> IsMaximizedAsync() => this.InvokeAsync<bool>();
/// <summary>
/// Minimizes the window. On some platforms the minimized window will be shown in the Dock.
@@ -378,7 +388,7 @@ public class BrowserWindow : ApiBase
/// Whether the window is minimized.
/// </summary>
/// <returns></returns>
public Task<bool> IsMinimizedAsync() => this.GetPropertyAsync<bool>();
public Task<bool> IsMinimizedAsync() => this.InvokeAsync<bool>();
/// <summary>
/// Sets whether the window should be in fullscreen mode.
@@ -390,10 +400,10 @@ public class BrowserWindow : ApiBase
/// Whether the window is in fullscreen mode.
/// </summary>
/// <returns></returns>
public Task<bool> IsFullScreenAsync() => this.GetPropertyAsync<bool>();
public Task<bool> IsFullScreenAsync() => this.InvokeAsync<bool>();
/// <summary>
/// This will make a window maintain an aspect ratio. The extra size allows a developer to have space,
/// This will make a window maintain an aspect ratio. The extra size allows a developer to have space,
/// specified in pixels, not included within the aspect ratio calculations. This API already takes into
/// account the difference between a windows size and its content size.
///
@@ -401,7 +411,7 @@ public class BrowserWindow : ApiBase
/// of controls on the left edge, 25 pixels of controls on the right edge and 50 pixels of controls below
/// the player. In order to maintain a 16:9 aspect ratio (standard aspect ratio for HD @1920x1080) within
/// the player itself we would call this function with arguments of 16/9 and[40, 50]. The second argument
/// doesnt care where the extra width and height are within the content viewonly that they exist. Just
/// doesnt care where the extra width and height are within the content viewonly that they exist. Just
/// sum any extra width and height areas you have within the overall content view.
/// </summary>
/// <param name="aspectRatio">The aspect ratio to maintain for some portion of the content view.</param>
@@ -410,7 +420,7 @@ public class BrowserWindow : ApiBase
this.CallMethod2(aspectRatio, extraSize);
/// <summary>
/// This will make a window maintain an aspect ratio. The extra size allows a developer to have space,
/// This will make a window maintain an aspect ratio. The extra size allows a developer to have space,
/// specified in pixels, not included within the aspect ratio calculations. This API already takes into
/// account the difference between a windows size and its content size.
///
@@ -418,7 +428,7 @@ public class BrowserWindow : ApiBase
/// of controls on the left edge, 25 pixels of controls on the right edge and 50 pixels of controls below
/// the player. In order to maintain a 16:9 aspect ratio (standard aspect ratio for HD @1920x1080) within
/// the player itself we would call this function with arguments of 16/9 and[40, 50]. The second argument
/// doesnt care where the extra width and height are within the content viewonly that they exist. Just
/// doesnt care where the extra width and height are within the content viewonly that they exist. Just
/// sum any extra width and height areas you have within the overall content view.
/// </summary>
/// <param name="aspectRatio">The aspect ratio to maintain for some portion of the content view.</param>
@@ -429,24 +439,27 @@ public class BrowserWindow : ApiBase
/// <summary>
/// Uses Quick Look to preview a file at a given path.
/// </summary>
/// <param name="path">The absolute path to the file to preview with QuickLook. This is important as
/// Quick Look uses the file name and file extension on the path to determine the content type of the
/// <param name="path">The absolute path to the file to preview with QuickLook. This is important as
/// Quick Look uses the file name and file extension on the path to determine the content type of the
/// file to open.</param>
[SupportedOSPlatform("macOS")]
public void PreviewFile(string path) => this.CallMethod1(path);
/// <summary>
/// Uses Quick Look to preview a file at a given path.
/// </summary>
/// <param name="path">The absolute path to the file to preview with QuickLook. This is important as
/// Quick Look uses the file name and file extension on the path to determine the content type of the
/// <param name="path">The absolute path to the file to preview with QuickLook. This is important as
/// Quick Look uses the file name and file extension on the path to determine the content type of the
/// file to open.</param>
/// <param name="displayname">The name of the file to display on the Quick Look modal view. This is
/// <param name="displayname">The name of the file to display on the Quick Look modal view. This is
/// purely visual and does not affect the content type of the file. Defaults to path.</param>
[SupportedOSPlatform("macOS")]
public void PreviewFile(string path, string displayname) => this.CallMethod2(path, displayname);
/// <summary>
/// Closes the currently open Quick Look panel.
/// </summary>
[SupportedOSPlatform("macOS")]
public void CloseFilePreview() => this.CallMethod0();
/// <summary>
@@ -466,7 +479,7 @@ public class BrowserWindow : ApiBase
/// Gets the bounds asynchronous.
/// </summary>
/// <returns></returns>
public Task<Rectangle> GetBoundsAsync() => this.GetPropertyAsync<Rectangle>();
public Task<Rectangle> GetBoundsAsync() => this.InvokeAsync<Rectangle>();
/// <summary>
/// Resizes and moves the windows client area (e.g. the web page) to the supplied bounds.
@@ -485,7 +498,7 @@ public class BrowserWindow : ApiBase
/// Gets the content bounds asynchronous.
/// </summary>
/// <returns></returns>
public Task<Rectangle> GetContentBoundsAsync() => this.GetPropertyAsync<Rectangle>();
public Task<Rectangle> GetContentBoundsAsync() => this.InvokeAsync<Rectangle>();
/// <summary>
/// Resizes the window to width and height.
@@ -506,7 +519,7 @@ public class BrowserWindow : ApiBase
/// Contains the windows width and height.
/// </summary>
/// <returns></returns>
public Task<int[]> GetSizeAsync() => this.GetPropertyAsync<int[]>();
public Task<int[]> GetSizeAsync() => this.InvokeAsync<int[]>();
/// <summary>
/// Resizes the windows client area (e.g. the web page) to width and height.
@@ -527,7 +540,7 @@ public class BrowserWindow : ApiBase
/// Contains the windows client areas width and height.
/// </summary>
/// <returns></returns>
public Task<int[]> GetContentSizeAsync() => this.GetPropertyAsync<int[]>();
public Task<int[]> GetContentSizeAsync() => this.InvokeAsync<int[]>();
/// <summary>
/// Sets the minimum size of window to width and height.
@@ -540,7 +553,7 @@ public class BrowserWindow : ApiBase
/// Contains the windows minimum width and height.
/// </summary>
/// <returns></returns>
public Task<int[]> GetMinimumSizeAsync() => this.GetPropertyAsync<int[]>();
public Task<int[]> GetMinimumSizeAsync() => this.InvokeAsync<int[]>();
/// <summary>
/// Sets the maximum size of window to width and height.
@@ -553,7 +566,7 @@ public class BrowserWindow : ApiBase
/// Contains the windows maximum width and height.
/// </summary>
/// <returns></returns>
public Task<int[]> GetMaximumSizeAsync() => this.GetPropertyAsync<int[]>();
public Task<int[]> GetMaximumSizeAsync() => this.InvokeAsync<int[]>();
/// <summary>
/// Sets whether the window can be manually resized by user.
@@ -565,12 +578,14 @@ public class BrowserWindow : ApiBase
/// Whether the window can be manually resized by user.
/// </summary>
/// <returns></returns>
public Task<bool> IsResizableAsync() => this.GetPropertyAsync<bool>();
public Task<bool> IsResizableAsync() => this.InvokeAsync<bool>();
/// <summary>
/// Sets whether the window can be moved by user. On Linux does nothing.
/// </summary>
/// <param name="movable"></param>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public void SetMovable(bool movable) => this.CallMethod1(movable);
/// <summary>
@@ -579,12 +594,16 @@ public class BrowserWindow : ApiBase
/// On Linux always returns true.
/// </summary>
/// <returns>On Linux always returns true.</returns>
public Task<bool> IsMovableAsync() => this.GetPropertyAsync<bool>();
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public Task<bool> IsMovableAsync() => this.InvokeAsync<bool>();
/// <summary>
/// Sets whether the window can be manually minimized by user. On Linux does nothing.
/// </summary>
/// <param name="minimizable"></param>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public void SetMinimizable(bool minimizable) => this.CallMethod1(minimizable);
/// <summary>
@@ -593,12 +612,16 @@ public class BrowserWindow : ApiBase
/// On Linux always returns true.
/// </summary>
/// <returns>On Linux always returns true.</returns>
public Task<bool> IsMinimizableAsync() => this.GetPropertyAsync<bool>();
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public Task<bool> IsMinimizableAsync() => this.InvokeAsync<bool>();
/// <summary>
/// Sets whether the window can be manually maximized by user. On Linux does nothing.
/// </summary>
/// <param name="maximizable"></param>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public void SetMaximizable(bool maximizable) => this.CallMethod1(maximizable);
/// <summary>
@@ -607,7 +630,9 @@ public class BrowserWindow : ApiBase
/// On Linux always returns true.
/// </summary>
/// <returns>On Linux always returns true.</returns>
public Task<bool> IsMaximizableAsync() => this.GetPropertyAsync<bool>();
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public Task<bool> IsMaximizableAsync() => this.InvokeAsync<bool>();
/// <summary>
/// Sets whether the maximize/zoom window button toggles fullscreen mode or maximizes the window.
@@ -619,12 +644,14 @@ public class BrowserWindow : ApiBase
/// Whether the maximize/zoom window button toggles fullscreen mode or maximizes the window.
/// </summary>
/// <returns></returns>
public Task<bool> IsFullScreenableAsync() => this.GetPropertyAsync<bool>();
public Task<bool> IsFullScreenableAsync() => this.InvokeAsync<bool>();
/// <summary>
/// Sets whether the window can be manually closed by user. On Linux does nothing.
/// </summary>
/// <param name="closable"></param>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public void SetClosable(bool closable) => this.CallMethod1(closable);
/// <summary>
@@ -633,37 +660,39 @@ public class BrowserWindow : ApiBase
/// On Linux always returns true.
/// </summary>
/// <returns>On Linux always returns true.</returns>
public Task<bool> IsClosableAsync() => this.GetPropertyAsync<bool>();
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public Task<bool> IsClosableAsync() => this.InvokeAsync<bool>();
/// <summary>
/// Sets whether the window should show always on top of other windows.
/// After setting this, the window is still a normal window, not a toolbox
/// Sets whether the window should show always on top of other windows.
/// After setting this, the window is still a normal window, not a toolbox
/// window which can not be focused on.
/// </summary>
/// <param name="flag"></param>
public void SetAlwaysOnTop(bool flag) => this.CallMethod1(flag);
/// <summary>
/// Sets whether the window should show always on top of other windows.
/// After setting this, the window is still a normal window, not a toolbox
/// Sets whether the window should show always on top of other windows.
/// After setting this, the window is still a normal window, not a toolbox
/// window which can not be focused on.
/// </summary>
/// <param name="flag"></param>
/// <param name="level">Values include normal, floating, torn-off-menu, modal-panel, main-menu,
/// status, pop-up-menu and screen-saver. The default is floating.
/// <param name="level">Values include normal, floating, torn-off-menu, modal-panel, main-menu,
/// status, pop-up-menu and screen-saver. The default is floating.
/// See the macOS docs</param>
public void SetAlwaysOnTop(bool flag, OnTopLevel level) => this.CallMethod2(flag, level.GetDescription());
/// <summary>
/// Sets whether the window should show always on top of other windows.
/// After setting this, the window is still a normal window, not a toolbox
/// Sets whether the window should show always on top of other windows.
/// After setting this, the window is still a normal window, not a toolbox
/// window which can not be focused on.
/// </summary>
/// <param name="flag"></param>
/// <param name="level">Values include normal, floating, torn-off-menu, modal-panel, main-menu,
/// status, pop-up-menu and screen-saver. The default is floating.
/// <param name="level">Values include normal, floating, torn-off-menu, modal-panel, main-menu,
/// status, pop-up-menu and screen-saver. The default is floating.
/// See the macOS docs</param>
/// <param name="relativeLevel">The number of layers higher to set this window relative to the given level.
/// <param name="relativeLevel">The number of layers higher to set this window relative to the given level.
/// The default is 0. Note that Apple discourages setting levels higher than 1 above screen-saver.</param>
public void SetAlwaysOnTop(bool flag, OnTopLevel level, int relativeLevel) => this.CallMethod3(flag, level.GetDescription(), relativeLevel);
@@ -671,7 +700,7 @@ public class BrowserWindow : ApiBase
/// Whether the window is always on top of other windows.
/// </summary>
/// <returns></returns>
public Task<bool> IsAlwaysOnTopAsync() => this.GetPropertyAsync<bool>();
public Task<bool> IsAlwaysOnTopAsync() => this.InvokeAsync<bool>();
/// <summary>
/// Moves window to the center of the screen.
@@ -721,7 +750,7 @@ public class BrowserWindow : ApiBase
/// Contains the windows current position.
/// </summary>
/// <returns></returns>
public Task<int[]> GetPositionAsync() => this.GetPropertyAsync<int[]>();
public Task<int[]> GetPositionAsync() => this.InvokeAsync<int[]>();
/// <summary>
/// Changes the title of native window to title.
@@ -735,23 +764,25 @@ public class BrowserWindow : ApiBase
/// Note: The title of web page can be different from the title of the native window.
/// </summary>
/// <returns></returns>
public Task<string> GetTitleAsync() => this.GetPropertyAsync<string>();
public Task<string> GetTitleAsync() => this.InvokeAsync<string>();
/// <summary>
/// Changes the attachment point for sheets on macOS.
/// By default, sheets are attached just below the window frame,
/// Changes the attachment point for sheets on macOS.
/// By default, sheets are attached just below the window frame,
/// but you may want to display them beneath a HTML-rendered toolbar.
/// </summary>
/// <param name="offsetY"></param>
[SupportedOSPlatform("macOS")]
public void SetSheetOffset(float offsetY) => this.CallMethod1(offsetY);
/// <summary>
/// Changes the attachment point for sheets on macOS.
/// By default, sheets are attached just below the window frame,
/// Changes the attachment point for sheets on macOS.
/// By default, sheets are attached just below the window frame,
/// but you may want to display them beneath a HTML-rendered toolbar.
/// </summary>
/// <param name="offsetY"></param>
/// <param name="offsetX"></param>
[SupportedOSPlatform("macOS")]
public void SetSheetOffset(float offsetY, float offsetX) => this.CallMethod2(offsetY, offsetX);
/// <summary>
@@ -764,6 +795,8 @@ public class BrowserWindow : ApiBase
/// Makes the window not show in the taskbar.
/// </summary>
/// <param name="skip"></param>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public void SetSkipTaskbar(bool skip) => this.CallMethod1(skip);
/// <summary>
@@ -776,39 +809,43 @@ public class BrowserWindow : ApiBase
/// Whether the window is in kiosk mode.
/// </summary>
/// <returns></returns>
public Task<bool> IsKioskAsync() => this.GetPropertyAsync<bool>();
public Task<bool> IsKioskAsync() => this.InvokeAsync<bool>();
/// <summary>
/// Returns the native type of the handle is HWND on Windows, NSView* on macOS, and Window (unsigned long) on Linux.
/// </summary>
/// <returns>string of the native handle obtained, HWND on Windows, NSView* on macOS, and Window (unsigned long) on Linux.</returns>
public Task<string> GetNativeWindowHandle() => this.GetPropertyAsync<string>();
public Task<string> GetNativeWindowHandle() => this.InvokeAsync<string>();
/// <summary>
/// Sets the pathname of the file the window represents,
/// Sets the pathname of the file the window represents,
/// and the icon of the file will show in windows title bar.
/// </summary>
/// <param name="filename"></param>
[SupportedOSPlatform("macOS")]
public void SetRepresentedFilename(string filename) => this.CallMethod1(filename);
/// <summary>
/// The pathname of the file the window represents.
/// </summary>
/// <returns></returns>
public Task<string> GetRepresentedFilenameAsync() => this.GetPropertyAsync<string>();
[SupportedOSPlatform("macOS")]
public Task<string> GetRepresentedFilenameAsync() => this.InvokeAsync<string>();
/// <summary>
/// Specifies whether the windows document has been edited,
/// Specifies whether the windows document has been edited,
/// and the icon in title bar will become gray when set to true.
/// </summary>
/// <param name="edited"></param>
[SupportedOSPlatform("macOS")]
public void SetDocumentEdited(bool edited) => this.CallMethod1(edited);
/// <summary>
/// Whether the windows document has been edited.
/// </summary>
/// <returns></returns>
public Task<bool> IsDocumentEditedAsync() => this.GetPropertyAsync<bool>();
[SupportedOSPlatform("macOS")]
public Task<bool> IsDocumentEditedAsync() => this.InvokeAsync<bool>();
/// <summary>
/// Focuses the on web view.
@@ -821,14 +858,14 @@ public class BrowserWindow : ApiBase
public void BlurWebView() => this.CallMethod0();
/// <summary>
/// The url can be a remote address (e.g. http://) or
/// The url can be a remote address (e.g. http://) or
/// a path to a local HTML file using the file:// protocol.
/// </summary>
/// <param name="url"></param>
public void LoadURL(string url) => this.CallMethod1(url);
/// <summary>
/// The url can be a remote address (e.g. http://) or
/// The url can be a remote address (e.g. http://) or
/// a path to a local HTML file using the file:// protocol.
/// </summary>
/// <param name="url"></param>
@@ -857,10 +894,12 @@ public class BrowserWindow : ApiBase
private List<MenuItem> _items = new List<MenuItem>();
/// <summary>
/// Sets the menu as the windows menu bar,
/// Sets the menu as the windows menu bar,
/// setting it to null will remove the menu bar.
/// </summary>
/// <param name="menuItems"></param>
[SupportedOSPlatform("Linux")]
[SupportedOSPlatform("Windows")]
public void SetMenu(MenuItem[] menuItems)
{
menuItems.AddMenuItemsId();
@@ -878,6 +917,8 @@ public class BrowserWindow : ApiBase
/// <summary>
/// Remove the window's menu bar.
/// </summary>
[SupportedOSPlatform("Linux")]
[SupportedOSPlatform("Windows")]
public void RemoveMenu() => this.CallMethod0();
/// <summary>
@@ -920,7 +961,7 @@ public class BrowserWindow : ApiBase
/// On Windows and Linux always returns true.
/// </summary>
/// <returns></returns>
public Task<bool> HasShadowAsync() => this.GetPropertyAsync<bool>();
public Task<bool> HasShadowAsync() => this.InvokeAsync<bool>();
/// <summary>
/// Gets the thumbar buttons.
@@ -939,17 +980,18 @@ public class BrowserWindow : ApiBase
private List<ThumbarButton> _thumbarButtons = new List<ThumbarButton>();
/// <summary>
/// Add a thumbnail toolbar with a specified set of buttons to the thumbnail
/// image of a window in a taskbar button layout. Returns a Boolean object
/// Add a thumbnail toolbar with a specified set of buttons to the thumbnail
/// image of a window in a taskbar button layout. Returns a Boolean object
/// indicates whether the thumbnail has been added successfully.
///
/// The number of buttons in thumbnail toolbar should be no greater than 7 due
/// The number of buttons in thumbnail toolbar should be no greater than 7 due
/// to the limited room.Once you setup the thumbnail toolbar, the toolbar cannot
/// be removed due to the platforms limitation.But you can call the API with an
/// empty array to clean the buttons.
/// </summary>
/// <param name="thumbarButtons"></param>
/// <returns>Whether the buttons were added successfully.</returns>
[SupportedOSPlatform("Windows")]
public Task<bool> SetThumbarButtonsAsync(ThumbarButton[] thumbarButtons)
{
var tcs = new TaskCompletionSource<bool>();
@@ -977,55 +1019,67 @@ public class BrowserWindow : ApiBase
/// an empty region: {x: 0, y: 0, width: 0, height: 0}.
/// </summary>
/// <param name="rectangle"></param>
[SupportedOSPlatform("Windows")]
public void SetThumbnailClip(Rectangle rectangle) => this.CallMethod1(rectangle);
/// <summary>
/// Sets the toolTip that is displayed when hovering over the window thumbnail in the taskbar.
/// </summary>
/// <param name="tooltip"></param>
[SupportedOSPlatform("Windows")]
public void SetThumbnailToolTip(string tooltip) => this.CallMethod1(tooltip);
/// <summary>
/// Sets the properties for the windows taskbar button.
///
/// Note: relaunchCommand and relaunchDisplayName must always be set together.
/// Note: relaunchCommand and relaunchDisplayName must always be set together.
/// If one of those properties is not set, then neither will be used.
/// </summary>
/// <param name="options"></param>
[SupportedOSPlatform("Windows")]
public void SetAppDetails(AppDetailsOptions options) => this.CallMethod1(options);
/// <summary>
/// Same as webContents.showDefinitionForSelection().
/// </summary>
[SupportedOSPlatform("macOS")]
public void ShowDefinitionForSelection() => this.CallMethod0();
/// <summary>
/// Sets whether the window menu bar should hide itself automatically.
/// Sets whether the window menu bar should hide itself automatically.
/// Once set the menu bar will only show when users press the single Alt key.
///
/// If the menu bar is already visible, calling setAutoHideMenuBar(true) wont hide it immediately.
/// </summary>
/// <param name="hide"></param>
[SupportedOSPlatform("Linux")]
[SupportedOSPlatform("Windows")]
public void SetAutoHideMenuBar(bool hide) => this.CallMethod1(hide);
/// <summary>
/// Whether menu bar automatically hides itself.
/// </summary>
/// <returns></returns>
public Task<bool> IsMenuBarAutoHideAsync() => this.GetPropertyAsync<bool>();
[SupportedOSPlatform("Linux")]
[SupportedOSPlatform("Windows")]
public Task<bool> IsMenuBarAutoHideAsync() => this.InvokeAsync<bool>();
/// <summary>
/// Sets whether the menu bar should be visible. If the menu bar is auto-hide,
/// users can still bring up the menu bar by pressing the single Alt key.
/// </summary>
/// <param name="visible"></param>
[SupportedOSPlatform("Linux")]
[SupportedOSPlatform("Windows")]
public void SetMenuBarVisibility(bool visible) => this.CallMethod1(visible);
/// <summary>
/// Whether the menu bar is visible.
/// </summary>
/// <returns></returns>
public Task<bool> IsMenuBarVisibleAsync() => this.GetPropertyAsync<bool>();
[SupportedOSPlatform("Linux")]
[SupportedOSPlatform("Windows")]
public Task<bool> IsMenuBarVisibleAsync() => this.InvokeAsync<bool>();
/// <summary>
/// Sets whether the window should be visible on all workspaces.
@@ -1033,6 +1087,8 @@ public class BrowserWindow : ApiBase
/// Note: This API does nothing on Windows.
/// </summary>
/// <param name="visible"></param>
[SupportedOSPlatform("Linux")]
[SupportedOSPlatform("macOS")]
public void SetVisibleOnAllWorkspaces(bool visible) => this.CallMethod1(visible);
/// <summary>
@@ -1041,12 +1097,14 @@ public class BrowserWindow : ApiBase
/// Note: This API always returns false on Windows.
/// </summary>
/// <returns></returns>
public Task<bool> IsVisibleOnAllWorkspacesAsync() => this.GetPropertyAsync<bool>();
[SupportedOSPlatform("Linux")]
[SupportedOSPlatform("macOS")]
public Task<bool> IsVisibleOnAllWorkspacesAsync() => this.InvokeAsync<bool>();
/// <summary>
/// Makes the window ignore all mouse events.
///
/// All mouse events happened in this window will be passed to the window
/// All mouse events happened in this window will be passed to the window
/// below this window, but if this window has focus, it will still receive keyboard events.
/// </summary>
/// <param name="ignore"></param>
@@ -1055,20 +1113,24 @@ public class BrowserWindow : ApiBase
/// <summary>
/// Prevents the window contents from being captured by other apps.
///
/// On macOS it sets the NSWindows sharingType to NSWindowSharingNone.
/// On macOS it sets the NSWindows sharingType to NSWindowSharingNone.
/// On Windows it calls SetWindowDisplayAffinity with WDA_MONITOR.
/// </summary>
/// <param name="enable"></param>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public void SetContentProtection(bool enable) => this.CallMethod1(enable);
/// <summary>
/// Changes whether the window can be focused.
/// </summary>
/// <param name="focusable"></param>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public void SetFocusable(bool focusable) => this.CallMethod1(focusable);
/// <summary>
/// Sets parent as current windows parent window,
/// Sets parent as current windows parent window,
/// passing null will turn current window into a top-level window.
/// </summary>
/// <param name="parent"></param>
@@ -1090,7 +1152,7 @@ public class BrowserWindow : ApiBase
/// <returns></returns>
public async Task<BrowserWindow> GetParentWindowAsync()
{
var browserWindowId = await this.GetPropertyAsync<int>().ConfigureAwait(false);
var browserWindowId = await this.InvokeAsync<int>().ConfigureAwait(false);
var browserWindow = Electron.WindowManager.BrowserWindows.ToList().Single(x => x.Id == browserWindowId);
return browserWindow;
}
@@ -1101,7 +1163,7 @@ public class BrowserWindow : ApiBase
/// <returns></returns>
public async Task<List<BrowserWindow>> GetChildWindowsAsync()
{
var browserWindowIds = await this.GetPropertyAsync<int[]>().ConfigureAwait(false);
var browserWindowIds = await this.InvokeAsync<int[]>().ConfigureAwait(false);
var browserWindows = new List<BrowserWindow>();
foreach (var id in browserWindowIds)
@@ -1117,15 +1179,17 @@ public class BrowserWindow : ApiBase
/// Controls whether to hide cursor when typing.
/// </summary>
/// <param name="autoHide"></param>
[SupportedOSPlatform("macOS")]
public void SetAutoHideCursor(bool autoHide) => this.CallMethod1(autoHide);
/// <summary>
/// Adds a vibrancy effect to the browser window.
/// Adds a vibrancy effect to the browser window.
/// Passing null or an empty string will remove the vibrancy effect on the window.
/// </summary>
/// <param name="type">Can be appearance-based, light, dark, titlebar, selection,
/// menu, popover, sidebar, medium-light or ultra-dark.
/// <param name="type">Can be appearance-based, light, dark, titlebar, selection,
/// menu, popover, sidebar, medium-light or ultra-dark.
/// See the macOS documentation for more details.</param>
[SupportedOSPlatform("macOS")]
public void SetVibrancy(Vibrancy type) => this.CallMethod1(type.GetDescription());
/// <summary>
@@ -1134,8 +1198,8 @@ public class BrowserWindow : ApiBase
public WebContents WebContents { get; internal set; }
/// <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>
/// <param name="browserView"></param>
@@ -1144,4 +1208,4 @@ public class BrowserWindow : ApiBase
// This message name does not match the default ApiBase naming convention.
BridgeConnector.Socket.Emit("browserWindow-setBrowserView", Id, browserView.Id);
}
}
}

View File

@@ -1,7 +1,9 @@
using ElectronNET.API.Entities;
using ElectronNET.API.Serialization;
using System.Runtime.Versioning;
using System.Text.Json;
using System.Threading.Tasks;
// ReSharper disable InconsistentNaming
namespace ElectronNET.API
@@ -9,7 +11,7 @@ namespace ElectronNET.API
/// <summary>
/// Perform copy and paste operations on the system clipboard.
/// </summary>
public sealed class Clipboard: ApiBase
public sealed class Clipboard : ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;
@@ -45,7 +47,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 = "") => GetPropertyAsync<string>(type);
public Task<string> ReadTextAsync(string type = "") => this.InvokeAsync<string>(type);
/// <summary>
/// Writes the text into the clipboard as plain text.
@@ -62,7 +64,7 @@ namespace ElectronNET.API
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public Task<string> ReadHTMLAsync(string type = "") => GetPropertyAsync<string>(type);
public Task<string> ReadHTMLAsync(string type = "") => this.InvokeAsync<string>(type);
/// <summary>
/// Writes markup to the clipboard.
@@ -79,7 +81,7 @@ namespace ElectronNET.API
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public Task<string> ReadRTFAsync(string type = "") => GetPropertyAsync<string>(type);
public Task<string> ReadRTFAsync(string type = "") => this.InvokeAsync<string>(type);
/// <summary>
/// Writes the text into the clipboard in RTF.
@@ -92,23 +94,27 @@ namespace ElectronNET.API
}
/// <summary>
/// Returns an Object containing title and url keys representing
/// the bookmark in the clipboard. The title and url values will
/// Returns an Object containing title and url keys representing
/// the bookmark in the clipboard. The title and url values will
/// be empty strings when the bookmark is unavailable.
/// </summary>
/// <returns></returns>
public Task<ReadBookmark> ReadBookmarkAsync() => GetPropertyAsync<ReadBookmark>();
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public Task<ReadBookmark> ReadBookmarkAsync() => this.InvokeAsync<ReadBookmark>();
/// <summary>
/// Writes the title and url into the clipboard as a bookmark.
///
/// Note: Most apps on Windows dont support pasting bookmarks
/// into them so you can use clipboard.write to write both a
/// into them so you can use clipboard.write to write both a
/// bookmark and fallback text to the clipboard.
/// </summary>
/// <param name="title"></param>
/// <param name="url"></param>
/// <param name="type"></param>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public void WriteBookmark(string title, string url, string type = "")
{
BridgeConnector.Socket.Emit("clipboard-writeBookmark", title, url, type);
@@ -120,13 +126,15 @@ namespace ElectronNET.API
/// find pasteboard whenever the application is activated.
/// </summary>
/// <returns></returns>
public Task<string> ReadFindTextAsync() => GetPropertyAsync<string>();
[SupportedOSPlatform("macOS")]
public Task<string> ReadFindTextAsync() => this.InvokeAsync<string>();
/// <summary>
/// macOS: Writes the text into the find pasteboard as plain text. This method uses
/// macOS: Writes the text into the find pasteboard as plain text. This method uses
/// synchronous IPC when called from the renderer process.
/// </summary>
/// <param name="text"></param>
[SupportedOSPlatform("macOS")]
public void WriteFindText(string text)
{
BridgeConnector.Socket.Emit("clipboard-writeFindText", text);
@@ -146,7 +154,7 @@ namespace ElectronNET.API
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public Task<string[]> AvailableFormatsAsync(string type = "") => GetPropertyAsync<string[]>(type);
public Task<string[]> AvailableFormatsAsync(string type = "") => this.InvokeAsync<string[]>(type);
/// <summary>
/// Writes data to the clipboard.
@@ -163,7 +171,7 @@ namespace ElectronNET.API
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public Task<NativeImage> ReadImageAsync(string type = "") => GetPropertyAsync<NativeImage>(type);
public Task<NativeImage> ReadImageAsync(string type = "") => this.InvokeAsync<NativeImage>(type);
/// <summary>
/// Writes an image to the clipboard.
@@ -175,4 +183,4 @@ namespace ElectronNET.API
BridgeConnector.Socket.Emit("clipboard-writeImage", JsonSerializer.Serialize(image, ElectronJson.Options), type);
}
}
}
}

View File

@@ -59,7 +59,5 @@ namespace ElectronNET.API
}
private event Action<Cookie, CookieChangedCause, bool> _changed;
}
}
}

View File

@@ -1,5 +1,6 @@
using ElectronNET.API.Entities;
using System;
using System.Runtime.Versioning;
using System.Text.Json;
using System.Threading.Tasks;
@@ -37,8 +38,8 @@ namespace ElectronNET.API
}
/// <summary>
/// Note: On Windows and Linux an open dialog can not be both a file selector
/// and a directory selector, so if you set properties to ['openFile', 'openDirectory']
/// Note: On Windows and Linux an open dialog can not be both a file selector
/// and a directory selector, so if you set properties to ['openFile', 'openDirectory']
/// on these platforms, a directory selector will be shown.
/// </summary>
/// <param name="browserWindow">The browserWindow argument allows the dialog to attach itself to a parent window, making it modal.</param>
@@ -50,9 +51,9 @@ namespace ElectronNET.API
var guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.Once<string[]>("showOpenDialogComplete" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("showOpenDialog",
browserWindow,
options,
BridgeConnector.Socket.Emit("showOpenDialog",
browserWindow,
options,
guid);
return tcs.Task;
@@ -167,9 +168,9 @@ namespace ElectronNET.API
/// <summary>
/// Displays a modal dialog that shows an error message.
///
/// This API can be called safely before the ready event the app module emits,
/// it is usually used to report errors in early stage of startup.If called
/// before the app readyevent on Linux, the message will be emitted to stderr,
/// This API can be called safely before the ready event the app module emits,
/// it is usually used to report errors in early stage of startup.If called
/// before the app readyevent on Linux, the message will be emitted to stderr,
/// and no GUI dialog will appear.
/// </summary>
/// <param name="title">The title to display in the error box.</param>
@@ -181,11 +182,13 @@ namespace ElectronNET.API
/// <summary>
/// On macOS, this displays a modal dialog that shows a message and certificate information,
/// and gives the user the option of trusting/importing the certificate. If you provide a
/// and gives the user the option of trusting/importing the certificate. If you provide a
/// browserWindow argument the dialog will be attached to the parent window, making it modal.
/// </summary>
/// <param name="options"></param>
/// <returns></returns>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public Task ShowCertificateTrustDialogAsync(CertificateTrustDialogOptions options)
{
return ShowCertificateTrustDialogAsync(null, options);
@@ -193,12 +196,14 @@ namespace ElectronNET.API
/// <summary>
/// On macOS, this displays a modal dialog that shows a message and certificate information,
/// and gives the user the option of trusting/importing the certificate. If you provide a
/// and gives the user the option of trusting/importing the certificate. If you provide a
/// browserWindow argument the dialog will be attached to the parent window, making it modal.
/// </summary>
/// <param name="browserWindow"></param>
/// <param name="options"></param>
/// <returns></returns>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public Task ShowCertificateTrustDialogAsync(BrowserWindow browserWindow, CertificateTrustDialogOptions options)
{
var tcs = new TaskCompletionSource<object>();
@@ -212,7 +217,5 @@ namespace ElectronNET.API
return tcs.Task;
}
}
}
}

View File

@@ -1,16 +1,16 @@
using ElectronNET.API.Entities;
using ElectronNET.API.Extensions;
using ElectronNET.API.Serialization;
using System.Collections.Generic;
using System.Text.Json;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
using ElectronNET.API.Entities;
using ElectronNET.API.Extensions;
namespace ElectronNET.API
{
/// <summary>
/// Control your app in the macOS dock.
/// </summary>
[SupportedOSPlatform("macOS")]
public sealed class Dock
{
private static Dock _dock;
@@ -208,7 +208,5 @@ namespace ElectronNET.API
{
BridgeConnector.Socket.Emit("dock-setIcon", image);
}
}
}
}

View File

@@ -140,7 +140,7 @@
/// <summary>
/// Allows you to execute native JavaScript/TypeScript code from the host process.
///
/// It is only possible if the Electron.NET CLI has previously added an
/// It is only possible if the Electron.NET CLI has previously added an
/// ElectronHostHook directory:
/// <c>electronize add HostHook</c>
/// </summary>
@@ -153,7 +153,7 @@
}
/// <summary>
/// Allows you to execute native Lock and Unlock process.
/// Allows you to execute native Lock and Unlock process.
/// </summary>
public static PowerMonitor PowerMonitor
{

View File

@@ -35,4 +35,4 @@ namespace ElectronNET.API.Entities
[DefaultValue(false)]
public bool Vertical { get; set; } = false;
}
}
}

View File

@@ -10,4 +10,4 @@
/// </summary>
public float ScaleFactor { get; set; } = 1.0f;
}
}
}

View File

@@ -28,4 +28,4 @@
/// </summary>
public bool IsAdminRightsRequired { get; set; }
}
}
}

View File

@@ -22,4 +22,4 @@
/// </summary>
public string ProxyCredentials { get; set; }
}
}
}

View File

@@ -1,5 +1,4 @@
using ElectronNET.Converter;
using System.ComponentModel;
using System.Text.Json.Serialization;
@@ -126,6 +125,11 @@ namespace ElectronNET.API.Entities
/// </summary>
public bool SkipTaskbar { get; set; }
/// <summary>
/// Determines if Blazor is used. Will disable "module" and "process" globals. Default is false.
/// </summary>
public bool IsRunningBlazor { get; set; }
/// <summary>
/// The kiosk mode. Default is false.
/// </summary>
@@ -291,8 +295,4 @@ namespace ElectronNET.API.Entities
/// </summary>
public string ProxyCredentials { get; set; }
}
}
}

View File

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

View File

@@ -26,4 +26,4 @@
/// </summary>
public string Version { get; set; }
}
}
}

View File

@@ -21,4 +21,4 @@
/// </summary>
public string[] Quotas { get; set; }
}
}
}

View File

@@ -1,10 +1,9 @@
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
{
/// <summary>
/// The cause of the change
/// The cause of the change
/// </summary>
public enum CookieChangedCause
{
@@ -35,4 +34,4 @@ namespace ElectronNET.API.Entities
[JsonPropertyName("expired_overwrite")]
expiredOverwrite
}
}
}

View File

@@ -49,7 +49,7 @@ namespace ElectronNET.API.Entities
public bool HttpOnly { get; set; }
/// <summary>
/// (optional) - The expiration date of the cookie as the number of seconds since the UNIX epoch.
/// (optional) - The expiration date of the cookie as the number of seconds since the UNIX epoch.
/// If omitted then the cookie becomes a session cookie and will not be retained between sessions.
/// </summary>
[DefaultValue(0)]

View File

@@ -20,4 +20,4 @@
/// </summary>
public float ScaleFactor { get; set; } = 1.0f;
}
}
}

View File

@@ -64,4 +64,4 @@
ETag = eTag;
}
}
}
}

View File

@@ -25,4 +25,4 @@
/// </summary>
public int UploadThroughput { get; set; }
}
}
}

View File

@@ -35,4 +35,4 @@
/// </summary>
public string Version { get; set; }
}
}
}

View File

@@ -1,4 +1,3 @@
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities

View File

@@ -77,6 +77,4 @@ namespace ElectronNET.API.Entities
/// </summary>
public InputEventType Type { get; set; }
}
}
}

View File

@@ -1,4 +1,3 @@
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
@@ -23,5 +22,4 @@ namespace ElectronNET.API.Entities
/// </summary>
public JumpListCategoryType Type { get; set; }
}
}
}

View File

@@ -1,4 +1,3 @@
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
@@ -54,6 +53,4 @@ namespace ElectronNET.API.Entities
/// </summary>
public JumpListItemType Type { get; set; }
}
}
}

View File

@@ -11,7 +11,7 @@
public int WorkingSetSize { get; set; }
/// <summary>
/// The maximum amount of memory that has ever been pinned to actual physical RAM.
/// The maximum amount of memory that has ever been pinned to actual physical RAM.
/// </summary>
public int PeakWorkingSetSize { get; set; }

View File

@@ -9,7 +9,7 @@ namespace ElectronNET.API.Entities
public class MenuItem
{
/// <summary>
/// Will be called with click(menuItem, browserWindow, event) when the menu item is
/// Will be called with click(menuItem, browserWindow, event) when the menu item is
/// clicked.
/// </summary>
[JsonIgnore]
@@ -96,6 +96,4 @@ namespace ElectronNET.API.Entities
/// </summary>
public string Position { get; set; }
}
}
}

View File

@@ -1,4 +1,3 @@
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
@@ -97,6 +96,4 @@ namespace ElectronNET.API.Entities
Message = message;
}
}
}
}

View File

@@ -21,4 +21,4 @@
/// </value>
public bool CheckboxChecked { get; set; }
}
}
}

View File

@@ -35,5 +35,4 @@ namespace ElectronNET.API.Entities
return new NativeImage(newDictionary);
}
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Runtime.Versioning;
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
@@ -43,6 +44,8 @@ namespace ElectronNET.API.Entities
/// <summary>
/// The timeout duration of the notification. Can be 'default' or 'never'.
/// </summary>
[SupportedOSPlatform("Linux")]
[SupportedOSPlatform("Windows")]
public string TimeoutType { get; set; }
/// <summary>
@@ -58,6 +61,7 @@ namespace ElectronNET.API.Entities
/// <summary>
/// The urgency level of the notification. Can be 'normal', 'critical', or 'low'.
/// </summary>
[SupportedOSPlatform("Linux")]
public string Urgency { get; set; }
/// <summary>
@@ -127,6 +131,7 @@ namespace ElectronNET.API.Entities
/// The string the user entered into the inline reply field
/// </summary>
[JsonIgnore]
[SupportedOSPlatform("macOS")]
public Action<string> OnReply { get; set; }
/// <summary>
@@ -142,6 +147,7 @@ namespace ElectronNET.API.Entities
/// macOS only - The index of the action that was activated
/// </summary>
[JsonIgnore]
[SupportedOSPlatform("macOS")]
public Action<string> OnAction { get; set; }
/// <summary>
@@ -164,4 +170,4 @@ namespace ElectronNET.API.Entities
Body = body;
}
}
}
}

View File

@@ -15,4 +15,4 @@ public class OnDidFailLoadInfo
/// Validated URL.
/// </summary>
public string ValidatedUrl { get; set; }
}
}

View File

@@ -14,4 +14,4 @@ public class OnDidNavigateInfo
/// HTTP response code.
/// </summary>
public int HttpResponseCode { get; set; }
}
}

View File

@@ -1,4 +1,3 @@
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
@@ -15,5 +14,4 @@ namespace ElectronNET.API.Entities
/// </summary>
public DevToolsMode Mode { get; set; }
}
}
}

View File

@@ -1,4 +1,3 @@
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
@@ -41,7 +40,7 @@ namespace ElectronNET.API.Entities
public string Message { get; set; }
/// <summary>
/// The filters specifies an array of file types that can be displayed or
/// The filters specifies an array of file types that can be displayed or
/// selected when you want to limit the user to a specific type. For example:
/// </summary>
/// <example>
@@ -57,5 +56,4 @@ namespace ElectronNET.API.Entities
/// </example>
public FileFilter[] Filters { get; set; }
}
}
}

View File

@@ -17,4 +17,4 @@ public class PageSize
public static implicit operator string(PageSize pageSize) => pageSize?._value;
public static implicit operator PageSize(string value) => new(value);
}
}

View File

@@ -20,7 +20,7 @@ namespace ElectronNET.API.Entities
AppData,
/// <summary>
/// The directory for storing your apps configuration files,
/// The directory for storing your apps configuration files,
/// which by default it is the appData directory appended with your apps name.
/// </summary>
[Description("userData")]
@@ -92,4 +92,4 @@ namespace ElectronNET.API.Entities
[Description("PepperFlashSystemPlugin")]
PepperFlashSystemPlugin
}
}
}

View File

@@ -7,4 +7,4 @@ namespace ElectronNET.API.Entities
/// <param name="Electron">Value representing Electron's version string</param>
/// <returns></returns>
public record ProcessVersions(string Chrome, string Electron);
}
}

View File

@@ -1,4 +1,3 @@
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
@@ -13,5 +12,4 @@ namespace ElectronNET.API.Entities
/// </summary>
public ProgressBarMode Mode { get; set; }
}
}
}

View File

@@ -30,4 +30,4 @@
/// </summary>
public string Transferred { get; set; }
}
}
}

View File

@@ -33,4 +33,4 @@
ProxyBypassRules = proxyBypassRules;
}
}
}
}

View File

@@ -15,4 +15,4 @@
/// </summary>
public string Note { get; set; }
}
}
}

View File

@@ -1,4 +1,3 @@
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities
@@ -25,7 +24,7 @@ namespace ElectronNET.API.Entities
public string Realm { get; set; }
/// <summary>
/// Scheme of the authentication. Can be basic, digest, ntlm, negotiate.
/// Scheme of the authentication. Can be basic, digest, ntlm, negotiate.
/// Must be provided if removing by origin.
/// </summary>
public Scheme Scheme { get; set; }
@@ -49,6 +48,4 @@ namespace ElectronNET.API.Entities
Type = type;
}
}
}
}

View File

@@ -20,4 +20,4 @@
/// </summary>
public string Quality { get; set; } = "best";
}
}
}

View File

@@ -27,7 +27,7 @@ namespace ElectronNET.API
public string ButtonLabel { get; set; }
/// <summary>
/// The filters specifies an array of file types that can be displayed or
/// The filters specifies an array of file types that can be displayed or
/// selected when you want to limit the user to a specific type. For example:
/// </summary>
/// <example>

View File

@@ -25,4 +25,4 @@ namespace ElectronNET.API.Entities
[Description("replace")]
Replace
}
}
}

View File

@@ -56,5 +56,4 @@ namespace ElectronNET.API.Entities
Icon = icon;
}
}
}
}

View File

@@ -1,4 +1,3 @@
using System.Text.Json.Serialization;
namespace ElectronNET.API.Entities

View File

@@ -10,4 +10,4 @@
/// </summary>
public float ScaleFactor { get; set; } = 1.0f;
}
}
}

View File

@@ -10,4 +10,4 @@
/// </summary>
public float ScaleFactor { get; set; } = 1.0f;
}
}
}

View File

@@ -10,4 +10,4 @@
/// </summary>
public float ScaleFactor { get; set; } = 1.0f;
}
}
}

View File

@@ -20,4 +20,4 @@
/// </summary>
public UpdateCancellationToken CancellationToken { get; set; }
}
}
}

View File

@@ -10,4 +10,4 @@
/// </summary>
public string Url { get; set; }
}
}
}

View File

@@ -213,4 +213,4 @@ namespace ElectronNET.API.Entities
[DefaultValue(false)]
public bool EnableRemoteModule { get; set; } = false;
}
}
}

View File

@@ -36,4 +36,4 @@ namespace ElectronNET.API.Extensions
return result;
}
}
}
}

View File

@@ -39,10 +39,10 @@ namespace ElectronNET.API
private Dictionary<string, Action> _shortcuts = new Dictionary<string, Action>();
/// <summary>
/// Registers a global shortcut of accelerator.
/// Registers a global shortcut of accelerator.
/// The callback is called when the registered shortcut is pressed by the user.
///
/// When the accelerator is already taken by other applications, this call will
/// When the accelerator is already taken by other applications, this call will
/// silently fail.This behavior is intended by operating systems, since they dont
/// want applications to fight for global shortcuts.
/// </summary>
@@ -66,7 +66,7 @@ namespace ElectronNET.API
}
/// <summary>
/// When the accelerator is already taken by other applications,
/// When the accelerator is already taken by other applications,
/// this call will still return false. This behavior is intended by operating systems,
/// since they dont want applications to fight for global shortcuts.
/// </summary>

View File

@@ -8,7 +8,7 @@ namespace ElectronNET.API
/// <summary>
/// Allows you to execute native JavaScript/TypeScript code from the host process.
///
/// It is only possible if the Electron.NET CLI has previously added an
/// It is only possible if the Electron.NET CLI has previously added an
/// ElectronHostHook directory:
/// <c>electronize add HostHook</c>
/// </summary>
@@ -48,10 +48,7 @@ namespace ElectronNET.API
/// <param name="arguments">Optional parameters.</param>
public void Call(string socketEventName, params dynamic[] arguments)
{
BridgeConnector.Socket.Once<string>(socketEventName + "Error" + oneCallguid, (result) =>
{
Electron.Dialog.ShowErrorBox("Host Hook Exception", result);
});
BridgeConnector.Socket.Once<string>(socketEventName + "Error" + oneCallguid, (result) => { Electron.Dialog.ShowErrorBox("Host Hook Exception", result); });
BridgeConnector.Socket.Emit(socketEventName, arguments, oneCallguid);
}
@@ -95,7 +92,5 @@ namespace ElectronNET.API
return tcs.Task;
}
}
}
}

View File

@@ -39,7 +39,7 @@ namespace ElectronNET.API
}
/// <summary>
/// Listens to channel, when a new message arrives listener would be called with
/// Listens to channel, when a new message arrives listener would be called with
/// listener(event, args...).
/// </summary>
/// <param name="channel">Channelname.</param>
@@ -71,7 +71,7 @@ namespace ElectronNET.API
}
/// <summary>
/// Send a message to the renderer process synchronously via channel,
/// Send a message to the renderer process synchronously via channel,
/// you can also send arbitrary arguments.
///
/// Note: Sending a synchronous message will block the whole renderer process,
@@ -160,7 +160,5 @@ namespace ElectronNET.API
{
BridgeConnector.Socket.Emit("sendToIpcRendererBrowserView", browserView.Id, channel, data);
}
}
}
}

View File

@@ -129,7 +129,5 @@ namespace ElectronNET.API
{
BridgeConnector.Socket.Emit("menu-contextMenuPopup", browserWindow.Id);
}
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using ElectronNET.API.Entities;
using ElectronNET.API.Extensions;
@@ -8,7 +9,7 @@ namespace ElectronNET.API
/// <summary>
/// Read and respond to changes in Chromium's native color theme.
/// </summary>
public sealed class NativeTheme: ApiBase
public sealed class NativeTheme : ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;
@@ -59,7 +60,7 @@ namespace ElectronNET.API
/// </item>
/// <item>
/// <description>The 'updated' event will be emitted</description>
/// </item>
/// </item>
/// </list>
/// <para/>
/// Settings this property to <see cref="ThemeSourceMode.Light"/> will have the following effects:
@@ -79,7 +80,7 @@ namespace ElectronNET.API
/// <item>
/// <description>The 'updated' event will be emitted</description>
/// </item>
/// </list>
/// </list>
/// The usage of this property should align with a classic "dark mode" state machine in your application where the user has three options.
/// <para/>
/// <list type="bullet">
@@ -107,26 +108,30 @@ 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() => GetPropertyAsync<ThemeSourceMode>();
public Task<ThemeSourceMode> GetThemeSourceAsync() => this.InvokeAsync<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() => GetPropertyAsync<bool>();
public Task<bool> ShouldUseDarkColorsAsync() => this.InvokeAsync<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() => GetPropertyAsync<bool>();
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public Task<bool> ShouldUseHighContrastColorsAsync() => this.InvokeAsync<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() => GetPropertyAsync<bool>();
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public Task<bool> ShouldUseInvertedColorSchemeAsync() => this.InvokeAsync<bool>();
/// <summary>
/// Emitted when something in the underlying NativeTheme has changed. This normally means that either the value of <see cref="ShouldUseDarkColorsAsync"/>,
@@ -138,4 +143,4 @@ namespace ElectronNET.API
remove => RemoveEvent(value, GetHashCode());
}
}
}
}

View File

@@ -9,7 +9,7 @@ namespace ElectronNET.API
/// <summary>
/// Create OS desktop notifications
/// </summary>
public sealed class Notification: ApiBase
public sealed class Notification : ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.NoDashUpperFirst;
private static Notification _notification;
@@ -88,10 +88,7 @@ namespace ElectronNET.API
isActionDefined = true;
BridgeConnector.Socket.Off("NotificationEventReply");
BridgeConnector.Socket.On<string[]>("NotificationEventReply", (args) =>
{
_notificationOptions.Single(x => x.ReplyID == args[0]).OnReply(args[1]);
});
BridgeConnector.Socket.On<string[]>("NotificationEventReply", (args) => { _notificationOptions.Single(x => x.ReplyID == args[0]).OnReply(args[1]); });
}
if (notificationOptions.OnAction != null)
@@ -100,10 +97,7 @@ namespace ElectronNET.API
isActionDefined = true;
BridgeConnector.Socket.Off("NotificationEventAction");
BridgeConnector.Socket.On<string[]>("NotificationEventAction", (args) =>
{
_notificationOptions.Single(x => x.ActionID == args[0]).OnAction(args[1]);
});
BridgeConnector.Socket.On<string[]>("NotificationEventAction", (args) => { _notificationOptions.Single(x => x.ActionID == args[0]).OnAction(args[1]); });
}
if (isActionDefined)
@@ -116,6 +110,6 @@ namespace ElectronNET.API
/// Whether or not desktop notifications are supported on the current system.
/// </summary>
/// <returns></returns>
public Task<bool> IsSupportedAsync() => GetPropertyAsync<bool>();
public Task<bool> IsSupportedAsync() => this.InvokeAsync<bool>();
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Runtime.Versioning;
// ReSharper disable InconsistentNaming
@@ -7,14 +8,16 @@ namespace ElectronNET.API
/// <summary>
/// Monitor power state changes..
/// </summary>
public sealed class PowerMonitor: ApiBase
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.
/// Emitted when the system is about to lock the screen.
/// </summary>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public event Action OnLockScreen
{
add => AddEvent(value);
@@ -22,8 +25,10 @@ namespace ElectronNET.API
}
/// <summary>
/// Emitted when the system is about to unlock the screen.
/// Emitted when the system is about to unlock the screen.
/// </summary>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public event Action OnUnLockScreen
{
add => AddEvent(value);
@@ -51,6 +56,8 @@ namespace ElectronNET.API
/// <summary>
/// Emitted when the system changes to AC power.
/// </summary>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public event Action OnAC
{
add => AddEvent(value);
@@ -60,6 +67,8 @@ namespace ElectronNET.API
/// <summary>
/// Emitted when system changes to battery power.
/// </summary>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public event Action OnBattery
{
add => AddEvent(value);
@@ -72,6 +81,8 @@ namespace ElectronNET.API
/// order for the app to exit cleanly.If `e.preventDefault()` is called, the app
/// should exit as soon as possible by calling something like `app.quit()`.
/// </summary>
[SupportedOSPlatform("Linux")]
[SupportedOSPlatform("macOS")]
public event Action OnShutdown
{
add => AddEvent(value);
@@ -104,4 +115,4 @@ namespace ElectronNET.API
}
}
}
}
}

View File

@@ -9,10 +9,11 @@ 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: ApiBase
public sealed class Process : ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;
internal Process()
{
}
@@ -43,8 +44,8 @@ namespace ElectronNET.API
/// <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> ExecPathAsync => GetPropertyAsync<string>();
/// </summary>
public Task<string> ExecPathAsync => this.InvokeAsync<string>();
/// <summary>
/// The process.argv property returns an array containing the command-line arguments passed
@@ -53,56 +54,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 => GetPropertyAsync<string[]>();
public Task<string[]> ArgvAsync => this.InvokeAsync<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 => GetPropertyAsync<string>();
public Task<string> TypeAsync => this.InvokeAsync<string>();
/// <summary>
/// The process.versions property returns an object listing the version strings of
/// chrome and electron.
/// </summary>
public Task<ProcessVersions> VersionsAsync => GetPropertyAsync<ProcessVersions>();
/// </summary>
public Task<ProcessVersions> VersionsAsync => this.InvokeAsync<ProcessVersions>();
/// <summary>
/// A Boolean. When app is started by being passed as parameter to the default app, this
/// property is true in the main process, otherwise it is false.
/// </summary>
public Task<bool> DefaultAppAsync => GetPropertyAsync<bool>();
public Task<bool> DefaultAppAsync => this.InvokeAsync<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 => GetPropertyAsync<bool>();
public Task<bool> IsMainFrameAsync => this.InvokeAsync<bool>();
/// <summary>
/// A String representing the path to the resources directory.
/// </summary>
public Task<string> ResourcesPathAsync => GetPropertyAsync<string>();
public Task<string> ResourcesPathAsync => this.InvokeAsync<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 => GetPropertyAsync<double>();
public Task<double> UpTimeAsync => this.InvokeAsync<double>();
/// <summary>
/// The PID of the electron process
/// </summary>
public Task<int> PidAsync => GetPropertyAsync<int>();
public Task<int> PidAsync => this.InvokeAsync<int>();
/// <summary>
/// The operating system CPU architecture for which the Node.js binary was compiled
/// </summary>
public Task<string> ArchAsync => GetPropertyAsync<string>();
public Task<string> ArchAsync => this.InvokeAsync<string>();
/// <summary>
/// A string identifying the operating system platform on which the Node.js process is running
/// </summary>
public Task<string> PlatformAsync => GetPropertyAsync<string>();
public Task<string> PlatformAsync => this.InvokeAsync<string>();
}
}
}

View File

@@ -1,6 +1,7 @@
using ElectronNET.API.Entities;
using System;
using System.Linq;
using System.Runtime.Versioning;
using System.Text.Json;
using System.Threading.Tasks;
using ElectronNET.API.Serialization;
@@ -10,7 +11,7 @@ namespace ElectronNET.API
/// <summary>
/// Retrieve information about screen size, displays, cursor position, etc.
/// </summary>
public sealed class Screen: ApiBase
public sealed class Screen : ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;
@@ -35,8 +36,8 @@ namespace ElectronNET.API
}
/// <summary>
/// Emitted when one or more metrics change in a display.
/// The changedMetrics is an array of strings that describe the changes.
/// Emitted when one or more metrics change in a display.
/// The changedMetrics is an array of strings that describe the changes.
/// Possible changes are bounds, workArea, scaleFactor and rotation.
/// </summary>
public event Action<Display, string[]> OnDisplayMetricsChanged
@@ -56,6 +57,7 @@ namespace ElectronNET.API
BridgeConnector.Socket.Emit("register-screen-display-metrics-changed", GetHashCode());
}
_onDisplayMetricsChanged += value;
}
remove
@@ -101,37 +103,38 @@ namespace ElectronNET.API
/// The current absolute position of the mouse pointer.
/// </summary>
/// <returns></returns>
public Task<Point> GetCursorScreenPointAsync() => GetPropertyAsync<Point>();
public Task<Point> GetCursorScreenPointAsync() => this.InvokeAsync<Point>();
/// <summary>
/// macOS: The height of the menu bar in pixels.
/// </summary>
/// <returns>The height of the menu bar in pixels.</returns>
public Task<Rectangle> GetMenuBarWorkAreaAsync() => GetPropertyAsync<Rectangle>();
[SupportedOSPlatform("macOS")]
public Task<Rectangle> GetMenuBarWorkAreaAsync() => this.InvokeAsync<Rectangle>();
/// <summary>
/// The primary display.
/// </summary>
/// <returns></returns>
public Task<Display> GetPrimaryDisplayAsync() => GetPropertyAsync<Display>();
public Task<Display> GetPrimaryDisplayAsync() => this.InvokeAsync<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() => GetPropertyAsync<Display[]>();
public Task<Display[]> GetAllDisplaysAsync() => this.InvokeAsync<Display[]>();
/// <summary>
/// The display nearest the specified point.
/// </summary>
/// <returns>The display nearest the specified point.</returns>
public Task<Display> GetDisplayNearestPointAsync(Point point) => GetPropertyAsync<Display>(point);
public Task<Display> GetDisplayNearestPointAsync(Point point) => this.InvokeAsync<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) => GetPropertyAsync<Display>(rectangle);
public Task<Display> GetDisplayMatchingAsync(Rectangle rectangle) => this.InvokeAsync<Display>(rectangle);
}
}
}

View File

@@ -373,7 +373,5 @@ namespace ElectronNET.API
return tcs.Task;
}
}
}
}

View File

@@ -1,8 +1,7 @@
using System.Runtime.Versioning;
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
{
@@ -68,7 +67,7 @@ namespace ElectronNET.API
}
/// <summary>
/// Open the given external protocol URL in the desktops default manner.
/// Open the given external protocol URL in the desktops default manner.
/// (For example, mailto: URLs in the users default mail agent).
/// </summary>
/// <param name="url">Max 2081 characters on windows.</param>
@@ -79,7 +78,7 @@ namespace ElectronNET.API
}
/// <summary>
/// Open the given external protocol URL in the desktops default manner.
/// Open the given external protocol URL in the desktops default manner.
/// (For example, mailto: URLs in the users default mail agent).
/// </summary>
/// <param name="url">Max 2081 characters on windows.</param>
@@ -133,6 +132,7 @@ namespace ElectronNET.API
/// <param name="operation">Default is <see cref="ShortcutLinkOperation.Create"/></param>
/// <param name="options">Structure of a shortcut.</param>
/// <returns>Whether the shortcut was created successfully.</returns>
[SupportedOSPlatform("Windows")]
public Task<bool> WriteShortcutLinkAsync(string shortcutPath, ShortcutLinkOperation operation, ShortcutDetails options)
{
var tcs = new TaskCompletionSource<bool>();
@@ -149,6 +149,7 @@ namespace ElectronNET.API
/// </summary>
/// <param name="shortcutPath">The path tot the shortcut.</param>
/// <returns><see cref="ShortcutDetails"/> of the shortcut.</returns>
[SupportedOSPlatform("Windows")]
public Task<ShortcutDetails> ReadShortcutLinkAsync(string shortcutPath)
{
var tcs = new TaskCompletionSource<ShortcutDetails>();
@@ -158,7 +159,5 @@ namespace ElectronNET.API
return tcs.Task;
}
}
}
}

View File

@@ -3,6 +3,7 @@ using ElectronNET.API.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Versioning;
using System.Text.Json;
using System.Threading.Tasks;
using ElectronNET.API.Serialization;
@@ -14,7 +15,7 @@ namespace ElectronNET.API
/// <summary>
/// Add icons and context menus to the system's notification area.
/// </summary>
public sealed class Tray: ApiBase
public sealed class Tray : ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;
@@ -38,6 +39,7 @@ namespace ElectronNET.API
BridgeConnector.Socket.Emit("register-tray-click", GetHashCode());
}
_click += value;
}
remove
@@ -56,6 +58,8 @@ namespace ElectronNET.API
/// <summary>
/// macOS, Windows: Emitted when the tray icon is right clicked.
/// </summary>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public event Action<TrayClickEventArgs, Rectangle> OnRightClick
{
add
@@ -72,6 +76,7 @@ namespace ElectronNET.API
BridgeConnector.Socket.Emit("register-tray-right-click", GetHashCode());
}
_rightClick += value;
}
remove
@@ -90,6 +95,8 @@ namespace ElectronNET.API
/// <summary>
/// macOS, Windows: Emitted when the tray icon is double clicked.
/// </summary>
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
public event Action<TrayClickEventArgs, Rectangle> OnDoubleClick
{
add
@@ -106,6 +113,7 @@ namespace ElectronNET.API
BridgeConnector.Socket.Emit("register-tray-double-click", GetHashCode());
}
_doubleClick += value;
}
remove
@@ -124,6 +132,7 @@ namespace ElectronNET.API
/// <summary>
/// Windows: Emitted when the tray balloon shows.
/// </summary>
[SupportedOSPlatform("Windows")]
public event Action OnBalloonShow
{
add => AddEvent(value, GetHashCode());
@@ -133,6 +142,7 @@ namespace ElectronNET.API
/// <summary>
/// Windows: Emitted when the tray balloon is clicked.
/// </summary>
[SupportedOSPlatform("Windows")]
public event Action OnBalloonClick
{
add => AddEvent(value, GetHashCode());
@@ -140,9 +150,10 @@ namespace ElectronNET.API
}
/// <summary>
/// Windows: Emitted when the tray balloon is closed
/// Windows: Emitted when the tray balloon is closed
/// because of timeout or user manually closes it.
/// </summary>
[SupportedOSPlatform("Windows")]
public event Action OnBalloonClosed
{
add => AddEvent(value, GetHashCode());
@@ -248,6 +259,7 @@ namespace ElectronNET.API
/// Sets the image associated with this tray icon when pressed on macOS.
/// </summary>
/// <param name="image"></param>
[SupportedOSPlatform("macOS")]
public async Task SetPressedImage(string image)
{
await BridgeConnector.Socket.Emit("tray-setPressedImage", image).ConfigureAwait(false);
@@ -266,6 +278,7 @@ namespace ElectronNET.API
/// macOS: Sets the title displayed aside of the tray icon in the status bar.
/// </summary>
/// <param name="title"></param>
[SupportedOSPlatform("macOS")]
public async Task SetTitle(string title)
{
await BridgeConnector.Socket.Emit("tray-setTitle", title).ConfigureAwait(false);
@@ -275,6 +288,7 @@ namespace ElectronNET.API
/// Windows: Displays a tray balloon.
/// </summary>
/// <param name="options"></param>
[SupportedOSPlatform("Windows")]
public async Task DisplayBalloon(DisplayBalloonOptions options)
{
await BridgeConnector.Socket.Emit("tray-displayBalloon", options).ConfigureAwait(false);
@@ -295,7 +309,6 @@ namespace ElectronNET.API
}
private const string ModuleName = "tray";
/// <summary>
@@ -330,4 +343,4 @@ namespace ElectronNET.API
public async Task Once<T>(string eventName, Action<T> action)
=> await Events.Instance.Once(ModuleName, eventName, action).ConfigureAwait(false);
}
}
}

View File

@@ -9,7 +9,7 @@ namespace ElectronNET.API;
/// <summary>
/// Render and control web pages.
/// </summary>
public class WebContents: ApiBase
public class WebContents : ApiBase
{
protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;
protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;
@@ -139,24 +139,25 @@ public class WebContents: ApiBase
/// Get system printers.
/// </summary>
/// <returns>printers</returns>
public Task<PrinterInfo[]> GetPrintersAsync() => GetPropertyAsync<PrinterInfo[]>();
public Task<PrinterInfo[]> GetPrintersAsync() => this.InvokeAsync<PrinterInfo[]>();
/// <summary>
/// Prints window's web page.
/// </summary>
/// <param name="options"></param>
/// <returns>success</returns>
public Task<bool> PrintAsync(PrintOptions options) => GetPropertyAsync<bool>(options);
public Task<bool> PrintAsync(PrintOptions options) => this.InvokeAsync<bool>(options);
/// <summary>
/// Prints window's web page.
/// </summary>
/// <returns>success</returns>
public Task<bool> PrintAsync() => GetPropertyAsync<bool>(string.Empty);
public Task<bool> PrintAsync() => this.InvokeAsync<bool>(string.Empty);
/// <summary>
/// Prints window's web page as PDF with Chromium's preview printing custom
/// settings.The landscape will be ignored if @page CSS at-rule is used in the web page.
/// By default, an empty options will be regarded as: Use page-break-before: always;
/// settings.The landscape will be ignored if @page CSS at-rule is used in the web page.
/// By default, an empty options will be regarded as: Use page-break-before: always;
/// CSS style to force to print to a new page.
/// </summary>
/// <param name="path"></param>
@@ -222,7 +223,7 @@ public class WebContents: ApiBase
}
/// <summary>
/// The async method will resolve when the page has finished loading,
/// The async method will resolve when the page has finished loading,
/// and rejects if the page fails to load.
///
/// A noop rejection handler is already attached, which avoids unhandled rejection
@@ -239,7 +240,7 @@ public class WebContents: ApiBase
}
/// <summary>
/// The async method will resolve when the page has finished loading,
/// The async method will resolve when the page has finished loading,
/// and rejects if the page fails to load.
///
/// A noop rejection handler is already attached, which avoids unhandled rejection
@@ -261,10 +262,7 @@ public class WebContents: ApiBase
tcs.SetResult(null);
});
BridgeConnector.Socket.Once<string>("webContents-loadURL-error" + Id, (error) =>
{
tcs.SetException(new InvalidOperationException(error));
});
BridgeConnector.Socket.Once<string>("webContents-loadURL-error" + Id, (error) => { tcs.SetException(new InvalidOperationException(error)); });
BridgeConnector.Socket.Emit("webContents-loadURL", Id, url, options);
@@ -282,4 +280,4 @@ public class WebContents: ApiBase
{
BridgeConnector.Socket.Emit("webContents-insertCSS", Id, isBrowserWindow, path);
}
}
}

View File

@@ -59,4 +59,4 @@ namespace ElectronNET.API.Entities
}
}
}
}
}

View File

@@ -158,8 +158,8 @@ 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>
/// <returns></returns>
@@ -169,8 +169,8 @@ 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>
/// <param name="options"></param>
@@ -192,6 +192,5 @@ namespace ElectronNET.API
return await tcs.Task.ConfigureAwait(false);
}
}
}

View File

@@ -121,4 +121,4 @@ internal class SocketIoFacade
{
_socket.Dispose();
}
}
}

View File

@@ -51,14 +51,14 @@ namespace ElectronNET.Common
return str;
}
public static string StripOn(this string str)
{
if (string.IsNullOrWhiteSpace(str) || !str.StartsWith("On", StringComparison.Ordinal))
{
return str;
}
return str.Substring(2);
}
@@ -66,7 +66,7 @@ namespace ElectronNET.Common
{
return string.Join("-", Regex.Split(str.StripOn(), "(?<!^)(?=[A-Z])")).ToLower(CultureInfo.InvariantCulture);
}
public static string ToCamelCaseEventName(this string str)
{
return str.StripOn().LowerFirst();
@@ -87,4 +87,4 @@ namespace ElectronNET.Common
return service == null || service.State == LifetimeState.Stopped;
}
}
}
}

View File

@@ -23,6 +23,7 @@ public class ModifierTypeListConverter : JsonConverter<List<ModifierType>>
{
throw new JsonException("Expected array for ModifierType list");
}
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndArray) break;
@@ -30,6 +31,7 @@ public class ModifierTypeListConverter : JsonConverter<List<ModifierType>>
var s = reader.GetString();
list.Add((ModifierType)Enum.Parse(typeof(ModifierType), s, ignoreCase: true));
}
return list;
}
@@ -40,6 +42,7 @@ public class ModifierTypeListConverter : JsonConverter<List<ModifierType>>
{
writer.WriteStringValue(modifier.ToString());
}
writer.WriteEndArray();
}
}
}

View File

@@ -42,5 +42,4 @@ public class PageSizeConverter : JsonConverter<PageSize>
JsonSerializer.Serialize(writer, value, ElectronJson.Options);
}
}
}
}

View File

@@ -42,5 +42,4 @@ public class TitleBarOverlayConverter : JsonConverter<TitleBarOverlay>
JsonSerializer.Serialize(writer, value, ElectronJson.Options);
}
}
}
}

View File

@@ -24,6 +24,8 @@
StartupManager.Initialize();
}
public static string ElectronExtraArguments { get; set; }
public static int? ElectronSocketPort { get; internal set; }
public static int? AspNetWebPort { get; internal set; }
@@ -52,4 +54,4 @@
return RuntimeControllerCore?.Socket;
}
}
}
}

View File

@@ -40,7 +40,7 @@
{
var isUnPacked = ElectronNetRuntime.StartupMethod.IsUnpackaged();
var electronBinaryName = ElectronNetRuntime.ElectronExecutable;
var args = Environment.CommandLine;
var args = string.Format("{0} {1}", ElectronNetRuntime.ElectronExtraArguments, Environment.CommandLine).Trim();
this.port = ElectronNetRuntime.ElectronSocketPort;
if (!this.port.HasValue)
@@ -49,10 +49,15 @@
ElectronNetRuntime.ElectronSocketPort = this.port;
}
Console.Error.WriteLine("[StartCore]: isUnPacked: {0}", isUnPacked);
Console.Error.WriteLine("[StartCore]: electronBinaryName: {0}", electronBinaryName);
Console.Error.WriteLine("[StartCore]: args: {0}", args);
this.electronProcess = new ElectronProcessActive(isUnPacked, electronBinaryName, args, this.port.Value);
this.electronProcess.Ready += this.ElectronProcess_Ready;
this.electronProcess.Stopped += this.ElectronProcess_Stopped;
Console.Error.WriteLine("[StartCore]: Before Start");
return this.electronProcess.Start();
}
@@ -82,11 +87,11 @@
private void HandleStopped()
{
if (this.socketBridge.State != LifetimeState.Stopped)
if (this.socketBridge != null && this.socketBridge.State != LifetimeState.Stopped)
{
this.socketBridge.Stop();
}
else if (this.electronProcess.State != LifetimeState.Stopped)
else if (this.electronProcess != null && this.electronProcess.State != LifetimeState.Stopped)
{
this.electronProcess.Stop();
}

View File

@@ -8,4 +8,4 @@
/// <summary>ASP.NET Core cross-platform app.</summary>
AspNetCoreApp,
}
}
}

View File

@@ -9,4 +9,4 @@
Stopping,
Stopped,
}
}
}

View File

@@ -34,4 +34,4 @@
/// </remarks>
UnpackedDotnetFirst,
}
}
}

View File

@@ -69,4 +69,4 @@
return null;
}
}
}
}

View File

@@ -21,6 +21,5 @@
port += 2;
}
}
}
}
}

View File

@@ -106,4 +106,4 @@
return null;
}
}
}
}

View File

@@ -5,6 +5,7 @@
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
/// <summary>
@@ -42,6 +43,11 @@
var electrondir = Path.Combine(dir.FullName, ".electron");
startCmd = Path.Combine(electrondir, "node_modules", "electron", "dist", "electron");
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
startCmd = Path.Combine(electrondir, "node_modules", "electron", "dist", "Electron.app", "Contents", "MacOS", "Electron");
}
args = $"main.js -unpackeddotnet --trace-warnings -electronforcedport={this.socketPort:D} " + this.extraArguments;
workingDir = electrondir;
}
@@ -68,22 +74,40 @@
private async Task StartInternal(string startCmd, string args, string directoriy)
{
await Task.Delay(10).ConfigureAwait(false);
this.process = new ProcessRunner("ElectronRunner");
this.process.ProcessExited += this.Process_Exited;
this.process.Run(startCmd, args, directoriy);
await Task.Delay(500).ConfigureAwait(false);
if (!this.process.IsRunning)
try
{
Task.Run(() => this.TransitionState(LifetimeState.Stopped));
await Task.Delay(10).ConfigureAwait(false);
throw new Exception("Failed to launch the Electron process.");
Console.Error.WriteLine("[StartInternal]: startCmd: {0}", startCmd);
Console.Error.WriteLine("[StartInternal]: args: {0}", args);
this.process = new ProcessRunner("ElectronRunner");
this.process.ProcessExited += this.Process_Exited;
this.process.Run(startCmd, args, directoriy);
await Task.Delay(500).ConfigureAwait(false);
Console.Error.WriteLine("[StartInternal]: after run:");
if (!this.process.IsRunning)
{
Console.Error.WriteLine("[StartInternal]: Process is not running: " + this.process.StandardError);
Console.Error.WriteLine("[StartInternal]: Process is not running: " + this.process.StandardOutput);
Task.Run(() => this.TransitionState(LifetimeState.Stopped));
throw new Exception("Failed to launch the Electron process.");
}
this.TransitionState(LifetimeState.Ready);
}
catch (Exception ex)
{
Console.Error.WriteLine("[StartInternal]: Exception: " + this.process?.StandardError);
Console.Error.WriteLine("[StartInternal]: Exception: " + this.process?.StandardOutput);
Console.Error.WriteLine("[StartInternal]: Exception: " + ex);
throw;
}
this.TransitionState(LifetimeState.Ready);
}
private void Process_Exited(object sender, EventArgs e)

View File

@@ -132,13 +132,19 @@
if (electronAssembly == null)
{
Console.WriteLine("GatherBuildInfo: Early exit");
return buildInfo;
}
if (electronAssembly.GetName().Name == "testhost" || electronAssembly.GetName().Name == "ReSharperTestRunner")
{
Console.WriteLine("GatherBuildInfo: Detected testhost");
electronAssembly = AppDomain.CurrentDomain.GetData("ElectronTestAssembly") as Assembly ?? electronAssembly;
}
else
{
Console.WriteLine("GatherBuildInfo: No testhost detected: " + electronAssembly.GetName().Name);
}
var attributes = electronAssembly.GetCustomAttributes<AssemblyMetadataAttribute>().ToList();

View File

@@ -30,5 +30,4 @@ namespace ElectronNET.API.Serialization
internal partial class ElectronJsonContext : JsonSerializerContext
{
}
}
}

View File

@@ -1,36 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\common.props" />
<Import Project="..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<IsPackable>False</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="17.3.2" />
</ItemGroup>
<PropertyGroup>
<_DllTargetPath>$(MSBuildThisFileDirectory)\..\ElectronNET\build</_DllTargetPath>
</PropertyGroup>
<Target BeforeTargets="AfterBuild" Name="CopyToBuildFolder">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<IsPackable>False</IsPackable>
</PropertyGroup>
<ItemGroup>
<OutputFiles Include="$(OutDir)**\*.dll"></OutputFiles>
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="17.3.2" />
</ItemGroup>
<Message Text="Copy ElectronNET.Build.dll to destination: $(_DllTargetPath)" Importance="high"/>
<Copy SourceFiles="@(OutputFiles)"
DestinationFolder="$(_DllTargetPath)\%(RecursiveDir)"
OverwriteReadOnlyFiles="true"></Copy>
</Target>
<PropertyGroup>
<_DllTargetPath>$(MSBuildThisFileDirectory)\..\ElectronNET\build</_DllTargetPath>
</PropertyGroup>
<Target BeforeTargets="AfterBuild" Name="CopyToBuildFolder">
<ItemGroup>
<OutputFiles Include="$(OutDir)**\*.dll"></OutputFiles>
</ItemGroup>
<Message Text="Copy ElectronNET.Build.dll to destination: $(_DllTargetPath)" Importance="high"/>
<Copy SourceFiles="@(OutputFiles)"
DestinationFolder="$(_DllTargetPath)\%(RecursiveDir)"
OverwriteReadOnlyFiles="true"></Copy>
</Target>
</Project>

View File

@@ -5,7 +5,7 @@
<ElectronNetDevMode>true</ElectronNetDevMode>
</PropertyGroup>
<Import Project="..\ElectronNET\build\ElectronNET.props" Condition="$(ElectronNetDevMode)" />
<Import Project="..\ElectronNET\build\ElectronNET.Core.props" Condition="$(ElectronNetDevMode)" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
@@ -69,9 +69,9 @@
<ProjectReference Include="..\ElectronNET.API\ElectronNET.API.csproj" Condition="$(ElectronNetDevMode)" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ElectronNET.Core" Version="0.1.0" Condition="'$(ElectronNetDevMode)' != 'true'" />
<PackageReference Include="ElectronNET.Core" Version="0.2.0" Condition="'$(ElectronNetDevMode)' != 'true'" />
</ItemGroup>
<Import Project="..\ElectronNET\build\ElectronNET.targets" Condition="$(ElectronNetDevMode)" />
<Import Project="..\ElectronNET\build\ElectronNET.Core.targets" Condition="$(ElectronNetDevMode)" />
</Project>

View File

@@ -1,20 +1,21 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Electron App",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"program": "${workspaceFolder}/main.js",
"sourceMaps": true,
"args": [
"--test=true",
"--blub=wuhuu"
]
}
]
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Electron App",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"program": "${workspaceFolder}/main.js",
"skipFiles": [ "<node_internals>/**" ],
"cwd": "${workspaceFolder}",
"console": "externalTerminal",
"args": [
"--test=true"
]
}
]
}

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