mirror of
https://github.com/ElectronNET/Electron.NET.git
synced 2026-02-06 21:28:53 +00:00
Compare commits
350 Commits
23.6.2
...
legacy/mai
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9bf393165 | ||
|
|
d3aa9783d3 | ||
|
|
a5bc910926 | ||
|
|
89033c61d4 | ||
|
|
90b4a287d9 | ||
|
|
e2615a8dc1 | ||
|
|
73330185de | ||
|
|
e1c5b7e3c2 | ||
|
|
a19e095f6e | ||
|
|
b7ed3d22f1 | ||
|
|
c8f944af4a | ||
|
|
2f73bb8b34 | ||
|
|
1f22be68d2 | ||
|
|
576140474e | ||
|
|
68c9e80417 | ||
|
|
4906babd78 | ||
|
|
e0000f7aba | ||
|
|
ff05ef20c8 | ||
|
|
79ce1c42e7 | ||
|
|
4e95bb3331 | ||
|
|
58bfa336a8 | ||
|
|
afa69280f5 | ||
|
|
8621d8cea3 | ||
|
|
9106391f60 | ||
|
|
490ef6231b | ||
|
|
89833f42fc | ||
|
|
252ab5050b | ||
|
|
2ff29e553d | ||
|
|
a1a5f6f9a6 | ||
|
|
3ea7e96324 | ||
|
|
a00a8a0251 | ||
|
|
e245d0d2f6 | ||
|
|
48a0d68313 | ||
|
|
4d5d6722a7 | ||
|
|
d910eec8df | ||
|
|
4f9b46c616 | ||
|
|
4308f2c6d6 | ||
|
|
87468ccd5d | ||
|
|
d863ff95f4 | ||
|
|
3a24b69063 | ||
|
|
d6c98759c5 | ||
|
|
6675571aaf | ||
|
|
3f8766ff9e | ||
|
|
9b881b1b71 | ||
|
|
339a319f3e | ||
|
|
d929102e18 | ||
|
|
26595bf290 | ||
|
|
5ca65f1939 | ||
|
|
b4b355eeac | ||
|
|
47774d2871 | ||
|
|
43cbdc15b8 | ||
|
|
540be39547 | ||
|
|
a7a8685341 | ||
|
|
0575413768 | ||
|
|
e8394277e7 | ||
|
|
5fe50b45bb | ||
|
|
70ca42aeaf | ||
|
|
f54ce1eb02 | ||
|
|
aa9c2caf47 | ||
|
|
ba8e941cf1 | ||
|
|
f0003ae953 | ||
|
|
1f5d70be83 | ||
|
|
1a1bd61e3e | ||
|
|
709780fd04 | ||
|
|
9a17d22343 | ||
|
|
7222c9e6c5 | ||
|
|
29b4f577a6 | ||
|
|
9698c80442 | ||
|
|
4afa535c31 | ||
|
|
0de9699a52 | ||
|
|
6f5fb16091 | ||
|
|
891870abde | ||
|
|
ab162d4829 | ||
|
|
ec12dbd6ad | ||
|
|
f05934acb8 | ||
|
|
0632112a3a | ||
|
|
793f714b9e | ||
|
|
e3fbce26d0 | ||
|
|
c45ea53a02 | ||
|
|
de56395946 | ||
|
|
b0262b36d0 | ||
|
|
0ffecd5bc7 | ||
|
|
b7196ff10d | ||
|
|
93f1875f8b | ||
|
|
6ca5563dc1 | ||
|
|
e643d0db08 | ||
|
|
9c89711d59 | ||
|
|
606b2a6481 | ||
|
|
ef13ec9cc4 | ||
|
|
b58b4579f9 | ||
|
|
13edd4c3ca | ||
|
|
967ccf385a | ||
|
|
4a44f3e150 | ||
|
|
d6e362c83c | ||
|
|
df15d249de | ||
|
|
a5bb3ad36b | ||
|
|
8f26ceed3d | ||
|
|
7f282c1346 | ||
|
|
8067f8e1ff | ||
|
|
468c8ba2fc | ||
|
|
ab694e22fc | ||
|
|
79a6ef322c | ||
|
|
0ef5edfdf6 | ||
|
|
7db609c699 | ||
|
|
127408afdb | ||
|
|
40eae5af3d | ||
|
|
26ba398428 | ||
|
|
56fe57db46 | ||
|
|
c8552041fb | ||
|
|
13a3753214 | ||
|
|
93ee1871ee | ||
|
|
86644e7366 | ||
|
|
2331ef43b4 | ||
|
|
b8845bb402 | ||
|
|
1767bcd5ad | ||
|
|
5338749e4d | ||
|
|
4790c4ebb2 | ||
|
|
d646b84c74 | ||
|
|
64e058b0b5 | ||
|
|
24a2005776 | ||
|
|
592148116b | ||
|
|
ba82b9a600 | ||
|
|
562cccbfae | ||
|
|
1406fc1d79 | ||
|
|
8e1e184d1e | ||
|
|
9e37d4d857 | ||
|
|
060fb19a6d | ||
|
|
291faa48de | ||
|
|
4358178524 | ||
|
|
4b314940d7 | ||
|
|
ed841558b8 | ||
|
|
36751db618 | ||
|
|
f229d540a8 | ||
|
|
546c617cd0 | ||
|
|
88e8051004 | ||
|
|
21427f0b44 | ||
|
|
159c1f46c1 | ||
|
|
8cb235527d | ||
|
|
4a3a5c6aa4 | ||
|
|
82bf94b2a2 | ||
|
|
17a7886d12 | ||
|
|
6be3019cb6 | ||
|
|
3460217021 | ||
|
|
427592de46 | ||
|
|
8f820d033a | ||
|
|
4118756711 | ||
|
|
ffdf034f5f | ||
|
|
946fbd7a72 | ||
|
|
6b0205467b | ||
|
|
a28df5339d | ||
|
|
f5a141a1c6 | ||
|
|
b5e2b660f7 | ||
|
|
431e401451 | ||
|
|
02faeae603 | ||
|
|
0d9483e325 | ||
|
|
1b14bb0fe5 | ||
|
|
b08a0755e6 | ||
|
|
7e89e27c26 | ||
|
|
e4deba2489 | ||
|
|
1d9e540fc2 | ||
|
|
c7d2dabbc3 | ||
|
|
2d940dbeee | ||
|
|
d9d655cae8 | ||
|
|
1b7f722f31 | ||
|
|
b1c5c12004 | ||
|
|
af0410998e | ||
|
|
e0e8572cc1 | ||
|
|
4ba8d9bf46 | ||
|
|
07d6fed712 | ||
|
|
5dbe62bcba | ||
|
|
438c8e1f14 | ||
|
|
ffedbcc5df | ||
|
|
9aad72431c | ||
|
|
4405eba2d5 | ||
|
|
067300bfec | ||
|
|
b2f5a0eb34 | ||
|
|
cbc150db06 | ||
|
|
cbac8541be | ||
|
|
2f9029e267 | ||
|
|
390135af8a | ||
|
|
be1182d302 | ||
|
|
54c86d9e2f | ||
|
|
2cc6823604 | ||
|
|
326efd353c | ||
|
|
bd96765db5 | ||
|
|
606bb019f7 | ||
|
|
a12a7e4287 | ||
|
|
5bf9aa811d | ||
|
|
5477bd7f36 | ||
|
|
134a5b1365 | ||
|
|
23791fcc3e | ||
|
|
751c48c804 | ||
|
|
316cf0108e | ||
|
|
4caa28dc87 | ||
|
|
ad46b1a7a2 | ||
|
|
2297669e6d | ||
|
|
ae92973814 | ||
|
|
5ebfa2b0bd | ||
|
|
1494c2f436 | ||
|
|
84f027cd8d | ||
|
|
f213ca4f8c | ||
|
|
22fa3f2780 | ||
|
|
b5cc631daf | ||
|
|
b5ff42a148 | ||
|
|
1e50f203d8 | ||
|
|
852b140525 | ||
|
|
7e5903f5bc | ||
|
|
62003ae5fc | ||
|
|
5cd152c1ed | ||
|
|
228a5cef31 | ||
|
|
c28355094e | ||
|
|
329df38765 | ||
|
|
5274fec200 | ||
|
|
9892a90038 | ||
|
|
1d1e60bc63 | ||
|
|
21b6b14df5 | ||
|
|
2445b59c4d | ||
|
|
9a8584795b | ||
|
|
e6ea9883fd | ||
|
|
e1edc764d6 | ||
|
|
51013d5825 | ||
|
|
664d5f7236 | ||
|
|
75d7924251 | ||
|
|
c2904f3f68 | ||
|
|
adef39f3ec | ||
|
|
836eebf256 | ||
|
|
124d24a19c | ||
|
|
67ea8c768e | ||
|
|
8604b50224 | ||
|
|
5559fc61b1 | ||
|
|
9be80abfcf | ||
|
|
6a4a7eff1c | ||
|
|
a637174b93 | ||
|
|
dc2662e52e | ||
|
|
801616cd53 | ||
|
|
9693c82792 | ||
|
|
a3fb411d8a | ||
|
|
172f6ded3f | ||
|
|
bbbc9e6f61 | ||
|
|
236c31abe0 | ||
|
|
374d92f3b1 | ||
|
|
ea40249a9c | ||
|
|
7f5db58edd | ||
|
|
d18700f64d | ||
|
|
47f4516ae2 | ||
|
|
bb8965fa91 | ||
|
|
c229d49765 | ||
|
|
4fae2aeef2 | ||
|
|
5f4b1628e5 | ||
|
|
25af4a7314 | ||
|
|
14ee45b88f | ||
|
|
badc9f26b6 | ||
|
|
4e7cebe519 | ||
|
|
ec74c7989a | ||
|
|
a2579b221f | ||
|
|
1e7ff5b6d6 | ||
|
|
eac14427df | ||
|
|
794248a83c | ||
|
|
9a938dc680 | ||
|
|
2d68ca5270 | ||
|
|
548609f69b | ||
|
|
7b5bac2083 | ||
|
|
5ba10136e2 | ||
|
|
aba77b1361 | ||
|
|
bd45e23768 | ||
|
|
35b18a9501 | ||
|
|
89d41a2750 | ||
|
|
efdaf0e341 | ||
|
|
0728577c40 | ||
|
|
224bc1ef65 | ||
|
|
7ad6803671 | ||
|
|
81a8367dac | ||
|
|
1161f59836 | ||
|
|
e7c56274e6 | ||
|
|
44d979fef4 | ||
|
|
2f0229235b | ||
|
|
18d425b042 | ||
|
|
5e82ae4246 | ||
|
|
48d5497045 | ||
|
|
be41cae3bd | ||
|
|
64b91fc235 | ||
|
|
efec886f73 | ||
|
|
8b03a6b006 | ||
|
|
144a0a0ddc | ||
|
|
8bbe6a96af | ||
|
|
e39e34234d | ||
|
|
67c592a060 | ||
|
|
bad59463a9 | ||
|
|
94efaf835e | ||
|
|
ac77643fc4 | ||
|
|
0393b0bd45 | ||
|
|
953f1e2641 | ||
|
|
fb99dbd5b5 | ||
|
|
fdbf7187b9 | ||
|
|
9a680a41ac | ||
|
|
f9693ce624 | ||
|
|
0090a7c239 | ||
|
|
81431599ec | ||
|
|
31094f9d2b | ||
|
|
bf48bc8227 | ||
|
|
87d97efcfa | ||
|
|
da9d9658f5 | ||
|
|
444c09fb4d | ||
|
|
ca9bee7bf0 | ||
|
|
0aab352f86 | ||
|
|
a8229f2fa9 | ||
|
|
9daaebcef6 | ||
|
|
67b59d95d4 | ||
|
|
8f71480b3e | ||
|
|
133dcd6b65 | ||
|
|
d9a7411904 | ||
|
|
b42eba8a70 | ||
|
|
e8e3649925 | ||
|
|
b6338ac7de | ||
|
|
b708b4b622 | ||
|
|
336c3b9400 | ||
|
|
bd08938c49 | ||
|
|
cbe0637e84 | ||
|
|
8063f49e4b | ||
|
|
d6b29f7350 | ||
|
|
237638a5b3 | ||
|
|
b910807ced | ||
|
|
7fe8f6e49e | ||
|
|
c4ff481131 | ||
|
|
9107b161b3 | ||
|
|
ec2261f1c5 | ||
|
|
b03bc7c9eb | ||
|
|
e6214491cf | ||
|
|
95d614796e | ||
|
|
126d39f4a5 | ||
|
|
8880e040f7 | ||
|
|
f200013165 | ||
|
|
82755e399d | ||
|
|
f07f2e9506 | ||
|
|
83fd5a5d4b | ||
|
|
6dee08379c | ||
|
|
8f5a7856d5 | ||
|
|
f78573401a | ||
|
|
d8ba9d9372 | ||
|
|
09cb7a640f | ||
|
|
2f3d2c00b6 | ||
|
|
3b7b592ac8 | ||
|
|
bcbe76211c | ||
|
|
505a5b2204 | ||
|
|
468a4fa35b | ||
|
|
94b5faafcd | ||
|
|
f08711e41b | ||
|
|
1a6d50d77a | ||
|
|
d188baaaff | ||
|
|
916eecf117 |
84
.devops/build-nuget.yaml
Normal file
84
.devops/build-nuget.yaml
Normal file
@@ -0,0 +1,84 @@
|
||||
variables:
|
||||
PackageVersion: 19.0.9.$(Build.BuildId)
|
||||
projectAPI: './ElectronNET.API/ElectronNET.API.csproj'
|
||||
projectCLI: './ElectronNET.CLI/ElectronNET.CLI.csproj'
|
||||
|
||||
trigger:
|
||||
- master
|
||||
|
||||
pool:
|
||||
vmImage: windows-latest
|
||||
|
||||
steps:
|
||||
- checkout: self
|
||||
submodules: true
|
||||
fetchDepth: 10
|
||||
|
||||
- task: NuGetToolInstaller@1
|
||||
|
||||
- task: UseDotNet@2
|
||||
displayName: 'Use .NET Core sdk'
|
||||
inputs:
|
||||
packageType: sdk
|
||||
version: 6.0.100
|
||||
installationPath: $(Agent.ToolsDirectory)/dotnet
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: 'restore nuget'
|
||||
inputs:
|
||||
command: 'restore'
|
||||
projects: '$(projectAPI)'
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: 'restore nuget'
|
||||
inputs:
|
||||
command: 'restore'
|
||||
projects: '$(projectCLI)'
|
||||
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
inputs:
|
||||
command: 'build'
|
||||
projects: '$(projectAPI)'
|
||||
arguments: '--configuration Release --force /property:Version=$(PackageVersion)'
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
inputs:
|
||||
command: 'build'
|
||||
projects: '$(projectCLI)'
|
||||
arguments: '--configuration Release --force /property:Version=$(PackageVersion)'
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
inputs:
|
||||
command: 'pack'
|
||||
packagesToPack: '$(projectAPI)'
|
||||
configuration: 'Release'
|
||||
versioningScheme: 'off'
|
||||
buildProperties: 'Version=$(PackageVersion)'
|
||||
arguments: -IncludeReferencedProjects
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
inputs:
|
||||
command: 'pack'
|
||||
packagesToPack: '$(projectCLI)'
|
||||
configuration: 'Release'
|
||||
versioningScheme: 'off'
|
||||
buildProperties: 'Version=$(PackageVersion)'
|
||||
|
||||
|
||||
|
||||
- task: NuGetCommand@2
|
||||
displayName: 'push API to nuget'
|
||||
inputs:
|
||||
command: 'push'
|
||||
packagesToPush: '$(Build.ArtifactStagingDirectory)/h5.ElectronNET.API.$(PackageVersion).nupkg'
|
||||
nuGetFeedType: 'external'
|
||||
publishFeedCredentials: 'nuget-curiosity'
|
||||
|
||||
- task: NuGetCommand@2
|
||||
displayName: 'push CLI to nuget'
|
||||
inputs:
|
||||
command: 'push'
|
||||
packagesToPush: '$(Build.ArtifactStagingDirectory)/h5.ElectronNET.CLI.$(PackageVersion).nupkg'
|
||||
nuGetFeedType: 'external'
|
||||
publishFeedCredentials: 'nuget-curiosity'
|
||||
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -1,6 +1,6 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [GregorBiswanger, FlorianRappl]
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
|
||||
47
.github/workflows/ci.yml
vendored
47
.github/workflows/ci.yml
vendored
@@ -1,47 +0,0 @@
|
||||
name: CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: |
|
||||
6.0.x
|
||||
7.0.x
|
||||
|
||||
- name: Build
|
||||
run: ./build.sh
|
||||
|
||||
windows:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: |
|
||||
6.0.x
|
||||
7.0.x
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
if ($env:GITHUB_REF -eq "refs/heads/main") {
|
||||
.\build.ps1 -Target Publish
|
||||
} elseif ($env:GITHUB_REF -eq "refs/heads/develop") {
|
||||
.\build.ps1 -Target PrePublish
|
||||
} else {
|
||||
.\build.ps1
|
||||
}
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -44,7 +44,7 @@ dlldata.c
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
!/artifacts/.gitkeep
|
||||
!/artifacts/readme.md
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
@@ -263,6 +263,3 @@ __pycache__/
|
||||
|
||||
# Mac Only settings file
|
||||
.DS_Store
|
||||
|
||||
# Nuke build tool
|
||||
.nuke/temp
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "Build Schema",
|
||||
"$ref": "#/definitions/build",
|
||||
"definitions": {
|
||||
"build": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Configuration": {
|
||||
"type": "string",
|
||||
"description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)",
|
||||
"enum": [
|
||||
"Debug",
|
||||
"Release"
|
||||
]
|
||||
},
|
||||
"Continue": {
|
||||
"type": "boolean",
|
||||
"description": "Indicates to continue a previously failed build attempt"
|
||||
},
|
||||
"Help": {
|
||||
"type": "boolean",
|
||||
"description": "Shows the help text for this build assembly"
|
||||
},
|
||||
"Host": {
|
||||
"type": "string",
|
||||
"description": "Host for execution. Default is 'automatic'",
|
||||
"enum": [
|
||||
"AppVeyor",
|
||||
"AzurePipelines",
|
||||
"Bamboo",
|
||||
"Bitbucket",
|
||||
"Bitrise",
|
||||
"GitHubActions",
|
||||
"GitLab",
|
||||
"Jenkins",
|
||||
"Rider",
|
||||
"SpaceAutomation",
|
||||
"TeamCity",
|
||||
"Terminal",
|
||||
"TravisCI",
|
||||
"VisualStudio",
|
||||
"VSCode"
|
||||
]
|
||||
},
|
||||
"NoLogo": {
|
||||
"type": "boolean",
|
||||
"description": "Disables displaying the NUKE logo"
|
||||
},
|
||||
"Partition": {
|
||||
"type": "string",
|
||||
"description": "Partition to use on CI"
|
||||
},
|
||||
"Plan": {
|
||||
"type": "boolean",
|
||||
"description": "Shows the execution plan (HTML)"
|
||||
},
|
||||
"Profile": {
|
||||
"type": "array",
|
||||
"description": "Defines the profiles to load",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"ReleaseNotesFilePath": {
|
||||
"type": "string",
|
||||
"description": "ReleaseNotesFilePath - To determine the SemanticVersion"
|
||||
},
|
||||
"Root": {
|
||||
"type": "string",
|
||||
"description": "Root directory during build execution"
|
||||
},
|
||||
"Skip": {
|
||||
"type": "array",
|
||||
"description": "List of targets to be skipped. Empty list skips all dependencies",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Clean",
|
||||
"Compile",
|
||||
"CompileSample",
|
||||
"CreatePackages",
|
||||
"Default",
|
||||
"ElectronizeCustomWin7TargetSample",
|
||||
"ElectronizeGenericTargetSample",
|
||||
"ElectronizeLinuxTargetSample",
|
||||
"ElectronizeMacOsTargetSample",
|
||||
"ElectronizeWindowsTargetSample",
|
||||
"Package",
|
||||
"PrePublish",
|
||||
"Publish",
|
||||
"PublishPackages",
|
||||
"PublishPreRelease",
|
||||
"PublishRelease",
|
||||
"Restore",
|
||||
"RunUnitTests"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Solution": {
|
||||
"type": "string",
|
||||
"description": "Path to a solution file that is automatically loaded"
|
||||
},
|
||||
"Target": {
|
||||
"type": "array",
|
||||
"description": "List of targets to be invoked. Default is '{default_target}'",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Clean",
|
||||
"Compile",
|
||||
"CompileSample",
|
||||
"CreatePackages",
|
||||
"Default",
|
||||
"ElectronizeCustomWin7TargetSample",
|
||||
"ElectronizeGenericTargetSample",
|
||||
"ElectronizeLinuxTargetSample",
|
||||
"ElectronizeMacOsTargetSample",
|
||||
"ElectronizeWindowsTargetSample",
|
||||
"Package",
|
||||
"PrePublish",
|
||||
"Publish",
|
||||
"PublishPackages",
|
||||
"PublishPreRelease",
|
||||
"PublishRelease",
|
||||
"Restore",
|
||||
"RunUnitTests"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Verbosity": {
|
||||
"type": "string",
|
||||
"description": "Logging verbosity during build execution. Default is 'Normal'",
|
||||
"enum": [
|
||||
"Minimal",
|
||||
"Normal",
|
||||
"Quiet",
|
||||
"Verbose"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"$schema": "./build.schema.json",
|
||||
"Solution": "src/ElectronNET.sln"
|
||||
}
|
||||
8
.travis.yml
Normal file
8
.travis.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
language: csharp
|
||||
mono: none
|
||||
dist: xenial
|
||||
dotnet: 3.1
|
||||
before_script:
|
||||
- export PATH="$PATH:/home/travis/.dotnet/tools"
|
||||
script:
|
||||
- ./buildAll.sh
|
||||
37
.vscode/tasks.json
vendored
37
.vscode/tasks.json
vendored
@@ -1,18 +1,21 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"command": "dotnet",
|
||||
"args": [],
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": ["build", "${workspaceRoot}/ElectronNET.CLI/ElectronNET.CLI.csproj"],
|
||||
"problemMatcher": "$msCompile",
|
||||
"group": {
|
||||
"_id": "build",
|
||||
"isDefault": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
"version": "2.0.0",
|
||||
"command": "dotnet",
|
||||
"args": [],
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceRoot}/ElectronNET.CLI/ElectronNET.CLI.csproj"
|
||||
],
|
||||
"problemMatcher": "$msCompile",
|
||||
"group": {
|
||||
"_id": "build",
|
||||
"isDefault": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
16
.vscode/tasks.json.old
vendored
Normal file
16
.vscode/tasks.json.old
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"version": "0.1.0",
|
||||
"command": "dotnet",
|
||||
"isShellCommand": true,
|
||||
"args": [],
|
||||
"tasks": [
|
||||
{
|
||||
"taskName": "build",
|
||||
"args": [
|
||||
"${workspaceRoot}/ElectronNET.CLI/ElectronNET.CLI.csproj"
|
||||
],
|
||||
"isBuildCommand": true,
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
]
|
||||
}
|
||||
53
Changelog.md
53
Changelog.md
@@ -1,43 +1,28 @@
|
||||
# 23.6.2
|
||||
# Not released
|
||||
|
||||
## ElectronNET.API
|
||||
# 18.6.1
|
||||
|
||||
* Fixed escaping of URL (#735) @cosmo0
|
||||
* Fixed huge memory waste in IpcMain.Once (#833) @Yuvix25
|
||||
* Fixed enabling of accessibility support (#798) @dlanorok
|
||||
* Updated `Display` to current spec (#828) @Yuvix25
|
||||
* Changed `ZoomFactor` type from `int` to `double` (#754) @Yuvix25
|
||||
* Added splash screen size config (#822) @NickRimmer
|
||||
* Added OSX ARM architecture detection (#821) @sajmonr
|
||||
* Added support for `did-navigate` event (#819) @NickRimmer
|
||||
* Added support for `will-redirect` event (#819) @NickRimmer
|
||||
* Added support for `did-fail-load` event (#819) @NickRimmer
|
||||
* Added support for `did-start-navigation` event (#819) @NickRimmer
|
||||
* Added support for `did-redirect-navigation` event (#819) @NickRimmer
|
||||
* Added support for `dom-ready` event (#813) @softworkz
|
||||
ElectronNET.CLI:
|
||||
|
||||
## ElectronNET.CLI
|
||||
* New Feature: Support for additional dotnet publish flags (thanks [danatcofo](https://github.com/danatcofo)) [\#655](https://github.com/ElectronNET/Electron.NET/pull/655)
|
||||
* New Feature: Support Apple Silicon Natively (thanks [bman46](https://github.com/bman46)) [\#624](https://github.com/ElectronNET/Electron.NET/pull/624)
|
||||
|
||||
* (none)
|
||||
ElectronNET.API:
|
||||
|
||||
## Infrastructure
|
||||
* New Feature: Support for .NET 6 (thanks [danatcofo](https://github.com/danatcofo)) [\#636](https://github.com/ElectronNET/Electron.NET/pull/636)
|
||||
* New Feature: Switch to async socket lib (thanks [theolivenbaum](https://github.com/theolivenbaum)) [\#595](https://github.com/ElectronNET/Electron.NET/pull/595)
|
||||
* New Feature: Conversion to use ImageSharp rather than System.Drawing.Common (thanks [danatcofo](https://github.com/danatcofo)) [\#658](https://github.com/ElectronNET/Electron.NET/pull/658)
|
||||
* New Feature: Support DI and Mocking better + Support launching app with file for win and linux (thanks [danatcofo](https://github.com/danatcofo)) [\#656](https://github.com/ElectronNET/Electron.NET/pull/656)
|
||||
* New Feature: Support launching app with file for win and linux (thanks [schaveyt](https://github.com/schaveyt)) [\#648](https://github.com/ElectronNET/Electron.NET/pull/648)
|
||||
* New Feature: Add ability to set a window's parent using BrowserWindowOptions (thanks [MutatedGamer](https://github.com/MutatedGamer)) [\#673](https://github.com/ElectronNET/Electron.NET/pull/673)
|
||||
* New Feature: changed the processing of loadUrl at CreateWindowAsync (thanks [yannikHoeflich](https://github.com/yannikHoeflich)) [\#631](https://github.com/ElectronNET/Electron.NET/pull/631)
|
||||
* New Feature: Recent Document Support for MacOS (thanks [danatcofo](https://github.com/danatcofo)) [\#634](https://github.com/ElectronNET/Electron.NET/pull/634)
|
||||
* New Feature: Support DI and Mocking better (thanks [danatcofo](https://github.com/danatcofo)) [\#633](https://github.com/ElectronNET/Electron.NET/pull/633)
|
||||
* New Feature: Allow ignoring certificate errors (thanks [javierlarota](https://github.com/javierlarota)) [\#626](https://github.com/ElectronNET/Electron.NET/pull/626)
|
||||
* New Feature: Log errors in the dotnet process (thanks [Meberem](https://github.com/Meberem)) [\#592](https://github.com/ElectronNET/Electron.NET/pull/592)
|
||||
* Fixed bug: Error on reloading a window after a second window is closed #664 (thanks [danatcofo](https://github.com/danatcofo)) [\#668](https://github.com/ElectronNET/Electron.NET/pull/668)
|
||||
|
||||
* Changed build system to NUKE (#757) @FlorianRappl
|
||||
* Updated target framework for host project (#753) @r-pankevicius
|
||||
* Fixed typo in README (#800) @franpersanchez
|
||||
|
||||
# 23.6.1
|
||||
|
||||
## ElectronNET.CLI
|
||||
|
||||
* New Feature: Upgrade to .NET 6 support
|
||||
|
||||
## ElectronNET.API
|
||||
|
||||
* New Feature: Native Electron 23.2.0 support, but not all new API features included (we search contributors)
|
||||
* New Feature: Upgrade to .NET 6 support
|
||||
* New Feature: Changed Web-Socket .NET Library to [SocketIOClient](https://github.com/doghappy/socket.io-client-csharp)
|
||||
* Breaking Changes: We removed deprecated API events/methods from ElectronNET.API [(More Details)](https://www.electronjs.org/docs/latest/breaking-changes)
|
||||
# Released
|
||||
|
||||
# 13.5.1
|
||||
|
||||
|
||||
810
src/ElectronNET.API/App.cs → ElectronNET.API/App.cs
Normal file → Executable file
810
src/ElectronNET.API/App.cs → ElectronNET.API/App.cs
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
474
ElectronNET.API/AutoUpdater.cs
Executable file
474
ElectronNET.API/AutoUpdater.cs
Executable file
@@ -0,0 +1,474 @@
|
||||
using ElectronNET.API.Entities;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using ElectronNET.API.Interfaces;
|
||||
using ElectronNET.API;
|
||||
|
||||
namespace ElectronNET.API
|
||||
{
|
||||
/// <summary>
|
||||
/// Enable apps to automatically update themselves. Based on electron-updater.
|
||||
/// </summary>
|
||||
public sealed class AutoUpdater : IAutoUpdater
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether to automatically download an update when it is found. (Default is true)
|
||||
/// </summary>
|
||||
public Task<bool> IsAutoDownloadEnabledAsync => BridgeConnector.OnResult<bool>("autoUpdater-autoDownload-get", "autoUpdater-autoDownload-get-reply");
|
||||
|
||||
/// <summary>
|
||||
/// Whether to automatically install a downloaded update on app quit (if `QuitAndInstall` was not called before).
|
||||
///
|
||||
/// Applicable only on Windows and Linux.
|
||||
/// </summary>
|
||||
public Task<bool> IsAutoInstallOnAppQuitEnabledAsync => BridgeConnector.OnResult<bool>("autoUpdater-autoInstallOnAppQuit-get", "autoUpdater-autoInstallOnAppQuit-get-reply");
|
||||
|
||||
/// <summary>
|
||||
/// *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").
|
||||
/// </summary>
|
||||
public Task<bool> IsAllowPrereleaseEnabledAsync => BridgeConnector.OnResult<bool>("autoUpdater-allowPrerelease-get", "autoUpdater-allowPrerelease-get-reply");
|
||||
|
||||
/// <summary>
|
||||
/// *GitHub provider only.*
|
||||
/// Get all release notes (from current version to latest), not just the latest (Default is false).
|
||||
/// </summary>
|
||||
public Task<bool> IsFullChangeLogEnabledAsync => BridgeConnector.OnResult<bool>("autoUpdater-fullChangelog-get", "autoUpdater-fullChangelog-get-reply");
|
||||
|
||||
public Task<bool> IsAllowDowngradeEnabledAsync => BridgeConnector.OnResult<bool>("autoUpdater-allowDowngrade-get", "autoUpdater-allowDowngrade-get-reply");
|
||||
|
||||
/// <summary>
|
||||
/// Whether to automatically download an update when it is found. (Default is true)
|
||||
/// </summary>
|
||||
public bool AutoDownload
|
||||
{
|
||||
set
|
||||
{
|
||||
BridgeConnector.Emit("autoUpdater-autoDownload-set", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether to automatically install a downloaded update on app quit (if `QuitAndInstall` was not called before).
|
||||
///
|
||||
/// Applicable only on Windows and Linux.
|
||||
/// </summary>
|
||||
public bool AutoInstallOnAppQuit
|
||||
{
|
||||
set
|
||||
{
|
||||
BridgeConnector.Emit("autoUpdater-autoInstallOnAppQuit-set", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// *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").
|
||||
/// </summary>
|
||||
public bool AllowPrerelease
|
||||
{
|
||||
set
|
||||
{
|
||||
BridgeConnector.Emit("autoUpdater-allowPrerelease-set", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// *GitHub provider only.*
|
||||
/// Get all release notes (from current version to latest), not just the latest (Default is false).
|
||||
/// </summary>
|
||||
public bool FullChangelog
|
||||
{
|
||||
set
|
||||
{
|
||||
BridgeConnector.Emit("autoUpdater-fullChangelog-set", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether to allow version downgrade (when a user from the beta channel wants to go back to the stable channel).
|
||||
/// Taken in account only if channel differs (pre-release version component in terms of semantic versioning).
|
||||
/// Default is false.
|
||||
/// </summary>
|
||||
public bool AllowDowngrade
|
||||
{
|
||||
set
|
||||
{
|
||||
BridgeConnector.Emit("autoUpdater-allowDowngrade-set", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For test only.
|
||||
/// </summary>
|
||||
public Task<string> GetUpdateConfigPathAsync => BridgeConnector.OnResult<string>("autoUpdater-updateConfigPath-get", "autoUpdater-updateConfigPath-get-reply");
|
||||
|
||||
/// <summary>
|
||||
/// The current application version
|
||||
/// </summary>
|
||||
public Task<SemVer> GetCurrentVersionAsync => BridgeConnector.OnResult<SemVer>("autoUpdater-updateConcurrentVersionfigPath-get", "autoUpdater-currentVersion-get-reply");
|
||||
|
||||
/// <summary>
|
||||
/// Get the update channel. Not applicable for GitHub.
|
||||
/// Doesn’t return channel from the update configuration, only if was previously set.
|
||||
/// </summary>
|
||||
public Task<string> GetChannelAsync => BridgeConnector.OnResult<string>("autoUpdater-channel-get", "autoUpdater-channel-get-reply");
|
||||
|
||||
/// <summary>
|
||||
/// The request headers.
|
||||
/// </summary>
|
||||
public Task<Dictionary<string, string>> GetRequestHeadersAsync => BridgeConnector.OnResult<Dictionary<string, string>>("autoUpdater-requestHeaders-get", "autoUpdater-requestHeaders-get-reply");
|
||||
|
||||
/// <summary>
|
||||
/// The request headers.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> RequestHeaders
|
||||
{
|
||||
set
|
||||
{
|
||||
BridgeConnector.Emit("autoUpdater-requestHeaders-set", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Emitted when there is an error while updating.
|
||||
/// </summary>
|
||||
public event Action<string> OnError
|
||||
{
|
||||
add
|
||||
{
|
||||
if (_error == null)
|
||||
{
|
||||
BridgeConnector.On<string>("autoUpdater-error" + GetHashCode(), (message) =>
|
||||
{
|
||||
_error(message.ToString());
|
||||
});
|
||||
|
||||
BridgeConnector.Emit("register-autoUpdater-error-event", GetHashCode());
|
||||
}
|
||||
_error += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_error -= value;
|
||||
|
||||
if (_error == null)
|
||||
BridgeConnector.Off("autoUpdater-error" + GetHashCode());
|
||||
}
|
||||
}
|
||||
|
||||
private event Action<string> _error;
|
||||
|
||||
/// <summary>
|
||||
/// Emitted when checking if an update has started.
|
||||
/// </summary>
|
||||
public event Action OnCheckingForUpdate
|
||||
{
|
||||
add
|
||||
{
|
||||
if (_checkingForUpdate == null)
|
||||
{
|
||||
BridgeConnector.On("autoUpdater-checking-for-update" + GetHashCode(), () =>
|
||||
{
|
||||
_checkingForUpdate();
|
||||
});
|
||||
|
||||
BridgeConnector.Emit("register-autoUpdater-checking-for-update-event", GetHashCode());
|
||||
}
|
||||
_checkingForUpdate += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_checkingForUpdate -= value;
|
||||
|
||||
if (_checkingForUpdate == null)
|
||||
BridgeConnector.Off("autoUpdater-checking-for-update" + GetHashCode());
|
||||
}
|
||||
}
|
||||
|
||||
private event Action _checkingForUpdate;
|
||||
|
||||
/// <summary>
|
||||
/// Emitted when there is an available update.
|
||||
/// The update is downloaded automatically if AutoDownload is true.
|
||||
/// </summary>
|
||||
public event Action<UpdateInfo> OnUpdateAvailable
|
||||
{
|
||||
add
|
||||
{
|
||||
if (_updateAvailable == null)
|
||||
{
|
||||
BridgeConnector.On<UpdateInfo>("autoUpdater-update-available" + GetHashCode(), (updateInfo) =>
|
||||
{
|
||||
_updateAvailable(updateInfo);
|
||||
});
|
||||
|
||||
BridgeConnector.Emit("register-autoUpdater-update-available-event", GetHashCode());
|
||||
}
|
||||
_updateAvailable += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_updateAvailable -= value;
|
||||
|
||||
if (_updateAvailable == null)
|
||||
BridgeConnector.Off("autoUpdater-update-available" + GetHashCode());
|
||||
}
|
||||
}
|
||||
|
||||
private event Action<UpdateInfo> _updateAvailable;
|
||||
|
||||
/// <summary>
|
||||
/// Emitted when there is no available update.
|
||||
/// </summary>
|
||||
public event Action<UpdateInfo> OnUpdateNotAvailable
|
||||
{
|
||||
add
|
||||
{
|
||||
if (_updateNotAvailable == null)
|
||||
{
|
||||
BridgeConnector.On<UpdateInfo>("autoUpdater-update-not-available" + GetHashCode(), (updateInfo) =>
|
||||
{
|
||||
_updateNotAvailable(updateInfo);
|
||||
});
|
||||
|
||||
BridgeConnector.Emit("register-autoUpdater-update-not-available-event", GetHashCode());
|
||||
}
|
||||
_updateNotAvailable += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_updateNotAvailable -= value;
|
||||
|
||||
if (_updateNotAvailable == null)
|
||||
BridgeConnector.Off("autoUpdater-update-not-available" + GetHashCode());
|
||||
}
|
||||
}
|
||||
|
||||
private event Action<UpdateInfo> _updateNotAvailable;
|
||||
|
||||
/// <summary>
|
||||
/// Emitted on download progress.
|
||||
/// </summary>
|
||||
public event Action<ProgressInfo> OnDownloadProgress
|
||||
{
|
||||
add
|
||||
{
|
||||
if (_downloadProgress == null)
|
||||
{
|
||||
BridgeConnector.On<ProgressInfo>("autoUpdater-download-progress" + GetHashCode(), (progressInfo) =>
|
||||
{
|
||||
_downloadProgress(progressInfo);
|
||||
});
|
||||
|
||||
BridgeConnector.Emit("register-autoUpdater-download-progress-event", GetHashCode());
|
||||
}
|
||||
_downloadProgress += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_downloadProgress -= value;
|
||||
|
||||
if (_downloadProgress == null)
|
||||
BridgeConnector.Off("autoUpdater-download-progress" + GetHashCode());
|
||||
}
|
||||
}
|
||||
|
||||
private event Action<ProgressInfo> _downloadProgress;
|
||||
|
||||
/// <summary>
|
||||
/// Emitted on download complete.
|
||||
/// </summary>
|
||||
public event Action<UpdateInfo> OnUpdateDownloaded
|
||||
{
|
||||
add
|
||||
{
|
||||
if (_updateDownloaded == null)
|
||||
{
|
||||
BridgeConnector.On<UpdateInfo>("autoUpdater-update-downloaded" + GetHashCode(), (updateInfo) =>
|
||||
{
|
||||
_updateDownloaded(updateInfo);
|
||||
});
|
||||
|
||||
BridgeConnector.Emit("register-autoUpdater-update-downloaded-event", GetHashCode());
|
||||
}
|
||||
_updateDownloaded += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_updateDownloaded -= value;
|
||||
|
||||
if (_updateDownloaded == null)
|
||||
BridgeConnector.Off("autoUpdater-update-downloaded" + GetHashCode());
|
||||
}
|
||||
}
|
||||
|
||||
private event Action<UpdateInfo> _updateDownloaded;
|
||||
|
||||
private static AutoUpdater _autoUpdater;
|
||||
private static readonly object _syncRoot = new();
|
||||
|
||||
internal AutoUpdater() { }
|
||||
|
||||
internal static AutoUpdater Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_autoUpdater == null)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
if (_autoUpdater == null)
|
||||
{
|
||||
_autoUpdater = new AutoUpdater();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _autoUpdater;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asks the server whether there is an update.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task<UpdateCheckResult> CheckForUpdatesAsync()
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<UpdateCheckResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
string guid = Guid.NewGuid().ToString();
|
||||
|
||||
BridgeConnector.On<UpdateCheckResult>("autoUpdaterCheckForUpdatesComplete" + guid, (updateCheckResult) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
BridgeConnector.Off("autoUpdaterCheckForUpdatesComplete" + guid);
|
||||
BridgeConnector.Off("autoUpdaterCheckForUpdatesError" + guid);
|
||||
taskCompletionSource.SetResult(updateCheckResult);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
taskCompletionSource.SetException(ex);
|
||||
}
|
||||
});
|
||||
BridgeConnector.On<string>("autoUpdaterCheckForUpdatesError" + guid, (error) =>
|
||||
{
|
||||
BridgeConnector.Off("autoUpdaterCheckForUpdatesComplete" + guid);
|
||||
BridgeConnector.Off("autoUpdaterCheckForUpdatesError" + guid);
|
||||
string message = "An error occurred in CheckForUpdatesAsync";
|
||||
if (error != null && !string.IsNullOrEmpty(error.ToString()))
|
||||
message = JsonConvert.SerializeObject(error);
|
||||
taskCompletionSource.SetException(new Exception(message));
|
||||
});
|
||||
|
||||
BridgeConnector.Emit("autoUpdaterCheckForUpdates", guid);
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asks the server whether there is an update.
|
||||
///
|
||||
/// This will immediately download an update, then install when the app quits.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task<UpdateCheckResult> CheckForUpdatesAndNotifyAsync()
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<UpdateCheckResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
string guid = Guid.NewGuid().ToString();
|
||||
|
||||
BridgeConnector.On<UpdateCheckResult>("autoUpdaterCheckForUpdatesAndNotifyComplete" + guid, (updateCheckResult) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
BridgeConnector.Off("autoUpdaterCheckForUpdatesAndNotifyComplete" + guid);
|
||||
BridgeConnector.Off("autoUpdaterCheckForUpdatesAndNotifyError" + guid);
|
||||
if (updateCheckResult == null)
|
||||
taskCompletionSource.SetResult(null);
|
||||
else
|
||||
taskCompletionSource.SetResult(updateCheckResult);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
taskCompletionSource.SetException(ex);
|
||||
}
|
||||
});
|
||||
BridgeConnector.On<string>("autoUpdaterCheckForUpdatesAndNotifyError" + guid, (error) =>
|
||||
{
|
||||
BridgeConnector.Off("autoUpdaterCheckForUpdatesAndNotifyComplete" + guid);
|
||||
BridgeConnector.Off("autoUpdaterCheckForUpdatesAndNotifyError" + guid);
|
||||
string message = "An error occurred in autoUpdaterCheckForUpdatesAndNotify";
|
||||
if (error != null)
|
||||
message = JsonConvert.SerializeObject(error);
|
||||
taskCompletionSource.SetException(new Exception(message));
|
||||
});
|
||||
|
||||
BridgeConnector.Emit("autoUpdaterCheckForUpdatesAndNotify", guid);
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
|
||||
/// <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.
|
||||
/// </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>
|
||||
public void QuitAndInstall(bool isSilent = false, bool isForceRunAfter = false)
|
||||
{
|
||||
BridgeConnector.EmitSync("prepare-for-update");
|
||||
BridgeConnector.EmitSync("autoUpdaterQuitAndInstall", isSilent, isForceRunAfter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start downloading update manually. You can use this method if "AutoDownload" option is set to "false".
|
||||
/// </summary>
|
||||
/// <returns>Path to downloaded file.</returns>
|
||||
public Task<string> DownloadUpdateAsync()
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
string guid = Guid.NewGuid().ToString();
|
||||
|
||||
BridgeConnector.On<string>("autoUpdaterDownloadUpdateComplete" + guid, (downloadedPath) =>
|
||||
{
|
||||
BridgeConnector.Off("autoUpdaterDownloadUpdateComplete" + guid);
|
||||
taskCompletionSource.SetResult(downloadedPath.ToString());
|
||||
});
|
||||
|
||||
BridgeConnector.Emit("autoUpdaterDownloadUpdate", guid);
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Feed URL.
|
||||
/// </summary>
|
||||
/// <returns>Feed URL.</returns>
|
||||
public Task<string> GetFeedURLAsync()
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
string guid = Guid.NewGuid().ToString();
|
||||
|
||||
BridgeConnector.On<string>("autoUpdaterGetFeedURLComplete" + guid, (downloadedPath) =>
|
||||
{
|
||||
BridgeConnector.Off("autoUpdaterGetFeedURLComplete" + guid);
|
||||
taskCompletionSource.SetResult(downloadedPath.ToString());
|
||||
});
|
||||
|
||||
BridgeConnector.Emit("autoUpdaterGetFeedURL", guid);
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
}
|
||||
}
|
||||
551
ElectronNET.API/BridgeConnector.cs
Normal file
551
ElectronNET.API/BridgeConnector.cs
Normal file
@@ -0,0 +1,551 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Nito.AsyncEx;
|
||||
using SocketIOClient;
|
||||
using SocketIOClient.Newtonsoft.Json;
|
||||
|
||||
namespace ElectronNET.API
|
||||
{
|
||||
internal static class BridgeConnector
|
||||
{
|
||||
internal static class EventTasks<T>
|
||||
{
|
||||
//Although SocketIO already manage event handlers, we need to manage this here as well for the OnResult calls,
|
||||
//because SocketIO will simply replace the existing event handler on every call to On(key, ...) , which means there is
|
||||
//a race condition between On / Off calls that can lead to tasks deadlocking forever without ever triggering their On handler
|
||||
|
||||
private static readonly Dictionary<string, TaskCompletionSource<T>> _taskCompletionSources = new();
|
||||
private static readonly Dictionary<string, string> _eventKeys = new();
|
||||
private static readonly object _lock = new();
|
||||
|
||||
/// <summary>
|
||||
/// Get or add a new TaskCompletionSource<typeparamref name="T"/> for a given event key
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="eventKey"></param>
|
||||
/// <param name="taskCompletionSource"></param>
|
||||
/// <param name="waitThisFirstAndThenTryAgain"></param>
|
||||
/// <returns>Returns true if a new TaskCompletionSource<typeparamref name="T"/> was added to the dictionary</returns>
|
||||
internal static bool TryGetOrAdd(string key, string eventKey, out TaskCompletionSource<T> taskCompletionSource, out Task waitThisFirstAndThenTryAgain)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_taskCompletionSources.TryGetValue(key, out taskCompletionSource))
|
||||
{
|
||||
taskCompletionSource = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
_taskCompletionSources[key] = taskCompletionSource;
|
||||
_eventKeys[key] = eventKey;
|
||||
waitThisFirstAndThenTryAgain = null;
|
||||
return true; //Was added, so we need to also register the socket events
|
||||
}
|
||||
|
||||
if (_eventKeys.TryGetValue(key, out var existingEventKey) && existingEventKey == eventKey)
|
||||
{
|
||||
waitThisFirstAndThenTryAgain = null;
|
||||
return false; //No need to register the socket events twice
|
||||
}
|
||||
|
||||
waitThisFirstAndThenTryAgain = taskCompletionSource.Task; //Will need to try again after the previous existing one is done
|
||||
|
||||
taskCompletionSource = null;
|
||||
|
||||
return true; //Need to register the socket events, but must first await the previous task to complete
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clean up the TaskCompletionSource<typeparamref name="T"/> from the dictionary if and only if it is the same as the passed argument
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="eventKey"></param>
|
||||
/// <param name="taskCompletionSource"></param>
|
||||
internal static void DoneWith(string key, string eventKey, TaskCompletionSource<T> taskCompletionSource)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_taskCompletionSources.TryGetValue(key, out var existingTaskCompletionSource)
|
||||
&& ReferenceEquals(existingTaskCompletionSource, taskCompletionSource))
|
||||
{
|
||||
_taskCompletionSources.Remove(key);
|
||||
}
|
||||
|
||||
if (_eventKeys.TryGetValue(key, out var existingEventKey) && existingEventKey == eventKey)
|
||||
{
|
||||
_eventKeys.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static SocketIO _socket;
|
||||
|
||||
private static readonly object _syncRoot = new();
|
||||
|
||||
private static readonly SemaphoreSlim _socketSemaphoreEmit = new(1, 1);
|
||||
private static readonly SemaphoreSlim _socketSemaphoreHandlers = new(1, 1);
|
||||
|
||||
private static AsyncManualResetEvent _connectedSocketEvent = new AsyncManualResetEvent();
|
||||
|
||||
private static Dictionary<string, Action<SocketIOResponse>> _eventHandlers = new();
|
||||
|
||||
private static Task<SocketIO> _waitForConnection
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureSocketTaskIsCreated();
|
||||
return GetSocket();
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<SocketIO> GetSocket()
|
||||
{
|
||||
await _connectedSocketEvent.WaitAsync();
|
||||
return _socket;
|
||||
}
|
||||
|
||||
public static bool IsConnected => _waitForConnection is Task task && task.IsCompletedSuccessfully;
|
||||
|
||||
public static void Emit(string eventString, params object[] args)
|
||||
{
|
||||
//We don't care about waiting for the event to be emitted, so this doesn't need to be async
|
||||
|
||||
Task.Run(() => EmitAsync(eventString, args));
|
||||
}
|
||||
|
||||
private static async Task EmitAsync(string eventString, object[] args)
|
||||
{
|
||||
if (App.SocketDebug)
|
||||
{
|
||||
Log("Sending event {0}", eventString);
|
||||
}
|
||||
|
||||
var socket = await _waitForConnection;
|
||||
|
||||
await _socketSemaphoreEmit.WaitAsync();
|
||||
|
||||
try
|
||||
{
|
||||
await socket.EmitAsync(eventString, args);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_socketSemaphoreEmit.Release();
|
||||
}
|
||||
|
||||
if (App.SocketDebug)
|
||||
{
|
||||
Log($"Sent event {eventString}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is only used on places where we need to be sure the event was sent on the socket, such as Quit, Exit, Relaunch and QuitAndInstall methods
|
||||
/// </summary>
|
||||
/// <param name="eventString"></param>
|
||||
/// <param name="args"></param>
|
||||
internal static void EmitSync(string eventString, params object[] args)
|
||||
{
|
||||
if (App.SocketDebug)
|
||||
{
|
||||
Log("Sending event {0}", eventString);
|
||||
}
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
var socket = await _waitForConnection;
|
||||
try
|
||||
{
|
||||
await _socketSemaphoreEmit.WaitAsync();
|
||||
await socket.EmitAsync(eventString, args);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_socketSemaphoreEmit.Release();
|
||||
}
|
||||
}).Wait();
|
||||
|
||||
|
||||
if (App.SocketDebug)
|
||||
{
|
||||
Log("Sent event {0}", eventString);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Off(string eventString)
|
||||
{
|
||||
EnsureSocketTaskIsCreated();
|
||||
|
||||
_socketSemaphoreHandlers.Wait();
|
||||
try
|
||||
{
|
||||
if (_eventHandlers.ContainsKey(eventString))
|
||||
{
|
||||
_eventHandlers.Remove(eventString);
|
||||
}
|
||||
|
||||
_socket.Off(eventString);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_socketSemaphoreHandlers.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public static void On(string eventString, Action fn)
|
||||
{
|
||||
EnsureSocketTaskIsCreated();
|
||||
|
||||
_socketSemaphoreHandlers.Wait();
|
||||
try
|
||||
{
|
||||
if (_eventHandlers.ContainsKey(eventString))
|
||||
{
|
||||
_eventHandlers.Remove(eventString);
|
||||
}
|
||||
|
||||
_eventHandlers.Add(eventString, _ =>
|
||||
{
|
||||
try
|
||||
{
|
||||
fn();
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogError(E, "Error running handler for event {0}", eventString);
|
||||
}
|
||||
});
|
||||
|
||||
_socket.On(eventString, _eventHandlers[eventString]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_socketSemaphoreHandlers.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public static void On<T>(string eventString, Action<T> fn)
|
||||
{
|
||||
EnsureSocketTaskIsCreated();
|
||||
|
||||
_socketSemaphoreHandlers.Wait();
|
||||
try
|
||||
{
|
||||
if (_eventHandlers.ContainsKey(eventString))
|
||||
{
|
||||
_eventHandlers.Remove(eventString);
|
||||
}
|
||||
|
||||
_eventHandlers.Add(eventString, o =>
|
||||
{
|
||||
try
|
||||
{
|
||||
fn(o.GetValue<T>(0));
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogError(E, "Error running handler for event {0}", eventString);
|
||||
}
|
||||
});
|
||||
|
||||
_socket.On(eventString, _eventHandlers[eventString]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_socketSemaphoreHandlers.Release();
|
||||
}
|
||||
}
|
||||
|
||||
private static void RehookHandlers(SocketIO newSocket)
|
||||
{
|
||||
_socketSemaphoreHandlers.Wait();
|
||||
try
|
||||
{
|
||||
foreach (var kv in _eventHandlers)
|
||||
{
|
||||
newSocket.On(kv.Key, kv.Value);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_socketSemaphoreHandlers.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Once<T>(string eventString, Action<T> fn)
|
||||
{
|
||||
On<T>(eventString, (o) =>
|
||||
{
|
||||
Off(eventString);
|
||||
fn(o);
|
||||
});
|
||||
}
|
||||
|
||||
public static async Task<T> OnResult<T>(string triggerEvent, string completedEvent, params object[] args)
|
||||
{
|
||||
string eventKey = completedEvent;
|
||||
|
||||
if (args is object && args.Length > 0) // If there are arguments passed, we generate a unique event key with the arguments
|
||||
// this allow us to wait for previous events first before registering new ones
|
||||
{
|
||||
var hash = new HashCode();
|
||||
foreach (var obj in args)
|
||||
{
|
||||
hash.Add(obj);
|
||||
}
|
||||
eventKey = $"{eventKey}-{(uint)hash.ToHashCode()}";
|
||||
}
|
||||
|
||||
if (EventTasks<T>.TryGetOrAdd(completedEvent, eventKey, out var taskCompletionSource, out var waitThisFirstAndThenTryAgain))
|
||||
{
|
||||
if (waitThisFirstAndThenTryAgain is object)
|
||||
{
|
||||
//There was a pending call with different parameters, so we need to wait that first and then call here again
|
||||
try
|
||||
{
|
||||
await waitThisFirstAndThenTryAgain;
|
||||
}
|
||||
catch
|
||||
{
|
||||
//Ignore any exceptions here so we can set a new event below
|
||||
//The exception will also be visible to the original first caller due to taskCompletionSource.Task
|
||||
}
|
||||
|
||||
//Try again to set the event
|
||||
return await OnResult<T>(triggerEvent, completedEvent, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
//A new TaskCompletionSource was added, so we need to register the completed event here
|
||||
|
||||
On<T>(completedEvent, (result) =>
|
||||
{
|
||||
Off(completedEvent);
|
||||
taskCompletionSource.SetResult(result);
|
||||
EventTasks<T>.DoneWith(completedEvent, eventKey, taskCompletionSource);
|
||||
});
|
||||
|
||||
await EmitAsync(triggerEvent, args);
|
||||
}
|
||||
}
|
||||
|
||||
return await taskCompletionSource.Task;
|
||||
}
|
||||
|
||||
|
||||
public static async Task<T> OnResult<T>(string triggerEvent, string completedEvent, CancellationToken cancellationToken, params object[] args)
|
||||
{
|
||||
string eventKey = completedEvent;
|
||||
|
||||
if (args is object && args.Length > 0) // If there are arguments passed, we generate a unique event key with the arguments
|
||||
// this allow us to wait for previous events first before registering new ones
|
||||
{
|
||||
var hash = new HashCode();
|
||||
foreach (var obj in args)
|
||||
{
|
||||
hash.Add(obj);
|
||||
}
|
||||
eventKey = $"{eventKey}-{(uint)hash.ToHashCode()}";
|
||||
}
|
||||
|
||||
if (EventTasks<T>.TryGetOrAdd(completedEvent, eventKey, out var taskCompletionSource, out var waitThisFirstAndThenTryAgain))
|
||||
{
|
||||
if (waitThisFirstAndThenTryAgain is object)
|
||||
{
|
||||
//There was a pending call with different parameters, so we need to wait that first and then call here again
|
||||
try
|
||||
{
|
||||
await Task.Run(() => waitThisFirstAndThenTryAgain, cancellationToken);
|
||||
}
|
||||
catch
|
||||
{
|
||||
//Ignore any exceptions here so we can set a new event below
|
||||
//The exception will also be visible to the original first caller due to taskCompletionSource.Task
|
||||
}
|
||||
|
||||
//Try again to set the event
|
||||
return await OnResult<T>(triggerEvent, completedEvent, cancellationToken, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
|
||||
{
|
||||
//A new TaskCompletionSource was added, so we need to register the completed event here
|
||||
|
||||
On<T>(completedEvent, (result) =>
|
||||
{
|
||||
Off(completedEvent);
|
||||
taskCompletionSource.SetResult(result);
|
||||
EventTasks<T>.DoneWith(completedEvent, eventKey, taskCompletionSource);
|
||||
});
|
||||
|
||||
Emit(triggerEvent, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return await taskCompletionSource.Task;
|
||||
}
|
||||
|
||||
internal static void Log(string formatString, params object[] args)
|
||||
{
|
||||
if (Logger is object)
|
||||
{
|
||||
Logger.LogInformation(formatString, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine(formatString, args);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void LogError(Exception E, string formatString, params object[] args)
|
||||
{
|
||||
if (Logger is object)
|
||||
{
|
||||
Logger.LogError(E, formatString, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine(formatString, args);
|
||||
Console.WriteLine(E.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private static Thread _backgroundMonitorThread;
|
||||
|
||||
private static void EnsureSocketTaskIsCreated()
|
||||
{
|
||||
if (_socket is null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(AuthKey))
|
||||
{
|
||||
throw new Exception("You must call Electron.ReadAuth() first thing on your main entry point.");
|
||||
}
|
||||
|
||||
if (HybridSupport.IsElectronActive)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
if (_socket is null)
|
||||
{
|
||||
if (HybridSupport.IsElectronActive)
|
||||
{
|
||||
var socket = new SocketIO($"http://localhost:{BridgeSettings.SocketPort}", new SocketIOOptions()
|
||||
{
|
||||
EIO = 4,
|
||||
Reconnection = true,
|
||||
ReconnectionAttempts = int.MaxValue,
|
||||
ReconnectionDelay = 500,
|
||||
ReconnectionDelayMax = 2000,
|
||||
RandomizationFactor = 0.5,
|
||||
ConnectionTimeout = TimeSpan.FromSeconds(10),
|
||||
Transport = SocketIOClient.Transport.TransportProtocol.WebSocket
|
||||
});
|
||||
|
||||
socket.JsonSerializer = new CamelCaseNewtonsoftJsonSerializer();
|
||||
|
||||
_connectedSocketEvent.Reset();
|
||||
|
||||
socket.OnConnected += (_, __) =>
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await socket.EmitAsync("auth", AuthKey);
|
||||
_connectedSocketEvent.Set();
|
||||
Log("ElectronNET socket {1} connected on port {0}!", BridgeSettings.SocketPort, socket.Id);
|
||||
});
|
||||
};
|
||||
|
||||
socket.OnReconnectAttempt += (_, __) =>
|
||||
{
|
||||
_connectedSocketEvent.Reset();
|
||||
Log("ElectronNET socket {1} is trying to reconnect on port {0}...", BridgeSettings.SocketPort, socket.Id);
|
||||
};
|
||||
|
||||
socket.OnReconnectError += (_, ex) =>
|
||||
{
|
||||
_connectedSocketEvent.Reset();
|
||||
Log("ElectronNET socket {1} failed to connect {0}", ex, socket.Id);
|
||||
};
|
||||
|
||||
|
||||
socket.OnReconnectFailed += (_, ex) =>
|
||||
{
|
||||
_connectedSocketEvent.Reset();
|
||||
Log("ElectronNET socket {1} failed to reconnect {0}", ex, socket.Id);
|
||||
};
|
||||
|
||||
socket.OnReconnected += (_, __) =>
|
||||
{
|
||||
_connectedSocketEvent.Set();
|
||||
Log("ElectronNET socket {1} reconnected on port {0}...", BridgeSettings.SocketPort, socket.Id);
|
||||
};
|
||||
|
||||
socket.OnDisconnected += (_, reason) =>
|
||||
{
|
||||
_connectedSocketEvent.Reset();
|
||||
Log("ElectronNET socket {2} disconnected with reason {0}, trying to reconnect on port {1}!", reason, BridgeSettings.SocketPort, socket.Id);
|
||||
};
|
||||
|
||||
socket.OnError += (_, msg) =>
|
||||
{
|
||||
//_connectedSocketEvent.Reset();
|
||||
Log("ElectronNET socket {1} error: {0}...", msg, socket.Id);
|
||||
};
|
||||
|
||||
_socket = socket;
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await socket.ConnectAsync();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e.ToString());
|
||||
|
||||
if (!App.TryRaiseOnSocketConnectFail())
|
||||
{
|
||||
Environment.Exit(0xDEAD);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
RehookHandlers(socket);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Missing Socket Port");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Missing Socket Port");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static ILogger<App> Logger { private get; set; }
|
||||
internal static string AuthKey { get; set; } = null;
|
||||
|
||||
private class CamelCaseNewtonsoftJsonSerializer : NewtonsoftJsonSerializer
|
||||
{
|
||||
public CamelCaseNewtonsoftJsonSerializer() : base()
|
||||
{
|
||||
OptionsProvider = () => new JsonSerializerSettings()
|
||||
{
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,5 +20,16 @@
|
||||
/// The web port.
|
||||
/// </value>
|
||||
public static string WebPort { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Manually set the port values instead of using the UseElectron extension method
|
||||
/// </summary>
|
||||
/// <param name="socketPort"></param>
|
||||
/// <param name="webPort"></param>
|
||||
public static void InitializePorts(int socketPort, int webPort)
|
||||
{
|
||||
SocketPort = socketPort.ToString();
|
||||
WebPort = webPort.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,29 +31,15 @@ namespace ElectronNET.API
|
||||
///
|
||||
/// (experimental)
|
||||
/// </summary>
|
||||
public Rectangle Bounds
|
||||
public Task<Rectangle> GetBoundsAsync() => BridgeConnector.OnResult<Rectangle>("browserView-getBounds", "browserView-getBounds-reply" + Id, Id);
|
||||
|
||||
/// <summary>
|
||||
/// Set the bounds of the current view inside the window
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void SetBounds(Rectangle value)
|
||||
{
|
||||
get
|
||||
{
|
||||
return Task.Run<Rectangle>(() =>
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<Rectangle>();
|
||||
|
||||
BridgeConnector.Socket.On("browserView-getBounds-reply", (result) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("browserView-getBounds-reply");
|
||||
taskCompletionSource.SetResult((Rectangle)result);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("browserView-getBounds", Id);
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}).Result;
|
||||
}
|
||||
set
|
||||
{
|
||||
BridgeConnector.Socket.Emit("browserView-setBounds", Id, JObject.FromObject(value, _jsonSerializer));
|
||||
}
|
||||
BridgeConnector.Emit("browserView-setBounds", Id, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -74,7 +60,7 @@ namespace ElectronNET.API
|
||||
/// <param name="options"></param>
|
||||
public void SetAutoResize(AutoResizeOptions options)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("browserView-setAutoResize", Id, JObject.FromObject(options, _jsonSerializer));
|
||||
BridgeConnector.Emit("browserView-setAutoResize", Id, options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -85,13 +71,7 @@ namespace ElectronNET.API
|
||||
/// <param name="color">Color in #aarrggbb or #argb form. The alpha channel is optional.</param>
|
||||
public void SetBackgroundColor(string color)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("browserView-setBackgroundColor", Id, color);
|
||||
BridgeConnector.Emit("browserView-setBackgroundColor", Id, color);
|
||||
}
|
||||
|
||||
private JsonSerializer _jsonSerializer = new JsonSerializer()
|
||||
{
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
};
|
||||
}
|
||||
}
|
||||
2135
ElectronNET.API/BrowserWindow.cs
Normal file
2135
ElectronNET.API/BrowserWindow.cs
Normal file
File diff suppressed because it is too large
Load Diff
144
src/ElectronNET.API/Clipboard.cs → ElectronNET.API/Clipboard.cs
Normal file → Executable file
144
src/ElectronNET.API/Clipboard.cs → ElectronNET.API/Clipboard.cs
Normal file → Executable file
@@ -2,17 +2,19 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading.Tasks;
|
||||
using ElectronNET.API.Interfaces;
|
||||
|
||||
namespace ElectronNET.API
|
||||
{
|
||||
/// <summary>
|
||||
/// Perform copy and paste operations on the system clipboard.
|
||||
/// </summary>
|
||||
public sealed class Clipboard
|
||||
public sealed class Clipboard : IClipboard
|
||||
{
|
||||
private static Clipboard _clipboard;
|
||||
private static object _syncRoot = new object();
|
||||
private static readonly object _syncRoot = new();
|
||||
|
||||
internal Clipboard() { }
|
||||
|
||||
@@ -40,21 +42,7 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns>The content in the clipboard as plain text.</returns>
|
||||
public Task<string> ReadTextAsync(string type = "")
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<string>();
|
||||
|
||||
BridgeConnector.Socket.On("clipboard-readText-Completed", (text) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("clipboard-readText-Completed");
|
||||
|
||||
taskCompletionSource.SetResult(text.ToString());
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("clipboard-readText", type);
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
public Task<string> ReadTextAsync(string type = "") => BridgeConnector.OnResult<string>("clipboard-readText", "clipboard-readText-Completed", type);
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text into the clipboard as plain text.
|
||||
@@ -63,7 +51,7 @@ namespace ElectronNET.API
|
||||
/// <param name="type"></param>
|
||||
public void WriteText(string text, string type = "")
|
||||
{
|
||||
BridgeConnector.Socket.Emit("clipboard-writeText", text, type);
|
||||
BridgeConnector.Emit("clipboard-writeText", text, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -71,21 +59,7 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public Task<string> ReadHTMLAsync(string type = "")
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<string>();
|
||||
|
||||
BridgeConnector.Socket.On("clipboard-readHTML-Completed", (text) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("clipboard-readHTML-Completed");
|
||||
|
||||
taskCompletionSource.SetResult(text.ToString());
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("clipboard-readHTML", type);
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
public Task<string> ReadHTMLAsync(string type = "") => BridgeConnector.OnResult<string>("clipboard-readHTML", "clipboard-readHTML-Completed", type);
|
||||
|
||||
/// <summary>
|
||||
/// Writes markup to the clipboard.
|
||||
@@ -94,7 +68,7 @@ namespace ElectronNET.API
|
||||
/// <param name="type"></param>
|
||||
public void WriteHTML(string markup, string type = "")
|
||||
{
|
||||
BridgeConnector.Socket.Emit("clipboard-writeHTML", markup, type);
|
||||
BridgeConnector.Emit("clipboard-writeHTML", markup, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -102,21 +76,8 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public Task<string> ReadRTFAsync(string type = "")
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<string>();
|
||||
public Task<string> ReadRTFAsync(string type = "") => BridgeConnector.OnResult<string>("clipboard-readRTF", "clipboard-readRTF-Completed", type);
|
||||
|
||||
BridgeConnector.Socket.On("clipboard-readRTF-Completed", (text) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("clipboard-readRTF-Completed");
|
||||
|
||||
taskCompletionSource.SetResult(text.ToString());
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("clipboard-readRTF", type);
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text into the clipboard in RTF.
|
||||
@@ -125,7 +86,7 @@ namespace ElectronNET.API
|
||||
/// <param name="type"></param>
|
||||
public void WriteRTF(string text, string type = "")
|
||||
{
|
||||
BridgeConnector.Socket.Emit("clipboard-writeHTML", text, type);
|
||||
BridgeConnector.Emit("clipboard-writeHTML", text, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -134,21 +95,9 @@ namespace ElectronNET.API
|
||||
/// be empty strings when the bookmark is unavailable.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task<ReadBookmark> ReadBookmarkAsync()
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<ReadBookmark>();
|
||||
|
||||
BridgeConnector.Socket.On("clipboard-readBookmark-Completed", (bookmark) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("clipboard-readBookmark-Completed");
|
||||
|
||||
taskCompletionSource.SetResult(((JObject)bookmark).ToObject<ReadBookmark>());
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("clipboard-readBookmark");
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
[SupportedOSPlatform("windows")]
|
||||
[SupportedOSPlatform("macos")]
|
||||
public Task<ReadBookmark> ReadBookmarkAsync() => BridgeConnector.OnResult<ReadBookmark>("clipboard-readBookmark", "clipboard-readBookmark-Completed");
|
||||
|
||||
/// <summary>
|
||||
/// Writes the title and url into the clipboard as a bookmark.
|
||||
@@ -160,9 +109,11 @@ namespace ElectronNET.API
|
||||
/// <param name="title"></param>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="type"></param>
|
||||
[SupportedOSPlatform("windows")]
|
||||
[SupportedOSPlatform("macos")]
|
||||
public void WriteBookmark(string title, string url, string type = "")
|
||||
{
|
||||
BridgeConnector.Socket.Emit("clipboard-writeBookmark", title, url, type);
|
||||
BridgeConnector.Emit("clipboard-writeBookmark", title, url, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -171,30 +122,18 @@ namespace ElectronNET.API
|
||||
/// find pasteboard whenever the application is activated.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task<string> ReadFindTextAsync()
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<string>();
|
||||
|
||||
BridgeConnector.Socket.On("clipboard-readFindText-Completed", (text) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("clipboard-readFindText-Completed");
|
||||
|
||||
taskCompletionSource.SetResult(text.ToString());
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("clipboard-readFindText");
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
[SupportedOSPlatform("macos")]
|
||||
public Task<string> ReadFindTextAsync() => BridgeConnector.OnResult<string>("clipboard-readFindText", "clipboard-readFindText-Completed");
|
||||
|
||||
/// <summary>
|
||||
/// 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);
|
||||
BridgeConnector.Emit("clipboard-writeFindText", text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -203,7 +142,7 @@ namespace ElectronNET.API
|
||||
/// <param name="type"></param>
|
||||
public void Clear(string type = "")
|
||||
{
|
||||
BridgeConnector.Socket.Emit("clipboard-clear", type);
|
||||
BridgeConnector.Emit("clipboard-clear", type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -211,21 +150,7 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public Task<string[]> AvailableFormatsAsync(string type = "")
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<string[]>();
|
||||
|
||||
BridgeConnector.Socket.On("clipboard-availableFormats-Completed", (formats) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("clipboard-availableFormats-Completed");
|
||||
|
||||
taskCompletionSource.SetResult(((JArray)formats).ToObject<string[]>());
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("clipboard-availableFormats", type);
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
public Task<string[]> AvailableFormatsAsync(string type = "") => BridgeConnector.OnResult<string[]>("clipboard-availableFormats", "clipboard-availableFormats-Completed", type);
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to the clipboard.
|
||||
@@ -234,7 +159,7 @@ namespace ElectronNET.API
|
||||
/// <param name="type"></param>
|
||||
public void Write(Data data, string type = "")
|
||||
{
|
||||
BridgeConnector.Socket.Emit("clipboard-write", JObject.FromObject(data, _jsonSerializer), type);
|
||||
BridgeConnector.Emit("clipboard-write", JObject.FromObject(data, _jsonSerializer), type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -242,24 +167,7 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public Task<NativeImage> ReadImageAsync(string type = "")
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<NativeImage>();
|
||||
|
||||
BridgeConnector.Socket.On("clipboard-readImage-Completed", (image) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("clipboard-readImage-Completed");
|
||||
|
||||
var nativeImage = ((JObject)image).ToObject<NativeImage>();
|
||||
|
||||
taskCompletionSource.SetResult(nativeImage);
|
||||
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("clipboard-readImage", type);
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
public Task<NativeImage> ReadImageAsync(string type = "") => BridgeConnector.OnResult<NativeImage>("clipboard-readImage", "clipboard-readImage-Completed", type);
|
||||
|
||||
/// <summary>
|
||||
/// Writes an image to the clipboard.
|
||||
@@ -268,10 +176,10 @@ namespace ElectronNET.API
|
||||
/// <param name="type"></param>
|
||||
public void WriteImage(NativeImage image, string type = "")
|
||||
{
|
||||
BridgeConnector.Socket.Emit("clipboard-writeImage", JsonConvert.SerializeObject(image), type);
|
||||
BridgeConnector.Emit("clipboard-writeImage", JsonConvert.SerializeObject(image), type);
|
||||
}
|
||||
|
||||
private JsonSerializer _jsonSerializer = new JsonSerializer()
|
||||
private static readonly JsonSerializer _jsonSerializer = new()
|
||||
{
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
@@ -8,7 +8,7 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
public sealed class CommandLine
|
||||
{
|
||||
internal CommandLine() { }
|
||||
private CommandLine() { }
|
||||
|
||||
internal static CommandLine Instance
|
||||
{
|
||||
@@ -31,7 +31,7 @@ namespace ElectronNET.API
|
||||
|
||||
private static CommandLine _commandLine;
|
||||
|
||||
private static object _syncRoot = new object();
|
||||
private static readonly object _syncRoot = new();
|
||||
|
||||
/// <summary>
|
||||
/// Append a switch (with optional value) to Chromium's command line.
|
||||
@@ -43,7 +43,7 @@ namespace ElectronNET.API
|
||||
/// </remarks>
|
||||
public void AppendSwitch(string the_switch, string value = "")
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appCommandLineAppendSwitch", the_switch, value);
|
||||
BridgeConnector.Emit("appCommandLineAppendSwitch", the_switch, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -57,7 +57,7 @@ namespace ElectronNET.API
|
||||
/// </remarks>
|
||||
public void AppendArgument(string value)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appCommandLineAppendArgument", value);
|
||||
BridgeConnector.Emit("appCommandLineAppendArgument", value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -66,24 +66,7 @@ namespace ElectronNET.API
|
||||
/// <param name="switchName">A command-line switch</param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns>Whether the command-line switch is present.</returns>
|
||||
public async Task<bool> HasSwitchAsync(string switchName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<bool>();
|
||||
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
|
||||
{
|
||||
BridgeConnector.Socket.On("appCommandLineHasSwitchCompleted", (result) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("appCommandLineHasSwitchCompleted");
|
||||
taskCompletionSource.SetResult((bool)result);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("appCommandLineHasSwitch", switchName);
|
||||
|
||||
return await taskCompletionSource.Task.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
public Task<bool> HasSwitchAsync(string switchName, CancellationToken cancellationToken = default) => BridgeConnector.OnResult<bool>("appCommandLineHasSwitch", "appCommandLineHasSwitchCompleted", cancellationToken, switchName);
|
||||
|
||||
/// <summary>
|
||||
/// The command-line switch value.
|
||||
@@ -94,23 +77,6 @@ namespace ElectronNET.API
|
||||
/// <remarks>
|
||||
/// Note: When the switch is not present or has no value, it returns empty string.
|
||||
/// </remarks>
|
||||
public async Task<string> GetSwitchValueAsync(string switchName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<string>();
|
||||
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
|
||||
{
|
||||
BridgeConnector.Socket.On("appCommandLineGetSwitchValueCompleted", (result) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("appCommandLineGetSwitchValueCompleted");
|
||||
taskCompletionSource.SetResult((string)result);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("appCommandLineGetSwitchValue", switchName);
|
||||
|
||||
return await taskCompletionSource.Task.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
public Task<string> GetSwitchValueAsync(string switchName, CancellationToken cancellationToken = default) => BridgeConnector.OnResult<string>("appCommandLineGetSwitchValue", "appCommandLineGetSwitchValueCompleted", cancellationToken, switchName);
|
||||
}
|
||||
}
|
||||
@@ -34,15 +34,12 @@ namespace ElectronNET.API
|
||||
{
|
||||
if (_changed == null)
|
||||
{
|
||||
BridgeConnector.Socket.On("webContents-session-cookies-changed" + Id, (args) =>
|
||||
BridgeConnector.On<CookieRemovedResponse>("webContents-session-cookies-changed" + Id, (args) =>
|
||||
{
|
||||
Cookie cookie = ((JArray)args)[0].ToObject<Cookie>();
|
||||
CookieChangedCause cause = ((JArray)args)[1].ToObject<CookieChangedCause>();
|
||||
bool removed = ((JArray)args)[2].ToObject<bool>();
|
||||
_changed(cookie, cause, removed);
|
||||
_changed(args.cookie, args.cause, args.removed);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("register-webContents-session-cookies-changed", Id);
|
||||
BridgeConnector.Emit("register-webContents-session-cookies-changed", Id);
|
||||
}
|
||||
_changed += value;
|
||||
}
|
||||
@@ -51,7 +48,7 @@ namespace ElectronNET.API
|
||||
_changed -= value;
|
||||
|
||||
if (_changed == null)
|
||||
BridgeConnector.Socket.Off("webContents-session-cookies-changed" + Id);
|
||||
BridgeConnector.Off("webContents-session-cookies-changed" + Id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,18 +62,16 @@ namespace ElectronNET.API
|
||||
/// <returns>A task which resolves an array of cookie objects.</returns>
|
||||
public Task<Cookie[]> GetAsync(CookieFilter filter)
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<Cookie[]>();
|
||||
var taskCompletionSource = new TaskCompletionSource<Cookie[]>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
string guid = Guid.NewGuid().ToString();
|
||||
|
||||
BridgeConnector.Socket.On("webContents-session-cookies-get-completed" + guid, (cookies) =>
|
||||
BridgeConnector.On<Cookie[]>("webContents-session-cookies-get-completed" + guid, (cookies) =>
|
||||
{
|
||||
Cookie[] result = ((JArray)cookies).ToObject<Cookie[]>();
|
||||
|
||||
BridgeConnector.Socket.Off("webContents-session-cookies-get-completed" + guid);
|
||||
taskCompletionSource.SetResult(result);
|
||||
BridgeConnector.Off("webContents-session-cookies-get-completed" + guid);
|
||||
taskCompletionSource.SetResult(cookies);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("webContents-session-cookies-get", Id, JObject.FromObject(filter, _jsonSerializer), guid);
|
||||
BridgeConnector.Emit("webContents-session-cookies-get", Id, JObject.FromObject(filter, _jsonSerializer), guid);
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
@@ -88,16 +83,16 @@ namespace ElectronNET.API
|
||||
/// <returns></returns>
|
||||
public Task SetAsync(CookieDetails details)
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<object>();
|
||||
var taskCompletionSource = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
string guid = Guid.NewGuid().ToString();
|
||||
|
||||
BridgeConnector.Socket.On("webContents-session-cookies-set-completed" + guid, () =>
|
||||
BridgeConnector.On("webContents-session-cookies-set-completed" + guid, () =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("webContents-session-cookies-set-completed" + guid);
|
||||
BridgeConnector.Off("webContents-session-cookies-set-completed" + guid);
|
||||
taskCompletionSource.SetResult(null);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("webContents-session-cookies-set", Id, JObject.FromObject(details, _jsonSerializer), guid);
|
||||
BridgeConnector.Emit("webContents-session-cookies-set", Id, JObject.FromObject(details, _jsonSerializer), guid);
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
@@ -110,16 +105,16 @@ namespace ElectronNET.API
|
||||
/// <returns>A task which resolves when the cookie has been removed</returns>
|
||||
public Task RemoveAsync(string url, string name)
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<object>();
|
||||
var taskCompletionSource = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
string guid = Guid.NewGuid().ToString();
|
||||
|
||||
BridgeConnector.Socket.On("webContents-session-cookies-remove-completed" + guid, () =>
|
||||
BridgeConnector.On("webContents-session-cookies-remove-completed" + guid, () =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("webContents-session-cookies-remove-completed" + guid);
|
||||
BridgeConnector.Off("webContents-session-cookies-remove-completed" + guid);
|
||||
taskCompletionSource.SetResult(null);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("webContents-session-cookies-remove", Id, url, name, guid);
|
||||
BridgeConnector.Emit("webContents-session-cookies-remove", Id, url, name, guid);
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
@@ -130,25 +125,26 @@ namespace ElectronNET.API
|
||||
/// <returns>A task which resolves when the cookie store has been flushed</returns>
|
||||
public Task FlushStoreAsync()
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<object>();
|
||||
var taskCompletionSource = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
string guid = Guid.NewGuid().ToString();
|
||||
|
||||
BridgeConnector.Socket.On("webContents-session-cookies-flushStore-completed" + guid, () =>
|
||||
BridgeConnector.On("webContents-session-cookies-flushStore-completed" + guid, () =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("webContents-session-cookies-flushStore-completed" + guid);
|
||||
BridgeConnector.Off("webContents-session-cookies-flushStore-completed" + guid);
|
||||
taskCompletionSource.SetResult(null);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("webContents-session-cookies-flushStore", Id, guid);
|
||||
BridgeConnector.Emit("webContents-session-cookies-flushStore", Id, guid);
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
|
||||
private JsonSerializer _jsonSerializer = new JsonSerializer()
|
||||
private static readonly JsonSerializer _jsonSerializer = new()
|
||||
{
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
DefaultValueHandling = DefaultValueHandling.Ignore
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
38
ElectronNET.API/DesktopCapturer.cs
Normal file
38
ElectronNET.API/DesktopCapturer.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System.Threading.Tasks;
|
||||
using ElectronNET.API.Entities;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ElectronNET.API
|
||||
{
|
||||
public sealed class DesktopCapturer
|
||||
{
|
||||
private static readonly object _syncRoot = new();
|
||||
private static DesktopCapturer _desktopCapturer;
|
||||
|
||||
internal DesktopCapturer() { }
|
||||
|
||||
internal static DesktopCapturer Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_desktopCapturer == null)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
if (_desktopCapturer == null)
|
||||
{
|
||||
_desktopCapturer = new DesktopCapturer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _desktopCapturer;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<DesktopCapturerSource[]> GetSourcesAsync(SourcesOption option)
|
||||
{
|
||||
return await BridgeConnector.OnResult<DesktopCapturerSource[]>("desktop-capturer-get-sources", "desktop-capturer-get-sources-result", option);
|
||||
}
|
||||
}
|
||||
}
|
||||
80
src/ElectronNET.API/Dialog.cs → ElectronNET.API/Dialog.cs
Normal file → Executable file
80
src/ElectronNET.API/Dialog.cs → ElectronNET.API/Dialog.cs
Normal file → Executable file
@@ -4,17 +4,20 @@ using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using ElectronNET.API.Interfaces;
|
||||
|
||||
namespace ElectronNET.API
|
||||
{
|
||||
/// <summary>
|
||||
/// Display native system dialogs for opening and saving files, alerting, etc.
|
||||
/// </summary>
|
||||
public sealed class Dialog
|
||||
public sealed class Dialog : IDialog
|
||||
{
|
||||
private static Dialog _dialog;
|
||||
private static object _syncRoot = new object();
|
||||
private static readonly object _syncRoot = new();
|
||||
|
||||
internal Dialog() { }
|
||||
|
||||
@@ -47,21 +50,23 @@ namespace ElectronNET.API
|
||||
/// <returns>An array of file paths chosen by the user</returns>
|
||||
public Task<string[]> ShowOpenDialogAsync(BrowserWindow browserWindow, OpenDialogOptions options)
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<string[]>();
|
||||
var taskCompletionSource = new TaskCompletionSource<string[]>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
string guid = Guid.NewGuid().ToString();
|
||||
|
||||
BridgeConnector.Socket.On("showOpenDialogComplete" + guid, (filePaths) =>
|
||||
BridgeConnector.On<string[]>("showOpenDialogComplete" + guid, (filePaths) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("showOpenDialogComplete" + guid);
|
||||
BridgeConnector.Off("showOpenDialogComplete" + guid);
|
||||
|
||||
var result = ((JArray)filePaths).ToObject<string[]>();
|
||||
taskCompletionSource.SetResult(result);
|
||||
var list = new List<string>();
|
||||
|
||||
foreach (var item in filePaths)
|
||||
{
|
||||
list.Add(HttpUtility.UrlDecode(item));
|
||||
}
|
||||
taskCompletionSource.SetResult(list.ToArray());
|
||||
});
|
||||
|
||||
|
||||
BridgeConnector.Socket.Emit("showOpenDialog",
|
||||
JObject.FromObject(browserWindow, _jsonSerializer),
|
||||
JObject.FromObject(options, _jsonSerializer), guid);
|
||||
BridgeConnector.Emit("showOpenDialog", browserWindow, options, guid);
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
@@ -74,20 +79,17 @@ namespace ElectronNET.API
|
||||
/// <returns>Returns String, the path of the file chosen by the user, if a callback is provided it returns an empty string.</returns>
|
||||
public Task<string> ShowSaveDialogAsync(BrowserWindow browserWindow, SaveDialogOptions options)
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<string>();
|
||||
var taskCompletionSource = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
string guid = Guid.NewGuid().ToString();
|
||||
|
||||
BridgeConnector.Socket.On("showSaveDialogComplete" + guid, (filename) =>
|
||||
BridgeConnector.On<string>("showSaveDialogComplete" + guid, (filename) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("showSaveDialogComplete" + guid);
|
||||
BridgeConnector.Off("showSaveDialogComplete" + guid);
|
||||
|
||||
taskCompletionSource.SetResult(filename.ToString());
|
||||
taskCompletionSource.SetResult(filename);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("showSaveDialog",
|
||||
JObject.FromObject(browserWindow, _jsonSerializer),
|
||||
JObject.FromObject(options, _jsonSerializer),
|
||||
guid);
|
||||
BridgeConnector.Emit("showSaveDialog", browserWindow, options, guid);
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
@@ -143,32 +145,27 @@ namespace ElectronNET.API
|
||||
/// <returns>The API call will be asynchronous and the result will be passed via MessageBoxResult.</returns>
|
||||
public Task<MessageBoxResult> ShowMessageBoxAsync(BrowserWindow browserWindow, MessageBoxOptions messageBoxOptions)
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<MessageBoxResult>();
|
||||
var taskCompletionSource = new TaskCompletionSource<MessageBoxResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var guid = Guid.NewGuid().ToString();
|
||||
|
||||
BridgeConnector.Socket.On("showMessageBoxComplete" + guid, (args) =>
|
||||
BridgeConnector.On<MessageBoxResponse>("showMessageBoxComplete" + guid, (args) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("showMessageBoxComplete" + guid);
|
||||
|
||||
var result = ((JArray)args);
|
||||
BridgeConnector.Off("showMessageBoxComplete" + guid);
|
||||
|
||||
taskCompletionSource.SetResult(new MessageBoxResult
|
||||
{
|
||||
Response = (int)result.First,
|
||||
CheckboxChecked = (bool)result.Last
|
||||
Response = args.response,
|
||||
CheckboxChecked = args.@checked
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
if (browserWindow == null)
|
||||
if (browserWindow is null)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("showMessageBox", JObject.FromObject(messageBoxOptions, _jsonSerializer), guid);
|
||||
BridgeConnector.Emit("showMessageBox", JObject.FromObject(messageBoxOptions, _jsonSerializer), guid);
|
||||
} else
|
||||
{
|
||||
BridgeConnector.Socket.Emit("showMessageBox",
|
||||
JObject.FromObject(browserWindow, _jsonSerializer),
|
||||
JObject.FromObject(messageBoxOptions, _jsonSerializer),
|
||||
guid);
|
||||
BridgeConnector.Emit("showMessageBox", JObject.FromObject(messageBoxOptions, _jsonSerializer), JObject.FromObject(messageBoxOptions, _jsonSerializer), guid);
|
||||
}
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
@@ -186,7 +183,7 @@ namespace ElectronNET.API
|
||||
/// <param name="content">The text content to display in the error box.</param>
|
||||
public void ShowErrorBox(string title, string content)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("showErrorBox", title, content);
|
||||
BridgeConnector.Emit("showErrorBox", title, content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -196,6 +193,8 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
[SupportedOSPlatform("windows")]
|
||||
[SupportedOSPlatform("macos")]
|
||||
public Task ShowCertificateTrustDialogAsync(CertificateTrustDialogOptions options)
|
||||
{
|
||||
return ShowCertificateTrustDialogAsync(null, options);
|
||||
@@ -209,26 +208,25 @@ namespace ElectronNET.API
|
||||
/// <param name="browserWindow"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
[SupportedOSPlatform("windows")]
|
||||
[SupportedOSPlatform("macos")]
|
||||
public Task ShowCertificateTrustDialogAsync(BrowserWindow browserWindow, CertificateTrustDialogOptions options)
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<object>();
|
||||
var taskCompletionSource = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
string guid = Guid.NewGuid().ToString();
|
||||
|
||||
BridgeConnector.Socket.On("showCertificateTrustDialogComplete" + guid, () =>
|
||||
BridgeConnector.On("showCertificateTrustDialogComplete" + guid, () =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("showCertificateTrustDialogComplete" + guid);
|
||||
BridgeConnector.Off("showCertificateTrustDialogComplete" + guid);
|
||||
taskCompletionSource.SetResult(null);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("showCertificateTrustDialog",
|
||||
JObject.FromObject(browserWindow, _jsonSerializer),
|
||||
JObject.FromObject(options, _jsonSerializer),
|
||||
guid);
|
||||
BridgeConnector.Emit("showCertificateTrustDialog", browserWindow, options, guid);
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
|
||||
private JsonSerializer _jsonSerializer = new JsonSerializer()
|
||||
private static readonly JsonSerializer _jsonSerializer = new()
|
||||
{
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
105
src/ElectronNET.API/Dock.cs → ElectronNET.API/Dock.cs
Normal file → Executable file
105
src/ElectronNET.API/Dock.cs → ElectronNET.API/Dock.cs
Normal file → Executable file
@@ -1,8 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ElectronNET.API.Entities;
|
||||
using ElectronNET.API.Extensions;
|
||||
using ElectronNET.API.Interfaces;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
@@ -12,10 +14,11 @@ namespace ElectronNET.API
|
||||
/// <summary>
|
||||
/// Control your app in the macOS dock.
|
||||
/// </summary>
|
||||
public sealed class Dock
|
||||
[SupportedOSPlatform("macos")]
|
||||
public sealed class Dock : IDock
|
||||
{
|
||||
private static Dock _dock;
|
||||
private static object _syncRoot = new object();
|
||||
private static readonly object _syncRoot = new();
|
||||
|
||||
internal Dock()
|
||||
{
|
||||
@@ -50,24 +53,11 @@ namespace ElectronNET.API
|
||||
/// <param name="type">Can be critical or informational. The default is informational.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Return an ID representing the request.</returns>
|
||||
public async Task<int> BounceAsync(DockBounceType type, CancellationToken cancellationToken = default)
|
||||
public Task<int> BounceAsync(DockBounceType type, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<int>();
|
||||
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
|
||||
{
|
||||
BridgeConnector.Socket.On("dock-bounce-completed", (id) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("dock-bounce-completed");
|
||||
taskCompletionSource.SetResult((int) id);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("dock-bounce", type.GetDescription());
|
||||
|
||||
return await taskCompletionSource.Task
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
return BridgeConnector.OnResult<int>("dock-bounce", "dock-bounce-completed", cancellationToken, type.GetDescription());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -76,7 +66,7 @@ namespace ElectronNET.API
|
||||
/// <param name="id">Id of the request.</param>
|
||||
public void CancelBounce(int id)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("dock-cancelBounce", id);
|
||||
BridgeConnector.Emit("dock-cancelBounce", id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -85,7 +75,7 @@ namespace ElectronNET.API
|
||||
/// <param name="filePath"></param>
|
||||
public void DownloadFinished(string filePath)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("dock-downloadFinished", filePath);
|
||||
BridgeConnector.Emit("dock-downloadFinished", filePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -94,7 +84,7 @@ namespace ElectronNET.API
|
||||
/// <param name="text"></param>
|
||||
public void SetBadge(string text)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("dock-setBadge", text);
|
||||
BridgeConnector.Emit("dock-setBadge", text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -102,24 +92,10 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The badge string of the dock.</returns>
|
||||
public async Task<string> GetBadgeAsync(CancellationToken cancellationToken = default)
|
||||
public Task<string> GetBadgeAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<string>();
|
||||
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
|
||||
{
|
||||
BridgeConnector.Socket.On("dock-getBadge-completed", (text) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("dock-getBadge-completed");
|
||||
taskCompletionSource.SetResult((string) text);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("dock-getBadge");
|
||||
|
||||
return await taskCompletionSource.Task
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
return BridgeConnector.OnResult<string>("dock-getBadge", "dock-getBadge-completed", cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -127,7 +103,7 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
public void Hide()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("dock-hide");
|
||||
BridgeConnector.Emit("dock-hide");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -135,7 +111,7 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
public void Show()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("dock-show");
|
||||
BridgeConnector.Emit("dock-show");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -144,24 +120,10 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Whether the dock icon is visible.</returns>
|
||||
public async Task<bool> IsVisibleAsync(CancellationToken cancellationToken = default)
|
||||
public Task<bool> IsVisibleAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<bool>();
|
||||
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
|
||||
{
|
||||
BridgeConnector.Socket.On("dock-isVisible-completed", (isVisible) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("dock-isVisible-completed");
|
||||
taskCompletionSource.SetResult((bool) isVisible);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("dock-isVisible");
|
||||
|
||||
return await taskCompletionSource.Task
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
return BridgeConnector.OnResult<bool>("dock-isVisible", "dock-isVisible-completed", cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -171,7 +133,7 @@ namespace ElectronNET.API
|
||||
/// The menu items.
|
||||
/// </value>
|
||||
public IReadOnlyCollection<MenuItem> MenuItems { get { return _items.AsReadOnly(); } }
|
||||
private List<MenuItem> _items = new List<MenuItem>();
|
||||
private readonly List<MenuItem> _items = new();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the application's dock menu.
|
||||
@@ -179,40 +141,21 @@ namespace ElectronNET.API
|
||||
public void SetMenu(MenuItem[] menuItems)
|
||||
{
|
||||
menuItems.AddMenuItemsId();
|
||||
BridgeConnector.Socket.Emit("dock-setMenu", JArray.FromObject(menuItems, _jsonSerializer));
|
||||
BridgeConnector.Emit("dock-setMenu", JArray.FromObject(menuItems, _jsonSerializer));
|
||||
_items.AddRange(menuItems);
|
||||
|
||||
BridgeConnector.Socket.Off("dockMenuItemClicked");
|
||||
BridgeConnector.Socket.On("dockMenuItemClicked", (id) => {
|
||||
MenuItem menuItem = _items.GetMenuItem(id.ToString());
|
||||
BridgeConnector.Off("dockMenuItemClicked");
|
||||
BridgeConnector.On<string>("dockMenuItemClicked", (id) => {
|
||||
MenuItem menuItem = _items.GetMenuItem(id);
|
||||
menuItem?.Click();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TODO: Menu (macOS) still to be implemented
|
||||
/// Gets the application's dock menu.
|
||||
/// </summary>
|
||||
public async Task<Menu> GetMenu(CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<Menu>();
|
||||
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
|
||||
{
|
||||
BridgeConnector.Socket.On("dock-getMenu-completed", (menu) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("dock-getMenu-completed");
|
||||
taskCompletionSource.SetResult(((JObject)menu).ToObject<Menu>());
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("dock-getMenu");
|
||||
|
||||
return await taskCompletionSource.Task
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
public Task<Menu> GetMenu(CancellationToken cancellationToken = default) => BridgeConnector.OnResult<Menu>("dock-getMenu", "dock-getMenu-completed", cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the image associated with this dock icon.
|
||||
@@ -220,10 +163,10 @@ namespace ElectronNET.API
|
||||
/// <param name="image"></param>
|
||||
public void SetIcon(string image)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("dock-setIcon", image);
|
||||
BridgeConnector.Emit("dock-setIcon", image);
|
||||
}
|
||||
|
||||
private JsonSerializer _jsonSerializer = new JsonSerializer()
|
||||
private static readonly JsonSerializer _jsonSerializer = new()
|
||||
{
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
144
ElectronNET.API/Electron.Experimental.cs
Normal file
144
ElectronNET.API/Electron.Experimental.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace ElectronNET.API
|
||||
{
|
||||
public static partial class Electron
|
||||
{
|
||||
/// <summary>
|
||||
/// Experimental code, use with care
|
||||
/// </summary>
|
||||
public static class Experimental
|
||||
{
|
||||
/// <summary>
|
||||
/// Starts electron from C#, use during development to avoid having to fully publish / build your app on every compile cycle
|
||||
/// You will need to run the CLI at least once (and once per update) to bootstrap all required files
|
||||
/// </summary>
|
||||
/// <param name="webPort"></param>
|
||||
/// <param name="projectPath"></param>
|
||||
/// <param name="extraElectronArguments"></param>
|
||||
/// <param name="clearCache"></param>
|
||||
/// <exception cref="DirectoryNotFoundException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public static async Task<int> StartElectronForDevelopment(int webPort, string projectPath = null, string[] extraElectronArguments = null, bool clearCache = false)
|
||||
{
|
||||
string aspCoreProjectPath;
|
||||
|
||||
if (!string.IsNullOrEmpty(projectPath))
|
||||
{
|
||||
if (Directory.Exists(projectPath))
|
||||
{
|
||||
aspCoreProjectPath = projectPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new DirectoryNotFoundException(projectPath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aspCoreProjectPath = Directory.GetCurrentDirectory();
|
||||
}
|
||||
|
||||
string tempPath = Path.Combine(aspCoreProjectPath, "obj", "Host");
|
||||
|
||||
if (!Directory.Exists(tempPath))
|
||||
{
|
||||
Directory.CreateDirectory(tempPath);
|
||||
}
|
||||
|
||||
var mainFileJs = Path.Combine(tempPath, "main.js");
|
||||
if (!File.Exists(mainFileJs))
|
||||
{
|
||||
throw new Exception("You need to run once the electronize-h5 start command to bootstrap the necessary files");
|
||||
}
|
||||
|
||||
var nodeModulesDirPath = Path.Combine(tempPath, "node_modules");
|
||||
|
||||
bool runNpmInstall = false;
|
||||
|
||||
if (!Directory.Exists(nodeModulesDirPath))
|
||||
{
|
||||
runNpmInstall = true;
|
||||
}
|
||||
|
||||
var packagesJson = Path.Combine(tempPath, "package.json");
|
||||
|
||||
var packagesPrevious = Path.Combine(tempPath, "package.json.previous");
|
||||
|
||||
if (!runNpmInstall)
|
||||
{
|
||||
if (File.Exists(packagesPrevious))
|
||||
{
|
||||
if (File.ReadAllText(packagesPrevious) != File.ReadAllText(packagesJson))
|
||||
{
|
||||
runNpmInstall = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
runNpmInstall = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (runNpmInstall)
|
||||
{
|
||||
throw new Exception("You need to run once the electronize-h5 start command to bootstrap the necessary files");
|
||||
}
|
||||
|
||||
string arguments = "";
|
||||
|
||||
if (extraElectronArguments is object)
|
||||
{
|
||||
arguments = string.Join(' ', extraElectronArguments);
|
||||
}
|
||||
|
||||
if (clearCache)
|
||||
{
|
||||
arguments += " --clear-cache=true";
|
||||
}
|
||||
|
||||
BridgeConnector.AuthKey = Guid.NewGuid().ToString().Replace("-", "");
|
||||
|
||||
var socketPort = FreeTcpPort();
|
||||
|
||||
arguments += $" --development=true --devauth={BridgeConnector.AuthKey} --devport={socketPort}";
|
||||
|
||||
string path = Path.Combine(tempPath, "node_modules", ".bin");
|
||||
bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
|
||||
if (isWindows)
|
||||
{
|
||||
ProcessHelper.Execute(@"electron.cmd ""..\..\main.js"" " + arguments, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessHelper.Execute(@"./electron ""../../main.js"" " + arguments, path);
|
||||
}
|
||||
|
||||
BridgeSettings.InitializePorts(socketPort, webPort);
|
||||
await Task.Delay(500);
|
||||
|
||||
return socketPort;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a free local TCP port
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static int FreeTcpPort()
|
||||
{
|
||||
TcpListener l = new TcpListener(IPAddress.Loopback, 0);
|
||||
l.Start();
|
||||
int port = ((IPEndPoint)l.LocalEndpoint).Port;
|
||||
l.Stop();
|
||||
return port;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,51 @@
|
||||
namespace ElectronNET.API
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Runtime.Versioning;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ElectronNET.API
|
||||
{
|
||||
/// <summary>
|
||||
/// The Electron.NET API
|
||||
/// </summary>
|
||||
public static class Electron
|
||||
public static partial class Electron
|
||||
{
|
||||
private static ILoggerFactory loggerFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Reads the auth key from the command line. This method must be called first thing.
|
||||
/// </summary>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public static void ReadAuth()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(BridgeConnector.AuthKey))
|
||||
{
|
||||
throw new Exception($"Don't call ReadAuth twice or from with {nameof(Experimental)}.{nameof(Experimental.StartElectronForDevelopment)}");
|
||||
}
|
||||
|
||||
var line = Console.ReadLine();
|
||||
|
||||
if(line.StartsWith("Auth="))
|
||||
{
|
||||
BridgeConnector.AuthKey = line.Substring("Auth=".Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("The call to Electron.ReadAuth must be the first thing your app entry point does");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the logger factory to be used by Electron, if any
|
||||
/// </summary>
|
||||
public static ILoggerFactory LoggerFactory
|
||||
{
|
||||
private get => loggerFactory; set
|
||||
{
|
||||
loggerFactory = value;
|
||||
BridgeConnector.Logger = value.CreateLogger<App>();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Communicate asynchronously from the main process to renderer processes.
|
||||
/// </summary>
|
||||
@@ -60,6 +101,11 @@
|
||||
/// </summary>
|
||||
public static Screen Screen { get { return Screen.Instance; } }
|
||||
|
||||
/// <summary>
|
||||
/// Access information about media sources that can be used to capture audio and video from the desktop using the navigator.mediaDevices.getUserMedia API.
|
||||
/// </summary>
|
||||
public static DesktopCapturer DesktopCapturer { get { return DesktopCapturer.Instance; } }
|
||||
|
||||
/// <summary>
|
||||
/// Perform copy and paste operations on the system clipboard.
|
||||
/// </summary>
|
||||
@@ -87,6 +133,7 @@
|
||||
/// <summary>
|
||||
/// Control your app in the macOS dock.
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("macos")]
|
||||
public static Dock Dock { get { return Dock.Instance; } }
|
||||
}
|
||||
}
|
||||
36
src/ElectronNET.API/ElectronNET.API.csproj → ElectronNET.API/ElectronNET.API.csproj
Normal file → Executable file
36
src/ElectronNET.API/ElectronNET.API.csproj → ElectronNET.API/ElectronNET.API.csproj
Normal file → Executable file
@@ -1,27 +1,34 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<PackageOutputPath>..\..\artifacts</PackageOutputPath>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<PackageOutputPath>..\artifacts</PackageOutputPath>
|
||||
<PackageId>ElectronNET.API</PackageId>
|
||||
<Authors>Gregor Biswanger, Florian Rappl</Authors>
|
||||
<Authors>Gregor Biswanger, Robert Muehsig</Authors>
|
||||
<Company />
|
||||
<Product>Electron.NET</Product>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageProjectUrl>https://github.com/ElectronNET/Electron.NET/</PackageProjectUrl>
|
||||
<Description>Building cross platform electron based desktop apps with .NET Core and ASP.NET Core.
|
||||
This package contains the API to access the "native" electron API.</Description>
|
||||
<Description>
|
||||
Building cross platform electron based desktop apps with .NET Core and ASP.NET Core.
|
||||
This package contains the API to access the "native" electron API.
|
||||
</Description>
|
||||
<RepositoryUrl>https://github.com/ElectronNET/Electron.NET/</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<PackageTags>electron aspnetcore</PackageTags>
|
||||
<PackageReleaseNotes>Changelog: https://github.com/ElectronNET/Electron.NET/blob/main/Changelog.md</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>Changelog: https://github.com/ElectronNET/Electron.NET/blob/master/Changelog.md</PackageReleaseNotes>
|
||||
<PackageIcon>PackageIcon.png</PackageIcon>
|
||||
<Version>99.0.0.0</Version>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TargetFrameworks>net6.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="PackageIcon.png" Pack="true" PackagePath="\" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(OS)' == 'Windows_NT'">
|
||||
<Exec Command="$(ProjectDir)devCleanup.cmd" IgnoreExitCode="true" />
|
||||
</Target>
|
||||
@@ -32,16 +39,17 @@ This package contains the API to access the "native" electron API.</Description>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0">
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="SocketIOClient" Version="3.0.8" />
|
||||
<PackageReference Include="SocketIOClient.Newtonsoft.Json" Version="3.0.7" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers" Version="0.4.410601">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
|
||||
<PackageReference Include="SocketIOClient" Version="3.0.6" />
|
||||
<PackageReference Include="System.Collections" Version="4.3.0" />
|
||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
</Project>
|
||||
@@ -18,7 +18,7 @@ namespace ElectronNET.API.Entities
|
||||
/// <summary>
|
||||
/// Gets or sets the scalefactor
|
||||
/// </summary>
|
||||
public float ScaleFactor { get; set; } = 1.0f;
|
||||
public float ScaleFactor { get; set; } = NativeImage.DefaultScaleFactor;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the buffer
|
||||
20
ElectronNET.API/Entities/BitmapOptions.cs
Normal file
20
ElectronNET.API/Entities/BitmapOptions.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("Use ImageOptions instead.")]
|
||||
public class BitmapOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the scale factor
|
||||
/// </summary>
|
||||
public float ScaleFactor { get; set; } = NativeImage.DefaultScaleFactor;
|
||||
/// <summary>
|
||||
/// Utility conversion for obsolete class
|
||||
/// </summary>
|
||||
public static implicit operator ImageOptions(BitmapOptions o) => new() {ScaleFactor = o.ScaleFactor};
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
@@ -36,62 +37,62 @@ namespace ElectronNET.API.Entities
|
||||
/// window's size will include window frame's size and be slightly larger. Default
|
||||
/// is false.
|
||||
/// </summary>
|
||||
public bool UseContentSize { get; set; }
|
||||
public bool? UseContentSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Show window in the center of the screen.
|
||||
/// </summary>
|
||||
public bool Center { get; set; }
|
||||
public bool? Center { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Window's minimum width. Default is 0.
|
||||
/// </summary>
|
||||
public int MinWidth { get; set; }
|
||||
public int? MinWidth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Window's minimum height. Default is 0.
|
||||
/// </summary>
|
||||
public int MinHeight { get; set; }
|
||||
public int? MinHeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Window's maximum width. Default is no limit.
|
||||
/// </summary>
|
||||
public int MaxWidth { get; set; }
|
||||
public int? MaxWidth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Window's maximum height. Default is no limit.
|
||||
/// </summary>
|
||||
public int MaxHeight { get; set; }
|
||||
public int? MaxHeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether window is resizable. Default is true.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
public bool Resizable { get; set; } = true;
|
||||
public bool? Resizable { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether window is movable. This is not implemented on Linux. Default is true.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
public bool Movable { get; set; } = true;
|
||||
public bool? Movable { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether window is minimizable. This is not implemented on Linux. Default is true.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
public bool Minimizable { get; set; } = true;
|
||||
public bool? Minimizable { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether window is maximizable. This is not implemented on Linux. Default is true.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
public bool Maximizable { get; set; } = true;
|
||||
public bool? Maximizable { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether window is closable. This is not implemented on Linux. Default is true.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
public bool Closable { get; set; } = true;
|
||||
public bool? Closable { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the window can be focused. Default is true. On Windows setting
|
||||
@@ -100,35 +101,35 @@ namespace ElectronNET.API.Entities
|
||||
/// always stay on top in all workspaces.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
public bool Focusable { get; set; } = true;
|
||||
public bool? Focusable { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the window should always stay on top of other windows. Default is false.
|
||||
/// </summary>
|
||||
public bool AlwaysOnTop { get; set; }
|
||||
public bool? AlwaysOnTop { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the window should show in fullscreen. When explicitly set to false the
|
||||
/// fullscreen button will be hidden or disabled on macOS.Default is false.
|
||||
/// </summary>
|
||||
public bool Fullscreen { get; set; }
|
||||
public bool? Fullscreen { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the window can be put into fullscreen mode. On macOS, also whether the
|
||||
/// maximize/zoom button should toggle full screen mode or maximize window.Default
|
||||
/// is true.
|
||||
/// </summary>
|
||||
public bool Fullscreenable { get; set; }
|
||||
public bool? Fullscreenable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to show the window in taskbar. Default is false.
|
||||
/// </summary>
|
||||
public bool SkipTaskbar { get; set; }
|
||||
public bool? SkipTaskbar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The kiosk mode. Default is false.
|
||||
/// </summary>
|
||||
public bool Kiosk { get; set; }
|
||||
public bool? Kiosk { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default window title. Default is "Electron.NET".
|
||||
@@ -145,40 +146,40 @@ namespace ElectronNET.API.Entities
|
||||
/// Whether window should be shown when created. Default is true.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
public bool Show { get; set; } = true;
|
||||
public bool? Show { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Specify false to create a . Default is true.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
public bool Frame { get; set; } = true;
|
||||
public bool? Frame { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this is a modal window. This only works when the window is a child
|
||||
/// window.Default is false.
|
||||
/// Whether this is a modal window. This only works when <see cref="Parent"/> is
|
||||
/// also specified. Default is false.
|
||||
/// </summary>
|
||||
public bool Modal { get; set; }
|
||||
public bool? Modal { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the web view accepts a single mouse-down event that simultaneously
|
||||
/// activates the window.Default is false.
|
||||
/// activates the window. Default is false.
|
||||
/// </summary>
|
||||
public bool AcceptFirstMouse { get; set; }
|
||||
public bool? AcceptFirstMouse { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to hide cursor when typing. Default is false.
|
||||
/// </summary>
|
||||
public bool DisableAutoHideCursor { get; set; }
|
||||
public bool? DisableAutoHideCursor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Auto hide the menu bar unless the Alt key is pressed. Default is false.
|
||||
/// </summary>
|
||||
public bool AutoHideMenuBar { get; set; }
|
||||
public bool? AutoHideMenuBar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enable the window to be resized larger than screen. Default is false.
|
||||
/// </summary>
|
||||
public bool EnableLargerThanScreen { get; set; }
|
||||
public bool? EnableLargerThanScreen { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Window's background color as Hexadecimal value, like #66CD00 or #FFF or
|
||||
@@ -190,18 +191,18 @@ namespace ElectronNET.API.Entities
|
||||
/// Whether window should have a shadow. This is only implemented on macOS. Default
|
||||
/// is true.
|
||||
/// </summary>
|
||||
public bool HasShadow { get; set; }
|
||||
public bool? HasShadow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Forces using dark theme for the window, only works on some GTK+3 desktop
|
||||
/// environments.Default is false.
|
||||
/// </summary>
|
||||
public bool DarkTheme { get; set; }
|
||||
public bool? DarkTheme { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Makes the window . Default is false.
|
||||
/// </summary>
|
||||
public bool Transparent { get; set; }
|
||||
public bool? Transparent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of window, default is normal window.
|
||||
@@ -213,13 +214,21 @@ namespace ElectronNET.API.Entities
|
||||
/// 'default' | 'hidden' | 'hiddenInset' | 'customButtonsOnHover'
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public TitleBarStyle TitleBarStyle { get; set; }
|
||||
public TitleBarStyle? TitleBarStyle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Shows the title in the tile bar in full screen mode on macOS for all
|
||||
/// titleBarStyle options.Default is false.
|
||||
/// </summary>
|
||||
public bool FullscreenWindowTitle { get; set; }
|
||||
public bool? FullscreenWindowTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Activate the Window Controls Overlay on Windows, when combined with <see cref="TitleBarStyle"/> = <see cref="TitleBarStyle.hidden"/>
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("win")]
|
||||
[SupportedOSPlatform("macos")]
|
||||
[DefaultValue(null)]
|
||||
public TitleBarOverlayConfig TitleBarOverlay { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Use WS_THICKFRAME style for frameless windows on Windows, which adds standard
|
||||
@@ -227,7 +236,7 @@ namespace ElectronNET.API.Entities
|
||||
/// animations. Default is true.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
public bool ThickFrame { get; set; } = true;
|
||||
public bool? ThickFrame { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Add a type of vibrancy effect to the window, only on macOS. Can be
|
||||
@@ -235,7 +244,7 @@ namespace ElectronNET.API.Entities
|
||||
/// medium-light or ultra-dark.
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public Vibrancy Vibrancy { get; set; }
|
||||
public Vibrancy? Vibrancy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Controls the behavior on macOS when option-clicking the green stoplight button
|
||||
@@ -244,7 +253,7 @@ namespace ElectronNET.API.Entities
|
||||
/// it to zoom to the width of the screen.This will also affect the behavior when
|
||||
/// calling maximize() directly.Default is false.
|
||||
/// </summary>
|
||||
public bool ZoomToPageWidth { get; set; }
|
||||
public bool? ZoomToPageWidth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Tab group name, allows opening the window as a native tab on macOS 10.12+.
|
||||
@@ -270,5 +279,19 @@ namespace ElectronNET.API.Entities
|
||||
/// These will only be used if the Proxy field is also set.
|
||||
/// </summary>
|
||||
public string ProxyCredentials { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The window to use as the created window's parent.
|
||||
/// </summary>
|
||||
[DefaultValue(null)]
|
||||
public BrowserWindow Parent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set a custom position for the traffic light buttons in frameless windows.
|
||||
/// </summary>
|
||||
|
||||
[DefaultValue(null)]
|
||||
[SupportedOSPlatform("macos")]
|
||||
public Point TrafficLightPosition { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace ElectronNET.API.Entities {
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The cause of the change
|
||||
/// </summary>
|
||||
10
ElectronNET.API/Entities/CookieRemovedResponse.cs
Normal file
10
ElectronNET.API/Entities/CookieRemovedResponse.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
public class CookieRemovedResponse
|
||||
{
|
||||
public Cookie cookie {get;set;}
|
||||
|
||||
public CookieChangedCause cause { get; set; }
|
||||
public bool removed { get; set; }
|
||||
}
|
||||
}
|
||||
32
ElectronNET.API/Entities/CreateFromBitmapOptions.cs
Normal file
32
ElectronNET.API/Entities/CreateFromBitmapOptions.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("Use CreateOptions instead")]
|
||||
public class CreateFromBitmapOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the width
|
||||
/// </summary>
|
||||
public int? Width { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the height
|
||||
/// </summary>
|
||||
public int? Height { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the scalefactor
|
||||
/// </summary>
|
||||
public float ScaleFactor { get; set; } = NativeImage.DefaultScaleFactor;
|
||||
|
||||
/// <summary>
|
||||
/// Utility conversion for obsolete class
|
||||
/// </summary>
|
||||
public static implicit operator CreateOptions(CreateFromBitmapOptions o) => new()
|
||||
{Width = o.Width, Height = o.Height, ScaleFactor = o.ScaleFactor};
|
||||
}
|
||||
}
|
||||
31
ElectronNET.API/Entities/CreateFromBufferOptions.cs
Normal file
31
ElectronNET.API/Entities/CreateFromBufferOptions.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("Use CreateOptions instead")]
|
||||
public class CreateFromBufferOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the width
|
||||
/// </summary>
|
||||
public int? Width { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the height
|
||||
/// </summary>
|
||||
public int? Height { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the scalefactor
|
||||
/// </summary>
|
||||
public float ScaleFactor { get; set; } = NativeImage.DefaultScaleFactor;
|
||||
/// <summary>
|
||||
/// Utility conversion for obsolete class
|
||||
/// </summary>
|
||||
public static implicit operator CreateOptions(CreateFromBufferOptions o) => new()
|
||||
{Width = o.Width, Height = o.Height, ScaleFactor = o.ScaleFactor};
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// Options for creating a new <see cref="NativeImage"/>
|
||||
/// </summary>
|
||||
public class CreateFromBufferOptions
|
||||
public class CreateOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the width
|
||||
@@ -18,6 +18,7 @@ namespace ElectronNET.API.Entities
|
||||
/// <summary>
|
||||
/// Gets or sets the scalefactor
|
||||
/// </summary>
|
||||
public float ScaleFactor { get; set; } = 1.0f;
|
||||
public float ScaleFactor { get; set; } = NativeImage.DefaultScaleFactor;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -34,5 +34,7 @@
|
||||
/// The title of the url at text.
|
||||
/// </summary>
|
||||
public string Bookmark { get; set; }
|
||||
|
||||
public NativeImage? Image { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
15
ElectronNET.API/Entities/DesktopCapturerSource.cs
Normal file
15
ElectronNET.API/Entities/DesktopCapturerSource.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
public sealed class DesktopCapturerSource
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public NativeImage Thumbnail { get; set; }
|
||||
|
||||
[JsonProperty("display_id")]
|
||||
public string DisplayId { get; set; }
|
||||
public NativeImage AppIcon { get; set; }
|
||||
}
|
||||
}
|
||||
65
ElectronNET.API/Entities/Display.cs
Normal file
65
ElectronNET.API/Entities/Display.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
public class DisplayChanged
|
||||
{
|
||||
public Display display { get; set; }
|
||||
public string[] metrics { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class Display
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the bounds.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The bounds.
|
||||
/// </value>
|
||||
public Rectangle Bounds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unique identifier associated with the display.
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Can be 0, 90, 180, 270, represents screen rotation in clock-wise degrees.
|
||||
/// </summary>
|
||||
public float Rotation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Output device's pixel scale factor.
|
||||
/// </summary>
|
||||
public float ScaleFactor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the size.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The size.
|
||||
/// </value>
|
||||
public Size Size { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Can be available, unavailable, unknown.
|
||||
/// </summary>
|
||||
public string TouchSupport { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the work area.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The work area.
|
||||
/// </value>
|
||||
public Rectangle WorkArea { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the size of the work area.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The size of the work area.
|
||||
/// </value>
|
||||
public Size WorkAreaSize { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
namespace ElectronNET.API.Entities
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class BitmapOptions
|
||||
public class ImageOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the scale factor
|
||||
/// </summary>
|
||||
public float ScaleFactor { get; set; } = 1.0f;
|
||||
public float ScaleFactor { get; set; } = NativeImage.DefaultScaleFactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
namespace ElectronNET.API.Entities
|
||||
using System;
|
||||
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class JumpListSettings
|
||||
{
|
||||
/// <summary>
|
||||
@@ -16,6 +15,6 @@
|
||||
/// in the Jump List. These items must not be re-added to the Jump List in the next call to <see cref="App.SetJumpList"/>, Windows will
|
||||
/// not display any custom category that contains any of the removed items.
|
||||
/// </summary>
|
||||
public JumpListItem[] RemovedItems { get; set; } = new JumpListItem[0];
|
||||
public JumpListItem[] RemovedItems { get; set; } = Array.Empty<JumpListItem>();
|
||||
}
|
||||
}
|
||||
@@ -158,6 +158,17 @@
|
||||
/// <summary>
|
||||
/// Only macOS: The submenu is a “Services” menu
|
||||
/// </summary>
|
||||
services
|
||||
services,
|
||||
|
||||
/// <summary>
|
||||
/// Only macOS: the submenue for "Recent Documents"
|
||||
/// </summary>
|
||||
recentdocuments,
|
||||
|
||||
/// <summary>
|
||||
/// Only macOS: the menu to clear the recent document list
|
||||
/// </summary>
|
||||
clearrecentdocuments,
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,11 @@
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
internal class MessageBoxResponse
|
||||
{
|
||||
public int response { get; set; }
|
||||
public bool @checked { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
@@ -1,12 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Formats.Png;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Formats.Png;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
@@ -16,10 +19,15 @@ namespace ElectronNET.API.Entities
|
||||
[JsonConverter(typeof(NativeImageJsonConverter))]
|
||||
public class NativeImage
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public const float DefaultScaleFactor = 1.0f;
|
||||
private readonly Dictionary<float, Image> _images = new Dictionary<float, Image>();
|
||||
|
||||
private bool _isTemplateImage;
|
||||
|
||||
private static readonly Dictionary<string, float> ScaleFactorPairs = new Dictionary<string, float>
|
||||
private static readonly Dictionary<string, float> ScaleFactorPairs = new()
|
||||
{
|
||||
{"@2x", 2.0f}, {"@3x", 3.0f}, {"@1x", 1.0f}, {"@4x", 4.0f},
|
||||
{"@5x", 5.0f}, {"@1.25x", 1.25f}, {"@1.33x", 1.33f}, {"@1.4x", 1.4f},
|
||||
@@ -36,8 +44,7 @@ namespace ElectronNET.API.Entities
|
||||
}
|
||||
private static Image BytesToImage(byte[] bytes)
|
||||
{
|
||||
var ms = new MemoryStream(bytes);
|
||||
return Image.FromStream(ms);
|
||||
return Image.Load(new MemoryStream(bytes));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -51,30 +58,35 @@ namespace ElectronNET.API.Entities
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static NativeImage CreateFromBitmap(Bitmap bitmap, CreateFromBitmapOptions options = null)
|
||||
public static NativeImage CreateFromImage(Image image, CreateFromBitmapOptions options = null)
|
||||
{
|
||||
if (options is null)
|
||||
{
|
||||
options = new CreateFromBitmapOptions();
|
||||
}
|
||||
|
||||
return new NativeImage(bitmap, options.ScaleFactor);
|
||||
return new NativeImage(image, options.ScaleFactor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static NativeImage CreateFromImage(Image image, CreateOptions options = null)
|
||||
=> new (image, options?.ScaleFactor ?? DefaultScaleFactor);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NativeImage from a byte array.
|
||||
/// </summary>
|
||||
public static NativeImage CreateFromBuffer(byte[] buffer, CreateFromBufferOptions options = null)
|
||||
public static NativeImage CreateFromBuffer(byte[] buffer, CreateOptions options = null)
|
||||
{
|
||||
if (options is null)
|
||||
{
|
||||
options = new CreateFromBufferOptions();
|
||||
}
|
||||
|
||||
var ms = new MemoryStream(buffer);
|
||||
var image = Image.FromStream(ms);
|
||||
var image = Image.Load(new MemoryStream(buffer));
|
||||
|
||||
return new NativeImage(image, options.ScaleFactor);
|
||||
return new NativeImage(image, options?.ScaleFactor ?? DefaultScaleFactor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -110,14 +122,14 @@ namespace ElectronNET.API.Entities
|
||||
throw new Exception($"Invalid scaling factor for '{path}'.");
|
||||
}
|
||||
|
||||
images[dpi.Value] = Image.FromFile(path);
|
||||
images[dpi.Value] = Image.Load(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
|
||||
var extension = Path.GetExtension(path);
|
||||
// Load as 1x dpi
|
||||
images[1.0f] = Image.FromFile(path);
|
||||
images[1.0f] = Image.Load(path);
|
||||
|
||||
foreach (var scale in ScaleFactorPairs)
|
||||
{
|
||||
@@ -127,7 +139,7 @@ namespace ElectronNET.API.Entities
|
||||
var dpi = ExtractDpiFromFilePath(fileName);
|
||||
if (dpi != null)
|
||||
{
|
||||
images[dpi.Value] = Image.FromFile(fileName);
|
||||
images[dpi.Value] = Image.Load(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,9 +158,9 @@ namespace ElectronNET.API.Entities
|
||||
/// <summary>
|
||||
/// Creates a NativeImage from a bitmap and scale factor
|
||||
/// </summary>
|
||||
public NativeImage(Image bitmap, float scaleFactor = 1.0f)
|
||||
public NativeImage(Image image, float scaleFactor = DefaultScaleFactor)
|
||||
{
|
||||
_images.Add(scaleFactor, bitmap);
|
||||
_images.Add(scaleFactor, image);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -164,7 +176,7 @@ namespace ElectronNET.API.Entities
|
||||
/// </summary>
|
||||
public NativeImage Crop(Rectangle rect)
|
||||
{
|
||||
var images = new Dictionary<float,Image>();
|
||||
var images = new Dictionary<float, Image>();
|
||||
foreach (var image in _images)
|
||||
{
|
||||
images.Add(image.Key, Crop(rect.X, rect.Y, rect.Width, rect.Height, image.Key));
|
||||
@@ -196,7 +208,7 @@ namespace ElectronNET.API.Entities
|
||||
if (options.Buffer.Length > 0)
|
||||
{
|
||||
_images[options.ScaleFactor] =
|
||||
CreateFromBuffer(options.Buffer, new CreateFromBufferOptions {ScaleFactor = options.ScaleFactor})
|
||||
CreateFromBuffer(options.Buffer, new CreateOptions {ScaleFactor = options.ScaleFactor})
|
||||
.GetScale(options.ScaleFactor);
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(options.DataUrl))
|
||||
@@ -214,7 +226,7 @@ namespace ElectronNET.API.Entities
|
||||
var image = GetScale(scaleFactor);
|
||||
if (image != null)
|
||||
{
|
||||
return image.Width / image.Height;
|
||||
return (float)image.Width / image.Height;
|
||||
}
|
||||
|
||||
return 0f;
|
||||
@@ -223,9 +235,9 @@ namespace ElectronNET.API.Entities
|
||||
/// <summary>
|
||||
/// Returns a byte array that contains the image's raw bitmap pixel data.
|
||||
/// </summary>
|
||||
public byte[] GetBitmap(BitmapOptions options)
|
||||
public byte[] GetBitmap(float scaleFactor)
|
||||
{
|
||||
return ToBitmap(new ToBitmapOptions{ ScaleFactor = options.ScaleFactor });
|
||||
return ToBitmap(scaleFactor).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -233,26 +245,14 @@ namespace ElectronNET.API.Entities
|
||||
/// </summary>
|
||||
public byte[] GetNativeHandle()
|
||||
{
|
||||
return ToBitmap(new ToBitmapOptions());
|
||||
return ToBitmap().ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the specified image based on scale factor
|
||||
/// </summary>
|
||||
public Size GetSize(float scaleFactor = 1.0f)
|
||||
{
|
||||
if (_images.ContainsKey(scaleFactor))
|
||||
{
|
||||
var image = _images[scaleFactor];
|
||||
return new Size
|
||||
{
|
||||
Width = image.Width,
|
||||
Height = image.Height
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
=> _images.TryGetValue(scaleFactor, out var image) ? image.Size() : null;
|
||||
|
||||
/// <summary>
|
||||
/// Checks to see if the NativeImage instance is empty.
|
||||
@@ -278,148 +278,99 @@ namespace ElectronNET.API.Entities
|
||||
/// <summary>
|
||||
/// Outputs a bitmap based on the scale factor
|
||||
/// </summary>
|
||||
public byte[] ToBitmap(ToBitmapOptions options)
|
||||
public MemoryStream ToBitmap(float scaleFactor = 1.0f)
|
||||
{
|
||||
return ImageToBytes(ImageFormat.Bmp, options.ScaleFactor);
|
||||
var ms = new MemoryStream();
|
||||
_images[scaleFactor].SaveAsBmp(ms);
|
||||
return ms;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Outputs a data URL based on the scale factor
|
||||
/// Outputs a PNG based on the scale factor
|
||||
/// </summary>
|
||||
public string ToDataURL(ToDataUrlOptions options)
|
||||
public string ToDataURL(ImageOptions options)
|
||||
=> _images.TryGetValue(options.ScaleFactor, out var image)
|
||||
? $"data:image/png;base64,{image.ToBase64String(PngFormat.Instance)}"
|
||||
: null;
|
||||
|
||||
public MemoryStream ToPng(float scaleFactor = 1.0f)
|
||||
{
|
||||
if (!_images.ContainsKey(options.ScaleFactor))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var image = _images[options.ScaleFactor];
|
||||
var mimeType = ImageCodecInfo.GetImageEncoders().FirstOrDefault(x => x.FormatID == image.RawFormat.Guid)?.MimeType;
|
||||
if (mimeType is null)
|
||||
{
|
||||
mimeType = "image/png";
|
||||
}
|
||||
|
||||
var bytes = ImageToBytes(image.RawFormat, options.ScaleFactor);
|
||||
var base64 = Convert.ToBase64String(bytes);
|
||||
|
||||
return $"data:{mimeType};base64,{base64}";
|
||||
var ms = new MemoryStream();
|
||||
_images[scaleFactor].SaveAsPng(ms);
|
||||
return ms;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Outputs a JPEG for the default scale factor
|
||||
/// </summary>
|
||||
public byte[] ToJPEG(int quality)
|
||||
public MemoryStream ToJpeg(int quality, float scaleFactor = 1.0f)
|
||||
{
|
||||
return ImageToBytes(ImageFormat.Jpeg, 1.0f, quality);
|
||||
var ms = new MemoryStream();
|
||||
_images[scaleFactor].SaveAsJpeg(ms, new SixLabors.ImageSharp.Formats.Jpeg.JpegEncoder() { Quality = quality });
|
||||
return ms;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Outputs a PNG for the specified scale factor
|
||||
/// Outputs a data URL based on the scale factor
|
||||
/// </summary>
|
||||
public byte[] ToPNG(ToPNGOptions options)
|
||||
public string ToDataURL(float scaleFactor = 1.0f)
|
||||
{
|
||||
return ImageToBytes(ImageFormat.Png, options.ScaleFactor);
|
||||
}
|
||||
|
||||
private byte[] ImageToBytes(ImageFormat imageFormat = null, float scaleFactor = 1.0f, int quality = 100)
|
||||
{
|
||||
using var ms = new MemoryStream();
|
||||
|
||||
if (_images.ContainsKey(scaleFactor))
|
||||
if (!_images.TryGetValue(scaleFactor, out var image))
|
||||
{
|
||||
var image = _images[scaleFactor];
|
||||
var encoderCodecInfo = GetEncoder(imageFormat ?? image.RawFormat);
|
||||
var encoder = Encoder.Quality;
|
||||
|
||||
var encoderParameters = new EncoderParameters(1)
|
||||
{
|
||||
Param = new[]
|
||||
{
|
||||
new EncoderParameter(encoder, quality)
|
||||
}
|
||||
};
|
||||
|
||||
image.Save(ms, encoderCodecInfo, encoderParameters);
|
||||
|
||||
return ms.ToArray();
|
||||
throw new KeyNotFoundException($"Missing scaleFactor = {scaleFactor}");
|
||||
}
|
||||
|
||||
return null;
|
||||
return image.ToBase64String(PngFormat.Instance);
|
||||
}
|
||||
|
||||
|
||||
private Image Resize(int? width, int? height, float scaleFactor = 1.0f)
|
||||
{
|
||||
if (!_images.ContainsKey(scaleFactor) || (width is null && height is null))
|
||||
if (!_images.TryGetValue(scaleFactor, out var image) || (width is null && height is null))
|
||||
{
|
||||
return null;
|
||||
throw new KeyNotFoundException($"Missing scaleFactor = {scaleFactor}");
|
||||
}
|
||||
|
||||
if (width is null && height is null)
|
||||
{
|
||||
throw new ArgumentNullException("Missing width or height");
|
||||
}
|
||||
|
||||
var image = _images[scaleFactor];
|
||||
using (var g = Graphics.FromImage(image))
|
||||
var aspect = GetAspectRatio(scaleFactor);
|
||||
width ??= Convert.ToInt32(image.Width * aspect);
|
||||
height ??= Convert.ToInt32(image.Height * aspect);
|
||||
width = Convert.ToInt32(width * scaleFactor);
|
||||
height = Convert.ToInt32(height * scaleFactor);
|
||||
|
||||
return image.Clone(c => c.Resize(new SixLabors.ImageSharp.Processing.ResizeOptions
|
||||
{
|
||||
g.CompositingQuality = CompositingQuality.HighQuality;
|
||||
|
||||
var aspect = GetAspectRatio(scaleFactor);
|
||||
|
||||
width ??= Convert.ToInt32(image.Width * aspect);
|
||||
height ??= Convert.ToInt32(image.Height * aspect);
|
||||
|
||||
width = Convert.ToInt32(width * scaleFactor);
|
||||
height = Convert.ToInt32(height * scaleFactor);
|
||||
|
||||
var bmp = new Bitmap(width.Value, height.Value);
|
||||
g.DrawImage(bmp,
|
||||
new System.Drawing.Rectangle(0, 0, image.Width, image.Height),
|
||||
new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height),
|
||||
GraphicsUnit.Pixel);
|
||||
|
||||
return bmp;
|
||||
}
|
||||
Size = new(width.Value, height.Value),
|
||||
Sampler = KnownResamplers.Triangle,
|
||||
}));
|
||||
}
|
||||
|
||||
private Image Crop(int? x, int? y, int? width, int? height, float scaleFactor = 1.0f)
|
||||
{
|
||||
if (!_images.ContainsKey(scaleFactor))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var image = _images[scaleFactor];
|
||||
using (var g = Graphics.FromImage(image))
|
||||
|
||||
if (!_images.TryGetValue(scaleFactor, out image))
|
||||
{
|
||||
g.CompositingQuality = CompositingQuality.HighQuality;
|
||||
|
||||
x ??= 0;
|
||||
y ??= 0;
|
||||
|
||||
x = Convert.ToInt32(x * scaleFactor);
|
||||
y = Convert.ToInt32(y * scaleFactor);
|
||||
|
||||
width ??= image.Width;
|
||||
height ??= image.Height;
|
||||
|
||||
width = Convert.ToInt32(width * scaleFactor);
|
||||
height = Convert.ToInt32(height * scaleFactor);
|
||||
|
||||
var bmp = new Bitmap(width.Value, height.Value);
|
||||
g.DrawImage(bmp, new System.Drawing.Rectangle(0, 0, image.Width, image.Height), new System.Drawing.Rectangle(x.Value, y.Value, width.Value, height.Value), GraphicsUnit.Pixel);
|
||||
|
||||
return bmp;
|
||||
throw new KeyNotFoundException($"Missing scaleFactor = {scaleFactor}");
|
||||
}
|
||||
}
|
||||
|
||||
x ??= 0;
|
||||
y ??= 0;
|
||||
|
||||
private ImageCodecInfo GetEncoder(ImageFormat format)
|
||||
{
|
||||
var codecs = ImageCodecInfo.GetImageDecoders();
|
||||
foreach (ImageCodecInfo codec in codecs)
|
||||
{
|
||||
if (codec.FormatID == format.Guid)
|
||||
{
|
||||
return codec;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
x = Convert.ToInt32(x * scaleFactor);
|
||||
y = Convert.ToInt32(y * scaleFactor);
|
||||
|
||||
width ??= image.Width;
|
||||
height ??= image.Height;
|
||||
|
||||
width = Convert.ToInt32(width * scaleFactor);
|
||||
height = Convert.ToInt32(height * scaleFactor);
|
||||
|
||||
return image.Clone(c => c.Crop(new SixLabors.ImageSharp.Rectangle(x.Value, y.Value, width.Value, height.Value)));
|
||||
}
|
||||
|
||||
internal Dictionary<float,string> GetAllScaledImages()
|
||||
@@ -429,12 +380,12 @@ namespace ElectronNET.API.Entities
|
||||
{
|
||||
foreach (var (scale, image) in _images)
|
||||
{
|
||||
dict.Add(scale, Convert.ToBase64String(ImageToBytes(null, scale)));
|
||||
dict.Add(scale, image.ToBase64String(PngFormat.Instance));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
BridgeConnector.LogError(ex, "Error getting scaled images");
|
||||
}
|
||||
|
||||
return dict;
|
||||
@@ -442,9 +393,9 @@ namespace ElectronNET.API.Entities
|
||||
|
||||
internal Image GetScale(float scaleFactor)
|
||||
{
|
||||
if (_images.ContainsKey(scaleFactor))
|
||||
if (_images.TryGetValue(scaleFactor, out var image))
|
||||
{
|
||||
return _images[scaleFactor];
|
||||
return image;
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -1,8 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Formats.Png;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
using SixLabors.ImageSharp;
|
||||
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
@@ -19,12 +22,15 @@ namespace ElectronNET.API.Entities
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var dict = serializer.Deserialize<Dictionary<float, string>>(reader);
|
||||
var dict = serializer.Deserialize<Dictionary<string, string>>(reader);
|
||||
var newDictionary = new Dictionary<float, Image>();
|
||||
foreach (var item in dict)
|
||||
{
|
||||
var bytes = Convert.FromBase64String(item.Value);
|
||||
newDictionary.Add(item.Key, Image.FromStream(new MemoryStream(bytes)));
|
||||
if (float.TryParse(item.Key, out var size))
|
||||
{
|
||||
var bytes = Convert.FromBase64String(item.Value);
|
||||
newDictionary.Add(size, Image.Load(new MemoryStream(bytes)));
|
||||
}
|
||||
}
|
||||
return new NativeImage(newDictionary);
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
namespace ElectronNET.API.Entities
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("macos")]
|
||||
public class NotificationAction
|
||||
{
|
||||
/// <summary>
|
||||
@@ -1,5 +1,6 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
@@ -17,6 +18,8 @@ namespace ElectronNET.API.Entities
|
||||
/// <summary>
|
||||
/// A subtitle for the notification, which will be displayed below the title.
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("macos")]
|
||||
|
||||
public string SubTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -38,38 +41,46 @@ namespace ElectronNET.API.Entities
|
||||
/// <summary>
|
||||
/// Whether or not to add an inline reply option to the notification.
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("macos")]
|
||||
public bool HasReply { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The timeout duration of the notification. Can be 'default' or 'never'.
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("windows")]
|
||||
[SupportedOSPlatform("linux")]
|
||||
public string TimeoutType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The placeholder to write in the inline reply input field.
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("macos")]
|
||||
public string ReplyPlaceholder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the sound file to play when the notification is shown.
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("macos")]
|
||||
public string Sound { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The urgency level of the notification. Can be 'normal', 'critical', or 'low'.
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("linux")]
|
||||
public string Urgency { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Actions to add to the notification. Please read the available actions and
|
||||
/// limitations in the NotificationAction documentation.
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("macos")]
|
||||
public NotificationAction Actions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A custom title for the close button of an alert. An empty string will cause the
|
||||
/// default localized text to be used.
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("macos")]
|
||||
public string CloseButtonText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -127,6 +138,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 +154,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>
|
||||
@@ -1,5 +1,6 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
@@ -39,6 +40,7 @@ namespace ElectronNET.API.Entities
|
||||
/// <summary>
|
||||
/// Message to display above input boxes.
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("macos")]
|
||||
public string Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
95
ElectronNET.API/Entities/OpenDialogProperty.cs
Normal file
95
ElectronNET.API/Entities/OpenDialogProperty.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public enum OpenDialogProperty
|
||||
{
|
||||
/// <summary>
|
||||
/// The open file
|
||||
/// </summary>
|
||||
openFile,
|
||||
|
||||
/// <summary>
|
||||
/// The open directory
|
||||
/// </summary>
|
||||
openDirectory,
|
||||
|
||||
/// <summary>
|
||||
/// The multi selections
|
||||
/// </summary>
|
||||
multiSelections,
|
||||
|
||||
/// <summary>
|
||||
/// The show hidden files
|
||||
/// </summary>
|
||||
showHiddenFiles,
|
||||
|
||||
/// <summary>
|
||||
/// The create directory
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("macos")]
|
||||
createDirectory,
|
||||
|
||||
/// <summary>
|
||||
/// The prompt to create
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("windows")]
|
||||
promptToCreate,
|
||||
|
||||
/// <summary>
|
||||
/// The no resolve aliases
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("macos")]
|
||||
noResolveAliases,
|
||||
|
||||
/// <summary>
|
||||
/// Treat packages, such as .app folders, as a directory instead of a file.
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("macos")]
|
||||
treatPackageAsDirectory,
|
||||
|
||||
/// <summary>
|
||||
/// Don't add the item being opened to recent documents list
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("windows")]
|
||||
dontAddToRecent
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public enum SaveDialogProperty
|
||||
{
|
||||
/// <summary>
|
||||
/// The show hidden files
|
||||
/// </summary>
|
||||
showHiddenFiles,
|
||||
|
||||
/// <summary>
|
||||
/// The create directory
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("macos")]
|
||||
createDirectory,
|
||||
|
||||
/// <summary>
|
||||
/// Treat packages, such as .app folders, as a directory instead of a file.
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("macos")]
|
||||
treatPackageAsDirectory,
|
||||
|
||||
/// <summary>
|
||||
/// Sets whether the user will be presented a confirmation dialog if the user types a file name that already exists.
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("linux")]
|
||||
showOverwriteConfirmation,
|
||||
|
||||
/// <summary>
|
||||
/// Don't add the item being opened to recent documents list
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("windows")]
|
||||
dontAddToRecent
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
@@ -12,11 +13,13 @@ namespace ElectronNET.API.Entities
|
||||
/// <see langword="true"/> to bring the opened application to the foreground. The default is <see langword="true"/>.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
[SupportedOSPlatform("macos")]
|
||||
public bool Activate { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// The working directory.
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("windows")]
|
||||
public string WorkingDirectory { get; set; }
|
||||
}
|
||||
}
|
||||
35
ElectronNET.API/Entities/PrintToPDFOptions.cs
Normal file
35
ElectronNET.API/Entities/PrintToPDFOptions.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class PrintToPDFOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the type of margins to use. Uses 0 for default margin, 1 for no
|
||||
/// margin, and 2 for minimum margin.
|
||||
/// </summary>
|
||||
public int MarginsType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specify page size of the generated PDF. Can be A3, A4, A5, Legal, Letter,
|
||||
/// Tabloid or an Object containing height and width in microns.
|
||||
/// </summary>
|
||||
public string PageSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to print CSS backgrounds.
|
||||
/// </summary>
|
||||
public bool PrintBackground { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to print selection only.
|
||||
/// </summary>
|
||||
public bool PrintSelectionOnly { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// true for landscape, false for portrait.
|
||||
/// </summary>
|
||||
public bool Landscape { get; set; }
|
||||
}
|
||||
}
|
||||
10
ElectronNET.API/Entities/ProcessVersions.cs
Normal file
10
ElectronNET.API/Entities/ProcessVersions.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace ElectronNET.API
|
||||
{
|
||||
/// <summary>
|
||||
/// An object listing the version strings specific to Electron
|
||||
/// </summary>
|
||||
/// <param name="Chrome">Value representing Chrome's version string</param>
|
||||
/// <param name="Electron">Value representing Electron's version string</param>
|
||||
/// <returns></returns>
|
||||
public record ProcessVersions(string Chrome, string Electron);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user