Compare commits

...

479 Commits

Author SHA1 Message Date
Gregor Biswanger
e9bf393165 Merge branch 'theolivenbaum-master' 2022-07-28 11:52:12 +02:00
Gregor Biswanger
d3aa9783d3 Merge of theolivenbaum PR 2022-07-28 11:51:18 +02:00
theolivenbaum
a5bc910926 Release 19.0.9 2022-07-22 10:45:24 +02:00
theolivenbaum
89033c61d4 Return socket port 2022-07-14 17:07:19 +02:00
theolivenbaum
90b4a287d9 Add experimental mode to start electron from C# (for development purposes) 2022-07-14 16:56:50 +02:00
theolivenbaum
e2615a8dc1 Import SocketIO code 2022-07-14 16:53:54 +02:00
theolivenbaum
73330185de Release 19.0.8 2022-07-12 13:43:12 +02:00
theolivenbaum
e1c5b7e3c2 Update main.js 2022-06-28 15:40:58 +02:00
theolivenbaum
a19e095f6e Fix wrong variable name 2022-06-27 16:04:32 +02:00
theolivenbaum
b7ed3d22f1 Update main.js 2022-06-27 14:53:21 +02:00
theolivenbaum
c8f944af4a Release 19.0.6 2022-06-27 14:35:16 +02:00
theolivenbaum
2f73bb8b34 Release 19.0.5 2022-06-21 10:48:40 +02:00
theolivenbaum
1f22be68d2 Drop net5.0 2022-06-09 10:23:29 +02:00
theolivenbaum
576140474e merge #624 2022-06-09 10:22:54 +02:00
theolivenbaum
68c9e80417 merge #673 2022-06-09 10:12:15 +02:00
theolivenbaum
4906babd78 Change to use ImageSharp 2022-06-08 21:28:38 +02:00
theolivenbaum
e0000f7aba Change to use ImageSharp 2022-06-08 21:28:30 +02:00
theolivenbaum
ff05ef20c8 Release 19.0.4 2022-06-08 20:52:35 +02:00
theolivenbaum
79ce1c42e7 Release 19.0.3 2022-06-08 20:20:57 +02:00
Gregor Biswanger
4e95bb3331 Static parameter for build commands method 2022-06-07 23:03:06 +02:00
Gregor Biswanger
58bfa336a8 Change to .NET 6 only 2022-06-07 22:59:26 +02:00
Gregor Biswanger
afa69280f5 Fixed merge conflicts 2022-06-07 22:55:00 +02:00
Gregor Biswanger
8621d8cea3 Merge branch 'master' into dev/electron-18-update 2022-06-07 22:48:13 +02:00
Gregor Biswanger
9106391f60 Merge pull request #698 from stackify/bad-master
#697 fixing conflicts in ElectronNET.CLI commands
2022-06-07 22:41:53 +02:00
Gregor Biswanger
490ef6231b .NET 6 support only 2022-06-07 22:40:44 +02:00
theolivenbaum
89833f42fc Release 19.0.2 2022-06-02 11:11:26 +02:00
theolivenbaum
252ab5050b Release 18.3.2 2022-06-02 11:10:38 +02:00
Daniel Gidman
2ff29e553d #697 fixing conflicts in ElectronNET.CLI commands 2022-05-31 13:49:49 -05:00
theolivenbaum
a1a5f6f9a6 Handle case where pipe breaks showing error message 2022-05-31 13:38:54 +02:00
theolivenbaum
3ea7e96324 Release 19.0.1 2022-05-27 10:10:28 +02:00
theolivenbaum
a00a8a0251 Release 18.3.0 2022-05-24 10:07:32 +02:00
theolivenbaum
e245d0d2f6 release also for 17.4.1 2022-04-23 17:02:54 +02:00
theolivenbaum
48a0d68313 Increase max message size to 100mb 2022-04-23 17:01:34 +02:00
theolivenbaum
4d5d6722a7 Check if version exists 2022-04-21 09:38:41 +02:00
theolivenbaum
d910eec8df Add releaser helper to automate updating versions 2022-04-21 09:36:22 +02:00
theolivenbaum
4f9b46c616 Electron Release 18.1.0 2022-04-21 09:16:05 +02:00
theolivenbaum
4308f2c6d6 Electron Release 17.4.1 2022-04-21 09:15:00 +02:00
theolivenbaum
87468ccd5d Update main.js 2022-04-20 13:05:25 +02:00
theolivenbaum
d863ff95f4 update to 18.0.4 2022-04-20 12:47:18 +02:00
theolivenbaum
3a24b69063 let user define own env variables to start 2022-04-20 12:36:51 +02:00
rafael-aero
d6c98759c5 handle also get nearest point 2022-04-13 20:53:33 +02:00
rafael-aero
6675571aaf handle fail on getdisplaymatching 2022-04-13 20:51:34 +02:00
rafael-aero
3f8766ff9e Build 17.4.0 2022-04-12 11:31:35 +02:00
rafael-aero
9b881b1b71 Roll back to electron 18.0.2
Roll back to electron 18.0.2
2022-04-12 10:41:28 +02:00
rafael-aero
339a319f3e fix race condition on electron socket initialization 2022-04-11 13:59:42 +02:00
rafael-aero
d929102e18 update to Electron 18.0.3 2022-04-10 22:37:43 +02:00
Gregor Biswanger
26595bf290 Refactor eslint hints 2022-04-06 22:34:56 +02:00
Gregor Biswanger
5ca65f1939 Update TypeScript 4.3.5 -> 4.6.3, replace typings to native socket.io 2022-04-06 22:33:54 +02:00
Gregor Biswanger
b4b355eeac Replace tslint with eslint 2022-04-06 22:33:06 +02:00
Gregor Biswanger
47774d2871 Update socket.io 2.4.0 -> 4.4.1, electron 13.1.5 -> 18.0.2, electron-updater 4.3.9 -> 4.6.5, replace tsint with eslint 2022-04-06 22:32:38 +02:00
Gregor Biswanger
43cbdc15b8 Merge branch 'yannikHoeflich-master' 2022-04-06 21:58:38 +02:00
Gregor Biswanger
540be39547 Merge fix: changed the processing of loadUrl at CreateWindowAsync #631 2022-04-06 21:58:20 +02:00
Gregor Biswanger
a7a8685341 Merge branch 'stackify-bug/644' 2022-04-06 19:20:13 +02:00
Gregor Biswanger
0575413768 Transpile new JavaScript host files 2022-04-06 19:19:46 +02:00
Gregor Biswanger
e8394277e7 Merge fix: Fix for #664, open for comment #644 2022-04-06 19:17:43 +02:00
Gregor Biswanger
5fe50b45bb Merge branch 'stackify-CrossPlatformNativeImage' 2022-04-06 19:03:35 +02:00
Gregor Biswanger
70ca42aeaf Merge fix: Conversion to use ImageSharp rather than System.Drawing.Common #658 2022-04-06 19:03:22 +02:00
Gregor Biswanger
f54ce1eb02 Merge branch 'stackify-feature/DI-MOC-Process' 2022-04-06 18:58:15 +02:00
Gregor Biswanger
aa9c2caf47 Merge fix: Support DI and Mocking better + Support launching app with file for win and linux #656 2022-04-06 18:58:02 +02:00
Gregor Biswanger
ba8e941cf1 Merge branch 'stackify-feature/dotnet-args' 2022-04-06 18:53:19 +02:00
Gregor Biswanger
f0003ae953 Merge fix: Support for additional dotnet publish flags #655 2022-04-06 18:52:58 +02:00
Gregor Biswanger
1f5d70be83 Merge branch 'schaveyt-feature/647-launching-app-w-file-win-linux' 2022-04-06 18:46:18 +02:00
Gregor Biswanger
1a1bd61e3e Merge fix: Support launching app with file for win and linux #648 2022-04-06 18:45:51 +02:00
Gregor Biswanger
709780fd04 Merge pull request #673 from MutatedGamer/parentOption
Add ability to set a window's parent using BrowserWindowOptions
2022-04-06 18:26:08 +02:00
Gregor Biswanger
9a17d22343 Merge branch 'stackify-NET6' 2022-04-06 18:10:31 +02:00
Gregor Biswanger
7222c9e6c5 Fix conflicts: Support for .NET 6 2022-04-06 18:10:18 +02:00
Gregor Biswanger
29b4f577a6 Merge pull request #634 from stackify/feature/RecentDocuments-Mac
Recent Document Support for MacOS
2022-04-06 16:35:00 +02:00
Gregor Biswanger
9698c80442 Merge pull request #633 from stackify/feature/DI-MOCK
Support DI and Mocking better.
2022-04-06 16:33:46 +02:00
Gregor Biswanger
4afa535c31 Merge pull request #626 from javierlarota/feature/ignore-cert-errors
Allow ignoring certificate errors
2022-04-06 16:30:00 +02:00
Gregor Biswanger
0de9699a52 Merge pull request #624 from bman46/master
Support Apple Silicon Natively
2022-04-06 16:28:14 +02:00
Gregor Biswanger
6f5fb16091 Merge pull request #595 from theolivenbaum/switch-to-new-socket-lib
Switch to async socket lib
2022-04-06 16:24:02 +02:00
Gregor Biswanger
891870abde Merge branch 'master' into switch-to-new-socket-lib 2022-04-06 16:23:47 +02:00
Gregor Biswanger
ab162d4829 Merge pull request #592 from Meberem/feature/log-dotnet-errors
Log errors in the dotnet process
2022-04-06 16:10:24 +02:00
rafael-aero
ec12dbd6ad Update electron to 18.0.2 2022-04-05 22:41:41 +02:00
rafael-aero
f05934acb8 Forgot to roll back to 18.0.1 2022-04-01 20:59:06 +02:00
rafael-aero
0632112a3a improve build command to try to read version from xml file 2022-04-01 19:03:09 +02:00
rafael-aero
793f714b9e Publish Electron 17.3.1 2022-04-01 18:37:16 +02:00
rafael-aero
e3fbce26d0 Remove default electron version parameter from CLI 2022-04-01 18:27:26 +02:00
rafael-aero
c45ea53a02 Update to Electron 18.0.1 2022-04-01 17:41:21 +02:00
rafael-aero
de56395946 Update to Electron 18.0.0 2022-03-29 10:13:20 +02:00
rafael-aero
b0262b36d0 Update electron to 17.3.0 2022-03-29 09:44:20 +02:00
rafael-aero
0ffecd5bc7 save projects 2022-03-25 12:12:35 +01:00
rafael-aero
b7196ff10d Merge branch 'master' of https://github.com/theolivenbaum/Electron.NET 2022-03-25 12:11:10 +01:00
rafael-aero
93f1875f8b remove again SocketIOClient as package was updated 2022-03-25 12:11:08 +01:00
theolivenbaum
6ca5563dc1 Update build-nuget.yaml for Azure Pipelines 2022-03-25 12:03:54 +01:00
rafael-aero
e643d0db08 Update 2022-03-25 10:30:51 +01:00
rafael-aero
9c89711d59 Import SocketIOClient code until next version is released 2022-03-25 10:23:56 +01:00
rafael-aero
606b2a6481 Update main.js 2022-03-24 19:32:15 +01:00
rafael-aero
ef13ec9cc4 update electron to 17.2.0 2022-03-24 18:45:28 +01:00
rafael-aero
b58b4579f9 Add dotenv and electron-notarize dependencies 2022-03-24 11:46:17 +01:00
rafael-aero
13edd4c3ca fix multi thread usage missing lock 2022-03-23 12:18:52 +01:00
rafael-aero
967ccf385a Add support for random port assignment 2022-03-22 18:51:32 +01:00
MutatedGamer
4a44f3e150 Set parent in createBrowserWindow 2022-03-21 20:34:38 -07:00
MutatedGamer
d6e362c83c Add Parent property to BrowserWindowOptions 2022-03-21 20:34:25 -07:00
rafael-aero
df15d249de Update to 17.1.2 2022-03-10 08:38:32 +01:00
rafael-aero
a5bb3ad36b Update ElectronNET.API.csproj 2022-03-07 23:36:18 +01:00
rafael-aero
8f26ceed3d update socket.io 2022-03-07 23:13:16 +01:00
rafael-aero
7f282c1346 Update to 17.1.1 2022-03-07 22:06:48 +01:00
rafael-aero
8067f8e1ff Update to 17.1.0, remove soon to be deprecated nativeWindowOpen optiojn 2022-03-03 08:21:35 +01:00
Daniel Gidman
468c8ba2fc #644 Check for null before taking actions. Also localize references to window on window creation 2022-02-23 14:58:44 -06:00
Daniel Gidman
ab694e22fc Change IsReady logic to also wait for connection to be open. This is to prevent actions occurring before the app can act upon them. 2022-02-23 14:57:05 -06:00
Robert Muehsig
79a6ef322c Merge pull request #609 from AndreasJagiella-EH/master
Set PublishSingleFile default back to false for NET5 compatibility
2022-02-21 23:01:46 +01:00
Robert Muehsig
0ef5edfdf6 Merge pull request #613 from aguang-xyz/fix/npe-when-target-not-specified
Fix IndexOutOfRangeException in build command parsing logic
2022-02-21 22:55:01 +01:00
Robert Muehsig
7db609c699 Merge pull request #607 from gpgpublickey/build_adds_help_publish_parameters
Adds help regarding to modify publish parameters
2022-02-21 22:49:48 +01:00
Robert Muehsig
127408afdb Merge pull request #598 from tub5/tub5-readme-fix
Update README.md
2022-02-21 22:47:53 +01:00
rafael-aero
40eae5af3d update to 17.0.1 2022-02-15 14:15:32 +01:00
rafael-aero
26ba398428 Add new WCO height option 2022-02-10 23:00:33 +01:00
rafael-aero
56fe57db46 Update to 17.0.0 2022-02-10 09:55:56 +01:00
rafael-aero
c8552041fb Add debug messages for update methods 2022-02-10 00:00:51 +01:00
rafael-aero
13a3753214 emit prepare-for-update 2022-02-09 22:18:04 +01:00
rafael-aero
93ee1871ee update electron to 16.0.8 2022-01-30 20:43:39 +01:00
Daniel Gidman
86644e7366 #637 Conversion to use ImageSharp rather than System.Drawing.Common for cross platform compatibility.
Breaking Changes:

* `System.Drawing.Common` is dropped and `SixLabors.ImageSharp` is introduced.
* uses of `NativeImage.CreateFromBitmap(bitmap, options);` is no longer supported, will cause failed builds.

Unexpected Behaviors:

* uses ToDataUrl will always create png data urls, unexpected output may happen for those that manipulate this output expecting a different data url format.

Obsoletions:

* `CreateFromBitmapOptions` & `CreateFromBufferOptions` have been consolidated into `CreateOptions`. Implicit conversions added to ease transition.
* `ToBitmapOptions`, `ToDataUrlOptions`, `ToPngOptions` & `BitmapOptions` have been consolidated into `ImageOptions`. Implicit conversions added to ease transition.
2022-01-26 11:07:48 -06:00
Daniel Gidman
2331ef43b4 Support electronize as a dotnet 6 target tool 2022-01-25 14:08:40 -06:00
Daniel Gidman
b8845bb402 Include Process into DI Mocking and interfaces 2022-01-25 10:45:49 -06:00
Daniel Gidman
1767bcd5ad Merge commit '64e058b0b59a4fbbd6c0ec9de2ee1850a66684c4' into feature/DI-MOC-Process
# Conflicts:
#	ElectronNET.API/ServiceCollectionExtensions.cs
2022-01-25 10:41:42 -06:00
Daniel Gidman
5338749e4d Fixed extraction of arguments 2022-01-21 20:03:31 -06:00
Daniel Gidman
4790c4ebb2 Support for additional dotnet publish flags. 2022-01-21 16:51:30 -06:00
rafael-aero
d646b84c74 update 16.0.7 2022-01-13 11:49:41 +01:00
Todd Schavey
64e058b0b5 #647 make ProcessVersions Entity a record to ensure readonly access to props
This is to address a PR #648 review comment to ensure that only the external
users are not able to modify the instance values.
2022-01-04 12:11:52 -05:00
Todd Schavey
24a2005776 #647 update XML documentation to ElectronNET.API Process members 2022-01-03 00:21:48 -05:00
Todd Schavey
592148116b #647 correct to ElectronNET.API Process member for versions field 2022-01-02 23:11:01 -05:00
Todd Schavey
ba82b9a600 #647 add to ElectronNET.API Process member interfaces for various fields 2022-01-02 22:46:53 -05:00
Todd Schavey
562cccbfae #647 add to ElectronNET.API Process member interfaces for argv and type 2022-01-02 18:28:39 -05:00
Todd Schavey
1406fc1d79 #647 add initial Process class to ElectronNET.API 2022-01-02 16:46:14 -05:00
Todd Schavey
8e1e184d1e #647 process argv for open-file for win and linux 2021-12-28 21:40:53 -05:00
rafael-aero
9e37d4d857 fix serializtion 2021-12-26 11:00:51 +01:00
rafael-aero
060fb19a6d Update NativeImageJsonConverter.cs 2021-12-26 09:46:55 +01:00
rafael-aero
291faa48de Missing including new file 2021-12-26 09:27:45 +01:00
rafael-aero
4358178524 Add support for DesktopCapturer 2021-12-26 09:03:48 +01:00
Daniel Gidman
4b314940d7 Update ElectronNET.sln
removing the full path reference as suggested.

Co-authored-by: alborozd <alborozd@gmail.com>
2021-12-23 10:54:44 -06:00
rafael-aero
ed841558b8 always exit if .net process exited 2021-12-23 16:54:06 +01:00
rafael-aero
36751db618 fix missing pipe option for detached process 2021-12-23 10:09:08 +01:00
rafael-aero
f229d540a8 Add simple socket auth via stdin exchange 2021-12-23 09:24:29 +01:00
rafael-aero
546c617cd0 Merge branch 'master' of https://github.com/theolivenbaum/Electron.NET 2021-12-17 13:29:49 +01:00
rafael-aero
88e8051004 update electron and electron updater 2021-12-17 13:29:47 +01:00
theolivenbaum
21427f0b44 Merge pull request #5 from theolivenbaum/clipboard-image-support-macos
add support for images in clipboards on macos
2021-12-15 18:31:49 +01:00
Pius Friesch
159c1f46c1 add support for images in clipboards on macos 2021-12-15 17:58:38 +01:00
rafael-aero
8cb235527d Change again socket reconnect logic 2021-12-15 10:44:59 +01:00
theolivenbaum
4a3a5c6aa4 Merge pull request #4 from theolivenbaum/clipboard
Clipboard
2021-12-13 18:13:47 +01:00
Pius Friesch
82bf94b2a2 fix writing images to clipboard when writing multiple formats 2021-12-13 17:40:57 +01:00
Pius Friesch
17a7886d12 formatting 2021-12-13 17:33:00 +01:00
Pius Friesch
6be3019cb6 fix typescript, based on changes to js 2021-12-13 17:31:48 +01:00
rafael-aero
3460217021 refactor socket reconnect 2021-12-13 16:22:08 +01:00
rafael-aero
427592de46 Add background thread to reconnect socket 2021-12-13 14:43:04 +01:00
rafael-aero
8f820d033a Merge branch 'master' of https://github.com/theolivenbaum/Electron.NET 2021-12-13 14:10:40 +01:00
rafael-aero
4118756711 change socket connect loop 2021-12-13 14:10:38 +01:00
Daniel Gidman
ffdf034f5f appveyor dedicated build 2021-12-09 14:01:55 -06:00
Daniel Gidman
946fbd7a72 Update appveyor image 2021-12-09 13:51:13 -06:00
Daniel Gidman
6b0205467b Support for .NET 6
Also included is the ability to target a specific project in the `electronize build/start` command using /dotnet-project
2021-12-09 13:11:24 -06:00
theolivenbaum
a28df5339d Merge pull request #3 from pfriesch/patch-1
Add Image to clipboard data
2021-12-09 17:50:54 +01:00
rafael-aero
f5a141a1c6 Update ElectronNET.API.csproj 2021-12-09 17:50:43 +01:00
Pius Friesch
b5e2b660f7 Add Image to clipboard data 2021-12-09 17:46:30 +01:00
javierlarota
431e401451 Feedback from code review. Improving logging of the domain names that will be ignored. 2021-12-09 04:22:35 +00:00
Daniel Gidman
02faeae603 Add support for Mac recent documents and clear recent documents commands on the Application Menu 2021-12-08 13:32:00 -06:00
Yannik Höflich
0d9483e325 Updated TryParseLoadUrl with UriBuilder for better readability 2021-12-08 17:30:44 +01:00
Daniel Gidman
1b14bb0fe5 Convert main static references off of Electron into interface implementation and expose the underlying Socket for low level interaction. 2021-12-07 11:52:43 -06:00
Brendan McShane
b08a0755e6 Revert automatic change by VS 2021-12-07 12:23:26 -05:00
Brendan McShane
7e89e27c26 Better way to check version
Checks to see if the dotnet 6 or greater is running.
2021-12-06 20:28:57 -05:00
Brendan McShane
e4deba2489 Add dotnet 6 check
Ensure that dotnet 6 is installed when compiling for MacOS ARM.
2021-12-06 20:17:46 -05:00
Brendan McShane
1d9e540fc2 Change back to dotnet 5 2021-12-06 20:17:08 -05:00
Yannik Höflich
c7d2dabbc3 changed the usage of loadUrl at CreateWindowAsync: adds protocol, host and port. You can also insert the port with {port} 2021-12-05 16:31:32 +01:00
theolivenbaum
2d940dbeee update to electron 16.0.4 2021-12-03 09:16:44 +01:00
javierlarota
d9d655cae8 Allow ignoring certificate errors when using an untrusted self-signed certificate for https communication with the AspCore backend.
We can ignore all cert errors or only cert errors from specific domain names configured in electron.manifest.json
2021-11-26 18:03:54 +00:00
theolivenbaum
1b7f722f31 Update Electron to 16.0.2, update electron-updater to 4.6.1 2021-11-25 08:06:49 +01:00
rafael-aero
b1c5c12004 fix null usage on ipc.js 2021-11-22 17:33:50 +01:00
rafael-aero
af0410998e update screenshot code 2021-11-22 11:38:16 +01:00
Brendan McShane
e0e8572cc1 Update README.md
Add notes about osx-arm64.
2021-11-20 21:35:02 -05:00
Brendan McShane
4ba8d9bf46 Add fix for Apple Silicon to build command 2021-11-20 18:25:46 -05:00
Brendan McShane
07d6fed712 Fix for build command 2021-11-20 18:24:41 -05:00
Brendan McShane
5dbe62bcba Add osx-arm64 support to electronize command
Updates the GetTargetPlatformInformationResult() function to add 'osx-arm64' target. 
Updates the 'default' case to automatically detect M1 mac.
2021-11-20 17:59:53 -05:00
Brendan McShane
438c8e1f14 Switch from dotnet 5.0 to dotnet 6.0
The 'osx-arm64' RID is only supported on .net versions greater than 6.0.
https://docs.microsoft.com/en-us/dotnet/core/rid-catalog
2021-11-20 17:56:33 -05:00
rafael-aero
ffedbcc5df Add missing GetFileIcon method 2021-11-20 16:37:38 +01:00
rafael-aero
9aad72431c Update electron to 16.0.1 2021-11-18 20:08:31 +01:00
rafael-aero
4405eba2d5 Add support for dark mode splashscreen 2021-11-17 14:19:07 +01:00
rafael-aero
067300bfec update nuget packages 2021-11-16 14:02:17 +01:00
theolivenbaum
b2f5a0eb34 Update to Electron 16 2021-11-16 06:45:59 +01:00
theolivenbaum
cbc150db06 Update to Electron 15.3.2 2021-11-16 06:43:15 +01:00
theolivenbaum
cbac8541be Add transparent option to webpreferences 2021-11-13 11:13:35 +01:00
rafael-aero
2f9029e267 add launch settings to test build 2021-11-10 11:07:46 +01:00
rafael-aero
390135af8a Revert "move .NET bin output to under Helpers folder to be compliant with macOS bundle formt "
This reverts commit be1182d302.
2021-11-10 11:06:40 +01:00
theolivenbaum
be1182d302 move .NET bin output to under Helpers folder to be compliant with macOS bundle formt 2021-11-10 07:57:22 +01:00
theolivenbaum
54c86d9e2f Fix auto-updater on mac not working 2021-11-10 07:46:25 +01:00
rafael-aero
2cc6823604 Update electron to 15.3.1 2021-11-09 18:16:45 +01:00
rafael-aero
326efd353c Update sdk to 6.0.100 2021-11-09 18:16:32 +01:00
rafael-aero
bd96765db5 Merge branch 'master' of https://github.com/theolivenbaum/Electron.NET 2021-11-05 11:01:33 +01:00
rafael-aero
606bb019f7 fix race condition causing unobserved exception 2021-11-05 11:01:32 +01:00
theolivenbaum
a12a7e4287 Update main.js 2021-11-03 07:51:59 +01:00
rafael-aero
5bf9aa811d Update main.js 2021-11-02 18:20:59 +01:00
rafael-aero
5477bd7f36 Add setImmediate to see if this fixes the macOS update bug 2021-11-02 15:39:57 +01:00
rafael-aero
134a5b1365 Merge branch 'master' of https://github.com/theolivenbaum/Electron.NET 2021-10-29 10:54:45 +02:00
rafael-aero
23791fcc3e fix path detection 2021-10-29 10:54:42 +02:00
theolivenbaum
751c48c804 Update Vibrancy.cs 2021-10-27 22:06:52 +02:00
theolivenbaum
316cf0108e Update Vibrancy.cs 2021-10-27 21:57:24 +02:00
rafael-aero
4caa28dc87 Merge branch 'master' of https://github.com/theolivenbaum/Electron.NET 2021-10-27 14:10:09 +02:00
rafael-aero
ad46b1a7a2 remove listeners on quitAndInstall to try fix macOS update issue 2021-10-27 14:10:07 +02:00
theolivenbaum
2297669e6d Update main.js 2021-10-27 09:11:33 +02:00
theolivenbaum
ae92973814 Update main.js 2021-10-26 22:58:54 +02:00
theolivenbaum
5ebfa2b0bd Update main.js 2021-10-26 21:34:35 +02:00
rafael-aero
1494c2f436 Update main.js 2021-10-26 18:15:37 +02:00
rafael-aero
84f027cd8d remove listeners on the call to before-quit-for-update 2021-10-26 16:27:44 +02:00
rafael-aero
f213ca4f8c move code for fixPath here 2021-10-26 15:58:55 +02:00
rafael-aero
22fa3f2780 Revert "Add fixPath to fix linux process spawn"
This reverts commit 1e50f203d8.
2021-10-26 15:41:02 +02:00
rafael-aero
b5cc631daf Revert "Update main.js"
This reverts commit b5ff42a148.
2021-10-26 15:41:00 +02:00
rafael-aero
b5ff42a148 Update main.js 2021-10-26 15:35:06 +02:00
rafael-aero
1e50f203d8 Add fixPath to fix linux process spawn
As suggested in https://github.com/electron/electron-packager/issues/603
2021-10-25 13:35:02 +02:00
rafael-aero
852b140525 Update to 15.3.0 2021-10-22 11:09:17 +02:00
rafael-aero
7e5903f5bc update to electron 15.1.2 2021-10-12 13:11:29 +02:00
rafael-aero
62003ae5fc Update BuildCommand.cs 2021-10-11 19:36:41 +02:00
Grey Wang
5cd152c1ed Fix build command logic when target is not specified 2021-10-09 20:41:12 +13:00
rafael-aero
228a5cef31 set missing return value
https://github.com/electron/electron/issues/31321
2021-10-07 18:13:32 +02:00
rafael-aero
c28355094e Update build-nuget.yaml 2021-10-07 17:54:28 +02:00
rafael-aero
329df38765 Update to Electron 15.1.1 2021-10-07 17:52:15 +02:00
AndreasJagiella-EH
5274fec200 Set PublishSingleFile default back to false for NET5 compatibility 2021-10-04 14:54:02 +02:00
Cristian Giagante
9892a90038 Adds help regarding to modify publish parameters 2021-09-26 19:54:25 -03:00
theolivenbaum
1d1e60bc63 Missed updating the nuget package version 2021-09-22 09:06:41 +02:00
theolivenbaum
21b6b14df5 Update Node to v16.9.6 2021-09-22 08:56:58 +02:00
theolivenbaum
2445b59c4d Update Electron to v15.0.0 2021-09-22 08:55:04 +02:00
rafael-aero
9a8584795b update to net6.0 2021-09-17 18:16:31 +02:00
rafael-aero
e6ea9883fd code cleanup 2021-09-17 16:05:40 +02:00
rafael-aero
e1edc764d6 update electron to 14.0.1 2021-09-16 19:39:16 +02:00
rafael-aero
51013d5825 code cleanup 2021-09-15 11:14:45 +02:00
rafael-aero
664d5f7236 Add method to get window by id 2021-09-15 11:02:54 +02:00
rafael-aero
75d7924251 Merge branch 'master' of https://github.com/theolivenbaum/Electron.NET 2021-09-15 10:58:45 +02:00
rafael-aero
c2904f3f68 Change second instance activation to raise event instead of trying to blindly open any window 2021-09-15 10:58:43 +02:00
theolivenbaum
adef39f3ec Change flags to nullable 2021-09-10 10:53:49 +02:00
theolivenbaum
836eebf256 Update browserWindows.js 2021-09-10 10:13:23 +02:00
theolivenbaum
124d24a19c Update browserWindows.ts 2021-09-10 10:12:56 +02:00
theolivenbaum
67ea8c768e Update BrowserWindow.cs 2021-09-10 10:11:41 +02:00
theolivenbaum
8604b50224 Add method to destroy all windows manually 2021-09-08 08:57:05 +02:00
theolivenbaum
5559fc61b1 force-destroy all windows on before-quit-for-update 2021-09-08 08:47:16 +02:00
theolivenbaum
9be80abfcf Add method to destroy splashscreen 2021-09-07 19:19:49 +02:00
theolivenbaum
6a4a7eff1c Workaround for electron freeze bug 2021-09-07 17:48:12 +02:00
theolivenbaum
a637174b93 typo 2021-09-07 15:00:35 +02:00
theolivenbaum
dc2662e52e Add way to set flags for Electron before the app starts 2021-09-07 14:36:57 +02:00
theolivenbaum
801616cd53 Let users set the color of the titlebar instead of just enabling it 2021-09-06 15:54:32 +02:00
theolivenbaum
9693c82792 Add TitleBarOverlay option 2021-09-06 15:18:59 +02:00
theolivenbaum
a3fb411d8a always keep default values when creating window 2021-09-06 12:39:32 +02:00
theolivenbaum
172f6ded3f Merge branch 'master' of https://github.com/theolivenbaum/Electron.NET 2021-09-06 11:45:01 +02:00
theolivenbaum
bbbc9e6f61 make splashscreen draggable 2021-09-06 11:44:57 +02:00
rafael-aero
236c31abe0 Merge branch 'master' of https://github.com/theolivenbaum/Electron.NET 2021-09-03 15:28:34 +02:00
rafael-aero
374d92f3b1 don't throw in case the tray was destroyed between calls 2021-09-03 15:28:32 +02:00
theolivenbaum
ea40249a9c refactor Socket to use a task completion source instead of a getter with locks 2021-09-02 20:37:22 +02:00
theolivenbaum
7f5db58edd fix deadlock case on emit before any Socket use 2021-09-02 20:06:01 +02:00
theolivenbaum
d18700f64d missing static flag 2021-09-02 18:29:02 +02:00
theolivenbaum
47f4516ae2 Add flag to check if the socket is connected 2021-09-02 18:20:11 +02:00
theolivenbaum
bb8965fa91 remove semaphore in favor of unique events per window /view create request 2021-09-02 17:24:07 +02:00
theolivenbaum
c229d49765 remove debug message 2021-09-02 16:45:20 +02:00
theolivenbaum
4fae2aeef2 fix ipc data serialization 2021-09-02 16:45:03 +02:00
theolivenbaum
5f4b1628e5 fix display serialization, serialize only window id when sending ipc message 2021-09-02 16:34:20 +02:00
theolivenbaum
25af4a7314 Update to Electron 14 2021-09-02 16:18:56 +02:00
rafael-aero
14ee45b88f Another attempt 2021-09-01 22:37:58 +02:00
rafael-aero
badc9f26b6 Revert "fix closed behaviour"
This reverts commit 4e7cebe519.
2021-09-01 22:25:50 +02:00
rafael-aero
4e7cebe519 fix closed behaviour 2021-09-01 22:10:44 +02:00
rafael-aero
ec74c7989a Update ipc.js 2021-09-01 21:31:30 +02:00
rafael-aero
a2579b221f fix wrong Id being passed - needed browser id, not webcontent id 2021-09-01 21:30:47 +02:00
rafael-aero
1e7ff5b6d6 fix getting id 2021-09-01 20:57:41 +02:00
rafael-aero
eac14427df Add event handler with sender id 2021-09-01 20:42:49 +02:00
rafael-aero
794248a83c fix creation of windows not being thread safe 2021-09-01 20:02:17 +02:00
rafael-aero
9a938dc680 use concurrent dictionary instead of list 2021-09-01 18:59:15 +02:00
rafael-aero
2d68ca5270 Fix LogError call 2021-09-01 18:29:20 +02:00
rafael-aero
548609f69b add handler for errors on socket.on calls 2021-09-01 18:28:44 +02:00
rafael-aero
7b5bac2083 Fix property assignment 2021-09-01 14:08:30 +02:00
rafael-aero
5ba10136e2 Add excludedFromShownWindowsMenu and TrafficLightPosition 2021-09-01 14:07:45 +02:00
tub5
aba77b1361 Update README.md
Fixed versions on the README
2021-08-31 11:56:26 +01:00
rafael-aero
bd45e23768 remove recreate behaviour from activate event on mac, and emit event to handler instead 2021-08-30 13:22:07 +02:00
rafael-aero
35b18a9501 ignore process closing if going for an update 2021-08-26 17:04:16 +02:00
rafael-aero
89d41a2750 restore serialization settings where it makes sense 2021-08-26 16:08:11 +02:00
rafael-aero
efdaf0e341 remove defaultvaluehandling setting as this breaks some cases
(like X:0 on browser view set bounds)
2021-08-26 15:59:52 +02:00
rafael-aero
0728577c40 missing using 2021-08-26 14:23:32 +02:00
rafael-aero
224bc1ef65 Add supported OS platform annotations 2021-08-26 14:22:54 +02:00
rafael-aero
7ad6803671 improve reconnect logic by waiting for reconnect before emit 2021-08-26 10:31:06 +02:00
rafael-aero
81a8367dac improve reconnect logic 2021-08-26 10:19:24 +02:00
rafael-aero
1161f59836 Update BridgeConnector.cs 2021-08-26 10:08:42 +02:00
rafael-aero
e7c56274e6 Update BridgeConnector.cs 2021-08-26 09:55:24 +02:00
rafael-aero
44d979fef4 Use ILogger instead of Console.WriteLine 2021-08-26 09:55:14 +02:00
theolivenbaum
2f0229235b fix for socket not being thread-safe 2021-08-26 08:40:36 +02:00
rafael-aero
18d425b042 Merge branch 'master' into switch-to-new-socket-lib 2021-08-25 17:08:53 +02:00
rafael-aero
5e82ae4246 add socket events to emit console messages 2021-08-25 13:38:30 +02:00
rafael-aero
48d5497045 Revert "Update main.js"
This reverts commit be41cae3bd.
2021-08-25 13:33:50 +02:00
rafael-aero
be41cae3bd Update main.js 2021-08-25 13:24:44 +02:00
rafael-aero
64b91fc235 Update main.js 2021-08-25 13:04:23 +02:00
rafael-aero
efec886f73 Update main.js 2021-08-25 11:33:32 +02:00
rafael-aero
8b03a6b006 remove stdio handling for detached case 2021-08-25 11:27:46 +02:00
rafael-aero
144a0a0ddc change argument name, detach process on creation 2021-08-25 11:14:21 +02:00
rafael-aero
8bbe6a96af Fix serialization of array of objects 2021-08-25 10:34:36 +02:00
rafael-aero
e39e34234d Update ProcessHelper.cs 2021-08-25 09:54:00 +02:00
rafael-aero
67c592a060 kill child process when electronize cli is killed 2021-08-25 09:38:37 +02:00
rafael-aero
bad59463a9 pass electron process id to child 2021-08-25 09:17:50 +02:00
rafael-aero
94efaf835e Merge branch 'master' of https://github.com/theolivenbaum/Electron.NET 2021-08-25 09:10:29 +02:00
rafael-aero
ac77643fc4 add variable to control kill behaviour 2021-08-25 09:10:27 +02:00
theolivenbaum
0393b0bd45 Merge branch 'master' into switch-to-new-socket-lib 2021-08-24 05:31:57 +02:00
theolivenbaum
953f1e2641 fix event names for when there are more than one window, view or webcontent Id 2021-08-24 05:31:46 +02:00
rafael-aero
fb99dbd5b5 add null return to avoid having to check for undefined 2021-08-23 18:28:00 +02:00
rafael-aero
fdbf7187b9 Update browserWindows.js 2021-08-23 15:30:47 +02:00
rafael-aero
9a680a41ac improve how we handle when window has been destroyed already 2021-08-23 14:59:41 +02:00
rafael-aero
f9693ce624 handle destroyed windows 2021-08-23 14:29:41 +02:00
rafael-aero
0090a7c239 fix wrong completed event name 2021-08-23 13:24:02 +02:00
rafael-aero
81431599ec Update ElectronNET.API.csproj 2021-08-23 13:01:38 +02:00
rafael-aero
31094f9d2b Remove unecessary JsonSerializer settings, fix default serializer 2021-08-23 11:57:42 +02:00
rafael-aero
bf48bc8227 replace remaining cases with OnResult, fix deserialization of json objects 2021-08-23 11:22:37 +02:00
rafael-aero
87d97efcfa Merge branch 'master' into switch-to-new-socket-lib 2021-08-21 09:17:43 +02:00
theolivenbaum
da9d9658f5 Update main.js 2021-08-21 09:17:20 +02:00
theolivenbaum
444c09fb4d Update main.js 2021-08-21 08:26:43 +02:00
rafael-aero
ca9bee7bf0 Merge branch 'master' into switch-to-new-socket-lib 2021-08-20 15:16:16 +02:00
rafael-aero
0aab352f86 remove yield call 2021-08-20 15:07:39 +02:00
rafael-aero
a8229f2fa9 add internal method to emit socket events synchronously, and use it for all exit, quit and relaunch methods 2021-08-20 15:06:58 +02:00
rafael-aero
9daaebcef6 Add timeout property for splashscreen 2021-08-20 14:56:47 +02:00
rafael-aero
67b59d95d4 fix quotes 2021-08-20 14:52:33 +02:00
rafael-aero
8f71480b3e Merge branch 'master' into switch-to-new-socket-lib 2021-08-20 14:49:56 +02:00
rafael-aero
133dcd6b65 Fix exit method 2021-08-20 14:49:49 +02:00
rafael-aero
d9a7411904 Merge branch 'master' into switch-to-new-socket-lib 2021-08-20 14:36:09 +02:00
rafael-aero
b42eba8a70 Handle non-zero exit codes from ASP.NET process 2021-08-20 14:36:02 +02:00
rafael-aero
e8e3649925 Merge branch 'master' into switch-to-new-socket-lib 2021-08-19 14:50:46 +02:00
rafael-aero
b6338ac7de log error messages from asp-net process 2021-08-19 14:50:30 +02:00
rafael-aero
b708b4b622 reset default values 2021-08-18 10:48:55 +02:00
rafael-aero
336c3b9400 cleanup for merge 2021-08-18 10:42:24 +02:00
rafael-aero
bd08938c49 Delete build-nuget.yaml 2021-08-18 10:32:41 +02:00
rafael-aero
cbe0637e84 Simplify repeated code with OnResult method, fix race condition with multiple calls to On/Off for the same event 2021-08-18 10:24:12 +02:00
rafael-aero
8063f49e4b run all continuations asyncronously 2021-08-17 16:28:07 +02:00
rafael-aero
d6b29f7350 avoid calling npm install if nothing changed 2021-08-09 17:43:54 +02:00
rafael-aero
237638a5b3 add command for simple build 2021-08-09 17:32:24 +02:00
Matt
b910807ced Log errors in the dotnet process 2021-08-04 17:33:09 +02:00
rafael-aero
7fe8f6e49e fix wrong object initializer 2021-07-21 17:04:29 +02:00
rafael-aero
c4ff481131 add debug option 2021-07-21 10:42:04 +02:00
rafael-aero
9107b161b3 Add prototype from-build-output command 2021-07-13 11:25:00 +02:00
rafael-aero
ec2261f1c5 Remove wrong ReleaseNoteInfo model 2021-07-13 09:08:31 +02:00
theolivenbaum
b03bc7c9eb Clean-up 2021-07-12 21:33:35 +02:00
theolivenbaum
e6214491cf Merge pull request #2 from theolivenbaum/remove-deprecated-socket-lib
Remove deprecated socket lib
2021-07-12 21:28:07 +02:00
theolivenbaum
95d614796e works 2021-07-12 21:27:40 +02:00
rafael-aero
126d39f4a5 wip 2021-07-12 19:50:39 +02:00
rafael-aero
8880e040f7 remove remaining .Result calls 2021-07-12 18:16:07 +02:00
rafael-aero
f200013165 add custom property handle for electronize start command 2021-07-12 17:05:26 +02:00
rafael-aero
82755e399d Add comments 2021-07-12 15:54:23 +02:00
rafael-aero
f07f2e9506 Update build-nuget.yaml 2021-07-12 15:53:02 +02:00
rafael-aero
83fd5a5d4b Add manual initialization methods 2021-07-12 15:52:30 +02:00
rafael-aero
6dee08379c Merge remote-tracking branch 'upstream/master' 2021-07-12 09:24:32 +02:00
Robert Muehsig
c2a8c627b9 13.5.1 2021-07-08 14:09:44 +02:00
Gregor Biswanger
1862094861 Merge pull request #585 from tub5/bug/584
If we provide the Version parameter and haven't included the version …
2021-07-02 17:18:41 +02:00
Gregor Biswanger
0ad89c7d22 RequestSingleInstanceLockAsync callback does work now - bug fix #519 2021-07-02 17:18:14 +02:00
tub5
0af664b8a6 If we provide the Version parameter and haven't included the version or product version dotnet flag then add them.
Fixes: #584
2021-07-02 16:07:31 +01:00
Gregor Biswanger
afcd113675 singleInstance handle command line arguments 2021-07-02 16:50:48 +02:00
Gregor Biswanger
0e22ee3fd3 Changed CLI help text 2021-07-02 12:47:51 +02:00
Gregor Biswanger
ce0cdf39c6 Update to native Electron 13.1.5, Update Changelog 2021-07-02 02:04:23 +02:00
Gregor Biswanger
305544ab42 Merge pull request #579 from tub5/bug/578
Upgrade to use Electron 12.0.12
2021-07-01 23:43:10 +02:00
Gregor Biswanger
78d9d601b1 Merge branch 'master' into bug/578 2021-07-01 23:42:09 +02:00
Gregor Biswanger
fdd643ba48 Merge pull request #573 from tantumalice/serialization-fix
Vibrancy serialization fix
2021-07-01 23:40:09 +02:00
Gregor Biswanger
29a257251f Merge pull request #570 from cristiangiagante/net5_compat
Changes PublishSingleFile default to false for NET5 compatibility
2021-07-01 23:38:27 +02:00
Gregor Biswanger
3676db89d3 Merge branch 'master' into net5_compat 2021-07-01 23:38:19 +02:00
Gregor Biswanger
29011189f8 Merge pull request #582 from ElectronNET/dependabot/npm_and_yarn/ElectronNET.Host/ws-7.4.6
Bump ws from 7.4.2 to 7.4.6 in /ElectronNET.Host
2021-07-01 23:25:54 +02:00
Gregor Biswanger
9d7d859764 Merge pull request #583 from ElectronNET/dependabot/npm_and_yarn/ElectronNET.Host/lodash-4.17.21
Bump lodash from 4.17.19 to 4.17.21 in /ElectronNET.Host
2021-07-01 23:25:24 +02:00
Gregor Biswanger
5cdda5595a Merge pull request #581 from ElectronNET/dependabot/npm_and_yarn/ElectronNET.Host/normalize-url-4.5.1
Bump normalize-url from 4.5.0 to 4.5.1 in /ElectronNET.Host
2021-07-01 23:25:01 +02:00
Gregor Biswanger
62fe944ae3 Merge pull request #565 from ElectronNET/dependabot/npm_and_yarn/ElectronNET.WebApp/ElectronHostHook/lodash-4.17.21
Bump lodash from 4.17.19 to 4.17.21 in /ElectronNET.WebApp/ElectronHostHook
2021-07-01 23:24:25 +02:00
Gregor Biswanger
617eb15df8 Merge pull request #562 from TSrgy/using-exit-code
Using exit code instead of seek for the term 'error'
2021-07-01 23:24:10 +02:00
Gregor Biswanger
bff71dc86a Merge pull request #561 from nfichter/proxy-credentials
Add support for proxies that require basic username/password authentication
2021-07-01 23:20:36 +02:00
Gregor Biswanger
f0280f420a Merge pull request #560 from nfichter/ipc-to-browser-view
Allow IpcMain to send IPC messages to BrowserViews
2021-07-01 23:18:55 +02:00
Gregor Biswanger
9f7809810f Merge pull request #559 from nfichter/insert-css
Add WebContents insertCSS functionality
2021-07-01 23:16:53 +02:00
Gregor Biswanger
e610c96550 Merge pull request #547 from Funkrusha/feature/enable-post-requests
Add PostData to LoadURLOptions to allow http-posts in LoadURL calls
2021-07-01 23:13:19 +02:00
Gregor Biswanger
f3bd3d07d5 Merge pull request #546 from tub5/master
Fixes Add ability to pass an argument for "Version" for both the "dot…
2021-07-01 22:55:15 +02:00
Gregor Biswanger
0e8cfec689 Merge branch 'master' into master 2021-07-01 22:55:09 +02:00
Gregor Biswanger
c1b3d422d5 Merge pull request #540 from MiniguyBrendan/master
Resolve #539, #357 - Fix splash screen interaction causing crashes, ghost dragging, and resizable behavior
2021-07-01 22:41:00 +02:00
dependabot[bot]
fc12363e11 Bump lodash from 4.17.19 to 4.17.21 in /ElectronNET.Host
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.19 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.19...4.17.21)

---
updated-dependencies:
- dependency-name: lodash
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-01 18:17:06 +00:00
dependabot[bot]
02f2fd770c Bump ws from 7.4.2 to 7.4.6 in /ElectronNET.Host
Bumps [ws](https://github.com/websockets/ws) from 7.4.2 to 7.4.6.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.4.2...7.4.6)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-01 18:16:42 +00:00
dependabot[bot]
5ee1918bb4 Bump normalize-url from 4.5.0 to 4.5.1 in /ElectronNET.Host
Bumps [normalize-url](https://github.com/sindresorhus/normalize-url) from 4.5.0 to 4.5.1.
- [Release notes](https://github.com/sindresorhus/normalize-url/releases)
- [Commits](https://github.com/sindresorhus/normalize-url/commits)

---
updated-dependencies:
- dependency-name: normalize-url
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-01 18:16:36 +00:00
dependabot[bot]
2213c61746 Bump lodash in /ElectronNET.WebApp/ElectronHostHook
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.19 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.19...4.17.21)

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-01 18:16:36 +00:00
Gregor Biswanger
3cdff747fe Merge pull request #531 from stackify/issue/523
fixes #523 allow for property overrides to be passed in
2021-07-01 20:12:04 +02:00
tub5
476cc9e505 Updating ContextIsolation as per the comment from @danatcofo. "on electron v12 WebPreferences.contextIsolation defaults to true… this means that window.require() will no longer function" 2021-06-28 15:55:16 +01:00
rafael-aero
8f5a7856d5 use new Electron 12 default values 2021-06-28 16:30:24 +02:00
rafael-aero
f78573401a fix strange issue with capitalization of assembly name 2021-06-28 16:08:00 +02:00
rafael-aero
d8ba9d9372 change assembly name 2021-06-28 15:48:15 +02:00
rafael-aero
09cb7a640f Update EmbeddedFileHelper.cs 2021-06-28 15:43:55 +02:00
rafael-aero
2f3d2c00b6 print all resource names 2021-06-28 15:43:40 +02:00
rafael-aero
3b7b592ac8 fix name on resource path 2021-06-28 15:21:41 +02:00
rafael-aero
bcbe76211c Add option to set electron version 2021-06-28 15:04:26 +02:00
rafael-aero
505a5b2204 fix NPM install 2021-06-28 15:01:10 +02:00
rafael-aero
468a4fa35b fix package name 2021-06-28 14:35:59 +02:00
rafael-aero
94b5faafcd add publish to nuget 2021-06-28 14:31:33 +02:00
rafael-aero
f08711e41b Fix variables 2021-06-28 14:26:27 +02:00
theolivenbaum
1a6d50d77a Set up CI with Azure Pipelines
[skip ci]
2021-06-28 14:19:47 +02:00
rafael-aero
d188baaaff Merge remote-tracking branch 'MiniguyBrendan/master' 2021-06-28 14:11:08 +02:00
rafael-aero
916eecf117 Merge branch 'bug/578' 2021-06-28 14:08:45 +02:00
tub5
fb8ca94e8e Upgrade to use Electron 12.0.12
Resolves #578
2021-06-28 12:46:17 +01:00
tub5
c94702fc60 Remove incorrect text at the top of the file 2021-06-28 12:10:05 +01:00
Alisa Semenova
cd9e06d5db Vibrancy serialization fix 2021-06-14 16:52:33 +03:00
Cristian Giagante
613f0a05b3 Changes PublishSingleFile default to false for NET5 compatibility 2021-06-02 22:39:28 -03:00
TSrgy
de2ce85a5c write command to console 2021-04-29 21:25:42 +05:00
TSrgy
e5d47e077b escape arguments for bash 2021-04-29 21:11:16 +05:00
TSrgy
ac77ccce9f Using exit code 2021-04-29 08:29:36 +05:00
Noah Fichter
504cc59760 Remove app argument from browserViewApi since it's no longer needed 2021-04-26 14:45:02 -04:00
Noah Fichter
0ee7097f31 Add support for proxies that require basic authentication 2021-04-26 14:38:41 -04:00
Noah Fichter
2d93d959f7 Allow IpcMain to send IPC messages to BrowserViews 2021-04-26 13:04:34 -04:00
Noah Fichter
a4d261a4e7 Add WebContents insertCSS functionality 2021-04-26 12:41:14 -04:00
Martin Schweizer
3838fe8971 Add PostData to LoadURLOptions to allow http-posts in LoadURL calls
Enable the possibility to post data to external Url's with the BrowserWindow.LoadURL function. The post data is provided through LoadURLOptions
2021-03-12 16:31:29 +01:00
tub5
b5e69f5dda Fixes Add ability to pass an argument for "Version" for both the "dotnet publish" and "electron-builder" commands #543 2021-03-04 14:45:52 +00:00
Brendan
55a3f10d37 Splash screen always renders on top 2021-02-18 13:32:45 -05:00
Brendan
7e494518f3 Fully ignore mouse events on splash screen (avoids drag + drop file into window) 2021-02-17 02:30:19 -05:00
Brendan
4596492cd9 Fix splash screen interaction causing crashes, fix splash screen content ghost drag, fix resizable splash screen. Resolves #539, #357
Using the browser-window-focus event would cause the splashScreen to be destroyed early (since regular mouse-focus events would cause the event to be fired).

Using the browser-window-created event produces the correct behavior.
2021-02-17 02:07:42 -05:00
Daniel Gidman
dd5bfd3961 Pass dotnet publsh /p: arguments to the publish command
use '/p:propertyName=value' or '/property:propertyName=value' to pass in dotnet build property overrides.

fixes #523
https://github.com/ElectronNET/Electron.NET/issues/523
2021-01-25 12:15:01 -06:00
dependabot[bot]
5d907864d8 Bump socket.io from 2.2.0 to 2.4.0 in /ElectronNET.Host
Bumps [socket.io](https://github.com/socketio/socket.io) from 2.2.0 to 2.4.0.
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/2.4.0/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/2.2.0...2.4.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-01-25 10:14:46 -06:00
Gregor Biswanger
30941df39c Update to .NET 5 infos 2021-01-22 00:16:04 +01:00
Gregor Biswanger
3588a8696d Update Changelog 2021-01-22 00:12:40 +01:00
Robert Muehsig
876bb98d92 11.5.1 2021-01-21 23:55:24 +01:00
Gregor Biswanger
427b57a002 Update Changelog 2021-01-21 22:06:08 +01:00
Gregor Biswanger
cc0b15c61e Merge pull request #528 from stackify/issue/527
Issue/527
2021-01-21 21:45:15 +01:00
Dan
8a0276daf9 Add ability to enable remote module in browser
The jump from Election 9x to 11x changed the default setting.  This exposes it so that user can re-enable it if needed.
2021-01-20 11:49:50 -06:00
Dan
e94196504e Support subscribing to unmapped events on App and Tray modules
`Electron.App.On("eventName", () => {});` or `Electron.App.On("eventName", obj => {});`

fix #527
2021-01-18 19:52:58 -06:00
Dan
6076c727d1 By blow fix of documentation
fix #500
2021-01-18 19:52:58 -06:00
Dan
300dc49dde Update the buildAll.sh so that you can run it successfully on a Mac 2021-01-18 19:52:58 -06:00
Dan
ce0f3fd61e Dock Menu support
fix #527
2021-01-18 19:52:58 -06:00
Dan
12f5eae65c Expose Electron members to the service provider
Used for class composition with IServiceProvider
2021-01-18 13:09:10 -06:00
Dan
3ef44cf878 Merge remote-tracking branch 'ElectronNET/master' 2021-01-18 10:30:57 -06:00
Gregor Biswanger
41fa8e9e74 Update WebApp to Electron 11.1.1 - Fix Chrome breaking changes with link ref=imports 2021-01-12 03:12:01 +01:00
Gregor Biswanger
49e21de465 Merge pull request #486 from stackify/bug/442
442: maintain references between socket.io connection events
2021-01-11 23:27:51 +01:00
Dan Gidman
d2f6308dd2 Merge remote-tracking branch 'upstream/master' into bug/442 2021-01-11 15:50:28 -06:00
Gregor Biswanger
f06b95803f Update to native Electron 11.1.1 - Fix breaking changes and refactoring. 2021-01-11 01:56:39 +01:00
Gregor Biswanger
b9feff3436 Merge pull request #522 from ElectronNET/dependabot/npm_and_yarn/ElectronNET.Host/ini-1.3.7
Bump ini from 1.3.5 to 1.3.7 in /ElectronNET.Host
2021-01-11 00:12:49 +01:00
Gregor Biswanger
335489d2d9 Merge pull request #509 from scottkuhl/issues/491-upgrade-to-net-5
Upgrade to .NET 5
2021-01-11 00:10:09 +01:00
Gregor Biswanger
6fe0c6f085 Merge pull request #506 from nathanwienand/add-publish-single-file
Added new build and start commandline options for single exe
2021-01-11 00:07:53 +01:00
Gregor Biswanger
f82d185865 Merge pull request #505 from aarong-av/aarong-av/donfigurable-default-port
Adding a configurable default electron port.
2021-01-11 00:05:14 +01:00
Gregor Biswanger
550e2c2625 Merge pull request #487 from ElectronNET/dependabot/npm_and_yarn/ElectronNET.Host/electron-9.3.1
Bump electron from 9.2.0 to 9.3.1 in /ElectronNET.Host
2021-01-11 00:03:05 +01:00
Gregor Biswanger
61f54ebd55 Merge pull request #480 from ElectronNET/dependabot/npm_and_yarn/ElectronNET.WebApp/ElectronHostHook/bl-4.0.3
Bump bl from 4.0.2 to 4.0.3 in /ElectronNET.WebApp/ElectronHostHook
2021-01-10 23:56:54 +01:00
Gregor Biswanger
c8c818a77a Merge pull request #478 from dlitty/master
Added support for launching the application with a file on MacOS
2021-01-10 23:55:20 +01:00
Gregor Biswanger
fc590f55d8 Merge pull request #474 from freosc/PullRequest
Avoid Blocking Calls in App and AutoUpdater
2021-01-10 23:50:48 +01:00
dependabot[bot]
5fbe01df30 Bump ini from 1.3.5 to 1.3.7 in /ElectronNET.Host
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.7.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.7)

Signed-off-by: dependabot[bot] <support@github.com>
2020-12-11 17:11:37 +00:00
Scott Kuhl
dbf4d0f720 Upgraded NuGet packages to the latest versions:
- Microsoft.SourceLink.GitHub 1.0.0-beta2-19367-01 > 1.0.0
- System.Drawing.Common 4.7.0 > 5.0.0
- Microsoft.VisualStudio.Web.CodeGeneration.Design 3.0.0 > 5.0.0
2020-11-21 16:24:24 -06:00
Scott Kuhl
f996b3023e Updated TypeScript from 3.8 to 4.0. 2020-11-21 16:13:49 -06:00
Scott Kuhl
7f62e7299b Updated .NET Core 3.1 to .NET 5.0. 2020-11-21 16:13:06 -06:00
Aaron Gilliland
b803e42a73 Minor fix due to a copy paste issue. 2020-11-14 19:15:54 -06:00
Nathan Wienand
da1838db60 adding new build and start commandline options for single exe 2020-11-12 11:15:37 +00:00
Aaron Gilliland
8af1f50b88 Adding a configurable default electron port. Our environment does not allow for random port assignment. Port 8000 is not an option for our environment. 2020-11-11 07:48:42 -06:00
dependabot[bot]
c4f2188c62 Bump electron from 9.2.0 to 9.3.1 in /ElectronNET.Host
Bumps [electron](https://github.com/electron/electron) from 9.2.0 to 9.3.1.
- [Release notes](https://github.com/electron/electron/releases)
- [Changelog](https://github.com/electron/electron/blob/master/docs/breaking-changes.md)
- [Commits](https://github.com/electron/electron/compare/v9.2.0...v9.3.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-10-06 18:02:00 +00:00
Dan Gidman
e73655bd68 442: maintain references between socket.io connection events
https://github.com/ElectronNET/Electron.NET/issues/442

remove deletes of modules during disconnect
add delete of hostHook during disconnect
check if modules exist before importing them curring connect
move local caches of modules into global scope.
2020-10-06 11:29:53 -05:00
dependabot[bot]
758424d3ce Bump bl from 4.0.2 to 4.0.3 in /ElectronNET.WebApp/ElectronHostHook
Bumps [bl](https://github.com/rvagg/bl) from 4.0.2 to 4.0.3.
- [Release notes](https://github.com/rvagg/bl/releases)
- [Commits](https://github.com/rvagg/bl/compare/v4.0.2...v4.0.3)

Signed-off-by: dependabot[bot] <support@github.com>
2020-09-02 17:53:24 +00:00
Dan Litty
7518acb3c2 Added support for launching the application with a file on MacOS by listening for the open-file and open-url events from the operating system, and forwarding them to the Electron.NET app when listeners are added 2020-08-31 16:47:05 -04:00
Fre
5522addc0b PR 2020-08-21 12:35:31 +02:00
Fre
7f204c2a42 PR 2020-08-21 12:32:33 +02:00
Fre
de13f49bb6 PR 2020-08-21 12:27:31 +02:00
Fre
bca37228d9 del asynchelper 2020-08-21 12:22:28 +02:00
Fre
e17a36f7cb small changes 2020-08-21 12:13:38 +02:00
Fre
deccebb582 Merge branch 'master' into freosc
# Conflicts:
#	ElectronNET.Host/main.js
2020-08-21 11:13:06 +02:00
Fre
776ccc21e8 Merge remote-tracking branch 'upstream/master' 2020-08-21 10:36:24 +02:00
Fre
d0c92cac85 avoid memory leak when re-adding the eventlisteners 2020-08-21 10:32:02 +02:00
Gregor Biswanger
b525bf1a9a Update Changelog for 9.31.3 - Update to the native Electron 9.2.0 support 2020-08-14 13:25:27 +02:00
Gregor Biswanger
6337cac588 Merge pull request #468 from duncanawoods/fix_bad_fontsize_if_position_is_set
set default WebPreferences.DefaultFontSize
2020-08-14 12:55:17 +02:00
Gregor Biswanger
5d4509babe Merge pull request #467 from duncanawoods/fix_ERR_UNKNOWN_URL_SCHEME
fix ERR_UNKNOWN_URL_SCHEME by intercepting file:// protocol
2020-08-14 12:51:56 +02:00
Gregor Biswanger
3eef85cddf Merge pull request #465 from duncanawoods/buildsh_linux_errors
buildAll.sh linux errors
2020-08-14 12:48:40 +02:00
Gregor Biswanger
3f582d6c4e Merge pull request #457 from kojo12228/add-fsharp-support
Search for .csproj and .fsproj in init and add commands
2020-08-14 12:44:45 +02:00
Gregor Biswanger
18c5a65d6d Merge pull request #453 from ElectronNET/dependabot/npm_and_yarn/ElectronNET.WebApp/ElectronHostHook/lodash-4.17.19
Bump lodash from 4.17.15 to 4.17.19 in /ElectronNET.WebApp/ElectronHostHook
2020-08-14 12:42:02 +02:00
Gregor Biswanger
f8bbb138d8 Merge pull request #450 from ElectronNET/dependabot/npm_and_yarn/ElectronNET.Host/lodash-4.17.19
Bump lodash from 4.17.15 to 4.17.19 in /ElectronNET.Host
2020-08-14 12:41:50 +02:00
Gregor Biswanger
7880d56e4c Merge pull request #445 from rbaker26/master
Update Documentation in the README.md
2020-08-14 12:41:06 +02:00
Gregor Biswanger
c16a888699 Merge pull request #463 from code-lever/master
Add target command line option found in 'build' to 'start' in CLI to …
2020-08-14 12:37:49 +02:00
Gregor Biswanger
814e046d5c Merge pull request #433 from BurtsevC/master
description added to package.json
2020-08-14 12:31:27 +02:00
duncan
d2457203bc Add build electron host to buildAll.sh 2020-08-14 10:19:11 +01:00
duncan
a70304948a set default WebPreferences.DefaultFontSize to fix tiny text when possition is set 2020-08-13 22:54:45 +01:00
duncan
a49b2ce278 fix ERR_UNKNOWN_URL_SCHEME by intercepting file:// protocol
fix whitespace

Revert "fix whitespace"

This reverts commit 608e364ebbabb19ffd6c3e3e0f357251c2e8e348.

fix whitespace
2020-08-13 20:46:10 +01:00
duncan
1577146187 buildall.sh disable win/osx builds on linux 2020-08-13 13:18:49 +01:00
duncan
d61f20dd67 buildall.sh restore original paths using pushd/pops 2020-08-13 13:15:47 +01:00
Gabe Cook
f7217b417f Add target command line option found in 'build' to 'start' in CLI to support custom targets in development. 2020-08-07 10:09:27 -05:00
Fre
e136ed4127 Merge branch 'master' of https://github.com/freosc/Electron.NET into freosc 2020-08-03 08:50:02 +02:00
Kojo Amoasi
7489543c75 search for .csproj and .fsproj in init and add 2020-07-22 13:42:00 +01:00
dependabot[bot]
cbf3032617 Bump lodash in /ElectronNET.WebApp/ElectronHostHook
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-20 23:26:19 +00:00
dependabot[bot]
68c54b9917 Bump lodash from 4.17.15 to 4.17.19 in /ElectronNET.Host
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-17 20:44:42 +00:00
Robert Muehsig
26d10fca38 9.31.2 2020-07-08 12:56:51 +02:00
Gregor Biswanger
bd15587079 Update to Electron 9.0.5 2020-07-08 12:56:50 +02:00
Gregor Biswanger
42613f5b56 Rollback to socket.io 2.2.0 2020-07-08 12:56:49 +02:00
Gregor Biswanger
62117df108 Update Changelog 2020-07-08 12:56:49 +02:00
Fre V
f68ea25cba Merge pull request #4 from ElectronNET/master
nieuwe versie
2020-07-08 11:25:37 +02:00
Fre
4e9de2abfa Aanpassingen autoupdate & async code 2020-07-08 11:16:00 +02:00
Bob Baker
a08d274dc1 Update README.md 2020-07-06 12:02:42 -07:00
Robert Muehsig
3dea16798b 9.31.2 2020-07-06 19:00:17 +02:00
Gregor Biswanger
bf8c7c8fa1 Update to Electron 9.0.5 2020-07-06 18:37:31 +02:00
Gregor Biswanger
06724f6eae Rollback to socket.io 2.2.0 2020-07-06 18:24:23 +02:00
Gregor Biswanger
83e579d44b Merge branch 'master' of https://github.com/ElectronNET/Electron.NET 2020-07-06 18:19:08 +02:00
Gregor Biswanger
ed67aa8072 Update Changelog 2020-07-06 18:19:02 +02:00
Fre V
f1ceaa208e Merge pull request #3 from ElectronNET/master
903
2020-07-06 15:59:12 +02:00
Gregor Biswanger
5e005499ef Merge pull request #435 from writzx/master
Enabled empty tray icon
2020-07-05 00:26:51 +02:00
Gregor Biswanger
975e4020dc Merge pull request #443 from rbaker26/master
Bug Fix, Fixed Publishing Issue ("Unknown argument: .")
2020-07-05 00:24:21 +02:00
Bob Baker
15ce35a7d9 removed extra . cause build failures 2020-07-03 23:19:19 -07:00
Writwick Das
de1637672a enabled empty tray icon
(fixes click event on macos)
2020-06-15 17:01:31 +02:00
BurtsevC
6b75f63135 description added to package.json 2020-06-13 15:53:52 +03:00
266 changed files with 11786 additions and 5569 deletions

84
.devops/build-nuget.yaml Normal file
View 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'

3
.gitignore vendored
View File

@@ -260,3 +260,6 @@ paket-files/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Mac Only settings file
.DS_Store

15
.vscode/tasks.json vendored
View File

@@ -1,16 +1,21 @@
{
"version": "0.1.0",
"version": "2.0.0",
"command": "dotnet",
"isShellCommand": true,
"args": [],
"tasks": [
{
"taskName": "build",
"label": "build",
"type": "shell",
"command": "dotnet",
"args": [
"build",
"${workspaceRoot}/ElectronNET.CLI/ElectronNET.CLI.csproj"
],
"isBuildCommand": true,
"problemMatcher": "$msCompile"
"problemMatcher": "$msCompile",
"group": {
"_id": "build",
"isDefault": false
}
}
]
}

16
.vscode/tasks.json.old vendored Normal file
View 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"
}
]
}

View File

@@ -1,7 +1,103 @@
# Not released
# 18.6.1
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)
ElectronNET.API:
* 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)
# Released
# 13.5.1
ElectronNET.CLI:
* New Feature: Using exit code instead of seek for the term 'error' (thanks [TSrgy](https://github.com/TSrgy)) [\#562](https://github.com/ElectronNET/Electron.NET/pull/562)
* Fixed bug: Allow for property overrides to be passed in (thanks [danatcofo](https://github.com/danatcofo)) [\#531](https://github.com/ElectronNET/Electron.NET/pull/531)
Use `/p:propertyName=value` or `/property:propertyName=value` to pass in property overrides. This is equivalent to the `-p:` option documented here: [https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish)
* Fixed bug: Add ability to pass an argument for "Version" for both the "dotnet publish" and "electron-builder" commands (thanks [tub5](https://github.com/tub5)) [\#546](https://github.com/ElectronNET/Electron.NET/pull/546)
* Fixed bug: Version flag not persisting with the referenced executable (thanks [tub5](https://github.com/tub5)) [\#585](https://github.com/ElectronNET/Electron.NET/pull/585)
* Fixed bug: Changes PublishSingleFile default to false for NET5 compatibility (thanks [cristiangiagante](https://github.com/cristiangiagante)) [\#570](https://github.com/ElectronNET/Electron.NET/pull/570)
ElectronNET.API:
* New Feature: Native Electron 13.1.5 support, but not all new features (we search contributors)
* Breaking API Changes (from native Electron 13.1.5):
- `Shell.MoveItemToTrashAsync` renamed with `Shell.TrashItemAsync`
- The deprecated extension APIs have been removed: `BrowserWindow.GetAllExtensionsAsync()`, `BrowserWindow.RemoveExtension()`, `BrowserWindow.AddExtensionAsync()`. Use the session APIs instead: `Session.GetAllExtensionsAsync()`, `Session.RemoveExtension()`, `Session.LoadExtensionAsync()`.
* New Feature: singleInstance handle command line arguments [\#520](https://github.com/ElectronNET/Electron.NET/issues/520)
* New Feature: Add WebContents [insertCSS](https://www.electronjs.org/docs/api/web-contents#contentsinsertcsscss-options) functionality (thanks [nfichter](https://github.com/nfichter)) [\#559](https://github.com/ElectronNET/Electron.NET/pull/559)
* New Feature: Allow IpcMain to send IPC messages to BrowserViews (thanks [nfichter](https://github.com/nfichter)) [\#560](https://github.com/ElectronNET/Electron.NET/pull/560)
* New Feature: Add support for proxies that require basic username/password authentication (thanks [nfichter](https://github.com/nfichter)) [\#561](https://github.com/ElectronNET/Electron.NET/pull/561)
* New Feature: Add PostData to LoadURLOptions to allow http-posts in LoadURL calls (thanks [Funkrusha](https://github.com/Funkrusha)) [\#547](https://github.com/ElectronNET/Electron.NET/pull/547)
* Fixed bug: Fix splash screen interaction causing crashes, ghost dragging, and resizable behavior #540 (thanks [MiniguyBrendan](https://github.com/MiniguyBrendan)) [\#540](https://github.com/ElectronNET/Electron.NET/pull/540)
* Fixed bug: Vibrancy serialization fix (thanks [tantumalice](https://github.com/tantumalice)) [\#573](https://github.com/ElectronNET/Electron.NET/pull/573)
# 11.5.1
ElectronNET.CLI:
* New Feature: Added new build and start commandline options for single exe (thanks [nathanwienand](https://github.com/nathanwienand)) [\#506](https://github.com/ElectronNET/Electron.NET/pull/506)
* New Feature: Set a description of the app in `electron.manifest.json` (thanks [BurtsevC](https://github.com/BurtsevC)) [\#433](https://github.com/ElectronNET/Electron.NET/pull/433)
* New Feature: Set a target for the start command (thanks [gabecook](https://github.com/gabecook)) [\#463](https://github.com/ElectronNET/Electron.NET/pull/463)
* New Feature: `electronize init` support for F# projects (thanks [kojo12228](https://github.com/kojo12228)) [\#457](https://github.com/ElectronNET/Electron.NET/pull/457)
* New Feature: Linux support for the buildAll.sh (thanks [duncanawoods](https://github.com/duncanawoods)) [\#465](https://github.com/ElectronNET/Electron.NET/pull/465)
* Fixed bug: ERR_UNKNOWN_URL_SCHEME by intercepting file:// protocol (thanks [duncanawoods](https://github.com/duncanawoods)) [\#467](https://github.com/ElectronNET/Electron.NET/pull/467)
ElectronNET.API:
* New Feature: Native Electron 11.1.1 support, but not all new features (we search contributors)
* Breaking API Changes (from native Electron 11.0): - Removed: BrowserView.{destroy, fromId, fromWebContents, getAllViews} and id property of BrowserView
* New Feature: Upgrade to .NET 5 (thanks [scottkuhl](https://github.com/scottkuhl)) [\#509](https://github.com/ElectronNET/Electron.NET/pull/509)
* New Feature: Extension Method for adding the Electron static class members to the standard MS DI Containers, this is a QOL issue only. `services.AddElectron()` (thanks [danatcofo](https://github.com/danatcofo )) [\#528](https://github.com/ElectronNET/Electron.NET/pull/528)
* New Feature: SetMenu completed for the Dock (MacOS) (thanks [danatcofo](https://github.com/danatcofo )) [\#528](https://github.com/ElectronNET/Electron.NET/pull/528)
Example for the Dock Menu
`Electron.Dock.SetMenu(new [] {
new MenuItem {
Label = "Dock Menu Item",
Click = () => {
// do something
}
},
});`
Example for consuming the activate event (MacOs only)
`Electron.App.On("activate", obj => {
var hasWindows = (bool)obj;
// do something
});`
* New Feature: On and Once implementations for the App and Tray to cover the plethora of events that are not mapped explicitly in those two modules. (thanks [danatcofo](https://github.com/danatcofo )) [\#528](https://github.com/ElectronNET/Electron.NET/pull/528)
* New Feature: Adding the `EnableRemoteModule` property to the WebPreferences object. As of Electron 10, this property defaulted to false and without it exposed you can't use the remote module within a window. (thanks [danatcofo](https://github.com/danatcofo )) [\#528](https://github.com/ElectronNET/Electron.NET/pull/528)
* New Feature: Adding a configurable default electron port. (thanks [aarong-av](https://github.com/aarong-av)) [\#505](https://github.com/ElectronNET/Electron.NET/pull/505)
* New Feature: Added support for launching the application with a file on MacOS (thanks [dlitty](https://github.com/dlitty)) [\#478](https://github.com/ElectronNET/Electron.NET/pull/478)
* Improved: Avoid Blocking Calls in App and AutoUpdater (thanks [freosc](https://github.com/freosc)) [\#474](https://github.com/ElectronNET/Electron.NET/pull/474)
* Fixed bug: Maintain references between socket.io connection events (thanks [danatcofo](https://github.com/danatcofo )) [\#468](https://github.com/ElectronNET/Electron.NET/pull/486)
* Fixed bug: Set default WebPreferences.DefaultFontSize (thanks [duncanawoods](https://github.com/duncanawoods)) [\#468](https://github.com/ElectronNET/Electron.NET/pull/468)
# 9.31.2
* Electron-Builder fixed for Windows builds.
# 9.31.1
ElectronNET.CLI:
@@ -25,6 +121,7 @@ ElectronNET.API:
* Notification-Api Enhancement: Added missing properties in Notifications (thanks [konstantingross](https://github.com/konstantingross)) [\#410](https://github.com/ElectronNET/Electron.NET/pull/410)
* BrowserWindows-Api Enhancement: Add missing API call for SetProgressBar options (thanks [konstantingross](https://github.com/konstantingross)) [\#416](https://github.com/ElectronNET/Electron.NET/pull/416)
* BrowserWindow Enhancement: Add BrowserWindow.GetNativeWindowHandle() (thanks [kdlslyv](https://github.com/kdlslyv)) [\#429](https://github.com/ElectronNET/Electron.NET/pull/429)
* HostHook-Api Enhancement: HostHook.CallAsync should use TaskCompletionSource.SetException instead of throwing exception (thanks [Fre V](https://github.com/freosc)) [\#430](https://github.com/ElectronNET/Electron.NET/pull/430)
* MacOS Enhancement: Application exit logic (thanks [dafergu2](https://github.com/dafergu2)) [\#405](https://github.com/ElectronNET/Electron.NET/pull/405)
* Fixed bug: ElectronNET.API.Entities.WebPreferences.ContextIsolation [DefaultValue(true)] [\#411](https://github.com/ElectronNET/Electron.NET/issues/411)

860
ElectronNET.API/App.cs Normal file → Executable file

File diff suppressed because it is too large Load Diff

305
ElectronNET.API/AutoUpdater.cs Normal file → Executable file
View File

@@ -1,40 +1,56 @@
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
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
{
get
{
return Task.Run<bool>(() =>
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("autoUpdater-autoDownload-get-reply", (result) =>
{
BridgeConnector.Socket.Off("autoUpdater-autoDownload-get-reply");
taskCompletionSource.SetResult((bool)result);
});
BridgeConnector.Socket.Emit("autoUpdater-autoDownload-get");
return taskCompletionSource.Task;
}).Result;
}
set
{
BridgeConnector.Socket.Emit("autoUpdater-autoDownload-set", value);
BridgeConnector.Emit("autoUpdater-autoDownload-set", value);
}
}
@@ -45,26 +61,9 @@ namespace ElectronNET.API
/// </summary>
public bool AutoInstallOnAppQuit
{
get
{
return Task.Run<bool>(() =>
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("autoUpdater-autoInstallOnAppQuit-get-reply", (result) =>
{
BridgeConnector.Socket.Off("autoUpdater-autoInstallOnAppQuit-get-reply");
taskCompletionSource.SetResult((bool)result);
});
BridgeConnector.Socket.Emit("autoUpdater-autoInstallOnAppQuit-get");
return taskCompletionSource.Task;
}).Result;
}
set
{
BridgeConnector.Socket.Emit("autoUpdater-autoInstallOnAppQuit-set", value);
BridgeConnector.Emit("autoUpdater-autoInstallOnAppQuit-set", value);
}
}
@@ -76,26 +75,9 @@ namespace ElectronNET.API
/// </summary>
public bool AllowPrerelease
{
get
{
return Task.Run<bool>(() =>
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("autoUpdater-allowPrerelease-get-reply", (result) =>
{
BridgeConnector.Socket.Off("autoUpdater-allowPrerelease-get-reply");
taskCompletionSource.SetResult((bool)result);
});
BridgeConnector.Socket.Emit("autoUpdater-allowPrerelease-get");
return taskCompletionSource.Task;
}).Result;
}
set
{
BridgeConnector.Socket.Emit("autoUpdater-allowPrerelease-set", value);
BridgeConnector.Emit("autoUpdater-allowPrerelease-set", value);
}
}
@@ -105,26 +87,9 @@ namespace ElectronNET.API
/// </summary>
public bool FullChangelog
{
get
{
return Task.Run<bool>(() =>
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("autoUpdater-fullChangelog-get-reply", (result) =>
{
BridgeConnector.Socket.Off("autoUpdater-fullChangelog-get-reply");
taskCompletionSource.SetResult((bool)result);
});
BridgeConnector.Socket.Emit("autoUpdater-fullChangelog-get");
return taskCompletionSource.Task;
}).Result;
}
set
{
BridgeConnector.Socket.Emit("autoUpdater-fullChangelog-set", value);
BridgeConnector.Emit("autoUpdater-fullChangelog-set", value);
}
}
@@ -135,75 +100,41 @@ namespace ElectronNET.API
/// </summary>
public bool AllowDowngrade
{
get
{
return Task.Run<bool>(() =>
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("autoUpdater-allowDowngrade-get-reply", (result) =>
{
BridgeConnector.Socket.Off("autoUpdater-allowDowngrade-get-reply");
taskCompletionSource.SetResult((bool)result);
});
BridgeConnector.Socket.Emit("autoUpdater-allowDowngrade-get");
return taskCompletionSource.Task;
}).Result;
}
set
{
BridgeConnector.Socket.Emit("autoUpdater-allowDowngrade-set", value);
BridgeConnector.Emit("autoUpdater-allowDowngrade-set", value);
}
}
/// <summary>
/// For test only.
/// </summary>
public string UpdateConfigPath
{
get
{
return Task.Run<string>(() =>
{
var taskCompletionSource = new TaskCompletionSource<string>();
public Task<string> GetUpdateConfigPathAsync => BridgeConnector.OnResult<string>("autoUpdater-updateConfigPath-get", "autoUpdater-updateConfigPath-get-reply");
BridgeConnector.Socket.On("autoUpdater-updateConfigPath-get-reply", (result) =>
{
BridgeConnector.Socket.Off("autoUpdater-updateConfigPath-get-reply");
taskCompletionSource.SetResult(result.ToString());
});
BridgeConnector.Socket.Emit("autoUpdater-updateConfigPath-get");
return taskCompletionSource.Task;
}).Result;
}
}
/// <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.
/// Doesnt return channel from the update configuration, only if was previously set.
/// </summary>
public string Channel
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
{
get
set
{
return Task.Run<string>(() =>
{
var taskCompletionSource = new TaskCompletionSource<string>();
BridgeConnector.Socket.On("autoUpdater-channel-get-reply", (result) =>
{
BridgeConnector.Socket.Off("autoUpdater-channel-get-reply");
taskCompletionSource.SetResult(result.ToString());
});
BridgeConnector.Socket.Emit("autoUpdater-channel-get");
return taskCompletionSource.Task;
}).Result;
BridgeConnector.Emit("autoUpdater-requestHeaders-set", value);
}
}
@@ -216,12 +147,12 @@ namespace ElectronNET.API
{
if (_error == null)
{
BridgeConnector.Socket.On("autoUpdater-error" + GetHashCode(), (message) =>
BridgeConnector.On<string>("autoUpdater-error" + GetHashCode(), (message) =>
{
_error(message.ToString());
});
BridgeConnector.Socket.Emit("register-autoUpdater-error-event", GetHashCode());
BridgeConnector.Emit("register-autoUpdater-error-event", GetHashCode());
}
_error += value;
}
@@ -230,7 +161,7 @@ namespace ElectronNET.API
_error -= value;
if (_error == null)
BridgeConnector.Socket.Off("autoUpdater-error" + GetHashCode());
BridgeConnector.Off("autoUpdater-error" + GetHashCode());
}
}
@@ -245,12 +176,12 @@ namespace ElectronNET.API
{
if (_checkingForUpdate == null)
{
BridgeConnector.Socket.On("autoUpdater-checking-for-update" + GetHashCode(), () =>
BridgeConnector.On("autoUpdater-checking-for-update" + GetHashCode(), () =>
{
_checkingForUpdate();
});
BridgeConnector.Socket.Emit("register-autoUpdater-checking-for-update-event", GetHashCode());
BridgeConnector.Emit("register-autoUpdater-checking-for-update-event", GetHashCode());
}
_checkingForUpdate += value;
}
@@ -259,7 +190,7 @@ namespace ElectronNET.API
_checkingForUpdate -= value;
if (_checkingForUpdate == null)
BridgeConnector.Socket.Off("autoUpdater-checking-for-update" + GetHashCode());
BridgeConnector.Off("autoUpdater-checking-for-update" + GetHashCode());
}
}
@@ -275,12 +206,12 @@ namespace ElectronNET.API
{
if (_updateAvailable == null)
{
BridgeConnector.Socket.On("autoUpdater-update-available" + GetHashCode(), (updateInfo) =>
BridgeConnector.On<UpdateInfo>("autoUpdater-update-available" + GetHashCode(), (updateInfo) =>
{
_updateAvailable(JObject.Parse(updateInfo.ToString()).ToObject<UpdateInfo>());
_updateAvailable(updateInfo);
});
BridgeConnector.Socket.Emit("register-autoUpdater-update-available-event", GetHashCode());
BridgeConnector.Emit("register-autoUpdater-update-available-event", GetHashCode());
}
_updateAvailable += value;
}
@@ -289,7 +220,7 @@ namespace ElectronNET.API
_updateAvailable -= value;
if (_updateAvailable == null)
BridgeConnector.Socket.Off("autoUpdater-update-available" + GetHashCode());
BridgeConnector.Off("autoUpdater-update-available" + GetHashCode());
}
}
@@ -304,12 +235,12 @@ namespace ElectronNET.API
{
if (_updateNotAvailable == null)
{
BridgeConnector.Socket.On("autoUpdater-update-not-available" + GetHashCode(), (updateInfo) =>
BridgeConnector.On<UpdateInfo>("autoUpdater-update-not-available" + GetHashCode(), (updateInfo) =>
{
_updateNotAvailable(JObject.Parse(updateInfo.ToString()).ToObject<UpdateInfo>());
_updateNotAvailable(updateInfo);
});
BridgeConnector.Socket.Emit("register-autoUpdater-update-not-available-event", GetHashCode());
BridgeConnector.Emit("register-autoUpdater-update-not-available-event", GetHashCode());
}
_updateNotAvailable += value;
}
@@ -318,7 +249,7 @@ namespace ElectronNET.API
_updateNotAvailable -= value;
if (_updateNotAvailable == null)
BridgeConnector.Socket.Off("autoUpdater-update-not-available" + GetHashCode());
BridgeConnector.Off("autoUpdater-update-not-available" + GetHashCode());
}
}
@@ -333,12 +264,12 @@ namespace ElectronNET.API
{
if (_downloadProgress == null)
{
BridgeConnector.Socket.On("autoUpdater-download-progress" + GetHashCode(), (progressInfo) =>
BridgeConnector.On<ProgressInfo>("autoUpdater-download-progress" + GetHashCode(), (progressInfo) =>
{
_downloadProgress(JObject.Parse(progressInfo.ToString()).ToObject<ProgressInfo>());
_downloadProgress(progressInfo);
});
BridgeConnector.Socket.Emit("register-autoUpdater-download-progress-event", GetHashCode());
BridgeConnector.Emit("register-autoUpdater-download-progress-event", GetHashCode());
}
_downloadProgress += value;
}
@@ -347,7 +278,7 @@ namespace ElectronNET.API
_downloadProgress -= value;
if (_downloadProgress == null)
BridgeConnector.Socket.Off("autoUpdater-download-progress" + GetHashCode());
BridgeConnector.Off("autoUpdater-download-progress" + GetHashCode());
}
}
@@ -362,12 +293,12 @@ namespace ElectronNET.API
{
if (_updateDownloaded == null)
{
BridgeConnector.Socket.On("autoUpdater-update-downloaded" + GetHashCode(), (updateInfo) =>
BridgeConnector.On<UpdateInfo>("autoUpdater-update-downloaded" + GetHashCode(), (updateInfo) =>
{
_updateDownloaded(JObject.Parse(updateInfo.ToString()).ToObject<UpdateInfo>());
_updateDownloaded(updateInfo);
});
BridgeConnector.Socket.Emit("register-autoUpdater-update-downloaded-event", GetHashCode());
BridgeConnector.Emit("register-autoUpdater-update-downloaded-event", GetHashCode());
}
_updateDownloaded += value;
}
@@ -376,14 +307,14 @@ namespace ElectronNET.API
_updateDownloaded -= value;
if (_updateDownloaded == null)
BridgeConnector.Socket.Off("autoUpdater-update-downloaded" + GetHashCode());
BridgeConnector.Off("autoUpdater-update-downloaded" + GetHashCode());
}
}
private event Action<UpdateInfo> _updateDownloaded;
private static AutoUpdater _autoUpdater;
private static object _syncRoot = new object();
private static readonly object _syncRoot = new();
internal AutoUpdater() { }
@@ -412,16 +343,33 @@ namespace ElectronNET.API
/// <returns></returns>
public Task<UpdateCheckResult> CheckForUpdatesAsync()
{
var taskCompletionSource = new TaskCompletionSource<UpdateCheckResult>();
var taskCompletionSource = new TaskCompletionSource<UpdateCheckResult>(TaskCreationOptions.RunContinuationsAsynchronously);
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("autoUpdaterCheckForUpdatesComplete" + guid, (updateCheckResult) =>
BridgeConnector.On<UpdateCheckResult>("autoUpdaterCheckForUpdatesComplete" + guid, (updateCheckResult) =>
{
BridgeConnector.Socket.Off("autoUpdaterCheckForUpdatesComplete" + guid);
taskCompletionSource.SetResult(JObject.Parse(updateCheckResult.ToString()).ToObject<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.Socket.Emit("autoUpdaterCheckForUpdates", guid);
BridgeConnector.Emit("autoUpdaterCheckForUpdates", guid);
return taskCompletionSource.Task;
}
@@ -434,16 +382,36 @@ namespace ElectronNET.API
/// <returns></returns>
public Task<UpdateCheckResult> CheckForUpdatesAndNotifyAsync()
{
var taskCompletionSource = new TaskCompletionSource<UpdateCheckResult>();
var taskCompletionSource = new TaskCompletionSource<UpdateCheckResult>(TaskCreationOptions.RunContinuationsAsynchronously);
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("autoUpdaterCheckForUpdatesAndNotifyComplete" + guid, (updateCheckResult) =>
BridgeConnector.On<UpdateCheckResult>("autoUpdaterCheckForUpdatesAndNotifyComplete" + guid, (updateCheckResult) =>
{
BridgeConnector.Socket.Off("autoUpdaterCheckForUpdatesAndNotifyComplete" + guid);
taskCompletionSource.SetResult(JObject.Parse(updateCheckResult.ToString()).ToObject<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.Socket.Emit("autoUpdaterCheckForUpdatesAndNotify", guid);
BridgeConnector.Emit("autoUpdaterCheckForUpdatesAndNotify", guid);
return taskCompletionSource.Task;
}
@@ -459,7 +427,8 @@ namespace ElectronNET.API
/// <param name="isForceRunAfter">Run the app after finish even on silent install. Not applicable for macOS. Ignored if `isSilent` is set to `false`.</param>
public void QuitAndInstall(bool isSilent = false, bool isForceRunAfter = false)
{
BridgeConnector.Socket.Emit("autoUpdaterQuitAndInstall", isSilent, isForceRunAfter);
BridgeConnector.EmitSync("prepare-for-update");
BridgeConnector.EmitSync("autoUpdaterQuitAndInstall", isSilent, isForceRunAfter);
}
/// <summary>
@@ -468,16 +437,16 @@ namespace ElectronNET.API
/// <returns>Path to downloaded file.</returns>
public Task<string> DownloadUpdateAsync()
{
var taskCompletionSource = new TaskCompletionSource<string>();
var taskCompletionSource = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("autoUpdaterDownloadUpdateComplete" + guid, (downloadedPath) =>
BridgeConnector.On<string>("autoUpdaterDownloadUpdateComplete" + guid, (downloadedPath) =>
{
BridgeConnector.Socket.Off("autoUpdaterDownloadUpdateComplete" + guid);
BridgeConnector.Off("autoUpdaterDownloadUpdateComplete" + guid);
taskCompletionSource.SetResult(downloadedPath.ToString());
});
BridgeConnector.Socket.Emit("autoUpdaterDownloadUpdate", guid);
BridgeConnector.Emit("autoUpdaterDownloadUpdate", guid);
return taskCompletionSource.Task;
}
@@ -488,16 +457,16 @@ namespace ElectronNET.API
/// <returns>Feed URL.</returns>
public Task<string> GetFeedURLAsync()
{
var taskCompletionSource = new TaskCompletionSource<string>();
var taskCompletionSource = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("autoUpdaterGetFeedURLComplete" + guid, (downloadedPath) =>
BridgeConnector.On<string>("autoUpdaterGetFeedURLComplete" + guid, (downloadedPath) =>
{
BridgeConnector.Socket.Off("autoUpdaterGetFeedURLComplete" + guid);
BridgeConnector.Off("autoUpdaterGetFeedURLComplete" + guid);
taskCompletionSource.SetResult(downloadedPath.ToString());
});
BridgeConnector.Socket.Emit("autoUpdaterGetFeedURL", guid);
BridgeConnector.Emit("autoUpdaterGetFeedURL", guid);
return taskCompletionSource.Task;
}

View File

@@ -1,44 +1,551 @@
using Quobject.SocketIoClientDotNet.Client;
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
{
private static Socket _socket;
private static object _syncRoot = new object();
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
public static Socket Socket
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
{
if(_socket == null && HybridSupport.IsElectronActive)
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
{
lock (_syncRoot)
{
if (_socket == null && HybridSupport.IsElectronActive)
{
_socket = IO.Socket("http://localhost:" + BridgeSettings.SocketPort);
_socket.On(Socket.EVENT_CONNECT, () =>
{
Console.WriteLine("BridgeConnector connected!");
});
}
}
await _socketSemaphoreEmit.WaitAsync();
await socket.EmitAsync(eventString, args);
}
else if(_socket == null && !HybridSupport.IsElectronActive)
finally
{
lock (_syncRoot)
{
if (_socket == null && !HybridSupport.IsElectronActive)
{
_socket = IO.Socket(new Uri("http://localhost"), new IO.Options { AutoConnect = false });
}
}
_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);
}
return _socket;
_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,
};
}
}
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -2,9 +2,6 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace ElectronNET.API
@@ -29,62 +26,22 @@ namespace ElectronNET.API
/// </summary>
public WebContents WebContents { get; internal set; }
/// <summary>
/// Whether the view is destroyed.
/// </summary>
public Task<bool> IsDestroyedAsync
{
get
{
return Task.Run<bool>(() =>
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("browserView-isDestroyed-reply", (result) =>
{
BridgeConnector.Socket.Off("browserView-isDestroyed-reply");
taskCompletionSource.SetResult((bool)result);
});
BridgeConnector.Socket.Emit("browserView-isDestroyed", Id);
return taskCompletionSource.Task;
});
}
}
/// <summary>
/// Resizes and moves the view to the supplied bounds relative to the window.
///
/// (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);
}
internal Action<BrowserView> Destroyed;
/// <summary>
/// BrowserView
/// </summary>
@@ -97,25 +54,13 @@ namespace ElectronNET.API
WebContents = new WebContents(id + 1000);
}
/// <summary>
/// Force closing the view, the `unload` and `beforeunload` events won't be emitted
/// for the web page.After you're done with a view, call this function in order to
/// free memory and other resources as soon as possible.
/// </summary>
public void Destroy()
{
BridgeConnector.Socket.Emit("browserView-destroy", Id);
Destroyed?.Invoke(this);
}
/// <summary>
/// (experimental)
/// </summary>
/// <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>
@@ -126,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
};
}
}

File diff suppressed because it is too large Load Diff

144
ElectronNET.API/Clipboard.cs Normal file → Executable file
View 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,

View File

@@ -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);
}
}

View File

@@ -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
};
}
}

View 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);
}
}
}

74
ElectronNET.API/Dialog.cs Normal file → Executable file
View File

@@ -4,18 +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() { }
@@ -48,26 +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[]>();
var list = new List<string>();
foreach (var item in result)
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;
}
@@ -80,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;
}
@@ -149,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;
@@ -192,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>
@@ -202,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);
@@ -215,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,

125
ElectronNET.API/Dock.cs Normal file → Executable file
View File

@@ -1,18 +1,24 @@
using System.Threading;
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;
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()
{
@@ -47,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>
@@ -73,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>
@@ -82,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>
@@ -91,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>
@@ -99,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>
@@ -124,7 +103,7 @@ namespace ElectronNET.API
/// </summary>
public void Hide()
{
BridgeConnector.Socket.Emit("dock-hide");
BridgeConnector.Emit("dock-hide");
}
/// <summary>
@@ -132,7 +111,7 @@ namespace ElectronNET.API
/// </summary>
public void Show()
{
BridgeConnector.Socket.Emit("dock-show");
BridgeConnector.Emit("dock-show");
}
/// <summary>
@@ -141,58 +120,42 @@ 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>
/// TODO: Menu (macOS) still to be implemented
/// Gets the dock menu items.
/// </summary>
/// <value>
/// The menu items.
/// </value>
public IReadOnlyCollection<MenuItem> MenuItems { get { return _items.AsReadOnly(); } }
private readonly List<MenuItem> _items = new();
/// <summary>
/// Sets the application's dock menu.
/// </summary>
public void SetMenu()
public void SetMenu(MenuItem[] menuItems)
{
BridgeConnector.Socket.Emit("dock-setMenu");
menuItems.AddMenuItemsId();
BridgeConnector.Emit("dock-setMenu", JArray.FromObject(menuItems, _jsonSerializer));
_items.AddRange(menuItems);
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.
@@ -200,7 +163,13 @@ namespace ElectronNET.API
/// <param name="image"></param>
public void SetIcon(string image)
{
BridgeConnector.Socket.Emit("dock-setIcon", image);
BridgeConnector.Emit("dock-setIcon", image);
}
private static readonly JsonSerializer _jsonSerializer = new()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
};
}
}

View 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;
}
}
}
}

View File

@@ -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; } }
}
}

24
ElectronNET.API/ElectronNET.API.csproj Normal file → Executable file
View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageOutputPath>..\artifacts</PackageOutputPath>
<PackageId>ElectronNET.API</PackageId>
@@ -10,8 +10,10 @@
<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>
@@ -20,6 +22,7 @@ This package contains the API to access the "native" electron API.</Description>
<PackageIcon>PackageIcon.png</PackageIcon>
<Version>99.0.0.0</Version>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<TargetFrameworks>net6.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
@@ -33,15 +36,20 @@ This package contains the API to access the "native" electron API.</Description>
<Exec Command="$(ProjectDir)devCleanup.sh" IgnoreExitCode="true" />
</Target>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19367-01">
<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="SocketIoClientDotNet" Version="1.0.5" />
<PackageReference Include="System.Drawing.Common" Version="4.7.0" />
<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>

View File

@@ -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

View File

@@ -1,13 +1,20 @@
namespace ElectronNET.API.Entities
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; } = 1.0f;
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};
}
}

View File

@@ -0,0 +1,18 @@
namespace ElectronNET.API.Entities
{
/// <summary>
///
/// </summary>
public class Blob : IPostData
{
/// <summary>
/// The object represents a Blob
/// </summary>
public string Type { get; } = "blob";
/// <summary>
/// The UUID of the Blob being uploaded
/// </summary>
public string BlobUUID { get; set; }
}
}

View File

@@ -9,5 +9,17 @@
/// See BrowserWindow.
/// </summary>
public WebPreferences WebPreferences { get; set; }
/// <summary>
/// A proxy to set on creation in the format host:port.
/// The proxy can be alternatively set using the BrowserView.WebContents.SetProxyAsync function.
/// </summary>
public string Proxy { get; set; }
/// <summary>
/// The credentials of the Proxy in the format username:password.
/// These will only be used if the Proxy field is also set.
/// </summary>
public string ProxyCredentials { get; set; }
}
}

View File

@@ -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+.
@@ -258,5 +267,31 @@ namespace ElectronNET.API.Entities
/// Settings of web page's features.
/// </summary>
public WebPreferences WebPreferences { get; set; }
/// <summary>
/// A proxy to set on creation in the format host:port.
/// The proxy can be alternatively set using the BrowserWindow.WebContents.SetProxyAsync function.
/// </summary>
public string Proxy { get; set; }
/// <summary>
/// The credentials of the Proxy in the format username:password.
/// 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; }
}
}

View File

@@ -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>

View 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; }
}
}

View File

@@ -1,8 +1,11 @@
namespace ElectronNET.API.Entities
using System;
namespace ElectronNET.API.Entities
{
/// <summary>
///
/// </summary>
[Obsolete("Use CreateOptions instead")]
public class CreateFromBitmapOptions
{
/// <summary>
@@ -18,6 +21,12 @@
/// <summary>
/// Gets or sets the scalefactor
/// </summary>
public float ScaleFactor { get; set; } = 1.0f;
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};
}
}

View File

@@ -1,8 +1,11 @@
using System;
namespace ElectronNET.API.Entities
{
/// <summary>
///
/// </summary>
[Obsolete("Use CreateOptions instead")]
public class CreateFromBufferOptions
{
/// <summary>
@@ -18,6 +21,11 @@ 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>
/// Utility conversion for obsolete class
/// </summary>
public static implicit operator CreateOptions(CreateFromBufferOptions o) => new()
{Width = o.Width, Height = o.Height, ScaleFactor = o.ScaleFactor};
}
}

View File

@@ -0,0 +1,24 @@
namespace ElectronNET.API.Entities
{
/// <summary>
/// Options for creating a new <see cref="NativeImage"/>
/// </summary>
public class CreateOptions
{
/// <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;
}
}

View File

@@ -34,5 +34,7 @@
/// The title of the url at text.
/// </summary>
public string Bookmark { get; set; }
public NativeImage? Image { get; set; }
}
}
}

View 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; }
}
}

View File

@@ -1,5 +1,10 @@
namespace ElectronNET.API.Entities
{
public class DisplayChanged
{
public Display display { get; set; }
public string[] metrics { get; set; }
}
/// <summary>
///
/// </summary>
@@ -21,12 +26,12 @@
/// <summary>
/// Can be 0, 90, 180, 270, represents screen rotation in clock-wise degrees.
/// </summary>
public int Rotation { get; set; }
public float Rotation { get; set; }
/// <summary>
/// Output device's pixel scale factor.
/// </summary>
public int ScaleFactor { get; set; }
public float ScaleFactor { get; set; }
/// <summary>
/// Gets or sets the size.

View File

@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ElectronNET.API.Entities
{
/// <summary>
/// Docs: https://electronjs.org/docs/api/structures/extension
/// </summary>
public class Extension
{
/// <summary>
///
/// </summary>
public string Id { get; set; }
/// <summary>
/// Copy of the extension's manifest data.
/// </summary>
public dynamic Manifest { get; set; }
/// <summary>
///
/// </summary>
public string Name { get; set; }
/// <summary>
/// The extension's file path.
/// </summary>
public string Path { get; set; }
/// <summary>
/// The extension's `chrome-extension://` URL.
/// </summary>
public string Url { get; set; }
/// <summary>
///
/// </summary>
public string Version { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
namespace ElectronNET.API.Entities
{
/// <summary>
/// Interface to use Electrons PostData Object
/// </summary>
public interface IPostData
{
/// <summary>
/// One of the following:
/// rawData - <see cref="UploadRawData"/> The data is available as a Buffer, in the rawData field.
/// file - <see cref="UploadFile"/> The object represents a file. The filePath, offset, length and modificationTime fields will be used to describe the file.
/// blob - <see cref="Blob"/> The object represents a Blob. The blobUUID field will be used to describe the Blob.
/// </summary>
public string Type { get; }
}
}

View File

@@ -0,0 +1,13 @@
namespace ElectronNET.API.Entities
{
/// <summary>
///
/// </summary>
public class ImageOptions
{
/// <summary>
/// Gets or sets the scale factor
/// </summary>
public float ScaleFactor { get; set; } = NativeImage.DefaultScaleFactor;
}
}

View File

@@ -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>();
}
}

View File

@@ -26,5 +26,11 @@
/// Extra headers for the request.
/// </summary>
public string ExtraHeaders { get; set; }
/// <summary>
/// PostData Object for the request.
/// Can be <see cref="UploadRawData"/>, <see cref="UploadFile"/> or <see cref="Blob"/>
/// </summary>
public IPostData[] PostData { get; set; }
}
}

View File

@@ -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,
}
}

View File

@@ -1,5 +1,11 @@
namespace ElectronNET.API.Entities
{
internal class MessageBoxResponse
{
public int response { get; set; }
public bool @checked { get; set; }
}
/// <summary>
///
/// </summary>

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -1,8 +1,11 @@
namespace ElectronNET.API.Entities
using System.Runtime.Versioning;
namespace ElectronNET.API.Entities
{
/// <summary>
///
/// </summary>
[SupportedOSPlatform("macos")]
public class NotificationAction
{
/// <summary>

View File

@@ -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>

View File

@@ -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>

View File

@@ -1,4 +1,6 @@
namespace ElectronNET.API.Entities
using System.Runtime.Versioning;
namespace ElectronNET.API.Entities
{
/// <summary>
///
@@ -28,21 +30,66 @@
/// <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>
/// The treat package as directory
/// Treat packages, such as .app folders, as a directory instead of a file.
/// </summary>
treatPackageAsDirectory
[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
}
}

View File

@@ -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; }
}
}

View 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);
}

View File

@@ -1,18 +0,0 @@
namespace ElectronNET.API.Entities
{
/// <summary>
///
/// </summary>
public class ReleaseNoteInfo
{
/// <summary>
/// The version.
/// </summary>
public string Version { get; set; }
/// <summary>
/// The note.
/// </summary>
public string Note { get; set; }
}
}

View File

@@ -1,31 +0,0 @@
namespace ElectronNET.API.Entities
{
/// <summary>
///
/// </summary>
public class RemoveClientCertificate
{
/// <summary>
/// Origin of the server whose associated client certificate must be removed from
/// the cache.
/// </summary>
public string Origin { get; set; }
/// <summary>
/// clientCertificate.
/// </summary>
public string Type { get; set; }
/// <summary>
///
/// </summary>
/// <param name="origin">Origin of the server whose associated client certificate
/// must be removed from the cache.</param>
/// <param name="type">clientCertificate.</param>
public RemoveClientCertificate(string origin, string type)
{
Origin = origin;
Type = type;
}
}
}

View File

@@ -1,4 +1,7 @@
using ElectronNET.API.Entities;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Runtime.Versioning;
namespace ElectronNET.API
{
@@ -46,16 +49,26 @@ namespace ElectronNET.API
/// <summary>
/// Message to display above text fields.
/// </summary>
[SupportedOSPlatform("macos")]
public string Message { get; set; }
/// <summary>
/// Custom label for the text displayed in front of the filename text field.
/// </summary>
[SupportedOSPlatform("macos")]
public string NameFieldLabel { get; set; }
/// <summary>
/// Show the tags input box, defaults to true.
/// </summary>
[SupportedOSPlatform("macos")]
public bool ShowsTagField { get; set; }
/// <summary>
/// Contains which features the dialog should use. The following values are supported:
/// 'openFile' | 'openDirectory' | 'multiSelections' | 'showHiddenFiles' | 'createDirectory' | 'promptToCreate' | 'noResolveAliases' | 'treatPackageAsDirectory'
/// </summary>
[JsonProperty("properties", ItemConverterType = typeof(StringEnumConverter))]
public SaveDialogProperty[] Properties { get; set; }
}
}

View File

@@ -0,0 +1,9 @@
namespace ElectronNET.API.Entities
{
public class SecondInstanceResponse
{
public string[] args { get; set; }
public string workingDirectory { get;set;}
}
}

View File

@@ -0,0 +1,59 @@
namespace ElectronNET.API.Entities
{
/// <summary>
///
/// </summary>
public class SemVer
{
/// <summary>
///
/// </summary>
public string Raw { get; set; }
/// <summary>
///
/// </summary>
public bool Loose { get; set; }
/// <summary>
///
/// </summary>
public SemVerOptions Options { get; set; }
/// <summary>
///
/// </summary>
public int Major { get; set; }
/// <summary>
///
/// </summary>
public int Minor { get; set; }
/// <summary>
///
/// </summary>
public int Patch { get; set; }
/// <summary>
///
/// </summary>
public string Version { get; set; }
/// <summary>
///
/// </summary>
public string[] Build { get; set; }
/// <summary>
///
/// </summary>
public string[] Prerelease { get; set; }
}
/// <summary>
///
/// </summary>
public class SemVerOptions {
/// <summary>
///
/// </summary>
public bool? Loose { get; set; }
/// <summary>
///
/// </summary>
public bool? IncludePrerelease { get; set; }
}
}

View File

@@ -20,5 +20,17 @@
/// The height.
/// </value>
public int Height { get; set; }
/// <summary>
/// Utility implicit conversion
/// </summary>
public static implicit operator SixLabors.ImageSharp.Size(Size s) =>
new (s.Width, s.Height);
/// <summary>
/// Utility implicit conversion
/// </summary>
public static implicit operator Size(SixLabors.ImageSharp.Size s) =>
new (){Height = s.Height, Width = s.Width};
}
}

View File

@@ -0,0 +1,9 @@
namespace ElectronNET.API.Entities
{
public sealed class SourcesOption
{
public string[] Types { get; set; }
public Size ThumbnailSize { get; set; }
public bool FetchWindowIcons { get; set; }
}
}

View File

@@ -28,4 +28,11 @@ namespace ElectronNET.API.Entities
/// </summary>
customButtonsOnHover
}
public class TitleBarOverlayConfig
{
public string color { get; set; }
public string symbolColor { get; set; }
public int height { get; set; }
}
}

View File

@@ -1,13 +1,20 @@
namespace ElectronNET.API.Entities
using System;
namespace ElectronNET.API.Entities
{
/// <summary>
///
/// </summary>
[Obsolete("Use ImageOptions instead.")]
public class ToBitmapOptions
{
/// <summary>
/// Gets or sets the scalefactor
/// </summary>
public float ScaleFactor { get; set; } = 1.0f;
public float ScaleFactor { get; set; } = NativeImage.DefaultScaleFactor;
/// <summary>
/// Utility conversion for obsolete class
/// </summary>
public static implicit operator ImageOptions(ToBitmapOptions o) => new () {ScaleFactor = o.ScaleFactor};
}
}

View File

@@ -1,13 +1,20 @@
namespace ElectronNET.API.Entities
using System;
namespace ElectronNET.API.Entities
{
/// <summary>
///
/// </summary>
[Obsolete("Use ImageOptions instead.")]
public class ToDataUrlOptions
{
/// <summary>
/// Gets or sets the scalefactor
/// </summary>
public float ScaleFactor { get; set; } = 1.0f;
public float ScaleFactor { get; set; } = NativeImage.DefaultScaleFactor;
/// <summary>
/// Utility conversion for obsolete class
/// </summary>
public static implicit operator ImageOptions(ToDataUrlOptions o) => new () {ScaleFactor = o.ScaleFactor};
}
}

View File

@@ -1,13 +1,20 @@
namespace ElectronNET.API.Entities
using System;
namespace ElectronNET.API.Entities
{
/// <summary>
///
/// </summary>
[Obsolete("Use ImageOptions instead.")]
public class ToPNGOptions
{
/// <summary>
/// Gets or sets the scalefactor
/// </summary>
public float ScaleFactor { get; set; } = 1.0f;
/// <summary>
/// Utility conversion for obsolete class
/// </summary>
public static implicit operator ImageOptions(ToPNGOptions o) => new () {ScaleFactor = o.ScaleFactor};
}
}

View File

@@ -1,5 +1,6 @@
namespace ElectronNET.API
{
/// <summary>
///
/// </summary>

View File

@@ -0,0 +1,8 @@
namespace ElectronNET.API.Entities
{
public class TrayClickEventResponse
{
public TrayClickEventArgs eventArgs { get; set; }
public Rectangle bounds { get; set; }
}
}

View File

@@ -1,4 +1,6 @@
namespace ElectronNET.API.Entities
using System;
namespace ElectronNET.API.Entities
{
/// <summary>
///
@@ -13,7 +15,7 @@
/// <summary>
///
/// </summary>
public UpdateFileInfo[] Files { get; set; } = new UpdateFileInfo[0];
public UpdateFileInfo[] Files { get; set; } = Array.Empty<UpdateFileInfo>();
/// <summary>
/// The release name.
@@ -23,7 +25,7 @@
/// <summary>
/// The release notes.
/// </summary>
public ReleaseNoteInfo[] ReleaseNotes { get; set; } = new ReleaseNoteInfo[0];
public string ReleaseNotes { get; set; }
/// <summary>
///

View File

@@ -0,0 +1,34 @@
namespace ElectronNET.API.Entities
{
/// <summary>
///
/// </summary>
public class UploadFile : IPostData
{
/// <summary>
/// The object represents a file.
/// </summary>
public string Type { get; } = "file";
/// <summary>
/// The path of the file being uploaded.
/// </summary>
public string FilePath { get; set; }
/// <summary>
/// The offset from the beginning of the file being uploaded, in bytes. Defaults to 0.
/// </summary>
public long Offset { get; set; } = 0;
/// <summary>
/// The length of the file being uploaded, <see cref="Offset"/>. Defaults to 0.
/// If set to -1, the whole file will be uploaded.
/// </summary>
public long Length { get; set; } = 0;
/// <summary>
/// The modification time of the file represented by a double, which is the number of seconds since the UNIX Epoch (Jan 1, 1970)
/// </summary>
public double ModificationTime { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
namespace ElectronNET.API.Entities
{
/// <summary>
///
/// </summary>
public class UploadRawData : IPostData
{
/// <summary>
/// The data is available as a Buffer, in the rawData field.
/// </summary>
public string Type { get; } = "rawData";
/// <summary>
/// The raw bytes of the post data in a Buffer.
/// </summary>
public byte[] Bytes { get; set; }
}
}

View File

@@ -1,4 +1,5 @@
using Newtonsoft.Json;
using System.Runtime.Serialization;
using System;
namespace ElectronNET.API.Entities
{
@@ -10,17 +11,20 @@ namespace ElectronNET.API.Entities
/// <summary>
/// The appearance based
/// </summary>
[JsonProperty("appearance-based")]
[EnumMember(Value = "appearance-based")]
[Obsolete("Removed in macOS Catalina (10.15).")]
appearanceBased,
/// <summary>
/// The light
/// </summary>
[Obsolete("Removed in macOS Catalina (10.15).")]
light,
/// <summary>
/// The dark
/// </summary>
[Obsolete("Removed in macOS Catalina (10.15).")]
dark,
/// <summary>
@@ -51,13 +55,39 @@ namespace ElectronNET.API.Entities
/// <summary>
/// The medium light
/// </summary>
[JsonProperty("medium-light")]
[EnumMember(Value = "medium-light")]
[Obsolete("Removed in macOS Catalina (10.15).")]
mediumLight,
/// <summary>
/// The ultra dark
/// </summary>
[JsonProperty("ultra-dark")]
ultraDark
[EnumMember(Value = "ultra-dark")]
[Obsolete("Removed in macOS Catalina (10.15).")]
ultraDark,
header,
sheet,
window,
hud,
[EnumMember(Value = "fullscreen-ui")]
fullscreenUI,
tooltip,
content,
[EnumMember(Value = "under-window")]
underWindow,
[EnumMember(Value = "under-page")]
underPage
}
}
}

View File

@@ -1,4 +1,4 @@
using System.ComponentModel;
using System.ComponentModel;
namespace ElectronNET.API.Entities
{
@@ -142,7 +142,7 @@ namespace ElectronNET.API.Entities
/// <summary>
/// Defaults to 16.
/// </summary>
public int DefaultFontSize { get; set; }
public int DefaultFontSize { get; set; } = 16;
/// <summary>
/// Defaults to 13.
@@ -171,6 +171,12 @@ namespace ElectronNET.API.Entities
/// </summary>
public bool Offscreen { get; set; }
/// <summary>
/// Whether to enable built-in spellcheck
/// </summary>
[DefaultValue(true)]
public bool Spellcheck { get; set; } = true;
/// <summary>
/// Whether to run Electron APIs and the specified preload script in a separate
/// JavaScript context. Defaults to false. The context that the preload script runs
@@ -184,14 +190,10 @@ namespace ElectronNET.API.Entities
/// can access this context in the dev tools by selecting the 'Electron Isolated
/// Context' entry in the combo box at the top of the Console tab. This option is
/// currently experimental and may change or be removed in future Electron releases.
/// Default value is false.
/// </summary>
[DefaultValue(false)]
public bool ContextIsolation { get; set; }
/// <summary>
/// Whether to use native window.open(). Defaults to false. This option is currently experimental.
/// </summary>
public bool NativeWindowOpen { get; set; }
public bool ContextIsolation { get; set; } = false;
/// <summary>
/// Whether to enable the Webview. Defaults to the value of the nodeIntegration option. The
@@ -206,5 +208,11 @@ namespace ElectronNET.API.Entities
/// </value>
[DefaultValue(false)]
public bool WebviewTag { get; set; } = false;
/// <summary>
/// Make the web view transparent
/// </summary>
[DefaultValue(false)]
public bool Transparent { get; set; } = false;
}
}

84
ElectronNET.API/Events.cs Normal file
View File

@@ -0,0 +1,84 @@
using System;
using System.Globalization;
namespace ElectronNET.API
{
/// <summary>
/// Generic Event Consumers for Electron Modules
/// </summary>
internal class Events
{
private static Events _events;
private static readonly object _syncRoot = new();
private readonly TextInfo _ti = new CultureInfo("en-US", false).TextInfo;
private Events()
{
}
public static Events Instance
{
get
{
if (_events == null)
{
lock (_syncRoot)
{
if (_events == null)
{
_events = new Events();
}
}
}
return _events;
}
}
/// <summary>
/// Subscribe to an unmapped electron event.
/// </summary>
/// <param name="moduleName">The name of the module, e.g. app, dock, etc...</param>
/// <param name="eventName">The name of the event</param>
/// <param name="fn">The event handler</param>
public void On(string moduleName, string eventName, Action fn) => On(moduleName, eventName, _ => fn());
/// <summary>
/// Subscribe to an unmapped electron event.
/// </summary>
/// <param name="moduleName">The name of the module, e.g. app, dock, etc...</param>
/// <param name="eventName">The name of the event</param>
/// <param name="fn">The event handler</param>
public void On(string moduleName, string eventName, Action<object> fn)
{
var listener = $"{moduleName}{_ti.ToTitleCase(eventName)}Completed";
var subscriber = $"register-{moduleName}-on-event";
BridgeConnector.On(listener, fn);
BridgeConnector.Emit(subscriber, eventName, listener);
}
/// <summary>
/// Subscribe to an unmapped electron event.
/// </summary>
/// <param name="moduleName">The name of the module, e.g. app, dock, etc...</param>
/// <param name="eventName">The name of the event</param>
/// <param name="fn">The event handler</param>
public void Once(string moduleName, string eventName, Action fn) => Once(moduleName, eventName, _ => fn());
/// <summary>
/// Subscribe to an unmapped electron event.
/// </summary>
/// <param name="moduleName">The name of the module, e.g. app, dock, etc...</param>
/// <param name="eventName">The name of the event</param>
/// <param name="fn">The event handler</param>
public void Once(string moduleName, string eventName, Action<object> fn)
{
var listener = $"{moduleName}{_ti.ToTitleCase(eventName)}Completed";
var subscriber = $"register-{moduleName}-once-event";
BridgeConnector.Once(listener, fn);
BridgeConnector.Emit(subscriber, eventName, listener);
}
}
}

View File

@@ -11,7 +11,7 @@ namespace ElectronNET.API.Extensions
Type type = enumerationValue.GetType();
if (!type.IsEnum)
{
throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue");
throw new ArgumentException("EnumerationValue must be of Enum type", nameof(enumerationValue));
}
//Tries to find a DescriptionAttribute for a potential friendly name

View File

@@ -28,7 +28,7 @@ namespace ElectronNET.API.Extensions
public static MenuItem GetMenuItem(this List<MenuItem> menuItems, string id)
{
MenuItem result = new MenuItem();
MenuItem result = new();
foreach (var item in menuItems)
{

View File

@@ -23,7 +23,7 @@ namespace ElectronNET.API.Extensions
public static ThumbarButton GetThumbarButton(this List<ThumbarButton> thumbarButtons, string id)
{
ThumbarButton result = new ThumbarButton("");
ThumbarButton result = new("");
foreach (var item in thumbarButtons)
{

34
ElectronNET.API/GlobalShortcut.cs Normal file → Executable file
View File

@@ -1,16 +1,17 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ElectronNET.API.Interfaces;
namespace ElectronNET.API
{
/// <summary>
/// Detect keyboard events when the application does not have keyboard focus.
/// </summary>
public sealed class GlobalShortcut
public sealed class GlobalShortcut : IGlobalShortcut
{
private static GlobalShortcut _globalShortcut;
private static object _syncRoot = new object();
private static readonly object _syncRoot = new();
internal GlobalShortcut() { }
@@ -33,7 +34,7 @@ namespace ElectronNET.API
}
}
private Dictionary<string, Action> _shortcuts = new Dictionary<string, Action>();
private readonly Dictionary<string, Action> _shortcuts = new();
/// <summary>
/// Registers a global shortcut of accelerator.
@@ -49,16 +50,16 @@ namespace ElectronNET.API
{
_shortcuts.Add(accelerator, function);
BridgeConnector.Socket.Off("globalShortcut-pressed");
BridgeConnector.Socket.On("globalShortcut-pressed", (shortcut) =>
BridgeConnector.Off("globalShortcut-pressed");
BridgeConnector.On<string>("globalShortcut-pressed", (shortcut) =>
{
if (_shortcuts.ContainsKey(shortcut.ToString()))
if (_shortcuts.ContainsKey(shortcut))
{
_shortcuts[shortcut.ToString()]();
}
});
BridgeConnector.Socket.Emit("globalShortcut-register", accelerator);
BridgeConnector.Emit("globalShortcut-register", accelerator);
}
}
@@ -68,21 +69,8 @@ namespace ElectronNET.API
/// since they dont want applications to fight for global shortcuts.
/// </summary>
/// <returns>Whether this application has registered accelerator.</returns>
public Task<bool> IsRegisteredAsync(string accelerator)
{
var taskCompletionSource = new TaskCompletionSource<bool>();
public Task<bool> IsRegisteredAsync(string accelerator) => BridgeConnector.OnResult<bool>("globalShortcut-isRegistered", "globalShortcut-isRegisteredCompleted", accelerator);
BridgeConnector.Socket.On("globalShortcut-isRegisteredCompleted", (isRegistered) =>
{
BridgeConnector.Socket.Off("globalShortcut-isRegisteredCompleted");
taskCompletionSource.SetResult((bool)isRegistered);
});
BridgeConnector.Socket.Emit("globalShortcut-isRegistered", accelerator);
return taskCompletionSource.Task;
}
/// <summary>
/// Unregisters the global shortcut of accelerator.
@@ -90,7 +78,7 @@ namespace ElectronNET.API
public void Unregister(string accelerator)
{
_shortcuts.Remove(accelerator);
BridgeConnector.Socket.Emit("globalShortcut-unregister", accelerator);
BridgeConnector.Emit("globalShortcut-unregister", accelerator);
}
/// <summary>
@@ -99,7 +87,7 @@ namespace ElectronNET.API
public void UnregisterAll()
{
_shortcuts.Clear();
BridgeConnector.Socket.Emit("globalShortcut-unregisterAll");
BridgeConnector.Emit("globalShortcut-unregisterAll");
}
}
}

71
ElectronNET.API/HostHook.cs Normal file → Executable file
View File

@@ -3,6 +3,7 @@ using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System;
using System.Threading.Tasks;
using ElectronNET.API.Interfaces;
namespace ElectronNET.API
{
@@ -13,11 +14,11 @@ namespace ElectronNET.API
/// ElectronHostHook directory:
/// <c>electronize add HostHook</c>
/// </summary>
public sealed class HostHook
public sealed class HostHook : IHostHook
{
private static HostHook _electronHostHook;
private static object _syncRoot = new object();
string oneCallguid = Guid.NewGuid().ToString();
private static readonly object _syncRoot = new();
readonly string oneCallguid = Guid.NewGuid().ToString();
internal HostHook() { }
@@ -47,13 +48,13 @@ namespace ElectronNET.API
/// <param name="arguments">Optional parameters.</param>
public void Call(string socketEventName, params dynamic[] arguments)
{
BridgeConnector.Socket.On(socketEventName + "Error" + oneCallguid, (result) =>
BridgeConnector.On<string>(socketEventName + "Error" + oneCallguid, (result) =>
{
BridgeConnector.Socket.Off(socketEventName + "Error" + oneCallguid);
Electron.Dialog.ShowErrorBox("Host Hook Exception", result.ToString());
BridgeConnector.Off(socketEventName + "Error" + oneCallguid);
Electron.Dialog.ShowErrorBox("Host Hook Exception", result);
});
BridgeConnector.Socket.Emit(socketEventName, arguments, oneCallguid);
BridgeConnector.Emit(socketEventName, arguments, oneCallguid);
}
/// <summary>
@@ -65,64 +66,26 @@ namespace ElectronNET.API
/// <returns></returns>
public Task<T> CallAsync<T>(string socketEventName, params dynamic[] arguments)
{
var taskCompletionSource = new TaskCompletionSource<T>();
var taskCompletionSource = new TaskCompletionSource<T>(TaskCreationOptions.RunContinuationsAsynchronously);
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On(socketEventName + "Error" + guid, (result) =>
BridgeConnector.On<string>(socketEventName + "Error" + guid, (result) =>
{
BridgeConnector.Socket.Off(socketEventName + "Error" + guid);
Electron.Dialog.ShowErrorBox("Host Hook Exception", result.ToString());
BridgeConnector.Off(socketEventName + "Error" + guid);
Electron.Dialog.ShowErrorBox("Host Hook Exception", result);
taskCompletionSource.SetException(new Exception($"Host Hook Exception {result}"));
});
BridgeConnector.Socket.On(socketEventName + "Complete" + guid, (result) =>
BridgeConnector.On<T>(socketEventName + "Complete" + guid, (result) =>
{
BridgeConnector.Socket.Off(socketEventName + "Error" + guid);
BridgeConnector.Socket.Off(socketEventName + "Complete" + guid);
T data = default;
try
{
if (result.GetType().IsValueType || result is string)
{
data = (T)result;
}
else
{
var token = JToken.Parse(result.ToString());
if (token is JArray)
{
data = token.ToObject<T>();
}
else if (token is JObject)
{
data = token.ToObject<T>();
}
else
{
data = (T)result;
}
}
}
catch (Exception exception)
{
taskCompletionSource.SetException(exception);
//throw new InvalidCastException("Return value does not match with the generic type.", exception);
}
taskCompletionSource.SetResult(data);
BridgeConnector.Off(socketEventName + "Error" + guid);
BridgeConnector.Off(socketEventName + "Complete" + guid);
taskCompletionSource.SetResult(result);
});
BridgeConnector.Socket.Emit(socketEventName, arguments, guid);
BridgeConnector.Emit(socketEventName, arguments, guid);
return taskCompletionSource.Task;
}
private JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
}
}

View File

@@ -0,0 +1,709 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using ElectronNET.API.Entities;
namespace ElectronNET.API.Interfaces
{
/// <summary>
/// Control your application's event lifecycle.
/// </summary>
public interface IApp
{
/// <summary>
/// Emitted when all windows have been closed.
/// <para/>
/// If you do not subscribe to this event and all windows are closed, the default behavior is to quit
/// the app; however, if you subscribe, you control whether the app quits or not.If the user pressed
/// Cmd + Q, or the developer called <see cref="Quit"/>, Electron will first try to close all the windows
/// and then emit the <see cref="WillQuit"/> event, and in this case the <see cref="WindowAllClosed"/> event
/// would not be emitted.
/// </summary>
event Action WindowAllClosed;
/// <summary>
/// Emitted before the application starts closing its windows.
/// <para/>
/// Note: If application quit was initiated by <see cref="AutoUpdater.QuitAndInstall"/> then <see cref="BeforeQuit"/>
/// is emitted after emitting close event on all windows and closing them.
/// <para/>
/// Note: On Windows, this event will not be emitted if the app is closed due to a shutdown/restart of the system or a user logout.
/// </summary>
event Func<QuitEventArgs, Task> BeforeQuit;
/// <summary>
/// Emitted when all windows have been closed and the application will quit.
/// <para/>
/// See the description of the <see cref="WindowAllClosed"/> event for the differences between the <see cref="WillQuit"/>
/// and <see cref="WindowAllClosed"/> events.
/// <para/>
/// Note: On Windows, this event will not be emitted if the app is closed due to a shutdown/restart of the system or a user logout.
/// </summary>
event Func<QuitEventArgs, Task> WillQuit;
/// <summary>
/// Emitted when the application is quitting.
/// <para/>
/// Note: On Windows, this event will not be emitted if the app is closed due to a shutdown/restart of the system or a user logout.
/// </summary>
event Func<Task> Quitting;
/// <summary>
/// Emitted when a <see cref="BrowserWindow"/> blurred.
/// </summary>
event Action BrowserWindowBlur;
/// <summary>
/// Emitted when a <see cref="BrowserWindow"/> gets focused.
/// </summary>
event Action BrowserWindowFocus;
/// <summary>
/// Emitted when a new <see cref="BrowserWindow"/> is created.
/// </summary>
event Action BrowserWindowCreated;
/// <summary>
/// Emitted when a new <see cref="WebContents"/> is created.
/// </summary>
event Action WebContentsCreated;
/// <summary>
/// Emitted when Chromes accessibility support changes. This event fires when assistive technologies, such as
/// screen readers, are enabled or disabled. See https://www.chromium.org/developers/design-documents/accessibility for more details.
/// </summary>
/// <returns><see langword="true"/> when Chrome's accessibility support is enabled, <see langword="false"/> otherwise.</returns>
event Action<bool> AccessibilitySupportChanged;
/// <summary>
/// Emitted when the application has finished basic startup.
/// </summary>
event Action Ready;
/// <summary>
/// Application host fully started.
/// </summary>
bool IsReady { get; }
/// <summary>
/// A <see cref="string"/> property that indicates the current application's name, which is the name in the
/// application's package.json file.
///
/// Usually the name field of package.json is a short lowercase name, according to the npm modules spec. You
/// should usually also specify a productName field, which is your application's full capitalized name, and
/// which will be preferred over name by Electron.
/// </summary>
string Name
{
set;
}
/// <summary>
/// A <see cref="string"/> property that indicates the current application's name, which is the name in the
/// application's package.json file.
///
/// Usually the name field of package.json is a short lowercase name, according to the npm modules spec. You
/// should usually also specify a productName field, which is your application's full capitalized name, and
/// which will be preferred over name by Electron.
/// </summary>
Task<string> GetNameAsync { get; }
/// <summary>
/// A <see cref="CommandLine"/> object that allows you to read and manipulate the command line arguments that Chromium uses.
/// </summary>
CommandLine CommandLine { get; }
/// <summary>
/// A <see cref="string"/> which is the user agent string Electron will use as a global fallback.
/// <para/>
/// This is the user agent that will be used when no user agent is set at the webContents or
/// session level. It is useful for ensuring that your entire app has the same user agent. Set to a
/// custom value as early as possible in your app's initialization to ensure that your overridden value
/// is used.
/// </summary>
string UserAgentFallback
{
set;
}
/// <summary>
/// A <see cref="string"/> which is the user agent string Electron will use as a global fallback.
/// <para/>
/// This is the user agent that will be used when no user agent is set at the webContents or
/// session level. It is useful for ensuring that your entire app has the same user agent. Set to a
/// custom value as early as possible in your app's initialization to ensure that your overridden value
/// is used.
/// </summary>
Task<string> GetUserAgentFallbackAsync { get; }
/// <summary>
/// Emitted when a MacOS user wants to open a file with the application. The open-file event is usually emitted
/// when the application is already open and the OS wants to reuse the application to open the file.
/// open-file is also emitted when a file is dropped onto the dock and the application is not yet running.
/// <para/>
/// On Windows, you have to parse the arguments using App.CommandLine to get the filepath.
/// </summary>
event Action<string> OpenFile;
/// <summary>
/// Emitted when a MacOS user wants to open a URL with the application. Your application's Info.plist file must
/// define the URL scheme within the CFBundleURLTypes key, and set NSPrincipalClass to AtomApplication.
/// </summary>
event Action<string> OpenUrl;
/// <summary>
/// Try to close all windows. The <see cref="BeforeQuit"/> event will be emitted first. If all windows are successfully
/// closed, the <see cref="WillQuit"/> event will be emitted and by default the application will terminate. This method
/// guarantees that all beforeunload and unload event handlers are correctly executed. It is possible
/// that a window cancels the quitting by returning <see langword="false"/> in the beforeunload event handler.
/// </summary>
void Quit();
/// <summary>
/// All windows will be closed immediately without asking user and the <see cref="BeforeQuit"/> and <see cref="WillQuit"/>
/// events will not be emitted.
/// </summary>
/// <param name="exitCode">Exits immediately with exitCode. exitCode defaults to 0.</param>
void Exit(int exitCode = 0);
/// <summary>
/// Relaunches the app when current instance exits. By default the new instance will use the same working directory
/// and command line arguments with current instance.
/// <para/>
/// Note that this method does not quit the app when executed, you have to call <see cref="Quit"/> or <see cref="Exit"/>
/// after calling <see cref="Relaunch()"/> to make the app restart.
/// <para/>
/// When <see cref="Relaunch()"/> is called for multiple times, multiple instances will be started after current instance
/// exited.
/// </summary>
void Relaunch();
/// <summary>
/// Relaunches the app when current instance exits. By default the new instance will use the same working directory
/// and command line arguments with current instance. When <see cref="RelaunchOptions.Args"/> is specified, the
/// <see cref="RelaunchOptions.Args"/> will be passed as command line arguments instead. When <see cref="RelaunchOptions.ExecPath"/>
/// is specified, the <see cref="RelaunchOptions.ExecPath"/> will be executed for relaunch instead of current app.
/// <para/>
/// Note that this method does not quit the app when executed, you have to call <see cref="Quit"/> or <see cref="Exit"/>
/// after calling <see cref="Relaunch()"/> to make the app restart.
/// <para/>
/// When <see cref="Relaunch()"/> is called for multiple times, multiple instances will be started after current instance
/// exited.
/// </summary>
/// <param name="relaunchOptions">Options for the relaunch.</param>
void Relaunch(RelaunchOptions relaunchOptions);
/// <summary>
/// On Linux, focuses on the first visible window. On macOS, makes the application the active app. On Windows, focuses
/// on the application's first window.
/// </summary>
void Focus();
/// <summary>
/// On Linux, focuses on the first visible window. On macOS, makes the application the active app. On Windows, focuses
/// on the application's first window.
/// <para/>
/// You should seek to use the <see cref="FocusOptions.Steal"/> option as sparingly as possible.
/// </summary>
void Focus(FocusOptions focusOptions);
/// <summary>
/// Hides all application windows without minimizing them.
/// </summary>
void Hide();
/// <summary>
/// Shows application windows after they were hidden. Does not automatically focus them.
/// </summary>
void Show();
/// <summary>
/// The current application directory.
/// </summary>
Task<string> GetAppPathAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Sets or creates a directory your app's logs which can then be manipulated with <see cref="GetPathAsync"/>
/// or <see cref="SetPath"/>.
/// <para/>
/// Calling <see cref="SetAppLogsPath"/> without a path parameter will result in this directory being set to
/// ~/Library/Logs/YourAppName on macOS, and inside the userData directory on Linux and Windows.
/// </summary>
/// <param name="path">A custom path for your logs. Must be absolute.</param>
void SetAppLogsPath(string path);
/// <summary>
/// The path to a special directory. If <see cref="GetPathAsync"/> is called without called
/// <see cref="SetAppLogsPath"/> being called first, a default directory will be created equivalent
/// to calling <see cref="SetAppLogsPath"/> without a path parameter.
/// </summary>
/// <param name="pathName">Special directory.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A path to a special directory or file associated with name.</returns>
Task<string> GetPathAsync(PathName pathName, CancellationToken cancellationToken = default);
/// <summary>
/// Overrides the path to a special directory or file associated with name. If the path specifies a directory
/// that does not exist, an Error is thrown. In that case, the directory should be created with fs.mkdirSync or similar.
/// <para/>
/// You can only override paths of a name defined in <see cref="GetPathAsync"/>.
/// <para/>
/// By default, web pages' cookies and caches will be stored under the <see cref="PathName.UserData"/> directory. If you
/// want to change this location, you have to override the <see cref="PathName.UserData"/> path before the <see cref="Ready"/>
/// event of the <see cref="App"/> module is emitted.
/// <param name="name">Special directory.</param>
/// <param name="path">New path to a special directory.</param>
/// </summary>
void SetPath(PathName name, string path);
/// <summary>
/// The version of the loaded application. If no version is found in the applications package.json file,
/// the version of the current bundle or executable is returned.
/// </summary>
/// <returns>The version of the loaded application.</returns>
Task<string> GetVersionAsync(CancellationToken cancellationToken = default);
/// <summary>
/// The current application locale. Possible return values are documented <see href="https://www.electronjs.org/docs/api/locales">here</see>.
/// <para/>
/// Note: When distributing your packaged app, you have to also ship the locales folder.
/// <para/>
/// Note: On Windows, you have to call it after the <see cref="Ready"/> events gets emitted.
/// </summary>
/// <returns>The current application locale.</returns>
Task<string> GetLocaleAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Adds path to the recent documents list. This list is managed by the OS. On Windows you can visit the
/// list from the task bar, and on macOS you can visit it from dock menu.
/// </summary>
/// <param name="path">Path to add.</param>
void AddRecentDocument(string path);
/// <summary>
/// Clears the recent documents list.
/// </summary>
void ClearRecentDocuments();
/// <summary>
/// Sets the current executable as the default handler for a protocol (aka URI scheme). It allows you to
/// integrate your app deeper into the operating system. Once registered, all links with your-protocol://
/// will be opened with the current executable. The whole link, including protocol, will be passed to your
/// application as a parameter.
/// <para/>
/// Note: On macOS, you can only register protocols that have been added to your app's info.plist, which
/// cannot be modified at runtime. However, you can change the file during build time via
/// <see href="https://www.electronforge.io/">Electron Forge</see>,
/// <see href="https://github.com/electron/electron-packager">Electron Packager</see>, or by editing info.plist
/// with a text editor. Please refer to
/// <see href="https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/TP40009249-102207-TPXREF115">Apple's documentation</see>
/// for details.
/// <para/>
/// Note: In a Windows Store environment (when packaged as an appx) this API will return true for all calls but
/// the registry key it sets won't be accessible by other applications. In order to register your Windows Store
/// application as a default protocol handler you <see href="https://docs.microsoft.com/en-us/uwp/schemas/appxpackage/uapmanifestschema/element-uap-protocol">must declare the protocol in your manifest</see>.
/// <para/>
/// The API uses the Windows Registry and LSSetDefaultHandlerForURLScheme internally.
/// </summary>
/// <param name="protocol">
/// The name of your protocol, without ://. For example, if you want your app to handle electron:// links,
/// call this method with electron as the parameter.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Whether the call succeeded.</returns>
Task<bool> SetAsDefaultProtocolClientAsync(string protocol, CancellationToken cancellationToken = default);
/// <summary>
/// Sets the current executable as the default handler for a protocol (aka URI scheme). It allows you to
/// integrate your app deeper into the operating system. Once registered, all links with your-protocol://
/// will be opened with the current executable. The whole link, including protocol, will be passed to your
/// application as a parameter.
/// <para/>
/// Note: On macOS, you can only register protocols that have been added to your app's info.plist, which
/// cannot be modified at runtime. However, you can change the file during build time via
/// <see href="https://www.electronforge.io/">Electron Forge</see>,
/// <see href="https://github.com/electron/electron-packager">Electron Packager</see>, or by editing info.plist
/// with a text editor. Please refer to
/// <see href="https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/TP40009249-102207-TPXREF115">Apple's documentation</see>
/// for details.
/// <para/>
/// Note: In a Windows Store environment (when packaged as an appx) this API will return true for all calls but
/// the registry key it sets won't be accessible by other applications. In order to register your Windows Store
/// application as a default protocol handler you <see href="https://docs.microsoft.com/en-us/uwp/schemas/appxpackage/uapmanifestschema/element-uap-protocol">must declare the protocol in your manifest</see>.
/// <para/>
/// The API uses the Windows Registry and LSSetDefaultHandlerForURLScheme internally.
/// </summary>
/// <param name="protocol">
/// The name of your protocol, without ://. For example, if you want your app to handle electron:// links,
/// call this method with electron as the parameter.</param>
/// <param name="path">The path to the Electron executable. Defaults to process.execPath</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Whether the call succeeded.</returns>
Task<bool> SetAsDefaultProtocolClientAsync(string protocol, string path, CancellationToken cancellationToken = default);
/// <summary>
/// Sets the current executable as the default handler for a protocol (aka URI scheme). It allows you to
/// integrate your app deeper into the operating system. Once registered, all links with your-protocol://
/// will be opened with the current executable. The whole link, including protocol, will be passed to your
/// application as a parameter.
/// <para/>
/// Note: On macOS, you can only register protocols that have been added to your app's info.plist, which
/// cannot be modified at runtime. However, you can change the file during build time via
/// <see href="https://www.electronforge.io/">Electron Forge</see>,
/// <see href="https://github.com/electron/electron-packager">Electron Packager</see>, or by editing info.plist
/// with a text editor. Please refer to
/// <see href="https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/TP40009249-102207-TPXREF115">Apple's documentation</see>
/// for details.
/// <para/>
/// Note: In a Windows Store environment (when packaged as an appx) this API will return true for all calls but
/// the registry key it sets won't be accessible by other applications. In order to register your Windows Store
/// application as a default protocol handler you <see href="https://docs.microsoft.com/en-us/uwp/schemas/appxpackage/uapmanifestschema/element-uap-protocol">must declare the protocol in your manifest</see>.
/// <para/>
/// The API uses the Windows Registry and LSSetDefaultHandlerForURLScheme internally.
/// </summary>
/// <param name="protocol">
/// The name of your protocol, without ://. For example, if you want your app to handle electron:// links,
/// call this method with electron as the parameter.</param>
/// <param name="path">The path to the Electron executable. Defaults to process.execPath</param>
/// <param name="args">Arguments passed to the executable. Defaults to an empty array.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Whether the call succeeded.</returns>
Task<bool> SetAsDefaultProtocolClientAsync(string protocol, string path, string[] args, CancellationToken cancellationToken = default);
/// <summary>
/// This method checks if the current executable as the default handler for a protocol (aka URI scheme).
/// If so, it will remove the app as the default handler.
/// </summary>
/// <param name="protocol">The name of your protocol, without ://.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Whether the call succeeded.</returns>
Task<bool> RemoveAsDefaultProtocolClientAsync(string protocol, CancellationToken cancellationToken = default);
/// <summary>
/// This method checks if the current executable as the default handler for a protocol (aka URI scheme).
/// If so, it will remove the app as the default handler.
/// </summary>
/// <param name="protocol">The name of your protocol, without ://.</param>
/// <param name="path">Defaults to process.execPath.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Whether the call succeeded.</returns>
Task<bool> RemoveAsDefaultProtocolClientAsync(string protocol, string path, CancellationToken cancellationToken = default);
/// <summary>
/// This method checks if the current executable as the default handler for a protocol (aka URI scheme).
/// If so, it will remove the app as the default handler.
/// </summary>
/// <param name="protocol">The name of your protocol, without ://.</param>
/// <param name="path">Defaults to process.execPath.</param>
/// <param name="args">Defaults to an empty array.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Whether the call succeeded.</returns>
Task<bool> RemoveAsDefaultProtocolClientAsync(string protocol, string path, string[] args, CancellationToken cancellationToken = default);
/// <summary>
/// This method checks if the current executable is the default handler for a protocol (aka URI scheme).
/// <para/>
/// Note: On macOS, you can use this method to check if the app has been registered as the default protocol
/// handler for a protocol. You can also verify this by checking ~/Library/Preferences/com.apple.LaunchServices.plist
/// on the macOS machine. Please refer to <see href="https://developer.apple.com/library/mac/documentation/Carbon/Reference/LaunchServicesReference/#//apple_ref/c/func/LSCopyDefaultHandlerForURLScheme">Apple's documentation</see>
/// for details.
/// <para/>
/// The API uses the Windows Registry and LSCopyDefaultHandlerForURLScheme internally.
/// </summary>
/// <param name="protocol">The name of your protocol, without ://.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Whether the current executable is the default handler for a protocol (aka URI scheme).</returns>
Task<bool> IsDefaultProtocolClientAsync(string protocol, CancellationToken cancellationToken = default);
/// <summary>
/// This method checks if the current executable is the default handler for a protocol (aka URI scheme).
/// <para/>
/// Note: On macOS, you can use this method to check if the app has been registered as the default protocol
/// handler for a protocol. You can also verify this by checking ~/Library/Preferences/com.apple.LaunchServices.plist
/// on the macOS machine. Please refer to <see href="https://developer.apple.com/library/mac/documentation/Carbon/Reference/LaunchServicesReference/#//apple_ref/c/func/LSCopyDefaultHandlerForURLScheme">Apple's documentation</see>
/// for details.
/// <para/>
/// The API uses the Windows Registry and LSCopyDefaultHandlerForURLScheme internally.
/// </summary>
/// <param name="protocol">The name of your protocol, without ://.</param>
/// <param name="path">Defaults to process.execPath.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Whether the current executable is the default handler for a protocol (aka URI scheme).</returns>
Task<bool> IsDefaultProtocolClientAsync(string protocol, string path, CancellationToken cancellationToken = default);
/// <summary>
/// This method checks if the current executable is the default handler for a protocol (aka URI scheme).
/// <para/>
/// Note: On macOS, you can use this method to check if the app has been registered as the default protocol
/// handler for a protocol. You can also verify this by checking ~/Library/Preferences/com.apple.LaunchServices.plist
/// on the macOS machine. Please refer to <see href="https://developer.apple.com/library/mac/documentation/Carbon/Reference/LaunchServicesReference/#//apple_ref/c/func/LSCopyDefaultHandlerForURLScheme">Apple's documentation</see>
/// for details.
/// <para/>
/// The API uses the Windows Registry and LSCopyDefaultHandlerForURLScheme internally.
/// </summary>
/// <param name="protocol">The name of your protocol, without ://.</param>
/// <param name="path">Defaults to process.execPath.</param>
/// <param name="args">Defaults to an empty array.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Whether the current executable is the default handler for a protocol (aka URI scheme).</returns>
Task<bool> IsDefaultProtocolClientAsync(string protocol, string path, string[] args, CancellationToken cancellationToken = default);
/// <summary>
/// Adds tasks to the <see cref="UserTask"/> category of the JumpList on Windows.
/// <para/>
/// Note: If you'd like to customize the Jump List even more use <see cref="SetJumpList"/> instead.
/// </summary>
/// <param name="userTasks">Array of <see cref="UserTask"/> objects.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Whether the call succeeded.</returns>
Task<bool> SetUserTasksAsync(UserTask[] userTasks, CancellationToken cancellationToken = default);
/// <summary>
/// Jump List settings for the application.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Jump List settings.</returns>
Task<JumpListSettings> GetJumpListSettingsAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Sets or removes a custom Jump List for the application. If categories is null the previously set custom
/// Jump List (if any) will be replaced by the standard Jump List for the app (managed by Windows).
/// <para/>
/// Note: If a <see cref="JumpListCategory"/> object has neither the <see cref="JumpListCategory.Type"/> nor
/// the <see cref="JumpListCategory.Name"/> property set then its <see cref="JumpListCategory.Type"/> is assumed
/// to be <see cref="JumpListCategoryType.tasks"/>. If the <see cref="JumpListCategory.Name"/> property is set but
/// the <see cref="JumpListCategory.Type"/> property is omitted then the <see cref="JumpListCategory.Type"/> is
/// assumed to be <see cref="JumpListCategoryType.custom"/>.
/// <para/>
/// Note: Users can remove items from custom categories, and Windows will not allow a removed item to be added
/// back into a custom category until after the next successful call to <see cref="SetJumpList"/>. Any attempt
/// to re-add a removed item to a custom category earlier than that will result in the entire custom category being
/// omitted from the Jump List. The list of removed items can be obtained using <see cref="GetJumpListSettingsAsync"/>.
/// </summary>
/// <param name="categories">Array of <see cref="JumpListCategory"/> objects.</param>
void SetJumpList(JumpListCategory[] categories);
/// <summary>
/// The return value of this method indicates whether or not this instance of your application successfully obtained
/// the lock. If it failed to obtain the lock, you can assume that another instance of your application is already
/// running with the lock and exit immediately.
/// <para/>
/// I.e.This method returns <see langword="true"/> if your process is the primary instance of your application and your
/// app should continue loading. It returns <see langword="false"/> if your process should immediately quit as it has
/// sent its parameters to another instance that has already acquired the lock.
/// <para/>
/// On macOS, the system enforces single instance automatically when users try to open a second instance of your app
/// in Finder, and the open-file and open-url events will be emitted for that.However when users start your app in
/// command line, the system's single instance mechanism will be bypassed, and you have to use this method to ensure
/// single instance.
/// </summary>
/// <param name="newInstanceOpened">Lambda with an array of the second instances command line arguments.
/// The second parameter is the working directory path.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>This method returns false if your process is the primary instance of the application and your app
/// should continue loading. And returns true if your process has sent its parameters to another instance, and
/// you should immediately quit.
/// </returns>
Task<bool> RequestSingleInstanceLockAsync(Action<string[], string> newInstanceOpened, CancellationToken cancellationToken = default);
/// <summary>
/// Releases all locks that were created by makeSingleInstance. This will allow
/// multiple instances of the application to once again run side by side.
/// </summary>
void ReleaseSingleInstanceLock();
/// <summary>
/// This method returns whether or not this instance of your app is currently holding the single instance lock.
/// You can request the lock with <see cref="RequestSingleInstanceLockAsync"/> and release with
/// <see cref="ReleaseSingleInstanceLock"/>.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
Task<bool> HasSingleInstanceLockAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Creates an NSUserActivity and sets it as the current activity. The activity is
/// eligible for <see href="https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/Handoff/HandoffFundamentals/HandoffFundamentals.html">Handoff</see>
/// to another device afterward.
/// </summary>
/// <param name="type">Uniquely identifies the activity. Maps to <see href="https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSUserActivity_Class/index.html#//apple_ref/occ/instp/NSUserActivity/activityType">NSUserActivity.activityType</see>.</param>
/// <param name="userInfo">App-specific state to store for use by another device.</param>
void SetUserActivity(string type, object userInfo);
/// <summary>
/// Creates an NSUserActivity and sets it as the current activity. The activity is
/// eligible for <see href="https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/Handoff/HandoffFundamentals/HandoffFundamentals.html">Handoff</see>
/// to another device afterward.
/// </summary>
/// <param name="type">
/// Uniquely identifies the activity. Maps to <see href="https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSUserActivity_Class/index.html#//apple_ref/occ/instp/NSUserActivity/activityType">NSUserActivity.activityType</see>.
/// </param>
/// <param name="userInfo">App-specific state to store for use by another device.</param>
/// <param name="webpageUrl">
/// The webpage to load in a browser if no suitable app is installed on the resuming device. The scheme must be http or https.
/// </param>
void SetUserActivity(string type, object userInfo, string webpageUrl);
/// <summary>
/// The type of the currently running activity.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
Task<string> GetCurrentActivityTypeAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Invalidates the current <see href="https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/Handoff/HandoffFundamentals/HandoffFundamentals.html">Handoff</see> user activity.
/// </summary>
void InvalidateCurrentActivity();
/// <summary>
/// Marks the current <see href="https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/Handoff/HandoffFundamentals/HandoffFundamentals.html">Handoff</see> user activity as inactive without invalidating it.
/// </summary>
void ResignCurrentActivity();
/// <summary>
/// Changes the <see href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx">Application User Model ID</see> to id.
/// </summary>
/// <param name="id">Model Id.</param>
void SetAppUserModelId(string id);
/// TODO: Check new parameter which is a function [App.ImportCertificate]
/// <summary>
/// Imports the certificate in pkcs12 format into the platform certificate store.
/// callback is called with the result of import operation, a value of 0 indicates
/// success while any other value indicates failure according to chromium net_error_list.
/// </summary>
/// <param name="options"></param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Result of import. Value of 0 indicates success.</returns>
Task<int> ImportCertificateAsync(ImportCertificateOptions options, CancellationToken cancellationToken = default);
/// <summary>
/// Memory and cpu usage statistics of all the processes associated with the app.
/// </summary>
/// <returns>
/// Array of ProcessMetric objects that correspond to memory and cpu usage
/// statistics of all the processes associated with the app.
/// <param name="cancellationToken">The cancellation token.</param>
/// </returns>
Task<ProcessMetric[]> GetAppMetricsAsync(CancellationToken cancellationToken = default);
/// <summary>
/// The Graphics Feature Status from chrome://gpu/.
/// <para/>
/// Note: This information is only usable after the gpu-info-update event is emitted.
/// <param name="cancellationToken">The cancellation token.</param>
/// </summary>
Task<GPUFeatureStatus> GetGpuFeatureStatusAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Sets the counter badge for current app. Setting the count to 0 will hide the badge.
/// On macOS it shows on the dock icon. On Linux it only works for Unity launcher.
/// <para/>
/// Note: Unity launcher requires the existence of a .desktop file to work, for more
/// information please read <see href="https://www.electronjs.org/docs/tutorial/desktop-environment-integration#unity-launcher">Desktop Environment Integration</see>.
/// </summary>
/// <param name="count">Counter badge.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Whether the call succeeded.</returns>
Task<bool> SetBadgeCountAsync(int count, CancellationToken cancellationToken = default);
/// <summary>
/// The current value displayed in the counter badge.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
Task<int> GetBadgeCountAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Whether the current desktop environment is Unity launcher.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
Task<bool> IsUnityRunningAsync(CancellationToken cancellationToken = default);
/// <summary>
/// If you provided path and args options to <see cref="SetLoginItemSettings"/> then you need to pass the same
/// arguments here for <see cref="LoginItemSettings.OpenAtLogin"/> to be set correctly.
/// </summary>
Task<LoginItemSettings> GetLoginItemSettingsAsync(CancellationToken cancellationToken = default);
/// <summary>
/// If you provided path and args options to <see cref="SetLoginItemSettings"/> then you need to pass the same
/// arguments here for <see cref="LoginItemSettings.OpenAtLogin"/> to be set correctly.
/// </summary>
/// <param name="options"></param>
/// <param name="cancellationToken">The cancellation token.</param>
Task<LoginItemSettings> GetLoginItemSettingsAsync(LoginItemSettingsOptions options, CancellationToken cancellationToken = default);
/// <summary>
/// Set the app's login item settings.
/// To work with Electron's autoUpdater on Windows, which uses <see href="https://github.com/Squirrel/Squirrel.Windows">Squirrel</see>,
/// you'll want to set the launch path to Update.exe, and pass arguments that specify your application name.
/// </summary>
/// <param name="loginSettings"></param>
void SetLoginItemSettings(LoginSettings loginSettings);
/// <summary>
/// <see langword="true"/> if Chrome's accessibility support is enabled, <see langword="false"/> otherwise. This API will
/// return <see langword="true"/> if the use of assistive technologies, such as screen readers, has been detected.
/// See <see href="chromium.org/developers/design-documents/accessibility">Chromium's accessibility docs</see> for more details.
/// </summary>
/// <returns><see langword="true"/> if Chromes accessibility support is enabled, <see langword="false"/> otherwise.</returns>
Task<bool> IsAccessibilitySupportEnabledAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Manually enables Chrome's accessibility support, allowing to expose accessibility switch to users in application settings.
/// See <see href="chromium.org/developers/design-documents/accessibility">Chromium's accessibility docs</see> for more details.
/// Disabled (<see langword="false"/>) by default.
/// <para/>
/// This API must be called after the <see cref="Ready"/> event is emitted.
/// <para/>
/// Note: Rendering accessibility tree can significantly affect the performance of your app. It should not be enabled by default.
/// </summary>
/// <param name="enabled">Enable or disable <see href="https://developers.google.com/web/fundamentals/accessibility/semantics-builtin/the-accessibility-tree">accessibility tree</see> rendering.</param>
void SetAccessibilitySupportEnabled(bool enabled);
/// <summary>
/// Show the app's about panel options. These options can be overridden with
/// <see cref="SetAboutPanelOptions"/>.
/// </summary>
void ShowAboutPanel();
/// <summary>
/// Set the about panel options. This will override the values defined in the app's .plist file on macOS. See the
/// <see href="https://developer.apple.com/reference/appkit/nsapplication/1428479-orderfrontstandardaboutpanelwith?language=objc">Apple docs</see>
/// for more details. On Linux, values must be set in order to be shown; there are no defaults.
/// <para/>
/// If you do not set credits but still wish to surface them in your app, AppKit will look for a file named "Credits.html",
/// "Credits.rtf", and "Credits.rtfd", in that order, in the bundle returned by the NSBundle class method main. The first file
/// found is used, and if none is found, the info area is left blank. See Apple
/// <see href="https://developer.apple.com/documentation/appkit/nsaboutpaneloptioncredits?language=objc">documentation</see> for more information.
/// </summary>
/// <param name="options">About panel options.</param>
void SetAboutPanelOptions(AboutPanelOptions options);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="App"/> module.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
void On(string eventName, Action fn);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="App"/> module.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
void On(string eventName, Action<object> fn);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="App"/> module once.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
void Once(string eventName, Action fn);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="App"/> module once.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
void Once(string eventName, Action<object> fn);
}
}

View File

@@ -0,0 +1,168 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ElectronNET.API.Entities;
namespace ElectronNET.API.Interfaces
{
/// <summary>
/// Enable apps to automatically update themselves. Based on electron-updater.
/// </summary>
public interface IAutoUpdater
{
/// <summary>
/// Whether to automatically download an update when it is found. (Default is true)
/// </summary>
bool AutoDownload { set; }
/// <summary>
/// Whether to automatically download an update when it is found. (Default is true)
/// </summary>
Task<bool> IsAutoDownloadEnabledAsync { get; }
/// <summary>
/// Whether to automatically install a downloaded update on app quit (if `QuitAndInstall` was not called before).
///
/// Applicable only on Windows and Linux.
/// </summary>
bool AutoInstallOnAppQuit { set; }
/// <summary>
/// Whether to automatically install a downloaded update on app quit (if `QuitAndInstall` was not called before).
///
/// Applicable only on Windows and Linux.
/// </summary>
Task<bool> IsAutoInstallOnAppQuitEnabledAsync { get; }
/// <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>
bool AllowPrerelease { set; }
/// <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>
Task<bool> IsAllowPrereleaseEnabledAsync { get; }
/// <summary>
/// *GitHub provider only.*
/// Get all release notes (from current version to latest), not just the latest (Default is false).
/// </summary>
bool FullChangelog { set; }
/// <summary>
/// *GitHub provider only.*
/// Get all release notes (from current version to latest), not just the latest (Default is false).
/// </summary>
Task<bool> IsFullChangeLogEnabledAsync { get; }
/// <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>
bool AllowDowngrade { set; }
Task<bool> IsAllowDowngradeEnabledAsync { get; }
/// <summary>
/// For test only.
/// </summary>
Task<string> GetUpdateConfigPathAsync { get; }
/// <summary>
/// The current application version
/// </summary>
Task<SemVer> GetCurrentVersionAsync { get; }
/// <summary>
/// Get the update channel. Not applicable for GitHub.
/// Doesnt return channel from the update configuration, only if was previously set.
/// </summary>
Task<string> GetChannelAsync { get; }
/// <summary>
/// The request headers.
/// </summary>
Task<Dictionary<string, string>> GetRequestHeadersAsync { get; }
/// <summary>
/// The request headers.
/// </summary>
Dictionary<string, string> RequestHeaders { set; }
/// <summary>
/// Emitted when there is an error while updating.
/// </summary>
event Action<string> OnError;
/// <summary>
/// Emitted when checking if an update has started.
/// </summary>
event Action OnCheckingForUpdate;
/// <summary>
/// Emitted when there is an available update.
/// The update is downloaded automatically if AutoDownload is true.
/// </summary>
event Action<UpdateInfo> OnUpdateAvailable;
/// <summary>
/// Emitted when there is no available update.
/// </summary>
event Action<UpdateInfo> OnUpdateNotAvailable;
/// <summary>
/// Emitted on download progress.
/// </summary>
event Action<ProgressInfo> OnDownloadProgress;
/// <summary>
/// Emitted on download complete.
/// </summary>
event Action<UpdateInfo> OnUpdateDownloaded;
/// <summary>
/// Asks the server whether there is an update.
/// </summary>
/// <returns></returns>
Task<UpdateCheckResult> CheckForUpdatesAsync();
/// <summary>
/// Asks the server whether there is an update.
///
/// This will immediately download an update, then install when the app quits.
/// </summary>
/// <returns></returns>
Task<UpdateCheckResult> CheckForUpdatesAndNotifyAsync();
/// <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>
void QuitAndInstall(bool isSilent = false, bool isForceRunAfter = false);
/// <summary>
/// Start downloading update manually. You can use this method if "AutoDownload" option is set to "false".
/// </summary>
/// <returns>Path to downloaded file.</returns>
Task<string> DownloadUpdateAsync();
/// <summary>
/// Feed URL.
/// </summary>
/// <returns>Feed URL.</returns>
Task<string> GetFeedURLAsync();
}
}

View File

@@ -0,0 +1,122 @@
using System.Threading.Tasks;
using ElectronNET.API.Entities;
namespace ElectronNET.API.Interfaces
{
/// <summary>
/// Perform copy and paste operations on the system clipboard.
/// </summary>
public interface IClipboard
{
/// <summary>
/// Read the content in the clipboard as plain text.
/// </summary>
/// <param name="type"></param>
/// <returns>The content in the clipboard as plain text.</returns>
Task<string> ReadTextAsync(string type = "");
/// <summary>
/// Writes the text into the clipboard as plain text.
/// </summary>
/// <param name="text"></param>
/// <param name="type"></param>
void WriteText(string text, string type = "");
/// <summary>
/// The content in the clipboard as markup.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
Task<string> ReadHTMLAsync(string type = "");
/// <summary>
/// Writes markup to the clipboard.
/// </summary>
/// <param name="markup"></param>
/// <param name="type"></param>
void WriteHTML(string markup, string type = "");
/// <summary>
/// The content in the clipboard as RTF.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
Task<string> ReadRTFAsync(string type = "");
/// <summary>
/// Writes the text into the clipboard in RTF.
/// </summary>
/// <param name="text"></param>
/// <param name="type"></param>
void WriteRTF(string text, string type = "");
/// <summary>
/// Returns an Object containing title and url keys representing
/// the bookmark in the clipboard. The title and url values will
/// be empty strings when the bookmark is unavailable.
/// </summary>
/// <returns></returns>
Task<ReadBookmark> ReadBookmarkAsync();
/// <summary>
/// Writes the title and url into the clipboard as a bookmark.
///
/// Note: Most apps on Windows dont support pasting bookmarks
/// into them so you can use clipboard.write to write both a
/// bookmark and fallback text to the clipboard.
/// </summary>
/// <param name="title"></param>
/// <param name="url"></param>
/// <param name="type"></param>
void WriteBookmark(string title, string url, string type = "");
/// <summary>
/// macOS: The text on the find pasteboard. This method uses synchronous IPC
/// when called from the renderer process. The cached value is reread from the
/// find pasteboard whenever the application is activated.
/// </summary>
/// <returns></returns>
Task<string> ReadFindTextAsync();
/// <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>
void WriteFindText(string text);
/// <summary>
/// Clears the clipboard content.
/// </summary>
/// <param name="type"></param>
void Clear(string type = "");
/// <summary>
/// An array of supported formats for the clipboard type.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
Task<string[]> AvailableFormatsAsync(string type = "");
/// <summary>
/// Writes data to the clipboard.
/// </summary>
/// <param name="data"></param>
/// <param name="type"></param>
void Write(Data data, string type = "");
/// <summary>
/// Reads an image from the clipboard.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
Task<NativeImage> ReadImageAsync(string type = "");
/// <summary>
/// Writes an image to the clipboard.
/// </summary>
/// <param name="image"></param>
/// <param name="type"></param>
void WriteImage(NativeImage image, string type = "");
}
}

View File

@@ -0,0 +1,102 @@
using System.Threading.Tasks;
using ElectronNET.API.Entities;
namespace ElectronNET.API.Interfaces
{
/// <summary>
/// Display native system dialogs for opening and saving files, alerting, etc.
/// </summary>
public interface IDialog
{
/// <summary>
/// Note: On Windows and Linux an open dialog can not be both a file selector
/// and a directory selector, so if you set properties to ['openFile', 'openDirectory']
/// on these platforms, a directory selector will be shown.
/// </summary>
/// <param name="browserWindow">The browserWindow argument allows the dialog to attach itself to a parent window, making it modal.</param>
/// <param name="options"></param>
/// <returns>An array of file paths chosen by the user</returns>
Task<string[]> ShowOpenDialogAsync(BrowserWindow browserWindow, OpenDialogOptions options);
/// <summary>
/// Dialog for save files.
/// </summary>
/// <param name="browserWindow">The browserWindow argument allows the dialog to attach itself to a parent window, making it modal.</param>
/// <param name="options"></param>
/// <returns>Returns String, the path of the file chosen by the user, if a callback is provided it returns an empty string.</returns>
Task<string> ShowSaveDialogAsync(BrowserWindow browserWindow, SaveDialogOptions options);
/// <summary>
/// Shows a message box, it will block the process until the message box is closed.
/// It returns the index of the clicked button. The browserWindow argument allows
/// the dialog to attach itself to a parent window, making it modal. If a callback
/// is passed, the dialog will not block the process.The API call will be
/// asynchronous and the result will be passed via callback(response).
/// </summary>
/// <param name="message"></param>
/// <returns>The API call will be asynchronous and the result will be passed via MessageBoxResult.</returns>
Task<MessageBoxResult> ShowMessageBoxAsync(string message);
/// <summary>
/// Shows a message box, it will block the process until the message box is closed.
/// It returns the index of the clicked button. The browserWindow argument allows
/// the dialog to attach itself to a parent window, making it modal. If a callback
/// is passed, the dialog will not block the process.The API call will be
/// asynchronous and the result will be passed via callback(response).
/// </summary>
/// <param name="messageBoxOptions"></param>
/// <returns>The API call will be asynchronous and the result will be passed via MessageBoxResult.</returns>
Task<MessageBoxResult> ShowMessageBoxAsync(MessageBoxOptions messageBoxOptions);
/// <summary>
/// Shows a message box, it will block the process until the message box is closed.
/// It returns the index of the clicked button. If a callback
/// is passed, the dialog will not block the process.
/// </summary>
/// <param name="browserWindow">The browserWindow argument allows the dialog to attach itself to a parent window, making it modal.</param>
/// <param name="message"></param>
/// <returns>The API call will be asynchronous and the result will be passed via MessageBoxResult.</returns>
Task<MessageBoxResult> ShowMessageBoxAsync(BrowserWindow browserWindow, string message);
/// <summary>
/// Shows a message box, it will block the process until the message box is closed.
/// It returns the index of the clicked button. If a callback
/// is passed, the dialog will not block the process.
/// </summary>
/// <param name="browserWindow">The browserWindow argument allows the dialog to attach itself to a parent window, making it modal.</param>
/// <param name="messageBoxOptions"></param>
/// <returns>The API call will be asynchronous and the result will be passed via MessageBoxResult.</returns>
Task<MessageBoxResult> ShowMessageBoxAsync(BrowserWindow browserWindow, MessageBoxOptions messageBoxOptions);
/// <summary>
/// Displays a modal dialog that shows an error message.
///
/// This API can be called safely before the ready event the app module emits,
/// it is usually used to report errors in early stage of startup.If called
/// before the app readyevent on Linux, the message will be emitted to stderr,
/// and no GUI dialog will appear.
/// </summary>
/// <param name="title">The title to display in the error box.</param>
/// <param name="content">The text content to display in the error box.</param>
void ShowErrorBox(string title, string content);
/// <summary>
/// On macOS, this displays a modal dialog that shows a message and certificate information,
/// and gives the user the option of trusting/importing the certificate. If you provide a
/// browserWindow argument the dialog will be attached to the parent window, making it modal.
/// </summary>
/// <param name="options"></param>
/// <returns></returns>
Task ShowCertificateTrustDialogAsync(CertificateTrustDialogOptions options);
/// <summary>
/// On macOS, this displays a modal dialog that shows a message and certificate information,
/// and gives the user the option of trusting/importing the certificate. If you provide a
/// browserWindow argument the dialog will be attached to the parent window, making it modal.
/// </summary>
/// <param name="browserWindow"></param>
/// <param name="options"></param>
/// <returns></returns>
Task ShowCertificateTrustDialogAsync(BrowserWindow browserWindow, CertificateTrustDialogOptions options);
}
}

View File

@@ -0,0 +1,93 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using ElectronNET.API.Entities;
namespace ElectronNET.API.Interfaces
{
/// <summary>
/// Control your app in the macOS dock.
/// </summary>
public interface IDock
{
/// <summary>
/// When <see cref="DockBounceType.Critical"/> is passed, the dock icon will bounce until either the application becomes
/// active or the request is canceled. When <see cref="DockBounceType.Informational"/> is passed, the dock icon will bounce
/// for one second. However, the request remains active until either the application becomes active or the request is canceled.
/// <para/>
/// Note: This method can only be used while the app is not focused; when the app is focused it will return -1.
/// </summary>
/// <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>
Task<int> BounceAsync(DockBounceType type, CancellationToken cancellationToken = default);
/// <summary>
/// Cancel the bounce of id.
/// </summary>
/// <param name="id">Id of the request.</param>
void CancelBounce(int id);
/// <summary>
/// Bounces the Downloads stack if the filePath is inside the Downloads folder.
/// </summary>
/// <param name="filePath"></param>
void DownloadFinished(string filePath);
/// <summary>
/// Sets the string to be displayed in the docks badging area.
/// </summary>
/// <param name="text"></param>
void SetBadge(string text);
/// <summary>
/// Gets the string to be displayed in the docks badging area.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The badge string of the dock.</returns>
Task<string> GetBadgeAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Hides the dock icon.
/// </summary>
void Hide();
/// <summary>
/// Shows the dock icon.
/// </summary>
void Show();
/// <summary>
/// Whether the dock icon is visible. The app.dock.show() call is asynchronous
/// so this method might not return true immediately after that call.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Whether the dock icon is visible.</returns>
Task<bool> IsVisibleAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Gets the dock menu items.
/// </summary>
/// <value>
/// The menu items.
/// </value>
IReadOnlyCollection<MenuItem> MenuItems { get; }
/// <summary>
/// Sets the application's dock menu.
/// </summary>
void SetMenu(MenuItem[] menuItems);
/// <summary>
/// TODO: Menu (macOS) still to be implemented
/// Gets the application's dock menu.
/// </summary>
Task<Menu> GetMenu(CancellationToken cancellationToken = default);
/// <summary>
/// Sets the image associated with this dock icon.
/// </summary>
/// <param name="image"></param>
void SetIcon(string image);
}
}

View File

@@ -0,0 +1,39 @@
using System;
using System.Threading.Tasks;
namespace ElectronNET.API.Interfaces
{
/// <summary>
/// Detect keyboard events when the application does not have keyboard focus.
/// </summary>
public interface IGlobalShortcut
{
/// <summary>
/// Registers a global shortcut of accelerator.
/// The callback is called when the registered shortcut is pressed by the user.
///
/// When the accelerator is already taken by other applications, this call will
/// silently fail.This behavior is intended by operating systems, since they dont
/// want applications to fight for global shortcuts.
/// </summary>
void Register(string accelerator, Action function);
/// <summary>
/// When the accelerator is already taken by other applications,
/// this call will still return false. This behavior is intended by operating systems,
/// since they dont want applications to fight for global shortcuts.
/// </summary>
/// <returns>Whether this application has registered accelerator.</returns>
Task<bool> IsRegisteredAsync(string accelerator);
/// <summary>
/// Unregisters the global shortcut of accelerator.
/// </summary>
void Unregister(string accelerator);
/// <summary>
/// Unregisters all of the global shortcuts.
/// </summary>
void UnregisterAll();
}
}

View File

@@ -0,0 +1,30 @@
using System.Threading.Tasks;
namespace ElectronNET.API.Interfaces
{
/// <summary>
/// Allows you to execute native JavaScript/TypeScript code from the host process.
///
/// It is only possible if the Electron.NET CLI has previously added an
/// ElectronHostHook directory:
/// <c>electronize add HostHook</c>
/// </summary>
public interface IHostHook
{
/// <summary>
/// Execute native JavaScript/TypeScript code.
/// </summary>
/// <param name="socketEventName">Socket name registered on the host.</param>
/// <param name="arguments">Optional parameters.</param>
void Call(string socketEventName, params dynamic[] arguments);
/// <summary>
/// Execute native JavaScript/TypeScript code.
/// </summary>
/// <typeparam name="T">Results from the executed host code.</typeparam>
/// <param name="socketEventName">Socket name registered on the host.</param>
/// <param name="arguments">Optional parameters.</param>
/// <returns></returns>
Task<T> CallAsync<T>(string socketEventName, params dynamic[] arguments);
}
}

View File

@@ -0,0 +1,65 @@
using System;
namespace ElectronNET.API.Interfaces
{
/// <summary>
/// Communicate asynchronously from the main process to renderer processes.
/// </summary>
public interface IIpcMain
{
/// <summary>
/// Listens to channel, when a new message arrives listener would be called with
/// listener(event, args...).
/// </summary>
/// <param name="channel">Channelname.</param>
/// <param name="listener">Callback Method.</param>
void On(string channel, Action<object> listener);
/// <summary>
/// Send a message to the renderer process synchronously via channel,
/// you can also send arbitrary arguments.
///
/// Note: Sending a synchronous message will block the whole renderer process,
/// unless you know what you are doing you should never use it.
/// </summary>
/// <param name="channel"></param>
/// <param name="listener"></param>
void OnSync(string channel, Func<object, object> listener);
/// <summary>
/// Adds a one time listener method for the event. This listener is invoked only
/// the next time a message is sent to channel, after which it is removed.
/// </summary>
/// <param name="channel">Channelname.</param>
/// <param name="listener">Callback Method.</param>
void Once(string channel, Action<object> listener);
/// <summary>
/// Removes listeners of the specified channel.
/// </summary>
/// <param name="channel">Channelname.</param>
void RemoveAllListeners(string channel);
/// <summary>
/// Send a message to the renderer process asynchronously via channel, you can also send
/// arbitrary arguments. Arguments will be serialized in JSON internally and hence
/// no functions or prototype chain will be included. The renderer process handles it by
/// listening for channel with ipcRenderer module.
/// </summary>
/// <param name="browserWindow">BrowserWindow with channel.</param>
/// <param name="channel">Channelname.</param>
/// <param name="data">Arguments data.</param>
void Send(BrowserWindow browserWindow, string channel, params object[] data);
/// <summary>
/// Send a message to the BrowserView renderer process asynchronously via channel, you can also send
/// arbitrary arguments. Arguments will be serialized in JSON internally and hence
/// no functions or prototype chain will be included. The renderer process handles it by
/// listening for channel with ipcRenderer module.
/// </summary>
/// <param name="browserView">BrowserView with channel.</param>
/// <param name="channel">Channelname.</param>
/// <param name="data">Arguments data.</param>
void Send(BrowserView browserView, string channel, params object[] data);
}
}

View File

@@ -0,0 +1,47 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using ElectronNET.API.Entities;
namespace ElectronNET.API.Interfaces
{
/// <summary>
/// Create native application menus and context menus.
/// </summary>
public interface IMenu
{
/// <summary>
/// Gets the menu items.
/// </summary>
/// <value>
/// The menu items.
/// </value>
IReadOnlyCollection<MenuItem> MenuItems { get; }
/// <summary>
/// Gets the context menu items.
/// </summary>
/// <value>
/// The context menu items.
/// </value>
IReadOnlyDictionary<int, ReadOnlyCollection<MenuItem>> ContextMenuItems { get; }
/// <summary>
/// Sets the application menu.
/// </summary>
/// <param name="menuItems">The menu items.</param>
void SetApplicationMenu(MenuItem[] menuItems);
/// <summary>
/// Sets the context menu.
/// </summary>
/// <param name="browserWindow">The browser window.</param>
/// <param name="menuItems">The menu items.</param>
void SetContextMenu(BrowserWindow browserWindow, MenuItem[] menuItems);
/// <summary>
/// Contexts the menu popup.
/// </summary>
/// <param name="browserWindow">The browser window.</param>
void ContextMenuPopup(BrowserWindow browserWindow);
}
}

View File

@@ -0,0 +1,101 @@
using System;
using System.Threading.Tasks;
using ElectronNET.API.Entities;
namespace ElectronNET.API.Interfaces
{
/// <summary>
/// Read and respond to changes in Chromium's native color theme.
/// </summary>
public interface INativeTheme
{
/// <summary>
/// Setting this property to <see cref="ThemeSourceMode.System"/> will remove the override and everything will be reset to the OS default. By default 'ThemeSource' is <see cref="ThemeSourceMode.System"/>.
/// <para/>
/// Settings this property to <see cref="ThemeSourceMode.Dark"/> will have the following effects:
/// <list type="bullet">
/// <item>
/// <description><see cref="ShouldUseDarkColorsAsync"/> will be <see langword="true"/> when accessed</description>
/// </item>
/// <item>
/// <description>Any UI Electron renders on Linux and Windows including context menus, devtools, etc. will use the dark UI.</description>
/// </item>
/// <item>
/// <description>Any UI the OS renders on macOS including menus, window frames, etc. will use the dark UI.</description>
/// </item>
/// <item>
/// <description>The 'prefers-color-scheme' CSS query will match 'dark' mode.</description>
/// </item>
/// <item>
/// <description>The 'updated' event will be emitted</description>
/// </item>
/// </list>
/// <para/>
/// Settings this property to <see cref="ThemeSourceMode.Light"/> will have the following effects:
/// <list type="bullet">
/// <item>
/// <description><see cref="ShouldUseDarkColorsAsync"/> will be <see langword="false"/> when accessed</description>
/// </item>
/// <item>
/// <description>Any UI Electron renders on Linux and Windows including context menus, devtools, etc. will use the light UI.</description>
/// </item>
/// <item>
/// <description>Any UI the OS renders on macOS including menus, window frames, etc. will use the light UI.</description>
/// </item>
/// <item>
/// <description>The 'prefers-color-scheme' CSS query will match 'light' mode.</description>
/// </item>
/// <item>
/// <description>The 'updated' event will be emitted</description>
/// </item>
/// </list>
/// The usage of this property should align with a classic "dark mode" state machine in your application where the user has three options.
/// <para/>
/// <list type="bullet">
/// <item>
/// <description>Follow OS: SetThemeSource(ThemeSourceMode.System);</description>
/// </item>
/// <item>
/// <description>Dark Mode: SetThemeSource(ThemeSourceMode.Dark);</description>
/// </item>
/// <item>
/// <description>Light Mode: SetThemeSource(ThemeSourceMode.Light);</description>
/// </item>
/// </list>
/// Your application should then always use <see cref="ShouldUseDarkColorsAsync"/> to determine what CSS to apply.
/// </summary>
/// <param name="themeSourceMode">The new ThemeSource.</param>
void SetThemeSource(ThemeSourceMode themeSourceMode);
/// <summary>
/// A <see cref="ThemeSourceMode"/> property that can be <see cref="ThemeSourceMode.System"/>, <see cref="ThemeSourceMode.Light"/> or <see cref="ThemeSourceMode.Dark"/>. It is used to override (<seealso cref="SetThemeSource"/>) and
/// supercede the value that Chromium has chosen to use internally.
/// </summary>
Task<ThemeSourceMode> GetThemeSourceAsync();
/// <summary>
/// A <see cref="bool"/> for if the OS / Chromium currently has a dark mode enabled or is
/// being instructed to show a dark-style UI. If you want to modify this value you
/// should use <see cref="SetThemeSource"/>.
/// </summary>
Task<bool> ShouldUseDarkColorsAsync();
/// <summary>
/// A <see cref="bool"/> for if the OS / Chromium currently has high-contrast mode enabled or is
/// being instructed to show a high-contrast UI.
/// </summary>
Task<bool> ShouldUseHighContrastColorsAsync();
/// <summary>
/// A <see cref="bool"/> for if the OS / Chromium currently has an inverted color scheme or is
/// being instructed to use an inverted color scheme.
/// </summary>
Task<bool> ShouldUseInvertedColorSchemeAsync();
/// <summary>
/// Emitted when something in the underlying NativeTheme has changed. This normally means that either the value of <see cref="ShouldUseDarkColorsAsync"/>,
/// <see cref="ShouldUseHighContrastColorsAsync"/> or <see cref="ShouldUseInvertedColorSchemeAsync"/> has changed. You will have to check them to determine which one has changed.
/// </summary>
event Action Updated;
}
}

View File

@@ -0,0 +1,23 @@
using System.Threading.Tasks;
using ElectronNET.API.Entities;
namespace ElectronNET.API.Interfaces
{
/// <summary>
/// Create OS desktop notifications
/// </summary>
public interface INotification
{
/// <summary>
/// Create OS desktop notifications
/// </summary>
/// <param name="notificationOptions"></param>
void Show(NotificationOptions notificationOptions);
/// <summary>
/// Whether or not desktop notifications are supported on the current system.
/// </summary>
/// <returns></returns>
Task<bool> IsSupportedAsync();
}
}

View File

@@ -0,0 +1,48 @@
using System;
namespace ElectronNET.API.Interfaces
{
/// <summary>
/// Monitor power state changes..
/// </summary>
public interface IPowerMonitor
{
/// <summary>
/// Emitted when the system is about to lock the screen.
/// </summary>
event Action OnLockScreen;
/// <summary>
/// Emitted when the system is about to unlock the screen.
/// </summary>
event Action OnUnLockScreen;
/// <summary>
/// Emitted when the system is suspending.
/// </summary>
event Action OnSuspend;
/// <summary>
/// Emitted when system is resuming.
/// </summary>
event Action OnResume;
/// <summary>
/// Emitted when the system changes to AC power.
/// </summary>
event Action OnAC;
/// <summary>
/// Emitted when system changes to battery power.
/// </summary>
event Action OnBattery;
/// <summary>
/// Emitted when the system is about to reboot or shut down. If the event handler
/// invokes `e.preventDefault()`, Electron will attempt to delay system shutdown in
/// order for the app to exit cleanly.If `e.preventDefault()` is called, the app
/// should exit as soon as possible by calling something like `app.quit()`.
/// </summary>
event Action OnShutdown;
}
}

View File

@@ -0,0 +1,66 @@
using System;
using System.Threading.Tasks;
using ElectronNET.API.Entities;
namespace ElectronNET.API.Interfaces
{
/// <summary>
/// Retrieve information about screen size, displays, cursor position, etc.
/// </summary>
public interface IScreen
{
/// <summary>
/// Emitted when an new Display has been added.
/// </summary>
event Action<Display> OnDisplayAdded;
/// <summary>
/// Emitted when oldDisplay has been removed.
/// </summary>
event Action<Display> OnDisplayRemoved;
/// <summary>
/// Emitted when one or more metrics change in a display.
/// The changedMetrics is an array of strings that describe the changes.
/// Possible changes are bounds, workArea, scaleFactor and rotation.
/// </summary>
event Action<Display, string[]> OnDisplayMetricsChanged;
/// <summary>
/// The current absolute position of the mouse pointer.
/// </summary>
/// <returns></returns>
Task<Point> GetCursorScreenPointAsync();
/// <summary>
/// macOS: The height of the menu bar in pixels.
/// </summary>
/// <returns>The height of the menu bar in pixels.</returns>
Task<int> GetMenuBarHeightAsync();
/// <summary>
/// The primary display.
/// </summary>
/// <returns></returns>
Task<Display> GetPrimaryDisplayAsync();
/// <summary>
/// An array of displays that are currently available.
/// </summary>
/// <returns>An array of displays that are currently available.</returns>
Task<Display[]> GetAllDisplaysAsync();
/// <summary>
/// The display nearest the specified point.
/// </summary>
/// <returns>The display nearest the specified point.</returns>
Task<Display> GetDisplayNearestPointAsync(Point point);
/// <summary>
/// The display that most closely intersects the provided bounds.
/// </summary>
/// <param name="rectangle"></param>
/// <returns>The display that most closely intersects the provided bounds.</returns>
Task<Display> GetDisplayMatchingAsync(Rectangle rectangle);
}
}

View File

@@ -0,0 +1,70 @@
using System.Threading.Tasks;
using ElectronNET.API.Entities;
namespace ElectronNET.API.Interfaces
{
/// <summary>
/// Manage files and URLs using their default applications.
/// </summary>
public interface IShell
{
/// <summary>
/// Show the given file in a file manager. If possible, select the file.
/// </summary>
/// <param name="fullPath">The full path to the directory / file.</param>
Task ShowItemInFolderAsync(string fullPath);
/// <summary>
/// Open the given file in the desktop's default manner.
/// </summary>
/// <param name="path">The path to the directory / file.</param>
/// <returns>The error message corresponding to the failure if a failure occurred, otherwise <see cref="string.Empty"/>.</returns>
Task<string> OpenPathAsync(string path);
/// <summary>
/// Open the given external protocol URL in the desktops default manner.
/// (For example, mailto: URLs in the users default mail agent).
/// </summary>
/// <param name="url">Max 2081 characters on windows.</param>
/// <returns>The error message corresponding to the failure if a failure occurred, otherwise <see cref="string.Empty"/>.</returns>
Task<string> OpenExternalAsync(string url);
/// <summary>
/// Open the given external protocol URL in the desktops default manner.
/// (For example, mailto: URLs in the users default mail agent).
/// </summary>
/// <param name="url">Max 2081 characters on windows.</param>
/// <param name="options">Controls the behavior of OpenExternal.</param>
/// <returns>The error message corresponding to the failure if a failure occurred, otherwise <see cref="string.Empty"/>.</returns>
Task<string> OpenExternalAsync(string url, OpenExternalOptions options);
/// <summary>
/// Move the given file to trash and returns a <see cref="bool"/> status for the operation.
/// </summary>
/// <param name="fullPath">The full path to the directory / file.</param>
/// <returns> Whether the item was successfully moved to the trash.</returns>
Task<bool> TrashItemAsync(string fullPath);
/// <summary>
/// Play the beep sound.
/// </summary>
void Beep();
/// <summary>
/// Creates or updates a shortcut link at shortcutPath.
/// </summary>
/// <param name="shortcutPath">The path to the shortcut.</param>
/// <param name="operation">Default is <see cref="ShortcutLinkOperation.Create"/></param>
/// <param name="options">Structure of a shortcut.</param>
/// <returns>Whether the shortcut was created successfully.</returns>
Task<bool> WriteShortcutLinkAsync(string shortcutPath, ShortcutLinkOperation operation, ShortcutDetails options);
/// <summary>
/// Resolves the shortcut link at shortcutPath.
/// An exception will be thrown when any error happens.
/// </summary>
/// <param name="shortcutPath">The path tot the shortcut.</param>
/// <returns><see cref="ShortcutDetails"/> of the shortcut.</returns>
Task<ShortcutDetails> ReadShortcutLinkAsync(string shortcutPath);
}
}

View File

@@ -0,0 +1,141 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ElectronNET.API.Entities;
namespace ElectronNET.API.Interfaces
{
/// <summary>
/// Add icons and context menus to the system's notification area.
/// </summary>
public interface ITray
{
/// <summary>
/// Emitted when the tray icon is clicked.
/// </summary>
event Action<TrayClickEventArgs, Rectangle> OnClick;
/// <summary>
/// macOS, Windows: Emitted when the tray icon is right clicked.
/// </summary>
event Action<TrayClickEventArgs, Rectangle> OnRightClick;
/// <summary>
/// macOS, Windows: Emitted when the tray icon is double clicked.
/// </summary>
event Action<TrayClickEventArgs, Rectangle> OnDoubleClick;
/// <summary>
/// Windows: Emitted when the tray balloon shows.
/// </summary>
event Action OnBalloonShow;
/// <summary>
/// Windows: Emitted when the tray balloon is clicked.
/// </summary>
event Action OnBalloonClick;
/// <summary>
/// Windows: Emitted when the tray balloon is closed
/// because of timeout or user manually closes it.
/// </summary>
event Action OnBalloonClosed;
/// <summary>
/// Gets the menu items.
/// </summary>
/// <value>
/// The menu items.
/// </value>
IReadOnlyCollection<MenuItem> MenuItems { get; }
/// <summary>
/// Shows the Traybar.
/// </summary>
/// <param name="image">The image.</param>
/// <param name="menuItem">The menu item.</param>
void Show(string image, MenuItem menuItem);
/// <summary>
/// Shows the Traybar.
/// </summary>
/// <param name="image">The image.</param>
/// <param name="menuItems">The menu items.</param>
void Show(string image, MenuItem[] menuItems);
/// <summary>
/// Shows the Traybar (empty).
/// </summary>
/// <param name="image">The image.</param>
void Show(string image);
/// <summary>
/// Destroys the tray icon immediately.
/// </summary>
void Destroy();
/// <summary>
/// Sets the image associated with this tray icon.
/// </summary>
/// <param name="image"></param>
void SetImage(string image);
/// <summary>
/// Sets the image associated with this tray icon when pressed on macOS.
/// </summary>
/// <param name="image"></param>
void SetPressedImage(string image);
/// <summary>
/// Sets the hover text for this tray icon.
/// </summary>
/// <param name="toolTip"></param>
void SetToolTip(string toolTip);
/// <summary>
/// macOS: Sets the title displayed aside of the tray icon in the status bar.
/// </summary>
/// <param name="title"></param>
void SetTitle(string title);
/// <summary>
/// Windows: Displays a tray balloon.
/// </summary>
/// <param name="options"></param>
void DisplayBalloon(DisplayBalloonOptions options);
/// <summary>
/// Whether the tray icon is destroyed.
/// </summary>
/// <returns></returns>
Task<bool> IsDestroyedAsync();
/// <summary>
/// Subscribe to an unmapped event on the <see cref="Tray"/> module.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
void On(string eventName, Action fn);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="Tray"/> module.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
void On(string eventName, Action<object> fn);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="Tray"/> module once.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
void Once(string eventName, Action fn);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="Tray"/> module once.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
void Once(string eventName, Action<object> fn);
}
}

View File

@@ -0,0 +1,68 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using ElectronNET.API.Entities;
namespace ElectronNET.API.Interfaces
{
/// <summary>
/// Manage Browser Windows and Views
/// </summary>
public interface IWindowManager
{
/// <summary>
/// Quit when all windows are closed. (Default is true)
/// </summary>
/// <value>
/// <c>true</c> if [quit window all closed]; otherwise, <c>false</c>.
/// </value>
bool IsQuitOnWindowAllClosed { get; set; }
/// <summary>
/// Gets the browser windows.
/// </summary>
/// <value>
/// The browser windows.
/// </value>
IReadOnlyCollection<BrowserWindow> BrowserWindows { get; }
/// <summary>
/// Gets the browser views.
/// </summary>
/// <value>
/// The browser view.
/// </value>
IReadOnlyCollection<BrowserView> BrowserViews { get; }
/// <summary>
/// Creates the window asynchronous.
/// </summary>
/// <param name="loadUrl">The load URL.</param>
/// <returns></returns>
Task<BrowserWindow> CreateWindowAsync(string loadUrl = "http://localhost");
/// <summary>
/// Creates the window asynchronous.
/// </summary>
/// <param name="options">The options.</param>
/// <param name="loadUrl">The load URL.</param>
/// <returns></returns>
Task<BrowserWindow> CreateWindowAsync(BrowserWindowOptions options, string loadUrl = "http://localhost");
/// <summary>
/// A BrowserView can be used to embed additional web content into a BrowserWindow.
/// It is like a child window, except that it is positioned relative to its owning window.
/// It is meant to be an alternative to the webview tag.
/// </summary>
/// <returns></returns>
Task<BrowserView> CreateBrowserViewAsync();
/// <summary>
/// A BrowserView can be used to embed additional web content into a BrowserWindow.
/// It is like a child window, except that it is positioned relative to its owning window.
/// It is meant to be an alternative to the webview tag.
/// </summary>
/// <param name="options"></param>
/// <returns></returns>
Task<BrowserView> CreateBrowserViewAsync(BrowserViewConstructorOptions options);
}
}

145
ElectronNET.API/IpcMain.cs Normal file → Executable file
View File

@@ -5,16 +5,17 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using ElectronNET.API.Interfaces;
namespace ElectronNET.API
{
/// <summary>
/// Communicate asynchronously from the main process to renderer processes.
/// </summary>
public sealed class IpcMain
public sealed class IpcMain : IIpcMain
{
private static IpcMain _ipcMain;
private static object _syncRoot = new object();
private static readonly object _syncRoot = new();
internal IpcMain() { }
@@ -37,6 +38,8 @@ namespace ElectronNET.API
}
}
public static bool IsConnected => BridgeConnector.IsConnected;
/// <summary>
/// Listens to channel, when a new message arrives listener would be called with
/// listener(event, args...).
@@ -45,13 +48,13 @@ namespace ElectronNET.API
/// <param name="listener">Callback Method.</param>
public void On(string channel, Action<object> listener)
{
BridgeConnector.Socket.Emit("registerIpcMainChannel", channel);
BridgeConnector.Socket.Off(channel);
BridgeConnector.Socket.On(channel, (args) =>
BridgeConnector.Emit("registerIpcMainChannel", channel);
BridgeConnector.Off(channel);
BridgeConnector.On<object[]>(channel, (args) =>
{
List<object> objectArray = FormatArguments(args);
var objectArray = FormatArguments(args);
if(objectArray.Count == 1)
if (objectArray.Count == 1)
{
listener(objectArray.First());
}
@@ -62,20 +65,41 @@ namespace ElectronNET.API
});
}
private List<object> FormatArguments(object args)
/// <summary>
/// Listens to channel, when a new message arrives listener would be called with
/// listener(event, args...). This listner will keep the window event sender id
/// </summary>
/// <param name="channel">Channelname.</param>
/// <param name="listener">Callback Method.</param>
public void OnWithId(string channel, Action<(int browserId, int webContentId, object arguments)> listener)
{
List<object> objectArray = ((JArray)args).ToObject<object[]>().ToList();
for (int index = 0; index < objectArray.Count; index++)
BridgeConnector.Emit("registerIpcMainChannelWithId", channel);
BridgeConnector.Off(channel);
BridgeConnector.On<ArgsAndIds>(channel, (data) =>
{
var item = objectArray[index];
if (item == null)
{
objectArray.Remove(item);
}
}
var objectArray = FormatArguments(data.args);
return objectArray;
if (objectArray.Count == 1)
{
listener((data.id, data.wcId, objectArray.First()));
}
else
{
listener((data.id, data.wcId, objectArray));
}
});
}
private class ArgsAndIds
{
public int id { get; set; }
public int wcId { get; set; }
public object[] args { get; set; }
}
private List<object> FormatArguments(object[] objectArray)
{
return objectArray.Where(o => o is object).ToList();
}
/// <summary>
@@ -89,9 +113,9 @@ namespace ElectronNET.API
/// <param name="listener"></param>
public void OnSync(string channel, Func<object, object> listener)
{
BridgeConnector.Socket.Emit("registerSyncIpcMainChannel", channel);
BridgeConnector.Socket.On(channel, (args) => {
List<object> objectArray = FormatArguments(args);
BridgeConnector.Emit("registerSyncIpcMainChannel", channel);
BridgeConnector.On<object[]>(channel, (args) => {
var objectArray = FormatArguments(args);
object parameter;
if (objectArray.Count == 1)
{
@@ -103,7 +127,7 @@ namespace ElectronNET.API
}
var result = listener(parameter);
BridgeConnector.Socket.Emit(channel + "Sync", result);
BridgeConnector.Emit(channel + "Sync", result);
});
}
@@ -115,10 +139,10 @@ namespace ElectronNET.API
/// <param name="listener">Callback Method.</param>
public void Once(string channel, Action<object> listener)
{
BridgeConnector.Socket.Emit("registerOnceIpcMainChannel", channel);
BridgeConnector.Socket.On(channel, (args) =>
BridgeConnector.Emit("registerOnceIpcMainChannel", channel);
BridgeConnector.Once<object[]>(channel, (args) =>
{
List<object> objectArray = FormatArguments(args);
var objectArray = FormatArguments(args);
if (objectArray.Count == 1)
{
@@ -137,7 +161,7 @@ namespace ElectronNET.API
/// <param name="channel">Channelname.</param>
public void RemoveAllListeners(string channel)
{
BridgeConnector.Socket.Emit("removeAllListenersIpcMainChannel", channel);
BridgeConnector.Emit("removeAllListenersIpcMainChannel", channel);
}
/// <summary>
@@ -151,9 +175,45 @@ namespace ElectronNET.API
/// <param name="data">Arguments data.</param>
public void Send(BrowserWindow browserWindow, string channel, params object[] data)
{
List<JObject> jobjects = new List<JObject>();
List<JArray> jarrays = new List<JArray>();
List<object> objects = new List<object>();
var objectsWithCorrectSerialization = new List<object>
{
browserWindow.Id,
channel
};
foreach (var parameterObject in data)
{
if(parameterObject.GetType().IsArray || parameterObject.GetType().IsGenericType && parameterObject is IEnumerable)
{
objectsWithCorrectSerialization.Add(JArray.FromObject(parameterObject, _jsonSerializer));
}
else if(parameterObject.GetType().IsClass && !parameterObject.GetType().IsPrimitive && !(parameterObject is string))
{
objectsWithCorrectSerialization.Add(JObject.FromObject(parameterObject, _jsonSerializer));
}
else if(parameterObject.GetType().IsPrimitive || (parameterObject is string))
{
objectsWithCorrectSerialization.Add(parameterObject);
}
}
BridgeConnector.Emit("sendToIpcRenderer", objectsWithCorrectSerialization.ToArray());
}
/// <summary>
/// Send a message to the BrowserView renderer process asynchronously via channel, you can also send
/// arbitrary arguments. Arguments will be serialized in JSON internally and hence
/// no functions or prototype chain will be included. The renderer process handles it by
/// listening for channel with ipcRenderer module.
/// </summary>
/// <param name="browserView">BrowserView with channel.</param>
/// <param name="channel">Channelname.</param>
/// <param name="data">Arguments data.</param>
public void Send(BrowserView browserView, string channel, params object[] data)
{
List<JObject> jobjects = new();
List<JArray> jarrays = new();
List<object> objects = new();
foreach (var parameterObject in data)
{
@@ -171,15 +231,36 @@ namespace ElectronNET.API
if(jobjects.Count > 0 || jarrays.Count > 0)
{
BridgeConnector.Socket.Emit("sendToIpcRenderer", JObject.FromObject(browserWindow, _jsonSerializer), channel, jarrays.ToArray(), jobjects.ToArray(), objects.ToArray());
BridgeConnector.Emit("sendToIpcRendererBrowserView", browserView.Id, channel, jarrays.ToArray(), jobjects.ToArray(), objects.ToArray());
}
else
{
BridgeConnector.Socket.Emit("sendToIpcRenderer", JObject.FromObject(browserWindow, _jsonSerializer), channel, data);
BridgeConnector.Emit("sendToIpcRendererBrowserView", browserView.Id, channel, data);
}
}
private JsonSerializer _jsonSerializer = new JsonSerializer()
/// <summary>
/// Log a message to the console output pipe. This is used when running with "detachedProcess" : true on the electron.manifest.json,
/// as in that case we can't open pipes to read the console output from the child process anymore
/// </summary>
/// <param name="text">Message to log</param>
public static void ConsoleLog(string text)
{
BridgeConnector.Emit("console-stdout", text);
}
/// <summary>
/// Log a message to the console error pipe. This is used when running with "detachedProcess" : true on the electron.manifest.json,
/// as in that case we can't open pipes to read the console output from the child process anymore
/// </summary>
/// <param name="text">Message to log</param>
public static void ConsoleError(string text)
{
BridgeConnector.Emit("console-stderr", text);
}
private readonly JsonSerializer _jsonSerializer = new()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,

View File

@@ -1,5 +1,4 @@
using System;
using System.Threading;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
@@ -16,7 +15,7 @@ namespace ElectronNET.API
{
App.Instance.IsReady = true;
Console.WriteLine("ASP.NET Core host has fully started.");
BridgeConnector.Log("ASP.NET Core host has fully started.");
});
}

32
ElectronNET.API/Menu.cs Normal file → Executable file
View File

@@ -6,16 +6,17 @@ using System.Collections.Generic;
using ElectronNET.API.Extensions;
using System.Linq;
using System.Collections.ObjectModel;
using ElectronNET.API.Interfaces;
namespace ElectronNET.API
{
/// <summary>
/// Create native application menus and context menus.
/// </summary>
public sealed class Menu
public sealed class Menu : IMenu
{
private static Menu _menu;
private static object _syncRoot = new object();
private static readonly object _syncRoot = new();
internal Menu() { }
@@ -45,7 +46,7 @@ namespace ElectronNET.API
/// The menu items.
/// </value>
public IReadOnlyCollection<MenuItem> MenuItems { get { return _menuItems.AsReadOnly(); } }
private List<MenuItem> _menuItems = new List<MenuItem>();
private readonly List<MenuItem> _menuItems = new();
/// <summary>
/// Sets the application menu.
@@ -58,12 +59,12 @@ namespace ElectronNET.API
menuItems.AddMenuItemsId();
menuItems.AddSubmenuTypes();
BridgeConnector.Socket.Emit("menu-setApplicationMenu", JArray.FromObject(menuItems, _jsonSerializer));
BridgeConnector.Emit("menu-setApplicationMenu", JArray.FromObject(menuItems, _jsonSerializer));
_menuItems.AddRange(menuItems);
BridgeConnector.Socket.Off("menuItemClicked");
BridgeConnector.Socket.On("menuItemClicked", (id) => {
MenuItem menuItem = _menuItems.GetMenuItem(id.ToString());
BridgeConnector.Off("menuItemClicked");
BridgeConnector.On<string>("menuItemClicked", (id) => {
MenuItem menuItem = _menuItems.GetMenuItem(id);
menuItem.Click?.Invoke();
});
}
@@ -75,7 +76,7 @@ namespace ElectronNET.API
/// The context menu items.
/// </value>
public IReadOnlyDictionary<int, ReadOnlyCollection<MenuItem>> ContextMenuItems { get; internal set; }
private Dictionary<int, List<MenuItem>> _contextMenuItems = new Dictionary<int, List<MenuItem>>();
private readonly Dictionary<int, List<MenuItem>> _contextMenuItems = new();
/// <summary>
/// Sets the context menu.
@@ -87,7 +88,7 @@ namespace ElectronNET.API
menuItems.AddMenuItemsId();
menuItems.AddSubmenuTypes();
BridgeConnector.Socket.Emit("menu-setContextMenu", browserWindow.Id, JArray.FromObject(menuItems, _jsonSerializer));
BridgeConnector.Emit("menu-setContextMenu", browserWindow.Id, JArray.FromObject(menuItems, _jsonSerializer));
if (!_contextMenuItems.ContainsKey(browserWindow.Id))
{
@@ -96,13 +97,10 @@ namespace ElectronNET.API
ContextMenuItems = new ReadOnlyDictionary<int, ReadOnlyCollection<MenuItem>>(x);
}
BridgeConnector.Socket.Off("contextMenuItemClicked");
BridgeConnector.Socket.On("contextMenuItemClicked", (results) =>
BridgeConnector.Off("contextMenuItemClicked");
BridgeConnector.On<MenuResponse>("contextMenuItemClicked", (results) =>
{
var id = ((JArray)results).First.ToString();
var browserWindowId = (int)((JArray)results).Last;
MenuItem menuItem = _contextMenuItems[browserWindowId].GetMenuItem(id);
MenuItem menuItem = _contextMenuItems[results.windowId].GetMenuItem(results.id);
menuItem.Click?.Invoke();
});
}
@@ -113,10 +111,10 @@ namespace ElectronNET.API
/// <param name="browserWindow">The browser window.</param>
public void ContextMenuPopup(BrowserWindow browserWindow)
{
BridgeConnector.Socket.Emit("menu-contextMenuPopup", browserWindow.Id);
BridgeConnector.Emit("menu-contextMenuPopup", browserWindow.Id);
}
private JsonSerializer _jsonSerializer = new JsonSerializer()
private readonly JsonSerializer _jsonSerializer = new()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore

View File

@@ -0,0 +1,8 @@
namespace ElectronNET.API
{
internal class MenuResponse
{
public string id { get; set; }
public int windowId { get; set; }
}
}

81
ElectronNET.API/NativeTheme.cs Normal file → Executable file
View File

@@ -1,17 +1,19 @@
using System;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using ElectronNET.API.Entities;
using ElectronNET.API.Extensions;
using ElectronNET.API.Interfaces;
namespace ElectronNET.API
{
/// <summary>
/// Read and respond to changes in Chromium's native color theme.
/// </summary>
public sealed class NativeTheme
public sealed class NativeTheme : INativeTheme
{
private static NativeTheme _nativeTheme;
private static object _syncRoot = new object();
private static readonly object _syncRoot = new();
internal NativeTheme() { }
@@ -94,88 +96,37 @@ namespace ElectronNET.API
{
var themeSource = themeSourceMode.GetDescription();
BridgeConnector.Socket.Emit("nativeTheme-themeSource", themeSource);
BridgeConnector.Emit("nativeTheme-themeSource", themeSource);
}
/// <summary>
/// A <see cref="ThemeSourceMode"/> property that can be <see cref="ThemeSourceMode.System"/>, <see cref="ThemeSourceMode.Light"/> or <see cref="ThemeSourceMode.Dark"/>. It is used to override (<seealso cref="SetThemeSource"/>) and
/// supercede the value that Chromium has chosen to use internally.
/// </summary>
public Task<ThemeSourceMode> GetThemeSourceAsync()
{
var taskCompletionSource = new TaskCompletionSource<ThemeSourceMode>();
BridgeConnector.Socket.On("nativeTheme-themeSource-getCompleted", (themeSource) =>
{
BridgeConnector.Socket.Off("nativeTheme-themeSource-getCompleted");
var themeSourceValue = (ThemeSourceMode)Enum.Parse(typeof(ThemeSourceMode), (string)themeSource, true);
taskCompletionSource.SetResult(themeSourceValue);
});
BridgeConnector.Socket.Emit("nativeTheme-themeSource-get");
return taskCompletionSource.Task;
}
public async Task<ThemeSourceMode> GetThemeSourceAsync() => Enum.Parse<ThemeSourceMode>(await BridgeConnector.OnResult<string>("nativeTheme-themeSource-get", "nativeTheme-themeSource-getCompleted"), true);
/// <summary>
/// A <see cref="bool"/> for if the OS / Chromium currently has a dark mode enabled or is
/// being instructed to show a dark-style UI. If you want to modify this value you
/// should use <see cref="SetThemeSource"/>.
/// </summary>
public Task<bool> ShouldUseDarkColorsAsync()
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("nativeTheme-shouldUseDarkColors-completed", (shouldUseDarkColors) => {
BridgeConnector.Socket.Off("nativeTheme-shouldUseDarkColors-completed");
taskCompletionSource.SetResult((bool)shouldUseDarkColors);
});
BridgeConnector.Socket.Emit("nativeTheme-shouldUseDarkColors");
return taskCompletionSource.Task;
}
public Task<bool> ShouldUseDarkColorsAsync() => BridgeConnector.OnResult<bool>("nativeTheme-shouldUseDarkColors", "nativeTheme-shouldUseDarkColors-completed");
/// <summary>
/// A <see cref="bool"/> for if the OS / Chromium currently has high-contrast mode enabled or is
/// being instructed to show a high-contrast UI.
/// </summary>
public Task<bool> ShouldUseHighContrastColorsAsync()
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("nativeTheme-shouldUseHighContrastColors-completed", (shouldUseHighContrastColors) => {
BridgeConnector.Socket.Off("nativeTheme-shouldUseHighContrastColors-completed");
taskCompletionSource.SetResult((bool)shouldUseHighContrastColors);
});
BridgeConnector.Socket.Emit("nativeTheme-shouldUseHighContrastColors");
return taskCompletionSource.Task;
}
[SupportedOSPlatform("windows")]
[SupportedOSPlatform("macos")]
public Task<bool> ShouldUseHighContrastColorsAsync() => BridgeConnector.OnResult<bool>("nativeTheme-shouldUseHighContrastColors", "nativeTheme-shouldUseHighContrastColors-completed");
/// <summary>
/// A <see cref="bool"/> for if the OS / Chromium currently has an inverted color scheme or is
/// being instructed to use an inverted color scheme.
/// </summary>
public Task<bool> ShouldUseInvertedColorSchemeAsync()
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("nativeTheme-shouldUseInvertedColorScheme-completed", (shouldUseInvertedColorScheme) => {
BridgeConnector.Socket.Off("nativeTheme-shouldUseInvertedColorScheme-completed");
taskCompletionSource.SetResult((bool)shouldUseInvertedColorScheme);
});
BridgeConnector.Socket.Emit("nativeTheme-shouldUseInvertedColorScheme");
return taskCompletionSource.Task;
}
[SupportedOSPlatform("windows")]
[SupportedOSPlatform("macos")]
public Task<bool> ShouldUseInvertedColorSchemeAsync() => BridgeConnector.OnResult<bool>("nativeTheme-shouldUseInvertedColorScheme", "nativeTheme-shouldUseInvertedColorScheme-completed");
/// <summary>
/// Emitted when something in the underlying NativeTheme has changed. This normally means that either the value of <see cref="ShouldUseDarkColorsAsync"/>,
@@ -187,12 +138,12 @@ namespace ElectronNET.API
{
if (_updated == null)
{
BridgeConnector.Socket.On("nativeTheme-updated" + GetHashCode(), () =>
BridgeConnector.On("nativeTheme-updated" + GetHashCode(), () =>
{
_updated();
});
BridgeConnector.Socket.Emit("register-nativeTheme-updated-event", GetHashCode());
BridgeConnector.Emit("register-nativeTheme-updated-event", GetHashCode());
}
_updated += value;
}
@@ -202,7 +153,7 @@ namespace ElectronNET.API
if (_updated == null)
{
BridgeConnector.Socket.Off("nativeTheme-updated" + GetHashCode());
BridgeConnector.Off("nativeTheme-updated" + GetHashCode());
}
}
}

51
ElectronNET.API/Notification.cs Normal file → Executable file
View File

@@ -6,16 +6,17 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ElectronNET.API.Interfaces;
namespace ElectronNET.API
{
/// <summary>
/// Create OS desktop notifications
/// </summary>
public sealed class Notification
public sealed class Notification : INotification
{
private static Notification _notification;
private static object _syncRoot = new object();
private static readonly object _syncRoot = new();
internal Notification() { }
@@ -38,7 +39,7 @@ namespace ElectronNET.API
}
}
private static List<NotificationOptions> _notificationOptions = new List<NotificationOptions>();
private static readonly List<NotificationOptions> _notificationOptions = new();
/// <summary>
/// Create OS desktop notifications
@@ -48,7 +49,7 @@ namespace ElectronNET.API
{
GenerateIDsForDefinedActions(notificationOptions);
BridgeConnector.Socket.Emit("createNotification", JObject.FromObject(notificationOptions, _jsonSerializer));
BridgeConnector.Emit("createNotification", JObject.FromObject(notificationOptions, _jsonSerializer));
}
private static void GenerateIDsForDefinedActions(NotificationOptions notificationOptions)
@@ -60,9 +61,9 @@ namespace ElectronNET.API
notificationOptions.ShowID = Guid.NewGuid().ToString();
isActionDefined = true;
BridgeConnector.Socket.Off("NotificationEventShow");
BridgeConnector.Socket.On("NotificationEventShow", (id) => {
_notificationOptions.Single(x => x.ShowID == id.ToString()).OnShow();
BridgeConnector.Off("NotificationEventShow");
BridgeConnector.On<string>("NotificationEventShow", (id) => {
_notificationOptions.Single(x => x.ShowID == id).OnShow();
});
}
@@ -71,9 +72,9 @@ namespace ElectronNET.API
notificationOptions.ClickID = Guid.NewGuid().ToString();
isActionDefined = true;
BridgeConnector.Socket.Off("NotificationEventClick");
BridgeConnector.Socket.On("NotificationEventClick", (id) => {
_notificationOptions.Single(x => x.ClickID == id.ToString()).OnClick();
BridgeConnector.Off("NotificationEventClick");
BridgeConnector.On<string>("NotificationEventClick", (id) => {
_notificationOptions.Single(x => x.ClickID == id).OnClick();
});
}
@@ -82,8 +83,8 @@ namespace ElectronNET.API
notificationOptions.CloseID = Guid.NewGuid().ToString();
isActionDefined = true;
BridgeConnector.Socket.Off("NotificationEventClose");
BridgeConnector.Socket.On("NotificationEventClose", (id) => {
BridgeConnector.Off("NotificationEventClose");
BridgeConnector.On<string>("NotificationEventClose", (id) => {
_notificationOptions.Single(x => x.CloseID == id.ToString()).OnClose();
});
}
@@ -93,10 +94,9 @@ namespace ElectronNET.API
notificationOptions.ReplyID = Guid.NewGuid().ToString();
isActionDefined = true;
BridgeConnector.Socket.Off("NotificationEventReply");
BridgeConnector.Socket.On("NotificationEventReply", (args) => {
var arguments = ((JArray)args).ToObject<string[]>();
_notificationOptions.Single(x => x.ReplyID == arguments[0].ToString()).OnReply(arguments[1].ToString());
BridgeConnector.Off("NotificationEventReply");
BridgeConnector.On<string[]>("NotificationEventReply", (args) => {
_notificationOptions.Single(x => x.ReplyID == args[0].ToString()).OnReply(args[1].ToString());
});
}
@@ -105,10 +105,9 @@ namespace ElectronNET.API
notificationOptions.ActionID = Guid.NewGuid().ToString();
isActionDefined = true;
BridgeConnector.Socket.Off("NotificationEventAction");
BridgeConnector.Socket.On("NotificationEventAction", (args) => {
var arguments = ((JArray)args).ToObject<string[]>();
_notificationOptions.Single(x => x.ReplyID == arguments[0].ToString()).OnAction(arguments[1].ToString());
BridgeConnector.Off("NotificationEventAction");
BridgeConnector.On<string[]>("NotificationEventAction", (args) => {
_notificationOptions.Single(x => x.ReplyID == args[0].ToString()).OnAction(args[1].ToString());
});
}
@@ -124,20 +123,20 @@ namespace ElectronNET.API
/// <returns></returns>
public Task<bool> IsSupportedAsync()
{
var taskCompletionSource = new TaskCompletionSource<bool>();
var taskCompletionSource = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
BridgeConnector.Socket.On("notificationIsSupportedComplete", (isSupported) =>
BridgeConnector.On<bool>("notificationIsSupportedComplete", (isSupported) =>
{
BridgeConnector.Socket.Off("notificationIsSupportedComplete");
taskCompletionSource.SetResult((bool)isSupported);
BridgeConnector.Off("notificationIsSupportedComplete");
taskCompletionSource.SetResult(isSupported);
});
BridgeConnector.Socket.Emit("notificationIsSupported");
BridgeConnector.Emit("notificationIsSupported");
return taskCompletionSource.Task;
}
private JsonSerializer _jsonSerializer = new JsonSerializer()
private static readonly JsonSerializer _jsonSerializer = new()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,

63
ElectronNET.API/PowerMonitor.cs Normal file → Executable file
View File

@@ -1,28 +1,32 @@
using System;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using ElectronNET.API.Interfaces;
namespace ElectronNET.API
{
/// <summary>
/// Monitor power state changes..
/// </summary>
public sealed class PowerMonitor
public sealed class PowerMonitor : IPowerMonitor
{
/// <summary>
/// Emitted when the system is about to lock the screen.
/// </summary>
[SupportedOSPlatform("windows")]
[SupportedOSPlatform("macos")]
public event Action OnLockScreen
{
add
{
if (_lockScreen == null)
{
BridgeConnector.Socket.On("pm-lock-screen" , () =>
BridgeConnector.On("pm-lock-screen" , () =>
{
_lockScreen();
});
BridgeConnector.Socket.Emit("register-pm-lock-screen");
BridgeConnector.Emit("register-pm-lock-screen");
}
_lockScreen += value;
}
@@ -31,7 +35,7 @@ namespace ElectronNET.API
_lockScreen -= value;
if (_lockScreen == null)
BridgeConnector.Socket.Off("pm-lock-screen");
BridgeConnector.Off("pm-lock-screen");
}
}
@@ -40,18 +44,20 @@ namespace ElectronNET.API
/// <summary>
/// Emitted when the system is about to unlock the screen.
/// </summary>
[SupportedOSPlatform("windows")]
[SupportedOSPlatform("macos")]
public event Action OnUnLockScreen
{
add
{
if (_unlockScreen == null)
{
BridgeConnector.Socket.On("pm-unlock-screen", () =>
BridgeConnector.On("pm-unlock-screen", () =>
{
_unlockScreen();
});
BridgeConnector.Socket.Emit("register-pm-unlock-screen");
BridgeConnector.Emit("register-pm-unlock-screen");
}
_unlockScreen += value;
}
@@ -60,7 +66,7 @@ namespace ElectronNET.API
_unlockScreen -= value;
if (_unlockScreen == null)
BridgeConnector.Socket.Off("pm-unlock-screen");
BridgeConnector.Off("pm-unlock-screen");
}
}
@@ -69,18 +75,20 @@ namespace ElectronNET.API
/// <summary>
/// Emitted when the system is suspending.
/// </summary>
[SupportedOSPlatform("windows")]
[SupportedOSPlatform("macos")]
public event Action OnSuspend
{
add
{
if (_suspend == null)
{
BridgeConnector.Socket.On("pm-suspend", () =>
BridgeConnector.On("pm-suspend", () =>
{
_suspend();
});
BridgeConnector.Socket.Emit("register-pm-suspend");
BridgeConnector.Emit("register-pm-suspend");
}
_suspend += value;
}
@@ -89,7 +97,7 @@ namespace ElectronNET.API
_suspend -= value;
if (_suspend == null)
BridgeConnector.Socket.Off("pm-suspend");
BridgeConnector.Off("pm-suspend");
}
}
@@ -98,18 +106,20 @@ namespace ElectronNET.API
/// <summary>
/// Emitted when system is resuming.
/// </summary>
[SupportedOSPlatform("windows")]
[SupportedOSPlatform("macos")]
public event Action OnResume
{
add
{
if (_resume == null)
{
BridgeConnector.Socket.On("pm-resume", () =>
BridgeConnector.On("pm-resume", () =>
{
_resume();
});
BridgeConnector.Socket.Emit("register-pm-resume");
BridgeConnector.Emit("register-pm-resume");
}
_resume += value;
}
@@ -118,7 +128,7 @@ namespace ElectronNET.API
_resume -= value;
if (_resume == null)
BridgeConnector.Socket.Off("pm-resume");
BridgeConnector.Off("pm-resume");
}
}
@@ -127,18 +137,20 @@ namespace ElectronNET.API
/// <summary>
/// Emitted when the system changes to AC power.
/// </summary>
[SupportedOSPlatform("windows")]
[SupportedOSPlatform("macos")]
public event Action OnAC
{
add
{
if (_onAC == null)
{
BridgeConnector.Socket.On("pm-on-ac", () =>
BridgeConnector.On("pm-on-ac", () =>
{
_onAC();
});
BridgeConnector.Socket.Emit("register-pm-on-ac");
BridgeConnector.Emit("register-pm-on-ac");
}
_onAC += value;
}
@@ -147,7 +159,7 @@ namespace ElectronNET.API
_onAC -= value;
if (_onAC == null)
BridgeConnector.Socket.Off("pm-on-ac");
BridgeConnector.Off("pm-on-ac");
}
}
@@ -156,18 +168,20 @@ namespace ElectronNET.API
/// <summary>
/// Emitted when system changes to battery power.
/// </summary>
[SupportedOSPlatform("windows")]
[SupportedOSPlatform("macos")]
public event Action OnBattery
{
add
{
if (_onBattery == null)
{
BridgeConnector.Socket.On("pm-on-battery", () =>
BridgeConnector.On("pm-on-battery", () =>
{
_onBattery();
});
BridgeConnector.Socket.Emit("register-pm-on-battery");
BridgeConnector.Emit("register-pm-on-battery");
}
_onBattery += value;
}
@@ -176,7 +190,7 @@ namespace ElectronNET.API
_onBattery -= value;
if (_onBattery == null)
BridgeConnector.Socket.Off("pm-on-battery");
BridgeConnector.Off("pm-on-battery");
}
}
@@ -189,18 +203,21 @@ namespace ElectronNET.API
/// order for the app to exit cleanly.If `e.preventDefault()` is called, the app
/// should exit as soon as possible by calling something like `app.quit()`.
/// </summary>
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public event Action OnShutdown
{
add
{
if (_shutdown == null)
{
BridgeConnector.Socket.On("pm-shutdown", () =>
BridgeConnector.On("pm-shutdown", () =>
{
_shutdown();
});
BridgeConnector.Socket.Emit("register-pm-shutdown");
BridgeConnector.Emit("register-pm-shutdown");
}
_shutdown += value;
}
@@ -209,14 +226,14 @@ namespace ElectronNET.API
_shutdown -= value;
if (_shutdown == null)
BridgeConnector.Socket.Off("pm-on-shutdown");
BridgeConnector.Off("pm-on-shutdown");
}
}
private event Action _shutdown;
private static PowerMonitor _powerMonitor;
private static object _syncRoot = new object();
private static readonly object _syncRoot = new();
internal PowerMonitor() { }

View File

@@ -0,0 +1,37 @@
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace ElectronNET.API
{
internal class ProcessHelper
{
public static void Execute(string command, string workingDirectoryPath)
{
using (Process cmd = new Process())
{
bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
if (isWindows)
{
cmd.StartInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
}
else
{
// works for OSX and Linux (at least on Ubuntu)
var escapedArgs = command.Replace("\"", "\\\"");
cmd.StartInfo = new ProcessStartInfo("bash", $"-c \"{escapedArgs}\"");
}
cmd.StartInfo.RedirectStandardInput = false;
cmd.StartInfo.RedirectStandardOutput = false;
cmd.StartInfo.RedirectStandardError = false;
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.UseShellExecute = false;
cmd.StartInfo.WorkingDirectory = workingDirectoryPath;
cmd.Start();
}
}
}
}

134
ElectronNET.API/Screen.cs Normal file → Executable file
View File

@@ -4,13 +4,14 @@ using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System;
using System.Threading.Tasks;
using ElectronNET.API.Interfaces;
namespace ElectronNET.API
{
/// <summary>
/// Retrieve information about screen size, displays, cursor position, etc.
/// </summary>
public sealed class Screen
public sealed class Screen : IScreen
{
/// <summary>
/// Emitted when an new Display has been added.
@@ -21,12 +22,12 @@ namespace ElectronNET.API
{
if (_onDisplayAdded == null)
{
BridgeConnector.Socket.On("screen-display-added-event" + GetHashCode(), (display) =>
BridgeConnector.On<Display>("screen-display-added-event" + GetHashCode(), (display) =>
{
_onDisplayAdded(((JObject)display).ToObject<Display>());
_onDisplayAdded(display);
});
BridgeConnector.Socket.Emit("register-screen-display-added", GetHashCode());
BridgeConnector.Emit("register-screen-display-added", GetHashCode());
}
_onDisplayAdded += value;
}
@@ -35,7 +36,7 @@ namespace ElectronNET.API
_onDisplayAdded -= value;
if (_onDisplayAdded == null)
BridgeConnector.Socket.Off("screen-display-added-event" + GetHashCode());
BridgeConnector.Off("screen-display-added-event" + GetHashCode());
}
}
@@ -50,12 +51,12 @@ namespace ElectronNET.API
{
if (_onDisplayRemoved == null)
{
BridgeConnector.Socket.On("screen-display-removed-event" + GetHashCode(), (display) =>
BridgeConnector.On<Display>("screen-display-removed-event" + GetHashCode(), (display) =>
{
_onDisplayRemoved(((JObject)display).ToObject<Display>());
_onDisplayRemoved(display);
});
BridgeConnector.Socket.Emit("register-screen-display-removed", GetHashCode());
BridgeConnector.Emit("register-screen-display-removed", GetHashCode());
}
_onDisplayRemoved += value;
}
@@ -64,7 +65,7 @@ namespace ElectronNET.API
_onDisplayRemoved -= value;
if (_onDisplayRemoved == null)
BridgeConnector.Socket.Off("screen-display-removed-event" + GetHashCode());
BridgeConnector.Off("screen-display-removed-event" + GetHashCode());
}
}
@@ -81,15 +82,12 @@ namespace ElectronNET.API
{
if (_onDisplayMetricsChanged == null)
{
BridgeConnector.Socket.On("screen-display-metrics-changed-event" + GetHashCode(), (args) =>
BridgeConnector.On<DisplayChanged>("screen-display-metrics-changed-event" + GetHashCode(), (args) =>
{
var display = ((JArray)args).First.ToObject<Display>();
var metrics = ((JArray)args).Last.ToObject<string[]>();
_onDisplayMetricsChanged(display, metrics);
_onDisplayMetricsChanged(args.display, args.metrics);
});
BridgeConnector.Socket.Emit("register-screen-display-metrics-changed", GetHashCode());
BridgeConnector.Emit("register-screen-display-metrics-changed", GetHashCode());
}
_onDisplayMetricsChanged += value;
}
@@ -98,14 +96,14 @@ namespace ElectronNET.API
_onDisplayMetricsChanged -= value;
if (_onDisplayMetricsChanged == null)
BridgeConnector.Socket.Off("screen-display-metrics-changed-event" + GetHashCode());
BridgeConnector.Off("screen-display-metrics-changed-event" + GetHashCode());
}
}
private event Action<Display, string[]> _onDisplayMetricsChanged;
private static Screen _screen;
private static object _syncRoot = new object();
private static readonly object _syncRoot = new();
internal Screen() { }
@@ -132,128 +130,38 @@ namespace ElectronNET.API
/// The current absolute position of the mouse pointer.
/// </summary>
/// <returns></returns>
public Task<Point> GetCursorScreenPointAsync()
{
var taskCompletionSource = new TaskCompletionSource<Point>();
BridgeConnector.Socket.On("screen-getCursorScreenPointCompleted", (point) =>
{
BridgeConnector.Socket.Off("screen-getCursorScreenPointCompleted");
taskCompletionSource.SetResult(((JObject)point).ToObject<Point>());
});
BridgeConnector.Socket.Emit("screen-getCursorScreenPoint");
return taskCompletionSource.Task;
}
public Task<Point> GetCursorScreenPointAsync() => BridgeConnector.OnResult<Point>("screen-getCursorScreenPoint", "screen-getCursorScreenPointCompleted");
/// <summary>
/// macOS: The height of the menu bar in pixels.
/// </summary>
/// <returns>The height of the menu bar in pixels.</returns>
public Task<int> GetMenuBarHeightAsync()
{
var taskCompletionSource = new TaskCompletionSource<int>();
BridgeConnector.Socket.On("screen-getMenuBarHeightCompleted", (height) =>
{
BridgeConnector.Socket.Off("screen-getMenuBarHeightCompleted");
taskCompletionSource.SetResult(int.Parse(height.ToString()));
});
BridgeConnector.Socket.Emit("screen-getMenuBarHeight");
return taskCompletionSource.Task;
}
public Task<int> GetMenuBarHeightAsync() => BridgeConnector.OnResult<int>("screen-getMenuBarHeight", "screen-getMenuBarHeightCompleted");
/// <summary>
/// The primary display.
/// </summary>
/// <returns></returns>
public Task<Display> GetPrimaryDisplayAsync()
{
var taskCompletionSource = new TaskCompletionSource<Display>();
public Task<Display> GetPrimaryDisplayAsync() => BridgeConnector.OnResult<Display>("screen-getPrimaryDisplay", "screen-getPrimaryDisplayCompleted");
BridgeConnector.Socket.On("screen-getPrimaryDisplayCompleted", (display) =>
{
BridgeConnector.Socket.Off("screen-getPrimaryDisplayCompleted");
taskCompletionSource.SetResult(((JObject)display).ToObject<Display>());
});
BridgeConnector.Socket.Emit("screen-getPrimaryDisplay");
return taskCompletionSource.Task;
}
/// <summary>
/// An array of displays that are currently available.
/// </summary>
/// <returns>An array of displays that are currently available.</returns>
public Task<Display[]> GetAllDisplaysAsync()
{
var taskCompletionSource = new TaskCompletionSource<Display[]>();
BridgeConnector.Socket.On("screen-getAllDisplaysCompleted", (displays) =>
{
BridgeConnector.Socket.Off("screen-getAllDisplaysCompleted");
taskCompletionSource.SetResult(((JArray)displays).ToObject<Display[]>());
});
BridgeConnector.Socket.Emit("screen-getAllDisplays");
return taskCompletionSource.Task;
}
public Task<Display[]> GetAllDisplaysAsync() => BridgeConnector.OnResult<Display[]>("screen-getAllDisplays", "screen-getAllDisplaysCompleted");
/// <summary>
/// The display nearest the specified point.
/// </summary>
/// <returns>The display nearest the specified point.</returns>
public Task<Display> GetDisplayNearestPointAsync(Point point)
{
var taskCompletionSource = new TaskCompletionSource<Display>();
BridgeConnector.Socket.On("screen-getDisplayNearestPointCompleted", (display) =>
{
BridgeConnector.Socket.Off("screen-getDisplayNearestPointCompleted");
taskCompletionSource.SetResult(((JObject)display).ToObject<Display>());
});
BridgeConnector.Socket.Emit("screen-getDisplayNearestPoint", JObject.FromObject(point, _jsonSerializer));
return taskCompletionSource.Task;
}
public Task<Display> GetDisplayNearestPointAsync(Point point) => BridgeConnector.OnResult<Display>("screen-getDisplayNearestPoint", "screen-getDisplayNearestPointCompleted", point);
/// <summary>
/// The display that most closely intersects the provided bounds.
/// </summary>
/// <param name="rectangle"></param>
/// <returns>The display that most closely intersects the provided bounds.</returns>
public Task<Display> GetDisplayMatchingAsync(Rectangle rectangle)
{
var taskCompletionSource = new TaskCompletionSource<Display>();
BridgeConnector.Socket.On("screen-getDisplayMatching", (display) =>
{
BridgeConnector.Socket.Off("screen-getDisplayMatching");
taskCompletionSource.SetResult(((JObject)display).ToObject<Display>());
});
BridgeConnector.Socket.Emit("screen-getDisplayMatching", JObject.FromObject(rectangle, _jsonSerializer));
return taskCompletionSource.Task;
}
private JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
public Task<Display> GetDisplayMatchingAsync(Rectangle rectangle) => BridgeConnector.OnResult<Display>("screen-getDisplayMatching", "screen-getDisplayMatchingCompleted", rectangle);
}
}

View File

@@ -0,0 +1,52 @@
using ElectronNET.API.Interfaces;
using Microsoft.Extensions.DependencyInjection;
namespace ElectronNET.API
{
/// <summary>
///
/// </summary>
public static class ServiceCollectionExtensions
{
/// <summary>
/// Adds the <see cref="Electron"/> Members to the Service Collection
/// </summary>
public static IServiceCollection AddElectron(this IServiceCollection services)
=> services
// adding in this manner to ensure late binding.
// this set for backwards compatibility
.AddSingleton(provider => IpcMain.Instance)
.AddSingleton(provider => App.Instance)
.AddSingleton(provider => AutoUpdater.Instance)
.AddSingleton(provider => WindowManager.Instance)
.AddSingleton(provider => Menu.Instance)
.AddSingleton(provider => Dialog.Instance)
.AddSingleton(provider => Notification.Instance)
.AddSingleton(provider => Tray.Instance)
.AddSingleton(provider => GlobalShortcut.Instance)
.AddSingleton(provider => Shell.Instance)
.AddSingleton(provider => Screen.Instance)
.AddSingleton(provider => Clipboard.Instance)
.AddSingleton(provider => HostHook.Instance)
.AddSingleton(provider => PowerMonitor.Instance)
.AddSingleton(provider => NativeTheme.Instance)
.AddSingleton(provider => Dock.Instance)
// this set for proper dependency injection
.AddSingleton<IIpcMain>(_ => IpcMain.Instance)
.AddSingleton<IApp>(_ => App.Instance)
.AddSingleton<IAutoUpdater>(_ => AutoUpdater.Instance)
.AddSingleton<IWindowManager>(_ => WindowManager.Instance)
.AddSingleton<IMenu>(_ => Menu.Instance)
.AddSingleton<IDialog>(_ => Dialog.Instance)
.AddSingleton<INotification>(_ => Notification.Instance)
.AddSingleton<ITray>(_ => Tray.Instance)
.AddSingleton<IGlobalShortcut>(_ => GlobalShortcut.Instance)
.AddSingleton<IShell>(_ => Shell.Instance)
.AddSingleton<IScreen>(_ => Screen.Instance)
.AddSingleton<IClipboard>(_ => Clipboard.Instance)
.AddSingleton<IHostHook>(_ => HostHook.Instance)
.AddSingleton<IPowerMonitor>(_ => PowerMonitor.Instance)
.AddSingleton<INativeTheme>(_ => NativeTheme.Instance)
.AddSingleton<IDock>(_ => Dock.Instance);
}
}

View File

@@ -37,7 +37,7 @@ namespace ElectronNET.API
/// <param name="domains">A comma-separated list of servers for which integrated authentication is enabled.</param>
public void AllowNTLMCredentialsForDomains(string domains)
{
BridgeConnector.Socket.Emit("webContents-session-allowNTLMCredentialsForDomains", Id, domains);
BridgeConnector.Emit("webContents-session-allowNTLMCredentialsForDomains", Id, domains);
}
/// <summary>
@@ -47,16 +47,16 @@ namespace ElectronNET.API
/// <returns></returns>
public Task ClearAuthCacheAsync(RemovePassword options)
{
var taskCompletionSource = new TaskCompletionSource<object>();
var taskCompletionSource = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-clearAuthCache-completed" + guid, () =>
BridgeConnector.On("webContents-session-clearAuthCache-completed" + guid, () =>
{
BridgeConnector.Socket.Off("webContents-session-clearAuthCache-completed" + guid);
BridgeConnector.Off("webContents-session-clearAuthCache-completed" + guid);
taskCompletionSource.SetResult(null);
});
BridgeConnector.Socket.Emit("webContents-session-clearAuthCache", Id, JObject.FromObject(options, _jsonSerializer), guid);
BridgeConnector.Emit("webContents-session-clearAuthCache", Id, options, guid);
return taskCompletionSource.Task;
}
@@ -64,19 +64,18 @@ namespace ElectronNET.API
/// <summary>
/// Clears the sessions HTTP authentication cache.
/// </summary>
/// <param name="options"></param>
public Task ClearAuthCacheAsync(RemoveClientCertificate options)
public Task ClearAuthCacheAsync()
{
var taskCompletionSource = new TaskCompletionSource<object>();
var taskCompletionSource = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-clearAuthCache-completed" + guid, () =>
BridgeConnector.On("webContents-session-clearAuthCache-completed" + guid, () =>
{
BridgeConnector.Socket.Off("webContents-session-clearAuthCache-completed" + guid);
BridgeConnector.Off("webContents-session-clearAuthCache-completed" + guid);
taskCompletionSource.SetResult(null);
});
BridgeConnector.Socket.Emit("webContents-session-clearAuthCache", Id, JObject.FromObject(options, _jsonSerializer), guid);
BridgeConnector.Emit("webContents-session-clearAuthCache", Id, guid);
return taskCompletionSource.Task;
}
@@ -87,16 +86,16 @@ namespace ElectronNET.API
/// <returns></returns>
public Task ClearCacheAsync()
{
var taskCompletionSource = new TaskCompletionSource<object>();
var taskCompletionSource = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-clearCache-completed" + guid, () =>
BridgeConnector.On("webContents-session-clearCache-completed" + guid, () =>
{
BridgeConnector.Socket.Off("webContents-session-clearCache-completed" + guid);
BridgeConnector.Off("webContents-session-clearCache-completed" + guid);
taskCompletionSource.SetResult(null);
});
BridgeConnector.Socket.Emit("webContents-session-clearCache", Id, guid);
BridgeConnector.Emit("webContents-session-clearCache", Id, guid);
return taskCompletionSource.Task;
}
@@ -107,16 +106,16 @@ namespace ElectronNET.API
/// <returns></returns>
public Task ClearHostResolverCacheAsync()
{
var taskCompletionSource = new TaskCompletionSource<object>();
var taskCompletionSource = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-clearHostResolverCache-completed" + guid, () =>
BridgeConnector.On("webContents-session-clearHostResolverCache-completed" + guid, () =>
{
BridgeConnector.Socket.Off("webContents-session-clearHostResolverCache-completed" + guid);
BridgeConnector.Off("webContents-session-clearHostResolverCache-completed" + guid);
taskCompletionSource.SetResult(null);
});
BridgeConnector.Socket.Emit("webContents-session-clearHostResolverCache", Id, guid);
BridgeConnector.Emit("webContents-session-clearHostResolverCache", Id, guid);
return taskCompletionSource.Task;
}
@@ -127,16 +126,16 @@ namespace ElectronNET.API
/// <returns></returns>
public Task ClearStorageDataAsync()
{
var taskCompletionSource = new TaskCompletionSource<object>();
var taskCompletionSource = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-clearStorageData-completed" + guid, () =>
BridgeConnector.On("webContents-session-clearStorageData-completed" + guid, () =>
{
BridgeConnector.Socket.Off("webContents-session-clearStorageData-completed" + guid);
BridgeConnector.Off("webContents-session-clearStorageData-completed" + guid);
taskCompletionSource.SetResult(null);
});
BridgeConnector.Socket.Emit("webContents-session-clearStorageData", Id, guid);
BridgeConnector.Emit("webContents-session-clearStorageData", Id, guid);
return taskCompletionSource.Task;
}
@@ -148,16 +147,16 @@ namespace ElectronNET.API
/// <returns></returns>
public Task ClearStorageDataAsync(ClearStorageDataOptions options)
{
var taskCompletionSource = new TaskCompletionSource<object>();
var taskCompletionSource = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-clearStorageData-options-completed" + guid, () =>
BridgeConnector.On("webContents-session-clearStorageData-options-completed" + guid, () =>
{
BridgeConnector.Socket.Off("webContents-session-clearStorageData-options-completed" + guid);
BridgeConnector.Off("webContents-session-clearStorageData-options-completed" + guid);
taskCompletionSource.SetResult(null);
});
BridgeConnector.Socket.Emit("webContents-session-clearStorageData-options", Id, JObject.FromObject(options, _jsonSerializer), guid);
BridgeConnector.Emit("webContents-session-clearStorageData-options", Id, options, guid);
return taskCompletionSource.Task;
}
@@ -172,7 +171,7 @@ namespace ElectronNET.API
/// <param name="options"></param>
public void CreateInterruptedDownload(CreateInterruptedDownloadOptions options)
{
BridgeConnector.Socket.Emit("webContents-session-createInterruptedDownload", Id, JObject.FromObject(options, _jsonSerializer));
BridgeConnector.Emit("webContents-session-createInterruptedDownload", Id, options);
}
/// <summary>
@@ -181,7 +180,7 @@ namespace ElectronNET.API
/// </summary>
public void DisableNetworkEmulation()
{
BridgeConnector.Socket.Emit("webContents-session-disableNetworkEmulation", Id);
BridgeConnector.Emit("webContents-session-disableNetworkEmulation", Id);
}
/// <summary>
@@ -190,7 +189,7 @@ namespace ElectronNET.API
/// <param name="options"></param>
public void EnableNetworkEmulation(EnableNetworkEmulationOptions options)
{
BridgeConnector.Socket.Emit("webContents-session-enableNetworkEmulation", Id, JObject.FromObject(options, _jsonSerializer));
BridgeConnector.Emit("webContents-session-enableNetworkEmulation", Id, options);
}
/// <summary>
@@ -198,7 +197,7 @@ namespace ElectronNET.API
/// </summary>
public void FlushStorageData()
{
BridgeConnector.Socket.Emit("webContents-session-flushStorageData", Id);
BridgeConnector.Emit("webContents-session-flushStorageData", Id);
}
/// <summary>
@@ -208,18 +207,16 @@ namespace ElectronNET.API
/// <returns></returns>
public Task<int[]> GetBlobDataAsync(string identifier)
{
var taskCompletionSource = new TaskCompletionSource<int[]>();
var taskCompletionSource = new TaskCompletionSource<int[]>(TaskCreationOptions.RunContinuationsAsynchronously);
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-getBlobData-completed" + guid, (buffer) =>
BridgeConnector.On<int[]>("webContents-session-getBlobData-completed" + guid, (buffer) =>
{
var result = ((JArray)buffer).ToObject<int[]>();
BridgeConnector.Socket.Off("webContents-session-getBlobData-completed" + guid);
taskCompletionSource.SetResult(result);
BridgeConnector.Off("webContents-session-getBlobData-completed" + guid);
taskCompletionSource.SetResult(buffer);
});
BridgeConnector.Socket.Emit("webContents-session-getBlobData", Id, identifier, guid);
BridgeConnector.Emit("webContents-session-getBlobData", Id, identifier, guid);
return taskCompletionSource.Task;
}
@@ -230,16 +227,16 @@ namespace ElectronNET.API
/// <returns>Callback is invoked with the session's current cache size.</returns>
public Task<int> GetCacheSizeAsync()
{
var taskCompletionSource = new TaskCompletionSource<int>();
var taskCompletionSource = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-getCacheSize-completed" + guid, (size) =>
BridgeConnector.On<int>("webContents-session-getCacheSize-completed" + guid, (size) =>
{
BridgeConnector.Socket.Off("webContents-session-getCacheSize-completed" + guid);
taskCompletionSource.SetResult((int)size);
BridgeConnector.Off("webContents-session-getCacheSize-completed" + guid);
taskCompletionSource.SetResult(size);
});
BridgeConnector.Socket.Emit("webContents-session-getCacheSize", Id, guid);
BridgeConnector.Emit("webContents-session-getCacheSize", Id, guid);
return taskCompletionSource.Task;
}
@@ -250,17 +247,16 @@ namespace ElectronNET.API
/// <returns></returns>
public Task<string[]> GetPreloadsAsync()
{
var taskCompletionSource = new TaskCompletionSource<string[]>();
var taskCompletionSource = new TaskCompletionSource<string[]>(TaskCreationOptions.RunContinuationsAsynchronously);
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-getPreloads-completed" + guid, (preloads) =>
BridgeConnector.On<string[]>("webContents-session-getPreloads-completed" + guid, (preloads) =>
{
var result = ((JArray)preloads).ToObject<string[]>();
BridgeConnector.Socket.Off("webContents-session-getPreloads-completed" + guid);
taskCompletionSource.SetResult(result);
BridgeConnector.Off("webContents-session-getPreloads-completed" + guid);
taskCompletionSource.SetResult(preloads);
});
BridgeConnector.Socket.Emit("webContents-session-getPreloads", Id, guid);
BridgeConnector.Emit("webContents-session-getPreloads", Id, guid);
return taskCompletionSource.Task;
}
@@ -271,16 +267,16 @@ namespace ElectronNET.API
/// <returns></returns>
public Task<string> GetUserAgent()
{
var taskCompletionSource = new TaskCompletionSource<string>();
var taskCompletionSource = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-getUserAgent-completed" + guid, (userAgent) =>
BridgeConnector.On<string>("webContents-session-getUserAgent-completed" + guid, (userAgent) =>
{
BridgeConnector.Socket.Off("webContents-session-getUserAgent-completed" + guid);
BridgeConnector.Off("webContents-session-getUserAgent-completed" + guid);
taskCompletionSource.SetResult(userAgent.ToString());
});
BridgeConnector.Socket.Emit("webContents-session-getUserAgent", Id, guid);
BridgeConnector.Emit("webContents-session-getUserAgent", Id, guid);
return taskCompletionSource.Task;
}
@@ -293,16 +289,16 @@ namespace ElectronNET.API
/// <returns></returns>
public Task<string> ResolveProxyAsync(string url)
{
var taskCompletionSource = new TaskCompletionSource<string>();
var taskCompletionSource = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-resolveProxy-completed" + guid, (proxy) =>
BridgeConnector.On<string>("webContents-session-resolveProxy-completed" + guid, (proxy) =>
{
BridgeConnector.Socket.Off("webContents-session-resolveProxy-completed" + guid);
BridgeConnector.Off("webContents-session-resolveProxy-completed" + guid);
taskCompletionSource.SetResult(proxy.ToString());
});
BridgeConnector.Socket.Emit("webContents-session-resolveProxy", Id, url, guid);
BridgeConnector.Emit("webContents-session-resolveProxy", Id, url, guid);
return taskCompletionSource.Task;
}
@@ -314,7 +310,7 @@ namespace ElectronNET.API
/// <param name="path"></param>
public void SetDownloadPath(string path)
{
BridgeConnector.Socket.Emit("webContents-session-setDownloadPath", Id, path);
BridgeConnector.Emit("webContents-session-setDownloadPath", Id, path);
}
/// <summary>
@@ -324,7 +320,7 @@ namespace ElectronNET.API
/// <param name="preloads"></param>
public void SetPreloads(string[] preloads)
{
BridgeConnector.Socket.Emit("webContents-session-setPreloads", Id, preloads);
BridgeConnector.Emit("webContents-session-setPreloads", Id, preloads);
}
/// <summary>
@@ -335,16 +331,16 @@ namespace ElectronNET.API
/// <returns></returns>
public Task SetProxyAsync(ProxyConfig config)
{
var taskCompletionSource = new TaskCompletionSource<object>();
var taskCompletionSource = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
string guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.On("webContents-session-setProxy-completed" + guid, () =>
BridgeConnector.On("webContents-session-setProxy-completed" + guid, () =>
{
BridgeConnector.Socket.Off("webContents-session-setProxy-completed" + guid);
BridgeConnector.Off("webContents-session-setProxy-completed" + guid);
taskCompletionSource.SetResult(null);
});
BridgeConnector.Socket.Emit("webContents-session-setProxy", Id, JObject.FromObject(config, _jsonSerializer), guid);
BridgeConnector.Emit("webContents-session-setProxy", Id, config, guid);
return taskCompletionSource.Task;
}
@@ -357,7 +353,7 @@ namespace ElectronNET.API
/// <param name="userAgent"></param>
public void SetUserAgent(string userAgent)
{
BridgeConnector.Socket.Emit("webContents-session-setUserAgent", Id, userAgent);
BridgeConnector.Emit("webContents-session-setUserAgent", Id, userAgent);
}
/// <summary>
@@ -373,14 +369,80 @@ namespace ElectronNET.API
/// example "en-US,fr,de,ko,zh-CN,ja".</param>
public void SetUserAgent(string userAgent, string acceptLanguages)
{
BridgeConnector.Socket.Emit("webContents-session-setUserAgent", Id, userAgent, acceptLanguages);
BridgeConnector.Emit("webContents-session-setUserAgent", Id, userAgent, acceptLanguages);
}
private JsonSerializer _jsonSerializer = new JsonSerializer()
/// <summary>
/// The keys are the extension names and each value is an object containing name and version properties.
/// Note: This API cannot be called before the ready event of the app module is emitted.
/// </summary>
/// <returns></returns>
public Task<ChromeExtensionInfo[]> GetAllExtensionsAsync()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
var taskCompletionSource = new TaskCompletionSource<ChromeExtensionInfo[]>(TaskCreationOptions.RunContinuationsAsynchronously);
BridgeConnector.On<ChromeExtensionInfo[]>("webContents-session-getAllExtensions-completed", (extensionslist) =>
{
BridgeConnector.Off("webContents-session-getAllExtensions-completed");
taskCompletionSource.SetResult(extensionslist);
});
BridgeConnector.Emit("webContents-session-getAllExtensions", Id);
return taskCompletionSource.Task;
}
/// <summary>
/// Remove Chrome extension with the specified name.
/// Note: This API cannot be called before the ready event of the app module is emitted.
/// </summary>
/// <param name="name">Name of the Chrome extension to remove</param>
public void RemoveExtension(string name)
{
BridgeConnector.Emit("webContents-session-removeExtension", Id, name);
}
/// <summary>
/// resolves when the extension is loaded.
///
/// This method will raise an exception if the extension could not be loaded.If
/// there are warnings when installing the extension (e.g. if the extension requests
/// an API that Electron does not support) then they will be logged to the console.
///
/// Note that Electron does not support the full range of Chrome extensions APIs.
/// See Supported Extensions APIs for more details on what is supported.
///
/// Note that in previous versions of Electron, extensions that were loaded would be
/// remembered for future runs of the application.This is no longer the case:
/// `loadExtension` must be called on every boot of your app if you want the
/// extension to be loaded.
///
/// This API does not support loading packed (.crx) extensions.
///
///** Note:** This API cannot be called before the `ready` event of the `app` module
/// is emitted.
///
///** Note:** Loading extensions into in-memory(non-persistent) sessions is not supported and will throw an error.
/// </summary>
/// <param name="path">Path to the Chrome extension</param>
/// <param name="allowFileAccess">Whether to allow the extension to read local files over `file://` protocol and
/// inject content scripts into `file://` pages. This is required e.g. for loading
/// devtools extensions on `file://` URLs. Defaults to false.</param>
/// <returns></returns>
public Task<Extension> LoadExtensionAsync(string path, bool allowFileAccess = false)
{
var taskCompletionSource = new TaskCompletionSource<Extension>(TaskCreationOptions.RunContinuationsAsynchronously);
BridgeConnector.On<Extension>("webContents-session-loadExtension-completed", (extension) =>
{
BridgeConnector.Off("webContents-session-loadExtension-completed");
taskCompletionSource.SetResult(extension);
});
BridgeConnector.Emit("webContents-session-loadExtension", Id, path, allowFileAccess);
return taskCompletionSource.Task;
}
}
}

93
ElectronNET.API/Shell.cs Normal file → Executable file
View File

@@ -4,16 +4,18 @@ using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System.Threading.Tasks;
using ElectronNET.API.Extensions;
using ElectronNET.API.Interfaces;
using System.Runtime.Versioning;
namespace ElectronNET.API
{
/// <summary>
/// Manage files and URLs using their default applications.
/// </summary>
public sealed class Shell
public sealed class Shell : IShell
{
private static Shell _shell;
private static object _syncRoot = new object();
private static readonly object _syncRoot = new();
internal Shell() { }
@@ -42,14 +44,14 @@ namespace ElectronNET.API
/// <param name="fullPath">The full path to the directory / file.</param>
public Task ShowItemInFolderAsync(string fullPath)
{
var taskCompletionSource = new TaskCompletionSource<object>();
var taskCompletionSource = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
BridgeConnector.Socket.On("shell-showItemInFolderCompleted", () =>
BridgeConnector.On("shell-showItemInFolderCompleted", () =>
{
BridgeConnector.Socket.Off("shell-showItemInFolderCompleted");
BridgeConnector.Off("shell-showItemInFolderCompleted");
});
BridgeConnector.Socket.Emit("shell-showItemInFolder", fullPath);
BridgeConnector.Emit("shell-showItemInFolder", fullPath);
return taskCompletionSource.Task;
}
@@ -61,16 +63,16 @@ namespace ElectronNET.API
/// <returns>The error message corresponding to the failure if a failure occurred, otherwise <see cref="string.Empty"/>.</returns>
public Task<string> OpenPathAsync(string path)
{
var taskCompletionSource = new TaskCompletionSource<string>();
var taskCompletionSource = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
BridgeConnector.Socket.On("shell-openPathCompleted", (errorMessage) =>
BridgeConnector.On<string>("shell-openPathCompleted", (errorMessage) =>
{
BridgeConnector.Socket.Off("shell-openPathCompleted");
BridgeConnector.Off("shell-openPathCompleted");
taskCompletionSource.SetResult((string) errorMessage);
taskCompletionSource.SetResult(errorMessage);
});
BridgeConnector.Socket.Emit("shell-openPath", path);
BridgeConnector.Emit("shell-openPath", path);
return taskCompletionSource.Task;
}
@@ -93,24 +95,25 @@ namespace ElectronNET.API
/// <param name="url">Max 2081 characters on windows.</param>
/// <param name="options">Controls the behavior of OpenExternal.</param>
/// <returns>The error message corresponding to the failure if a failure occurred, otherwise <see cref="string.Empty"/>.</returns>
public Task<string> OpenExternalAsync(string url, OpenExternalOptions options)
{
var taskCompletionSource = new TaskCompletionSource<string>();
var taskCompletionSource = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
BridgeConnector.Socket.On("shell-openExternalCompleted", (error) =>
BridgeConnector.On<string>("shell-openExternalCompleted", (error) =>
{
BridgeConnector.Socket.Off("shell-openExternalCompleted");
BridgeConnector.Off("shell-openExternalCompleted");
taskCompletionSource.SetResult((string) error);
taskCompletionSource.SetResult(error);
});
if (options == null)
{
BridgeConnector.Socket.Emit("shell-openExternal", url);
BridgeConnector.Emit("shell-openExternal", url);
}
else
{
BridgeConnector.Socket.Emit("shell-openExternal", url, JObject.FromObject(options, _jsonSerializer));
BridgeConnector.Emit("shell-openExternal", url, options);
}
return taskCompletionSource.Task;
@@ -120,22 +123,10 @@ namespace ElectronNET.API
/// Move the given file to trash and returns a <see cref="bool"/> status for the operation.
/// </summary>
/// <param name="fullPath">The full path to the directory / file.</param>
/// <param name="deleteOnFail">Whether or not to unilaterally remove the item if the Trash is disabled or unsupported on the volume.</param>
/// <returns> Whether the item was successfully moved to the trash.</returns>
public Task<bool> MoveItemToTrashAsync(string fullPath, bool deleteOnFail)
public Task<bool> TrashItemAsync(string fullPath)
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("shell-moveItemToTrashCompleted", (success) =>
{
BridgeConnector.Socket.Off("shell-moveItemToTrashCompleted");
taskCompletionSource.SetResult((bool) success);
});
BridgeConnector.Socket.Emit("shell-moveItemToTrash", fullPath, deleteOnFail);
return taskCompletionSource.Task;
return BridgeConnector.OnResult<bool>("shell-trashItem", "shell-trashItem-completed", fullPath);
}
/// <summary>
@@ -143,7 +134,7 @@ namespace ElectronNET.API
/// </summary>
public void Beep()
{
BridgeConnector.Socket.Emit("shell-beep");
BridgeConnector.Emit("shell-beep");
}
/// <summary>
@@ -153,20 +144,10 @@ namespace ElectronNET.API
/// <param name="operation">Default is <see cref="ShortcutLinkOperation.Create"/></param>
/// <param name="options">Structure of a shortcut.</param>
/// <returns>Whether the shortcut was created successfully.</returns>
[SupportedOSPlatform("windows")]
public Task<bool> WriteShortcutLinkAsync(string shortcutPath, ShortcutLinkOperation operation, ShortcutDetails options)
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("shell-writeShortcutLinkCompleted", (success) =>
{
BridgeConnector.Socket.Off("shell-writeShortcutLinkCompleted");
taskCompletionSource.SetResult((bool) success);
});
BridgeConnector.Socket.Emit("shell-writeShortcutLink", shortcutPath, operation.GetDescription(), JObject.FromObject(options, _jsonSerializer));
return taskCompletionSource.Task;
return BridgeConnector.OnResult<bool>("shell-writeShortcutLink", "shell-writeShortcutLinkCompleted", shortcutPath, operation.GetDescription(), options);
}
/// <summary>
@@ -175,30 +156,10 @@ namespace ElectronNET.API
/// </summary>
/// <param name="shortcutPath">The path tot the shortcut.</param>
/// <returns><see cref="ShortcutDetails"/> of the shortcut.</returns>
[SupportedOSPlatform("windows")]
public Task<ShortcutDetails> ReadShortcutLinkAsync(string shortcutPath)
{
var taskCompletionSource = new TaskCompletionSource<ShortcutDetails>();
BridgeConnector.Socket.On("shell-readShortcutLinkCompleted", (shortcutDetails) =>
{
BridgeConnector.Socket.Off("shell-readShortcutLinkCompleted");
var shortcutObject = shortcutDetails as JObject;
var details = shortcutObject?.ToObject<ShortcutDetails>();
taskCompletionSource.SetResult(details);
});
BridgeConnector.Socket.Emit("shell-readShortcutLink", shortcutPath);
return taskCompletionSource.Task;
return BridgeConnector.OnResult<ShortcutDetails>("shell-readShortcutLink", "shell-readShortcutLinkCompleted", shortcutPath);
}
private readonly JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
}
}

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