Compare commits

..

324 Commits

Author SHA1 Message Date
Lea Anthony
2a64ed19a3 v2.0.0-alpha.11 2021-01-22 14:57:50 +11:00
Lea Anthony
47bca0be88 Support updating tray labels in an efficient manner 2021-01-16 11:35:49 +11:00
Lea Anthony
7ac8cc6b8b Add Menu.Merge() to combine 2 menus 2021-01-15 11:53:55 +11:00
Lea Anthony
b435ec1217 v2.0.0-alpha.10 2021-01-14 20:43:26 +11:00
Lea Anthony
688d4fee6a UpdateTrayMenu -> SetTrayMenu (upsert). Support no menus on trays. 2021-01-14 16:13:59 +11:00
Lea Anthony
29ffeaa9f3 Misc tidy up 2021-01-14 13:55:20 +11:00
Lea Anthony
742e4ba2cb Remove WailsInit and WailsShutdown methodsr 2021-01-14 11:07:06 +11:00
Lea Anthony
0a0063de1f bump version 2021-01-14 00:28:15 +11:00
Lea Anthony
1b7d1e61cc v2.0.0-alpha.8 2021-01-13 23:47:15 +11:00
Lea Anthony
15a273458e Ensure build directory exists when building 2021-01-13 23:46:47 +11:00
Lea Anthony
eef8eb756f Bump version 2021-01-13 22:56:09 +11:00
Lea Anthony
e65118e962 Fixed and refactored context menu support 2021-01-13 22:51:44 +11:00
Lea Anthony
de06fc7dcc Remove a ton of unused code 2021-01-13 21:29:20 +11:00
Lea Anthony
a86fbbb440 Removal of menu IDs. WARNING: context menus are currently broken 2021-01-13 21:14:44 +11:00
Lea Anthony
3045ec107f attempt at preventing menu flicker when removing an icon 2021-01-13 20:47:08 +11:00
Lea Anthony
3a9557ad30 Support removal of tray icons 2021-01-13 20:38:46 +11:00
Lea Anthony
583153383a Refactor, tidy up and trim the fat! 2021-01-13 20:19:01 +11:00
Lea Anthony
3f53e8fd5f Refactor, tidy up and trim the fat! 2021-01-13 11:47:54 +11:00
Lea Anthony
5c9402323a Initial support for multiple traymenus 2021-01-13 10:28:32 +11:00
Lea Anthony
1921862b53 Partially introduce context menu changes back 2021-01-12 21:20:08 +11:00
Lea Anthony
0f7acd39fc [WIP] Fix the madness 2021-01-12 20:39:19 +11:00
Lea Anthony
1a7507f524 [WIP] Add tray menu store + refactor 2021-01-12 16:55:30 +11:00
Lea Anthony
db6dde3e50 [WIP] Support tray in menu manager 2021-01-12 15:55:28 +11:00
Lea Anthony
4e58b7697a Add context menu to menumanager. Slight refactor. 2021-01-11 14:19:01 +11:00
Lea Anthony
55d7d9693f Removed Menu GetByID / RemoveByID 2021-01-11 13:41:07 +11:00
Lea Anthony
b4b7c9d306 Implemented MenuItem.Remove() to remove from the menu structures 2021-01-11 11:57:49 +11:00
Lea Anthony
a4153fae57 Remove Menu.On() 2021-01-11 11:25:48 +11:00
Lea Anthony
8053357d99 Support Menu updates! 2021-01-11 11:21:28 +11:00
Lea Anthony
7347d2caa2 Add wails debug command 2021-01-11 11:20:25 +11:00
Lea Anthony
e6491bcbb7 Fix bad deallocation of context menus 2021-01-11 07:03:59 +11:00
Lea Anthony
26a291dbee [WIP] Use json payload for click message 2021-01-11 06:40:00 +11:00
Lea Anthony
8ee8c9b07c [WIP] New menu processor 2021-01-10 21:31:13 +11:00
Lea Anthony
3a2d01813a Don't inline functions in debug builds 2021-01-10 20:32:25 +11:00
Lea Anthony
d2dadc386f Add combo modifier to kitchen sink 2021-01-08 11:39:18 +11:00
Lea Anthony
faa8f02b08 Bugfix for message dialog icons 2021-01-08 11:39:02 +11:00
Lea Anthony
fbee9ba240 Support UpdateContextMenus. Submenus are now *menu.Menu. Tidy up++ 2021-01-08 06:28:51 +11:00
Lea Anthony
2a69786d7e Remove old code (woohoo!) 2021-01-07 21:36:39 +11:00
Lea Anthony
f460bf91ef [WIP] Normalisation of context menus creation/callbacks.
TODO: UpdateContextMenu()
2021-01-07 21:34:04 +11:00
Lea Anthony
bd74d45a91 Normalisation of callbacks for menus. App menu converted to new Menus. 2021-01-06 20:50:41 +11:00
Lea Anthony
c65522f0b6 Huge refactor of menus. Start of normalisation of callbacks. 2021-01-06 17:36:59 +11:00
Lea Anthony
5f2c437136 Bugfix dealloc contextmenus. Create common.h. WIP: new menu handling 2021-01-06 12:53:11 +11:00
Lea Anthony
87e974e080 Refactor/Tidy up Ffenestri darwin 2021-01-06 11:56:01 +11:00
Lea Anthony
f77729fc0b v2.0.0-alpha.6 2021-01-05 14:28:50 +11:00
Lea Anthony
2a8ce96830 Remove custom asset bundling. Use Go's embed instead! 2021-01-05 14:28:18 +11:00
Lea Anthony
9be539cfb8 Force rebuild each time to pick up .h changes Tidy up go.mod. Bump version. 2021-01-05 14:01:53 +11:00
Lea Anthony
e44f2fe06d Moved version out of main. 2021-01-05 13:26:31 +11:00
Lea Anthony
ad65d55abd Misc fixes for module build 2021-01-05 13:20:44 +11:00
Lea Anthony
2b5bbfd897 Script to rebuild runtime_*.c 2021-01-05 13:01:38 +11:00
Lea Anthony
d2020fedda Move generated assets to build dir. Precompile platform runtime. 2021-01-05 13:01:03 +11:00
Lea Anthony
98789bd85a Fix rollup-plugin-svelte in KS 2021-01-04 22:23:07 +11:00
Lea Anthony
e6ace2fafd Add Pace to Thanks 2021-01-04 19:52:12 +11:00
Lea Anthony
a55fc4d0e9 Refactor TrayOptions to Tray. Add ID. 2021-01-04 15:58:28 +11:00
Lea Anthony
a09e9d4586 Merge branch 'develop' into feature/v2-mac 2021-01-04 13:54:02 +11:00
Lea Anthony
ba7c8cf0e0 Merge branch 'develop' into feature/v2-mac 2021-01-04 13:41:36 +11:00
Lea Anthony
60f67d4642 Remove old method 2021-01-03 22:07:05 +11:00
Lea Anthony
0dc6c20c65 Provide a better error message when trying to bind functions 2021-01-03 22:05:40 +11:00
Lea Anthony
5d41aad539 Misc lint fixes 2021-01-03 21:31:19 +11:00
Lea Anthony
e9a0e45d5c Support js & css in link tags 2021-01-03 21:20:29 +11:00
Lea Anthony
2dedd0b702 Expose Store 2021-01-03 20:20:44 +11:00
Lea Anthony
1889973af1 Dedupe assetbundle 2021-01-03 20:06:07 +11:00
Lea Anthony
75e852451c Fix context menu bug 2021-01-03 09:56:45 +11:00
Lea Anthony
cfee44b18b Fix typo 2021-01-03 05:31:05 +11:00
Lea Anthony
f384fc7562 Add -k flag for debug purposes 2021-01-03 05:02:48 +11:00
Lea Anthony
44c55d06a6 Create dialog dir if missing 2021-01-02 13:37:58 +11:00
Lea Anthony
f4ca9a6b9e Update svelte dependencies 2021-01-02 13:37:15 +11:00
Lea Anthony
a54d875ceb Fix misc build issues 2021-01-01 13:00:38 +11:00
Lea Anthony
657df8bdda Use assets dir in project for all application assets 2021-01-01 12:53:06 +11:00
Lea Anthony
c0fabc0bb7 Default dialog icon generation improvement 2021-01-01 12:43:21 +11:00
Lea Anthony
4fd476bb7d Default readme for assets directory 2021-01-01 12:42:52 +11:00
Lea Anthony
be0a9ddf6b Handle WailsInit() errors 2021-01-01 12:39:59 +11:00
Lea Anthony
f7db0b7373 Fix return values of default App method 2021-01-01 12:37:52 +11:00
Lea Anthony
5ca57e446a Extra guards during destroy 2021-01-01 12:37:16 +11:00
Lea Anthony
33a27b06a6 Add Message dialog to Kitchen Sink 2020-12-31 14:52:45 +11:00
Lea Anthony
b50acaba91 Fix 'ResolvesAliases' typo 2020-12-31 11:04:10 +11:00
Lea Anthony
6253ac30b7 Support Message dialog in JS runtime 2020-12-31 11:02:32 +11:00
Lea Anthony
2a93e2694d Retina & theme aware dialog icons. Default icons + override ability 2020-12-30 22:36:23 +11:00
Lea Anthony
91fb3501c5 Support custom dialog icons. Move icons to new dir. 2020-12-30 08:27:00 +11:00
Lea Anthony
c7d5e7de72 Add CopyDir 2020-12-30 08:25:16 +11:00
Lea Anthony
02ef02ec9e Support wails doctor for Mac 2020-12-30 00:18:59 +11:00
Lea Anthony
f77626490f Support Tray.SetIcon in KitchenSink 2020-12-29 15:22:00 +11:00
Lea Anthony
6fd13fb4d4 Support Tray.SetIcon in runtime 2020-12-29 15:20:35 +11:00
Lea Anthony
e18ba0eb81 Handle no tray icons 2020-12-28 14:49:15 +11:00
Lea Anthony
25f464c177 Refactor accelerator to keys package 2020-12-26 14:58:22 +11:00
Lea Anthony
57a9d5f472 Update server client API 2020-12-26 07:37:40 +11:00
Lea Anthony
3b0f852f37 Updated accelerators API 2020-12-26 06:11:22 +11:00
Lea Anthony
a85c8ba894 Remove "WithAccellerator" methods. Now mandatory in base methods 2020-12-26 06:01:10 +11:00
Lea Anthony
f0c932713b Support changing tray icon at runtime
Support both icon & text in tray
2020-12-24 10:05:55 +11:00
Lea Anthony
8625e99625 Add OnThemeChange
Refactor Theme change handling
2020-12-24 07:30:20 +11:00
Lea Anthony
c79f86fd03 Remove old tray icon, add new 2020-12-23 06:56:56 +11:00
Lea Anthony
a0774cf71c Support loading multiple tray icons 2020-12-23 06:55:45 +11:00
Lea Anthony
16b872352d Support Text label tray 2020-12-22 18:08:38 +11:00
Lea Anthony
e414eda151 Fix race condition 2020-12-21 07:19:33 +11:00
Lea Anthony
719f4b5113 Remove debug output 2020-12-21 07:19:20 +11:00
Lea Anthony
8b75d57cff Use release instead of dealloc 2020-12-21 07:18:52 +11:00
Lea Anthony
7aea6980b5 Remove context menu debug log 2020-12-20 21:06:34 +11:00
Lea Anthony
99e790944f Merge branch 'v2-mac-fixes' into feature/v2-mac
# Conflicts:
#	v2/internal/ffenestri/ffenestri_darwin.c
#	v2/internal/ffenestri/ffenestri_darwin.go
#	v2/internal/ffenestri/ffenestri_darwin.h
2020-12-20 21:02:39 +11:00
Lea Anthony
937f0f77c2 Fix NPE 2020-12-20 21:00:32 +11:00
Lea Anthony
c86aa7d3c8 Handle null modifiers 2020-12-20 17:55:14 +11:00
Lea Anthony
d380a8d6a7 Bugfix for context menus
Proper releasing of NSMenus
2020-12-20 14:09:15 +11:00
Lea Anthony
a8995c5377 Support context menu data
Support StartHidden
2020-12-18 15:50:25 +11:00
Lea Anthony
34ac62e4ac Updated tray icon 2020-12-16 08:59:01 +11:00
Lea Anthony
a1f9d9ca06 Handle oncontext event 2020-12-16 08:54:24 +11:00
Lea Anthony
e6fbd03346 Bugfix error message 2020-12-16 08:53:11 +11:00
Lea Anthony
dd35f0119b Better error handling 2020-12-11 05:41:24 +11:00
Lea Anthony
b837b1e131 Tray menu support
Bugfix move after tray use
Refactored options to handle default tray/menu
2020-12-10 07:16:10 +11:00
Lea Anthony
0802d0d57a Tray menu callbacks working 2020-12-07 07:08:33 +11:00
Lea Anthony
6fa2ebdd4f Lint fix & tidy up 2020-12-06 21:15:23 +11:00
Lea Anthony
11bf564b73 Preliminary Tray support 2020-12-06 21:05:21 +11:00
Lea Anthony
65bea04080 Pass radio callback through methods 2020-12-06 17:52:05 +11:00
Lea Anthony
4572b790c6 Pass checkbox callback through methods 2020-12-06 17:47:41 +11:00
Lea Anthony
f419941065 Pass menuItemMap through methods instead of global 2020-12-06 17:32:19 +11:00
Lea Anthony
d3d965ee1f more logger fixes 2020-12-06 07:14:19 +11:00
Lea Anthony
2a55983bc9 Fix logger 2020-12-05 14:44:28 +11:00
Lea Anthony
7e42052da0 InsertBefore/InsertAfter supported 2020-12-05 14:14:46 +11:00
Lea Anthony
e8bb950e06 Updates for dynamic menus
Cleanup of logging
2020-12-05 07:52:59 +11:00
Lea Anthony
13dc0c78df Remove browser test 2020-12-04 15:06:01 +11:00
Lea Anthony
a081c1e498 Support for dynamic menus.
Fixed bug in accelerator handling
2020-12-04 15:04:51 +11:00
Lea Anthony
a3e50e760e Tidy Up dialog 2020-12-02 05:56:20 +11:00
Lea Anthony
b6aa53175f Create Menu struct for kitchensink 2020-12-02 05:55:02 +11:00
Lea Anthony
094d8d4b75 fix bug with function key comparisons 2020-12-01 09:11:16 +11:00
Lea Anthony
0fa67c94c1 Graceful shudown - FINALLY! 2020-11-29 15:56:14 +11:00
Lea Anthony
083aee1588 Support F-keys & a couple more system keys 2020-11-29 15:24:27 +11:00
Lea Anthony
5c39467879 Support more accelerator keys 2020-11-29 14:18:53 +11:00
Lea Anthony
fb1d4c6325 Support for Accelerators! 2020-11-28 20:57:07 +11:00
Lea Anthony
a0fe2f1e13 UTF-8 test 2020-11-27 22:22:30 +11:00
Lea Anthony
dbe6000632 Support for radio menu items 2020-11-27 22:07:44 +11:00
Lea Anthony
42dc96cf6b Support checkboxes 2020-11-25 08:10:27 +11:00
Lea Anthony
4fd3516f41 Support Hidden/Disabled. Normal->Text 2020-11-24 20:12:10 +11:00
Lea Anthony
6f218264ed Initial support for menus 2020-11-24 19:43:25 +11:00
Lea Anthony
810b3c7440 Add default menu for mac apps 2020-11-21 21:38:18 +11:00
Lea Anthony
40fdf75042 Disable context menu in production mode 2020-11-21 20:32:55 +11:00
Lea Anthony
bc260b08b2 Better devtools handling 2020-11-21 12:40:19 +11:00
Lea Anthony
b920f45f60 Formatting update. 2020-11-21 12:07:55 +11:00
Lea Anthony
7f02f6886f Improved project generation 2020-11-21 11:56:01 +11:00
Lea Anthony
aa271d6498 Support git init. Get author details. 2020-11-21 11:43:13 +11:00
Lea Anthony
9e6ae4d762 Support building Mac package 2020-11-21 07:09:25 +11:00
Lea Anthony
ef8b58b208 Set log level to ERROR for production build 2020-11-20 14:53:42 +11:00
Lea Anthony
0422921dc7 Misc documentation updates 2020-11-20 14:45:35 +11:00
Lea Anthony
5ba03937c3 Updated Dialog Examples 2020-11-19 08:56:57 +11:00
Lea Anthony
cc4967d457 Add dialog to kitchensink 2020-11-19 07:04:42 +11:00
Lea Anthony
eaeecbb180 Support Dialog in runtime 2020-11-19 07:04:08 +11:00
Lea Anthony
069de31003 Convert args to [] 2020-11-19 07:03:12 +11:00
Lea Anthony
ae5c74b6cd ResolveAlias -> ResolvesAlias 2020-11-19 07:02:29 +11:00
Lea Anthony
716888dcb2 Disable module generation 2020-11-17 21:46:20 +11:00
Lea Anthony
ca4e2b2391 Cosmetic changes 2020-11-17 21:44:48 +11:00
Lea Anthony
630abbd3c8 Rmoved v1 dep :/ 2020-11-17 21:36:10 +11:00
Lea Anthony
33f40c2eac relative replace in go.mod 2020-11-17 21:29:31 +11:00
Lea Anthony
7c7b6ba082 Runtime updates 2020-11-17 21:19:09 +11:00
Lea Anthony
205a6db9f1 Open link to website/github 2020-11-17 21:19:00 +11:00
Lea Anthony
659fe1b281 Disable set title if needed 2020-11-17 21:18:38 +11:00
Lea Anthony
e86d622219 Add appconfig store 2020-11-17 07:02:58 +11:00
Lea Anthony
ee3da60002 Sync new JS syncstores on creation 2020-11-17 06:58:14 +11:00
Lea Anthony
88643134c9 Add AppConfig to runtime.System 2020-11-17 06:57:43 +11:00
Lea Anthony
56553bb683 Remove logger from json encoded app config 2020-11-17 06:56:51 +11:00
Lea Anthony
cd14f4221e Merge branch 'develop' into feature/v2-mac 2020-11-16 07:12:01 +11:00
Lea Anthony
108fcbb161 Comment about window title 2020-11-15 15:42:46 +11:00
Lea Anthony
e12762a584 Un/Fullscreen, SetTitle in Kitchen Sink 2020-11-15 15:10:09 +11:00
Lea Anthony
98cc356b92 Un/Fullscreen, SetTitle in Runtime 2020-11-15 15:09:33 +11:00
Lea Anthony
32ba9e78fe Improved fullscreen support 2020-11-15 15:08:46 +11:00
Lea Anthony
a737d85fa5 Fixd typos in runtime 2020-11-15 12:22:03 +11:00
Lea Anthony
435ac02647 Update runtime.Window 2020-11-15 12:18:37 +11:00
Lea Anthony
255b4e103a Add Window to kitchensink 2020-11-15 12:01:43 +11:00
Lea Anthony
bd8771849b Support size/position in Go runtime 2020-11-15 12:01:15 +11:00
Lea Anthony
b32349effe Improve min/maximise 2020-11-15 12:00:57 +11:00
Lea Anthony
cd03b4b633 Merge branch 'feature/v2-mac' of github.com:wailsapp/wails into feature/v2-mac 2020-11-15 10:18:33 +11:00
Lea Anthony
c45315d61d Add window to runtime 2020-11-15 10:16:56 +11:00
Lea Anthony
62374b9b53 Js package generation (#554)
* WIP

* Generation of index.js

* Add RelativeToCwd

* Add JSDoc comments

* Convert to ES6 syntax

* Fix typo

* Initial generation of typescript declarations

* Typescript improvements

* Improved @returns jsdoc

* Improved declaration files

* Simplified output

* Rename file

* Tidy up

* Revert "Simplified output"

This reverts commit 15cdf7382b.

* Now parsing actual code

* Support Array types

* Reimagined parser

* Wrap parsing in Parser

* Rewritten module generator (TS Only)

* Final touches

* Slight refactor to improve output

* Struct comments. External struct literal binding

* Reworked project parser *working*

* remove debug info

* Refactor of parser

* remove the spew

* Better Ts support

* Better project generation logic

* Support local functions in bind()

* JS Object generation. Linting.

* Support json tags in module generation

* Updated mod files

* Support vscode file generation

* Better global.d.ts

* add ts-check to templates

* Support TS declaration files

* improved 'generate' command for module
2020-11-15 09:25:38 +11:00
Lea Anthony
ddb875f788 Dialog WIP 2020-10-24 14:06:57 +11:00
Lea Anthony
9a32852119 Add JS runtime Dialog 2020-10-23 23:56:33 +11:00
Lea Anthony
e795283482 Huge improvement to calls: Now handles objects 2020-10-23 22:24:30 +11:00
Lea Anthony
e6036d31cf Add System to kitchensink 2020-10-23 11:46:12 +11:00
Lea Anthony
5a85a6e4f9 Expose System methods in Go runtime 2020-10-23 11:24:52 +11:00
Lea Anthony
0113fbff4f Update runtime.System to make all methods 2020-10-23 11:19:38 +11:00
Lea Anthony
145656bc43 Improved runtime.System 2020-10-23 10:42:00 +11:00
Lea Anthony
6153c48c86 Update title 2020-10-21 06:52:52 +11:00
Lea Anthony
912c0125e5 Add Browser examples 2020-10-21 06:40:17 +11:00
Lea Anthony
dc2ad3cd3e Remove debug line 2020-10-21 06:02:07 +11:00
Lea Anthony
e3783c5480 Fix browser runtime export 2020-10-20 09:24:03 +11:00
Lea Anthony
440abbe3b6 JS Runtime v1.0.8 2020-10-20 09:10:54 +11:00
Lea Anthony
95369d7c3d Unify Browser runtime 2020-10-20 09:10:09 +11:00
Lea Anthony
9e0023961b Update Browser runtime API 2020-10-20 07:16:56 +11:00
Lea Anthony
307e07b4c8 Finish events page 2020-10-20 06:45:46 +11:00
Lea Anthony
fb88eadb58 Tidy up events runtime 2020-10-20 06:45:21 +11:00
Lea Anthony
6fdf088531 Revert Fatal on JS Error 2020-10-20 06:45:02 +11:00
Lea Anthony
07b6fc0c52 Update runtime in kitchensink 2020-10-18 16:49:08 +11:00
Lea Anthony
1b466090e8 Remove old Event methods 2020-10-18 16:47:48 +11:00
Lea Anthony
c990760f22 Remove old event methods 2020-10-18 16:44:32 +11:00
Lea Anthony
aeb7d857ee Support Emit & Once. Improved On. 2020-10-18 11:49:27 +11:00
Lea Anthony
78f99c2697 update runtime definitions 2020-10-18 11:48:56 +11:00
Lea Anthony
7885718d42 Disable annoying smart quotes 2020-10-18 11:48:38 +11:00
Lea Anthony
288da8c147 Improved error handling? 2020-10-18 11:48:20 +11:00
Lea Anthony
7e31db809a Add Events.On 2020-10-17 21:07:00 +11:00
Lea Anthony
fb0ccfc8e6 WIP Events.On 2020-10-17 15:10:13 +11:00
Lea Anthony
c9bf4e3d48 refactor clilogger 2020-10-17 13:47:13 +11:00
Lea Anthony
2a59272b86 hook in windowWillClose 2020-10-16 14:02:49 +11:00
Lea Anthony
ff5e2862b8 Fix change in logging levels 2020-10-13 07:49:47 +11:00
Lea Anthony
51678afdc7 @wails/runtime v1.0.4 2020-10-13 07:35:36 +11:00
Lea Anthony
3b6a3df03d Update logger constants to fix default values 2020-10-13 07:34:36 +11:00
Lea Anthony
1c97559151 logging: slight refactor 2020-10-13 06:43:38 +11:00
Lea Anthony
082e695c83 Fix log level reactivity.
Misc fixes and tweaks
2020-10-12 23:36:37 +11:00
Lea Anthony
4a5e4d3a5e Move preview for SetLogLevel 2020-10-12 20:55:47 +11:00
Lea Anthony
8988f29cea More Logging updates 2020-10-12 20:54:33 +11:00
Lea Anthony
6150010d17 Runtime defs update.
Slight System refactor
2020-10-12 20:01:37 +11:00
Lea Anthony
c165b97d57 SetLogLevel fully supported 2020-10-12 06:56:51 +11:00
Lea Anthony
39c599d2de Link component 2020-10-12 06:56:32 +11:00
Lea Anthony
be952ba2da Terminal output component 2020-10-12 06:56:22 +11:00
Lea Anthony
5a141d343e Better looking scrollbar 2020-10-12 06:55:42 +11:00
Lea Anthony
7e4ad307aa Fully refactored logging 2020-10-11 15:10:25 +11:00
Lea Anthony
d8bb418851 Runtime refactor 2020-10-11 13:33:55 +11:00
Lea Anthony
f1cd84d0c8 Support dynamic loglevel 2020-10-10 15:06:27 +11:00
Lea Anthony
ba6538da7c Made go runtime package public.
Using loglevel store to keep loglevel in sync
2020-10-10 13:57:32 +11:00
Lea Anthony
afea1cbb4c Support SetLogLevel() at runtime
Refactor of loglevel
2020-10-10 07:31:23 +11:00
Lea Anthony
19fbc884ae Fix number of methods in Log 2020-10-09 15:44:08 +11:00
Lea Anthony
67861e4f70 Updated Logger interface 2020-10-09 15:39:11 +11:00
Lea Anthony
228285f693 Support Print logging 2020-10-09 15:13:45 +11:00
Lea Anthony
9f62a08cd2 Move Info message to Trace 2020-10-09 14:59:12 +11:00
Lea Anthony
d97cd1b75f Runtime v1.0.1 2020-10-09 14:52:07 +11:00
Lea Anthony
5fd8312f63 Support Print in JS runtime 2020-10-09 14:51:26 +11:00
Lea Anthony
90b7d5f519 Support log level 2020-10-09 14:36:42 +11:00
Lea Anthony
93f4549efa Support trace in go runtime 2020-10-09 14:36:28 +11:00
Lea Anthony
b5c8dfac97 Support Trace in kitchensink 2020-10-09 14:36:15 +11:00
Lea Anthony
ee01b7759e Migrate runtime to @wails 2020-10-09 14:35:43 +11:00
Lea Anthony
8dba591cda Add trace to JS runtime 2020-10-09 14:35:30 +11:00
Lea Anthony
302db87bec Debug refactor 2020-10-09 14:01:35 +11:00
Lea Anthony
161ff3b32a Make Ffenestri use logging subsystem. 2020-10-09 12:15:25 +11:00
Lea Anthony
ffdfbb8ae5 Major logging refactor 2020-10-09 11:50:45 +11:00
Lea Anthony
53b54a8e52 Revert logger package 2020-10-09 10:33:11 +11:00
Lea Anthony
0403e0a783 Make logger a public package 2020-10-09 10:30:01 +11:00
Lea Anthony
8a2acacc37 Start Events. List styling moved to global scope. 2020-10-08 21:03:45 +11:00
Lea Anthony
256e84c4d4 Improved CodeBlock. Dark mode to store. 2020-10-08 20:51:14 +11:00
Lea Anthony
c10e8788d8 Add logging to kitchen sink 2020-10-08 07:39:15 +11:00
Lea Anthony
6eb89f61b3 Add Log to Go runtime 2020-10-08 07:39:01 +11:00
Lea Anthony
e3d2ff9ea1 Remove log package 2020-10-08 07:38:47 +11:00
Lea Anthony
665dfa6aee WIP 2020-10-07 21:09:05 +11:00
Lea Anthony
4f7e2128d1 Better drag support 2020-10-07 07:11:00 +11:00
Lea Anthony
8112facb4e Fix right click crash 2020-10-07 06:44:58 +11:00
Lea Anthony
944261b5e4 initial kitchen sink 2020-10-07 00:52:00 +11:00
Lea Anthony
ba528d0534 Debugging 2020-10-07 00:51:22 +11:00
Lea Anthony
a28afe86ce Remove unused event messages 2020-10-04 13:37:29 +11:00
Lea Anthony
5e0026e124 Update runtime to v1.0.3 2020-10-04 12:07:56 +11:00
Lea Anthony
f23ed3c319 Add Store to go runtime 2020-10-04 12:07:42 +11:00
Lea Anthony
6aae2eb1df Support setting app state at startup 2020-10-04 12:07:10 +11:00
Lea Anthony
f4943bc26c Remove generated files 2020-10-04 11:54:05 +11:00
Lea Anthony
1c6578e6ef Use IsDarkMode state store 2020-10-04 11:50:05 +11:00
Lea Anthony
5ef200f21c Refactor system. Add IsDarkMode state store 2020-10-04 11:42:42 +11:00
Lea Anthony
b3822137f7 Refactor store. Add get(). 2020-10-04 11:41:39 +11:00
Lea Anthony
858789f442 Port Sync Store 2020-10-04 07:22:00 +11:00
Lea Anthony
3209b39488 Support System calls in Go Runtime 2020-10-03 20:46:18 +10:00
Lea Anthony
0c9f6edeb6 Add system calls to js runtime 2020-10-03 20:45:37 +10:00
Lea Anthony
aabcef2958 Add System calls to runtime 2020-10-03 20:45:04 +10:00
Lea Anthony
10d68b2676 Small fixes to frontend events 2020-10-03 15:29:34 +10:00
Lea Anthony
e960afe8f6 Support OnMultiple 2020-10-03 15:10:38 +10:00
Lea Anthony
ae677ce9db Misc fixes for events 2020-10-03 15:03:14 +10:00
Lea Anthony
7f9c59a021 Support theme mode change event 2020-10-02 15:12:56 +10:00
Lea Anthony
d8fdc96899 Add IsDarkMode
Updated runtime test
2020-10-02 11:41:46 +10:00
Lea Anthony
c3280e8b60 Update runtime test 2020-10-02 07:45:41 +10:00
Lea Anthony
26a1f78d56 Support Translucent Window Background 2020-10-02 07:45:22 +10:00
Lea Anthony
ee9c98c515 Refactor Part 2 2020-10-02 07:11:24 +10:00
Lea Anthony
29ec06fb0a Refactor part 1 2020-10-02 06:52:08 +10:00
Lea Anthony
c1155e255b Add default appearance 2020-09-30 20:03:08 +10:00
Lea Anthony
4e39566118 Rename vibrancy to appearance 2020-09-30 19:54:41 +10:00
Lea Anthony
3f3094f0aa Support vibrancy and transparency for webview
Options Colour -> RGBA
2020-09-30 07:25:15 +10:00
Lea Anthony
84730d2f4d Tidy up 2020-09-29 20:36:38 +10:00
Lea Anthony
b8bb891275 Frameless is calculated for Mac 2020-09-29 20:34:54 +10:00
Lea Anthony
7bcb5be1a5 Update tests 2020-09-29 07:44:02 +10:00
Lea Anthony
081c842149 Support window dragging 2020-09-29 07:33:16 +10:00
Lea Anthony
6bdcec8105 WIP: Basics of window drag 2020-09-28 22:08:53 +10:00
Lea Anthony
3c7937bff9 Tidy Up 2020-09-28 21:22:11 +10:00
Lea Anthony
d7f832c00e Support SaveDialog 2020-09-28 21:13:57 +10:00
Lea Anthony
8cd39f6a9a Support default directory 2020-09-27 20:40:36 +10:00
Lea Anthony
ac27137e5a Filter support 2020-09-27 20:26:16 +10:00
Lea Anthony
762632d55a Add comments 2020-09-27 15:15:25 +10:00
Lea Anthony
48c17dac87 Support all dialog properties 2020-09-27 15:05:55 +10:00
Lea Anthony
8666935caf Support multiple files in dialog 2020-09-27 14:49:38 +10:00
Lea Anthony
0ec6707263 Support selecting files+dirs 2020-09-27 14:46:30 +10:00
Lea Anthony
d4224772b4 Initial support for OpenDialog 2020-09-27 14:32:08 +10:00
Lea Anthony
cd99376da9 Use options struct for dialogs 2020-09-27 10:17:30 +10:00
Lea Anthony
02fd4ec477 Revert changes to v1 2020-09-27 07:58:30 +10:00
Lea Anthony
3b851e9a22 change service bus topics for dialogs 2020-09-26 16:21:18 +10:00
Lea Anthony
5ce5e129cf Remove old dialog code 2020-09-26 16:16:25 +10:00
Lea Anthony
9b0f58ddf5 Support OpenDialog 2020-09-26 16:08:55 +10:00
Lea Anthony
bed5619d4e WIP: Support multiple value return 2020-09-25 07:09:55 +10:00
Lea Anthony
69c4e6ea28 Min/Max size supported 2020-09-24 21:43:37 +10:00
Lea Anthony
ea7b593693 Fix minmax app 2020-09-24 21:29:26 +10:00
Lea Anthony
7ac833e396 Sample titlebars 2020-09-24 06:45:34 +10:00
Lea Anthony
a5e909337e Support TitleBar Default
Fixed merging defaults
2020-09-24 06:39:08 +10:00
Lea Anthony
0c120eccc9 Support HiddenInset Titlebar 2020-09-24 06:22:49 +10:00
Lea Anthony
e6addafcdd Support hidden titlebar 2020-09-24 06:19:00 +10:00
Lea Anthony
ef11f45df8 Refactored mac titlebar options 2020-09-24 05:57:32 +10:00
Lea Anthony
72fc2204b4 Moved options to own package 2020-09-24 05:46:39 +10:00
Lea Anthony
15c08ef425 Support runtime colour change 2020-09-23 08:48:11 +10:00
Lea Anthony
52bb397105 Support colour 2020-09-22 20:46:36 +10:00
Lea Anthony
5572fccaf6 Add Toolbar support for Mac 2020-09-22 17:48:39 +10:00
Lea Anthony
65d591e2a6 Support more mac window options 2020-09-22 17:19:35 +10:00
Lea Anthony
4bf59301e5 Add HideTitleBar 2020-09-21 17:13:23 +10:00
Lea Anthony
629e8f73f4 Add Mac Application Options 2020-09-21 17:07:10 +10:00
Lea Anthony
eb68ba5120 fix setsize and setposition 2020-09-19 23:19:34 +10:00
Lea Anthony
a8bff7868b Got get frame working 2020-09-19 07:40:45 +10:00
Lea Anthony
ae04b4fcc0 WIP [bugged] 2020-09-18 21:04:23 +10:00
Lea Anthony
5eb91dd3fa More refactoring 2020-09-16 21:23:35 +10:00
Lea Anthony
3ad537fdbb Tidy up 2020-09-16 21:14:18 +10:00
Lea Anthony
2c570bb4f6 Support tons of stuff! 2020-09-16 21:11:17 +10:00
Lea Anthony
461f3aec0a Get it compiling again! 2020-09-16 20:06:32 +10:00
Lea Anthony
fd47122e39 Only show window when rendered 2020-09-15 19:57:34 -05:00
Lea Anthony
8de013f192 vscode stuff 2020-09-15 19:57:34 -05:00
Lea Anthony
1dd3a602d7 Support Un/Fullscreen 2020-09-15 19:57:34 -05:00
Lea Anthony
a84a49a13f ignore test builds 2020-09-15 19:57:34 -05:00
Lea Anthony
64a6a69bbd Update packages 2020-09-15 19:57:33 -05:00
Lea Anthony
d75b9f26f1 Callback hooks for MOAE 2020-09-15 19:57:33 -05:00
Lea Anthony
10cb7f830f Fix logger 2020-09-15 19:57:33 -05:00
Lea Anthony
dd3e6de9b2 Add Center + refactor prefs 2020-09-15 19:57:33 -05:00
Lea Anthony
d42b84abc1 Callbacks working 2020-09-15 19:57:33 -05:00
Lea Anthony
b6c649041b Support sending messages to the backend 2020-09-15 19:57:33 -05:00
Lea Anthony
93ec65be6a More feature flag removal 2020-09-15 19:57:30 -05:00
Lea Anthony
bfa8929c47 Remove feature flag code 2020-09-15 19:55:52 -05:00
Lea Anthony
360713c803 lint 2020-09-15 19:55:51 -05:00
Lea Anthony
26ce682824 Ignore favicon for desktop 2020-09-15 19:55:51 -05:00
Lea Anthony
65b546c0f9 Evaluation working correctly. Still WIP 2020-09-15 19:55:51 -05:00
Travis McLane
31494bba22 add darwin platform for server 2020-09-15 19:55:51 -05:00
Lea Anthony
f25abb0b26 Semi runs 2020-09-15 19:55:51 -05:00
Lea Anthony
e831bc75c6 Stubs in place to compile 2020-09-15 19:55:51 -05:00
Lea Anthony
852bbd148c Get it compiling 2020-09-15 19:55:50 -05:00
Travis McLane
c158fd369a Merge commit 'a213e8bcd1d8e4e5c764978879d875d2d55dd400' as 'v2' 2020-09-15 19:52:54 -05:00
Travis McLane
a213e8bcd1 Squashed 'v2/' content from commit 72ef153
git-subtree-dir: v2
git-subtree-split: 72ef15359e36e42b18d9407f74c762f83eb9a099
2020-09-15 19:52:54 -05:00
507 changed files with 46627 additions and 750 deletions

12
.github/FUNDING.yml vendored
View File

@@ -1,12 +0,0 @@
# These are supported funding model platforms
github: [leaanthony]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@@ -13,10 +13,10 @@ jobs:
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- name: Set up Go 1.16
- name: Set up Go 1.13
uses: actions/setup-go@v1
with:
go-version: 1.16
go-version: 1.13
id: go
- name: Check out code into the Go module directory

View File

@@ -13,10 +13,10 @@ jobs:
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- name: Set up Go 1.16
- name: Set up Go 1.13
uses: actions/setup-go@v1
with:
go-version: 1.16
go-version: 1.13
id: go
- name: Check out code into the Go module directory

View File

@@ -15,10 +15,10 @@ jobs:
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- name: Set up Go 1.16
- name: Set up Go 1.13
uses: actions/setup-go@v1
with:
go-version: 1.16
go-version: 1.13
id: go
- name: Check out code into the Go module directory

9
.gitignore vendored
View File

@@ -17,8 +17,13 @@ cmd/wails/wails
.DS_Store
tmp
node_modules/
package.json.md5
v2/test/**/frontend/dist
v2/test/**/build/
v2/test/frameless/icon.png
v2/test/hidden/icon.png
v2/test/kitchensink/frontend/public/bundle.*
v2/pkg/parser/testproject/frontend/wails
v2/test/kitchensink/frontend/public
v2/internal/ffenestri/runtime.c
v2/internal/runtime/assets/desktop.js
v2/test/kitchensink/build/darwin/desktop/kitchensink
v2/test/kitchensink/frontend/package.json.md5

View File

@@ -1,4 +1,8 @@
{
"go.formatTool": "goimports",
"eslint.alwaysShowStatus": true
"eslint.alwaysShowStatus": true,
"files.associations": {
"__locale": "c",
"ios": "c"
}
}

View File

@@ -40,9 +40,4 @@ Wails is what it is because of the time and effort given by these great people.
* [Balakrishna Prasad Ganne](https://github.com/aayush420)
* [Charaf Rezrazi](https://github.com/Rezrazi)
* [misitebao](https://github.com/misitebao)
* [Elie Grenon](https://github.com/DrunkenPoney)
* [SophieAu](https://github.com/SophieAu)
* [Alexander Matviychuk](https://github.com/alexmat)
* [RH12503](https://github.com/RH12503)
* [hi019](https://github.com/hi019)
* [Elie Grenon](https://github.com/DrunkenPoney)

View File

@@ -2,7 +2,7 @@
<img src="logo_cropped.png" width="40%"><br/>
</p>
<p align="center">
Build desktop applications using Go & Web Technologies.<br/><br/>
A framework for building desktop applications using Go & Web Technologies.<br/><br/>
<a href="https://github.com/wailsapp/wails/blob/master/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg"></a>
<a href="https://goreportcard.com/report/github.com/wailsapp/wails"><img src="https://goreportcard.com/badge/github.com/wailsapp/wails"/></a>
<a href="http://godoc.org/github.com/wailsapp/wails"><img src="https://img.shields.io/badge/godoc-reference-blue.svg"/></a>
@@ -20,7 +20,7 @@ The official docs can be found at [https://wails.app](https://wails.app).
## Features
- Use standard Go for the backend
- Use standard Go libraries/frameworks for the backend
- Use any frontend technology to build your UI
- Quickly create Vue, Vuetify or React frontends for your Go programs
- Expose Go methods/functions to the frontend via a single bind command
@@ -30,21 +30,6 @@ The official docs can be found at [https://wails.app](https://wails.app).
- Powerful cli tool
- Multiplatform
## Sponsors
This project is supported by these kind people / companies:
<a href="https://www.jetbrains.com?from=Wails" style="width:100px"><img src="jetbrains-grayscale.png" width="100"/></a>
<a href="https://pace.dev" style="width:100px"><img src="pace.jpeg" width="100"/></a>
<a href="https://github.com/tc-hib" style="width:50px;border-radius: 50%">
<img src="https://github.com/tc-hib.png?size=50" width="50" style="border-radius: 50%"/>
</a>
<a href="https://github.com/picatz" style="width:50px;border-radius: 50%">
<img src="https://github.com/picatz.png?size=50" width="50" style="border-radius: 50%"/>
</a>
<a href="https://github.com/tylertravisty" style="width:50px;border-radius: 50%">
<img src="https://github.com/tylertravisty.png?size=50" width="50" style="border-radius: 50%"/>
</a>
## Installation
@@ -129,59 +114,17 @@ It is recommended at this stage to read the comprehensive documentation at [http
When I saw WebView, I thought "What I really want is tooling around building a WebView app, a bit like Rails is to Ruby". So initially it was a play on words (Webview on Rails). It just so happened to also be a homophone of the English name for the [Country](https://en.wikipedia.org/wiki/Wales) I am from. So it stuck.
## Contributors
<a href="https://github.com/qaisjp"><img src="https://github.com/qaisjp.png?size=40" width="40"/></a>
<a href="https://github.com/alee792"><img src="https://github.com/alee792.png?size=40" width="40"/></a>
<a href="https://github.com/lanzafame"><img src="https://github.com/lanzafame.png?size=40" width="40"/></a>
<a href="https://github.com/mattn"><img src="https://github.com/mattn.png?size=40" width="40"/></a>
<a href="https://github.com/0xflotus"><img src="https://github.com/0xflotus.png?size=40" width="40"/></a>
<a href="https://github.com/mdhender"><img src="https://github.com/mdhender.png?size=40" width="40"/></a>
<a href="https://github.com/fishfishfish2104"><img src="https://github.com/fishfishfish2104.png?size=40" width="40"/></a>
<a href="https://github.com/intelwalk"><img src="https://github.com/intelwalk.png?size=40" width="40"/></a>
<a href="https://github.com/ocelotsloth"><img src="https://github.com/ocelotsloth.png?size=40" width="40"/></a>
<a href="https://github.com/bh90210"><img src="https://github.com/bh90210.png?size=40" width="40"/></a>
<a href="https://github.com/iceleo-com"><img src="https://github.com/iceleo-com.png?size=40" width="40"/></a>
<a href="https://github.com/fallendusk"><img src="https://github.com/fallendusk.png?size=40" width="40"/></a>
<a href="https://github.com/Chronophylos"><img src="https://github.com/Chronophylos.png?size=40" width="40"/></a>
<a href="https://github.com/Vaelatern"><img src="https://github.com/Vaelatern.png?size=40" width="40"/></a>
<a href="https://github.com/mewmew"><img src="https://github.com/mewmew.png?size=40" width="40"/></a>
<a href="https://github.com/kraney"><img src="https://github.com/kraney.png?size=40" width="40"/></a>
<a href="https://github.com/JackMordaunt"><img src="https://github.com/JackMordaunt.png?size=40" width="40"/></a>
<a href="https://github.com/MichaelHipp"><img src="https://github.com/MichaelHipp.png?size=40" width="40"/></a>
<a href="https://github.com/tmclane"><img src="https://github.com/tmclane.png?size=40" width="40"/></a>
<a href="https://github.com/Rested"><img src="https://github.com/Rested.png?size=40" width="40"/></a>
<a href="https://github.com/Jarek-SRT"><img src="https://github.com/Jarek-SRT.png?size=40" width="40"/></a>
<a href="https://github.com/konez2k"><img src="https://github.com/konez2k.png?size=40" width="40"/></a>
<a href="https://github.com/sayuthisobri"><img src="https://github.com/sayuthisobri.png?size=40" width="40"/></a>
<a href="https://github.com/dedo1911"><img src="https://github.com/dedo1911.png?size=40" width="40"/></a>
<a href="https://github.com/fdidron"><img src="https://github.com/fdidron.png?size=40" width="40"/></a>
<a href="https://github.com/Splode"><img src="https://github.com/Splode.png?size=40" width="40"/></a>
<a href="https://github.com/Lyimmi"><img src="https://github.com/Lyimmi.png?size=40" width="40"/></a>
<a href="https://github.com/Unix4ever"><img src="https://github.com/Unix4ever.png?size=40" width="40"/></a>
<a href="https://github.com/timkippdev"><img src="https://github.com/timkippdev.png?size=40" width="40"/></a>
<a href="https://github.com/kyoto44"><img src="https://github.com/kyoto44.png?size=40" width="40"/></a>
<a href="https://github.com/artooro"><img src="https://github.com/artooro.png?size=40" width="40"/></a>
<a href="https://github.com/ilgityildirim"><img src="https://github.com/ilgityildirim.png?size=40" width="40"/></a>
<a href="https://github.com/gelleson"><img src="https://github.com/gelleson.png?size=40" width="40"/></a>
<a href="https://github.com/kmuchmore"><img src="https://github.com/kmuchmore.png?size=40" width="40"/></a>
<a href="https://github.com/aayush420"><img src="https://github.com/aayush420.png?size=40" width="40"/></a>
<a href="https://github.com/Rezrazi"><img src="https://github.com/Rezrazi.png?size=40" width="40"/></a>
<a href="https://github.com/misitebao"><img src="https://github.com/misitebao.png?size=40" width="40"/></a>
<a href="https://github.com/DrunkenPoney"><img src="https://github.com/DrunkenPoney.png?size=40" width="40"/></a>
<a href="https://github.com/SophieAu"><img src="https://github.com/SophieAu.png?size=40" width="40"/></a>
<a href="https://github.com/alexmat"><img src="https://github.com/alexmat.png?size=40" width="40"/></a>
<a href="https://github.com/RH12503"><img src="https://github.com/RH12503.png?size=40" width="40"/></a>
<a href="https://github.com/hi019"><img src="https://github.com/hi019.png?size=40" width="40"/></a></a>
<a href="https://github.com/Igogrek"><img src="https://github.com/Igogrek.png?size=40" width="40"/></a></a>
<a href="https://github.com/aschey"><img src="https://github.com/aschey.png?size=40" width="40"/></a></a>
## Special Mentions
## Shoulders of Giants
Without the following people, this project would never have existed:
* [Dustin Krysak](https://wiki.ubuntu.com/bashfulrobot) - His support and feedback has been immense. More patience than you can throw a stick at (Not long now Dustin!).
* [Serge Zaitsev](https://github.com/zserge) - Creator of [Webview](https://github.com/zserge/webview) which Wails uses for the windowing.
And without [these people](CONTRIBUTORS.md), it wouldn't be what it is today. A huge thank you to each and every one of you!
Special Mentions:
* [Byron](https://github.com/bh90210) - At times, Byron has single handedly kept this project alive. Without his incredible input, we never would have got to v1.
This project was mainly coded to the following albums:
@@ -207,8 +150,7 @@ This project was mainly coded to the following albums:
## Special Thanks
<p align="center" style="text-align: center">
<a href="https://pace.dev"><img src="pace.jpeg"/></a><br/>
A *huge* thanks to <a href="https://pace.dev">Pace</a> for sponsoring the project and helping the efforts to get Wails ported to Apple Silicon!<br/><br/>
A *huge* thanks to <a href="https://pace.dev"><img src="pace.jpeg"/> Pace</a> for sponsoring the project and helping the efforts to get Wails ported to Apple Silicon!<br/><br/>
If you are looking for a Project Management tool that's powerful but quick and easy to use, check them out!<br/><br/>
</p>

10
cmd/cmd-mewn.go Normal file

File diff suppressed because one or more lines are too long

View File

@@ -24,7 +24,7 @@ func (g *GitHubHelper) GetVersionTags() ([]*SemanticVersion, error) {
result := []*SemanticVersion{}
var err error
resp, err := http.Get("https://api.github.com/repos/wailsapp/wails/releases")
resp, err := http.Get("https://api.github.com/repos/wailsapp/wails/tags")
if err != nil {
return result, err
}

View File

@@ -2,6 +2,7 @@ package cmd
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"os/user"
@@ -11,12 +12,13 @@ import (
"strings"
"time"
"github.com/leaanthony/mewn"
"github.com/leaanthony/mewn/lib"
"github.com/leaanthony/slicer"
"github.com/leaanthony/spinner"
wailsruntime "github.com/wailsapp/wails/runtime"
)
const xgoVersion = "1.16.2"
const xgoVersion = "1.0.1"
var fs = NewFSHelper()
@@ -59,6 +61,30 @@ func InstallGoDependencies(verbose bool) error {
return nil
}
// EmbedAssets will embed the built frontend assets via mewn.
func EmbedAssets() ([]string, error) {
mewnFiles := lib.GetMewnFiles([]string{}, false)
referencedAssets, err := lib.GetReferencedAssets(mewnFiles)
if err != nil {
return []string{}, err
}
targetFiles := []string{}
for _, referencedAsset := range referencedAssets {
packfileData, err := lib.GeneratePackFileString(referencedAsset, false)
if err != nil {
return []string{}, err
}
targetFile := filepath.Join(referencedAsset.BaseDir, referencedAsset.PackageName+"-mewn.go")
targetFiles = append(targetFiles, targetFile)
ioutil.WriteFile(targetFile, []byte(packfileData), 0644)
}
return targetFiles, nil
}
func InitializeCrossCompilation(verbose bool) error {
// Check Docker
if err := CheckIfInstalled("docker"); err != nil {
@@ -101,10 +127,7 @@ func BuildDocker(binaryName string, buildMode string, projectOptions *ProjectOpt
// Check build directory
buildDirectory := filepath.Join(fs.Cwd(), "build")
if !fs.DirExists(buildDirectory) {
err := fs.MkDir(buildDirectory)
if err != nil {
return err
}
fs.MkDir(buildDirectory)
}
buildCommand := slicer.String()
@@ -175,6 +198,11 @@ func BuildDocker(binaryName string, buildMode string, projectOptions *ProjectOpt
// BuildNative builds on the target platform itself.
func BuildNative(binaryName string, forceRebuild bool, buildMode string, projectOptions *ProjectOptions) error {
// Check Mewn is installed
if err := CheckMewn(projectOptions.Verbose); err != nil {
return err
}
if err := CheckWindres(); err != nil {
return err
}
@@ -247,6 +275,12 @@ func BuildNative(binaryName string, forceRebuild bool, buildMode string, project
func BuildApplication(binaryName string, forceRebuild bool, buildMode string, packageApp bool, projectOptions *ProjectOptions) error {
var err error
// embed resources
targetFiles, err := EmbedAssets()
if err != nil {
return err
}
if projectOptions.CrossCompile {
if err := InitializeCrossCompilation(projectOptions.Verbose); err != nil {
return err
@@ -262,6 +296,20 @@ func BuildApplication(binaryName string, forceRebuild bool, buildMode string, pa
}
}
// cleanup temporary embedded assets
defer func() {
for _, filename := range targetFiles {
if err := os.Remove(filename); err != nil {
fmt.Println(err)
}
}
// Removed by popular demand
// TODO: Potentially add a flag to cleanup
// if projectOptions.Platform == "windows" {
// helper.CleanWindows(projectOptions)
// }
}()
if projectOptions.CrossCompile {
err = BuildDocker(binaryName, buildMode, projectOptions)
} else {
@@ -326,6 +374,30 @@ func BuildFrontend(projectOptions *ProjectOptions) error {
return nil
}
// CheckMewn checks if mewn is installed and if not, attempts to fetch it
func CheckMewn(verbose bool) (err error) {
programHelper := NewProgramHelper(verbose)
if !programHelper.IsInstalled("mewn") {
var buildSpinner *spinner.Spinner
if !verbose {
buildSpinner = spinner.New()
buildSpinner.SetSpinSpeed(50)
buildSpinner.Start("Installing Mewn asset packer...")
}
err := programHelper.InstallGoPackage("github.com/leaanthony/mewn/cmd/mewn")
if err != nil {
if buildSpinner != nil {
buildSpinner.Error()
}
return err
}
if buildSpinner != nil {
buildSpinner.Success()
}
}
return nil
}
// CheckWindres checks if Windres is installed and if not, aborts
func CheckWindres() (err error) {
if runtime.GOOS != "windows" { // FIXME: Handle windows cross-compile for windows!
@@ -421,18 +493,11 @@ func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forc
}
// Update md5sum file
err := os.WriteFile(md5sumFile, []byte(packageJSONMD5), 0644)
if err != nil {
return err
}
ioutil.WriteFile(md5sumFile, []byte(packageJSONMD5), 0644)
}
// Install the runtime
if caller == "build" {
err = InstallProdRuntime(projectDir, projectOptions)
} else {
err = InstallBridge(projectDir, projectOptions)
}
err = InstallRuntime(caller, projectDir, projectOptions)
if err != nil {
return err
}
@@ -445,17 +510,28 @@ func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forc
return nil
}
// InstallRuntime installs the correct runtime for the type of build
func InstallRuntime(caller string, projectDir string, projectOptions *ProjectOptions) error {
if caller == "build" {
return InstallProdRuntime(projectDir, projectOptions)
}
return InstallBridge(projectDir, projectOptions)
}
// InstallBridge installs the relevant bridge javascript library
func InstallBridge(projectDir string, projectOptions *ProjectOptions) error {
bridgeFileData := mewn.String("../runtime/assets/bridge.js")
bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, "node_modules", "@wailsapp", "runtime", "init.js")
err := fs.CreateFile(bridgeFileTarget, wailsruntime.BridgeJS)
err := fs.CreateFile(bridgeFileTarget, []byte(bridgeFileData))
return err
}
// InstallProdRuntime installs the production runtime
func InstallProdRuntime(projectDir string, projectOptions *ProjectOptions) error {
prodInit := mewn.String("../runtime/js/runtime/init.js")
bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, "node_modules", "@wailsapp", "runtime", "init.js")
err := fs.CreateFile(bridgeFileTarget, wailsruntime.InitJS)
err := fs.CreateFile(bridgeFileTarget, []byte(prodInit))
return err
}
@@ -519,9 +595,3 @@ func ldFlags(po *ProjectOptions, buildMode string) string {
}
return ldflags
}
func getGitConfigValue(key string) (string, error) {
output, err := exec.Command("git", "config", "--get", "--null", key).Output()
// When using --null git appends a null character (\u0000) to the command output
return strings.TrimRight(string(output), "\u0000"), err
}

View File

@@ -67,10 +67,6 @@ const (
Ctlos
// EndeavourOS linux distribution
EndeavourOS
// Crux linux distribution
Crux
// RHEL distribution
RHEL
)
// DistroInfo contains all the information relating to a linux distribution
@@ -133,8 +129,6 @@ func parseOsRelease(osRelease string) *DistroInfo {
result.Distribution = Fedora
case "centos":
result.Distribution = CentOS
case "rhel":
result.Distribution = RHEL
case "arch":
result.Distribution = Arch
case "archlabs":
@@ -181,8 +175,6 @@ func parseOsRelease(osRelease string) *DistroInfo {
result.Distribution = Solus
case "endeavouros":
result.Distribution = EndeavourOS
case "crux":
result.Distribution = Crux
default:
result.Distribution = Unknown
}
@@ -263,17 +255,6 @@ func RpmInstalled(packageName string) (bool, error) {
return exitCode == 0, nil
}
// PrtGetInstalled uses prt-get to see if a package is installed
func PrtGetInstalled(packageName string) (bool, error) {
program := NewProgramHelper()
prtget := program.FindProgram("prt-get")
if prtget == nil {
return false, fmt.Errorf("cannot check dependencies: prt-get not found")
}
_, _, exitCode, _ := prtget.Run("isinst", packageName)
return exitCode == 0, nil
}
// RequestSupportForDistribution promts the user to submit a request to support their
// currently unsupported distribution
func RequestSupportForDistribution(distroInfo *DistroInfo) error {

View File

@@ -138,25 +138,6 @@ distributions:
help: Please install with `sudo yum install gtk3-devel` and try again
- name: webkitgtk3-devel
help: Please install with `sudo yum install webkitgtk3-devel` and try again
rhel:
id: rhel
releases:
default:
version: default
name: Red Hat Enterprise Linux
gccversioncommand: *gccdumpversion
programs:
- name: gcc
help: Please install with `sudo yum install gcc-c++ make` and try again
- name: pkg-config
help: Please install with `sudo yum install pkgconf-pkg-config` and try again
- name: npm
help: Please install with `sudo yum install epel-release && sudo yum install nodejs` and try again
libraries:
- name: gtk3-devel
help: Please install with `sudo yum install gtk3-devel` and try again
- name: webkitgtk3-devel
help: Please install with `sudo yum install webkitgtk3-devel` and try again
fedora:
id: fedora
releases:
@@ -326,22 +307,3 @@ distributions:
gccversioncommand: *gccdumpfullversion
programs: *opensusedefaultprograms
libraries: *opensusedefaultlibraries
crux:
id: crux
releases:
default:
version: default
name: Crux Linux
gccversioncommand: *gccdumpversion
programs:
- name: gcc
help: Please install with `sudo prt-get depinst gcc-c++ make` and try again
- name: pkg-config
help: Please install with `sudo prt-get depinst pkg-config` and try again
- name: npm
help: Please install with `sudo prt-get depinst nodejs` and try again
libraries:
- name: gtk3
help: Please install with `sudo prt-get depinst gtk3` and try again
- name: webkitgtk
help: Please install with `sudo prt-get depinst webkitgtk` and try again

View File

@@ -354,7 +354,7 @@ func (b *PackageHelper) PackageWindows(po *ProjectOptions, cleanUp bool) error {
"docker", "run", "--rm",
"-v", outputDir + ":/build",
"--entrypoint", "/bin/sh",
"wailsapp/xgo:1.16.2",
"wailsapp/xgo:latest",
"-c", "/usr/bin/x86_64-w64-mingw32-windres -o /build/" + basename + "-res.syso /build/" + basename + ".rc",
}
if err := NewProgramHelper().RunCommandArray(args); err != nil {

View File

@@ -99,16 +99,11 @@ func (s *SystemHelper) setup() error {
if config.Name != "" {
systemConfig["name"] = PromptRequired("What is your name", config.Name)
} else if n, err := getGitConfigValue("user.name"); err == nil && n != "" {
systemConfig["name"] = PromptRequired("What is your name", n)
} else {
systemConfig["name"] = PromptRequired("What is your name")
}
if config.Email != "" {
systemConfig["email"] = PromptRequired("What is your email address", config.Email)
} else if e, err := getGitConfigValue("user.email"); err == nil && e != "" {
systemConfig["email"] = PromptRequired("What is your email address", e)
} else {
systemConfig["email"] = PromptRequired("What is your email address")
}
@@ -185,7 +180,7 @@ func (s *SystemHelper) Initialise() error {
return s.setup()
}
// SystemConfig - Defines system wide configuration data
// SystemConfig - Defines system wode configuration data
type SystemConfig struct {
Name string `json:"name"`
Email string `json:"email"`
@@ -283,7 +278,7 @@ func CheckDependencies(logger *Logger) (bool, error) {
libraryChecker = DpkgInstalled
case Arch, ArcoLinux, ArchLabs, Ctlos, Manjaro, ManjaroARM, EndeavourOS:
libraryChecker = PacmanInstalled
case CentOS, Fedora, Tumbleweed, Leap, RHEL:
case CentOS, Fedora, Tumbleweed, Leap:
libraryChecker = RpmInstalled
case Gentoo:
libraryChecker = EqueryInstalled
@@ -291,8 +286,6 @@ func CheckDependencies(logger *Logger) (bool, error) {
libraryChecker = XbpsInstalled
case Solus:
libraryChecker = EOpkgInstalled
case Crux:
libraryChecker = PrtGetInstalled
default:
return false, RequestSupportForDistribution(distroInfo)
}

View File

@@ -3,7 +3,7 @@
"version": "0.0.0",
"scripts": {
"ng": "npx ng",
"serve": "npx ng serve --poll=2000 --host=0.0.0.0",
"start": "npx ng serve --poll=2000 --host=0.0.0.0",
"build": "npx ng build --single-bundle true --output-hashing none --prod --bundle-styles false",
"test": "npx ng test",
"lint": "npx ng lint",

View File

@@ -1,7 +1,7 @@
package main
import (
_ "embed"
"github.com/leaanthony/mewn"
"github.com/wailsapp/wails"
)
@@ -9,14 +9,11 @@ func basic() string {
return "World!"
}
//go:embed frontend/dist/my-app/main.js
var js string
//go:embed frontend/dist/my-app/styles.css
var css string
func main() {
js := mewn.String("./frontend/dist/my-app/main.js")
css := mewn.String("./frontend/dist/my-app/styles.css")
app := wails.CreateApp(&wails.AppConfig{
Width: 1024,
Height: 768,

View File

@@ -14,7 +14,7 @@
"author": "bh90210 <ktc@pm.me>",
"created": "2019-06-15 18:23:48.666414555 +0300 EEST m=+223.934866008",
"frontenddir": "frontend",
"serve": "npm run serve",
"serve": "npx ng serve --poll=2000",
"bridge": "src",
"wailsdir": ""
}

View File

@@ -12,7 +12,7 @@
"@wailsapp/runtime": "^1.0.10"
},
"scripts": {
"serve": "react-scripts start",
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"

View File

@@ -1,7 +1,7 @@
package main
import (
_ "embed"
"github.com/leaanthony/mewn"
"github.com/wailsapp/wails"
)
@@ -9,14 +9,11 @@ func basic() string {
return "World!"
}
//go:embed frontend/build/static/js/main.js
var js string
//go:embed frontend/build/static/css/main.css
var css string
func main() {
js := mewn.String("./frontend/build/static/js/main.js")
css := mewn.String("./frontend/build/static/css/main.css")
app := wails.CreateApp(&wails.AppConfig{
Width: 1024,
Height: 768,

View File

@@ -8,7 +8,7 @@
"author": "bh90210 <ktc@pm.me>",
"created": "2019-06-07 18:23:48.666414555 +0300 EEST m=+223.934866008",
"frontenddir": "frontend",
"serve": "npm run serve",
"serve": "npm run start",
"bridge": "src",
"wailsdir": ""
}

View File

@@ -3,7 +3,7 @@
"author": "{{.Author.Name}}<{{.Author.Email}}>",
"scripts": {
"build": "rollup -c",
"serve": "rollup -c -w",
"dev": "rollup -c -w",
"start": "sirv public"
},
"devDependencies": {

View File

@@ -80,6 +80,7 @@ export default {
{
targets: '> 0.25%, not dead, IE 11',
modules: false,
spec: true,
useBuiltIns: 'usage',
forceAllTransforms: true,
corejs: 3,

View File

@@ -1,7 +1,7 @@
package main
import (
_ "embed"
"github.com/leaanthony/mewn"
"github.com/wailsapp/wails"
)
@@ -9,13 +9,9 @@ func basic() string {
return "World!"
}
//go:embed frontend/public/build/bundle.js
var js string
//go:embed frontend/public/build/bundle.css
var css string
func main() {
js := mewn.String("./frontend/public/build/bundle.js")
css := mewn.String("./frontend/public/build/bundle.css")
app := wails.CreateApp(&wails.AppConfig{
Width: 1024,

View File

@@ -8,7 +8,7 @@
"author": "Tim Kipp <timkipp.22.developer@gmail.com>",
"created": "2020-09-06 13:06:10.469848 -0700 PDT m=+213.578828559",
"frontenddir": "frontend",
"serve": "npm run serve",
"serve": "npm run dev",
"bridge": "src",
"wailsdir": ""
}

View File

@@ -1,18 +1,15 @@
package main
import (
_ "embed"
"github.com/leaanthony/mewn"
"github.com/wailsapp/wails"
)
//go:embed frontend/build/main.js
var js string
//go:embed frontend/build/main.css
var css string
func main() {
js := mewn.String("./frontend/build/main.js")
css := mewn.String("./frontend/build/main.css")
app := wails.CreateApp(&wails.AppConfig{
Width: 1024,
Height: 768,

View File

@@ -1,7 +1,7 @@
package main
import (
_ "embed"
"github.com/leaanthony/mewn"
"github.com/wailsapp/wails"
)
@@ -9,14 +9,11 @@ func basic() string {
return "Hello World!"
}
//go:embed frontend/dist/app.js
var js string
//go:embed frontend/dist/app.css
var css string
func main() {
js := mewn.String("./frontend/dist/app.js")
css := mewn.String("./frontend/dist/app.css")
app := wails.CreateApp(&wails.AppConfig{
Width: 1024,
Height: 768,

View File

@@ -1,7 +1,7 @@
package main
import (
_ "embed"
"github.com/leaanthony/mewn"
"github.com/wailsapp/wails"
)
@@ -9,14 +9,11 @@ func basic() string {
return "Hello World!"
}
//go:embed frontend/dist/app.js
var js string
//go:embed frontend/dist/app.css
var css string
func main() {
js := mewn.String("./frontend/dist/app.js")
css := mewn.String("./frontend/dist/app.css")
app := wails.CreateApp(&wails.AppConfig{
Width: 1024,
Height: 768,

View File

@@ -1,7 +1,7 @@
package main
import (
_ "embed"
"github.com/leaanthony/mewn"
"github.com/wailsapp/wails"
)
@@ -9,14 +9,11 @@ func basic() string {
return "Hello World!"
}
//go:embed frontend/dist/app.js
var js string
//go:embed frontend/dist/app.css
var css string
func main() {
js := mewn.String("./frontend/dist/app.js")
css := mewn.String("./frontend/dist/app.css")
app := wails.CreateApp(&wails.AppConfig{
Width: 1024,
Height: 768,

View File

@@ -1,7 +1,7 @@
package main
import (
_ "embed"
"github.com/leaanthony/mewn"
"github.com/wailsapp/wails"
)
@@ -9,14 +9,11 @@ func basic() string {
return "Hello World!"
}
//go:embed frontend/dist/app.js
var js string
//go:embed frontend/dist/app.css
var css string
func main() {
js := mewn.String("./frontend/dist/app.js")
css := mewn.String("./frontend/dist/app.css")
app := wails.CreateApp(&wails.AppConfig{
Width: 1024,
Height: 768,

View File

@@ -1,4 +1,4 @@
package cmd
// Version - Wails version
const Version = "v1.16.3"
const Version = "v1.11.0"

View File

@@ -39,6 +39,12 @@ Create your first project by running 'wails init'.`
return err
}
// Check Mewn
err = cmd.CheckMewn(false)
if err != nil {
return err
}
// Check for errors
// CheckDependencies() returns !errors
// so to get the right message in this

View File

@@ -2,7 +2,6 @@ package main
import (
"fmt"
"log"
"os"
"runtime"
"strings"
@@ -53,10 +52,7 @@ func init() {
var b strings.Builder
for _, plat := range getSupportedPlatforms() {
_, err := fmt.Fprintf(&b, " - %s\n", plat)
if err != nil {
log.Fatal(err)
}
fmt.Fprintf(&b, " - %s\n", plat)
}
initCmd.StringFlag("x",
fmt.Sprintf("Cross-compile application to specified platform via xgo\n%s", b.String()),
@@ -84,7 +80,7 @@ func init() {
fs := cmd.NewFSHelper()
err := projectOptions.LoadConfig(fs.Cwd())
if err != nil {
return fmt.Errorf("unable to find 'project.json'. Please check you are in a Wails project directory")
return fmt.Errorf("Unable to find 'project.json'. Please check you are in a Wails project directory")
}
// Set firebug flag
@@ -147,6 +143,12 @@ func init() {
if err != nil {
return err
}
// Ensure that runtime init.js is the production version
err = cmd.InstallProdRuntime(projectDir, projectOptions)
if err != nil {
return err
}
}
// Move to project directory

View File

@@ -27,13 +27,19 @@ func init() {
logger.PrintSmallBanner(message)
fmt.Println()
// Check Mewn is installed
err := cmd.CheckMewn(verbose)
if err != nil {
return err
}
// Project options
projectOptions := &cmd.ProjectOptions{}
// Check we are in project directory
// Check project.json loads correctly
fs := cmd.NewFSHelper()
err := projectOptions.LoadConfig(fs.Cwd())
err = projectOptions.LoadConfig(fs.Cwd())
if err != nil {
return err
}

View File

@@ -31,18 +31,6 @@ type AppConfig struct {
// Indicates whether your app should be resizable
Resizable bool
// Minimum width of a resizable window. If set, MinHeight should also be set.
MinWidth int
// Minimum height of a resizable window. If set, MinWidth should also be set.
MinHeight int
// Maximum width of a resizable window. If set, MaxHeight should also be set.
MaxWidth int
// Maximum height of a resizable window. If set, MaxWidth should also be set.
MaxHeight int
// Indicated if the devtools should be disabled
DisableInspector bool
}
@@ -77,26 +65,6 @@ func (a *AppConfig) GetResizable() bool {
return a.Resizable
}
// GetMinWidth returns the minimum width of the window
func (a *AppConfig) GetMinWidth() int {
return a.MinWidth
}
// GetMinHeight returns the minimum height of the window
func (a *AppConfig) GetMinHeight() int {
return a.MinHeight
}
// GetMaxWidth returns the maximum width of the window
func (a *AppConfig) GetMaxWidth() int {
return a.MaxWidth
}
// GetMaxHeight returns the maximum height of the window
func (a *AppConfig) GetMaxHeight() int {
return a.MaxHeight
}
// GetDisableInspector returns true if the inspector should be disabled
func (a *AppConfig) GetDisableInspector() bool {
return a.DisableInspector
@@ -147,23 +115,6 @@ func (a *AppConfig) merge(in *AppConfig) error {
if in.Height != 0 {
a.Height = in.Height
}
if in.MinWidth != 0 {
a.MinWidth = in.MinWidth
}
if in.MinHeight != 0 {
a.MinHeight = in.MinHeight
}
if in.MaxWidth != 0 {
a.MaxWidth = in.MaxWidth
}
if in.MaxHeight != 0 {
a.MaxHeight = in.MaxHeight
}
a.Resizable = in.Resizable
a.DisableInspector = in.DisableInspector
@@ -176,12 +127,8 @@ func newConfig(userConfig *AppConfig) (*AppConfig, error) {
Width: 800,
Height: 600,
Resizable: true,
MinWidth: -1,
MinHeight: -1,
MaxWidth: -1,
MaxHeight: -1,
Title: "My Wails App",
Colour: "",
Colour: "#FFF", // White by default
HTML: defaultHTML,
}

5
go.mod
View File

@@ -9,6 +9,7 @@ require (
github.com/jackmordaunt/icns v1.0.0
github.com/kennygrant/sanitize v1.2.4
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/leaanthony/mewn v0.10.7
github.com/leaanthony/slicer v1.4.0
github.com/leaanthony/spinner v0.5.3
github.com/mattn/go-colorable v0.1.1 // indirect
@@ -21,10 +22,10 @@ require (
github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba
golang.org/x/image v0.0.0-20200430140353-33d19683fad8
golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c
golang.org/x/text v0.3.0
gopkg.in/AlecAivazis/survey.v1 v1.8.4
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22
)
go 1.16
go 1.13

5
go.sum
View File

@@ -26,6 +26,8 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/leaanthony/mewn v0.10.7 h1:jCcNJyIUOpwj+I5SuATvCugDjHkoo+j6ubEOxxrxmPA=
github.com/leaanthony/mewn v0.10.7/go.mod h1:CRkTx8unLiSSilu/Sd7i1LwrdaAL+3eQ3ses99qGMEQ=
github.com/leaanthony/slicer v1.4.0 h1:Q9u4w+UBU4WHjXnEDdz+eRLMKF/rnyosRBiqULnc1J8=
github.com/leaanthony/slicer v1.4.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
github.com/leaanthony/spinner v0.5.3 h1:IMTvgdQCec5QA4qRy0wil4XsRP+QcG1OwLWVK/LPZ5Y=
@@ -64,6 +66,7 @@ github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba h1:2DHfQOxcpWdGf5
github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba/go.mod h1:iLnlXG2Pakcii2CU0cbY07DRCSvpWNa7nFxtevhOChk=
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw=
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -78,6 +81,8 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/AlecAivazis/survey.v1 v1.8.4 h1:10xXXN3wgIhPheb5NI58zFgZv32Ana7P3Tl4shW+0Qc=

View File

@@ -115,15 +115,15 @@ func (b *Manager) generateTypescriptDefinitions() error {
for structname, methodList := range b.structList {
structname = strings.SplitN(structname, ".", 2)[1]
output.WriteString(fmt.Sprintf("interface %s {\n", structname))
output.WriteString(fmt.Sprintf("Interface %s {\n", structname))
for _, method := range methodList {
output.WriteString(fmt.Sprintf("\t%s(...args : any[]):Promise<any>\n", method))
output.WriteString(fmt.Sprintf("\t%s: (...args : any[]) => Promise\n", method))
}
output.WriteString("}\n")
}
output.WriteString("\n")
output.WriteString("interface Backend {\n")
output.WriteString("Interface Backend {\n")
for structname := range b.structList {
structname = strings.SplitN(structname, ".", 2)[1]
@@ -136,8 +136,7 @@ declare global {
interface Window {
backend: Backend;
}
}
export {};`
}`
output.WriteString(globals)
b.log.Info("Written Typescript file: " + typescriptDefinitionFilename)

View File

@@ -18,7 +18,6 @@ type Manager struct {
log *logger.CustomLogger
renderer interfaces.Renderer // Messages will be dispatched to the frontend
wg sync.WaitGroup
mu sync.Mutex
}
// NewManager creates a new event manager with a 100 event buffer
@@ -43,12 +42,12 @@ func (e *Manager) PushEvent(eventData *messages.EventData) {
// means it does not expire (default).
type eventListener struct {
callback func(...interface{}) // Function to call with emitted event data
counter uint // Expire after counter callbacks. 0 = infinite
counter int // Expire after counter callbacks. 0 = infinite
expired bool // Indicates if the listener has expired
}
// Creates a new event listener from the given callback function
func (e *Manager) addEventListener(eventName string, callback func(...interface{}), counter uint) error {
func (e *Manager) addEventListener(eventName string, callback func(...interface{}), counter int) error {
// Sanity check inputs
if callback == nil {
@@ -76,30 +75,7 @@ func (e *Manager) addEventListener(eventName string, callback func(...interface{
// On adds a listener for the given event
func (e *Manager) On(eventName string, callback func(...interface{})) {
// Add a persistent eventListener (counter = 0)
err := e.addEventListener(eventName, callback, 0)
if err != nil {
e.log.Error(err.Error())
}
}
// Once adds a listener for the given event that will auto remove
// after one callback
func (e *Manager) Once(eventName string, callback func(...interface{})) {
// Add a persistent eventListener (counter = 0)
err := e.addEventListener(eventName, callback, 1)
if err != nil {
e.log.Error(err.Error())
}
}
// OnMultiple adds a listener for the given event that will trigger
// at most <counter> times.
func (e *Manager) OnMultiple(eventName string, callback func(...interface{}), counter uint) {
// Add a persistent eventListener (counter = 0)
err := e.addEventListener(eventName, callback, counter)
if err != nil {
e.log.Error(err.Error())
}
e.addEventListener(eventName, callback, 0)
}
// Emit broadcasts the given event to the subscribed listeners
@@ -132,24 +108,20 @@ func (e *Manager) Start(renderer interfaces.Renderer) {
})
// Notify renderer
err := e.renderer.NotifyEvent(event)
if err != nil {
e.log.Error(err.Error())
}
e.renderer.NotifyEvent(event)
e.mu.Lock()
// Notify Go listeners
var listenersToRemove []*eventListener
// Iterate listeners
for _, listener := range e.listeners[event.Name] {
if !listener.expired {
// Call listener, perhaps with data
if event.Data == nil {
go listener.callback()
} else {
unpacked := event.Data.([]interface{})
go listener.callback(unpacked...)
}
// Call listener, perhaps with data
if event.Data == nil {
go listener.callback()
} else {
unpacked := event.Data.([]interface{})
go listener.callback(unpacked...)
}
// Update listen counter
@@ -161,8 +133,15 @@ func (e *Manager) Start(renderer interfaces.Renderer) {
}
}
e.mu.Unlock()
// Remove expired listeners in place
if len(listenersToRemove) > 0 {
listeners := e.listeners[event.Name][:0]
for _, listener := range listeners {
if !listener.expired {
listeners = append(listeners, listener)
}
}
}
case <-e.quitChannel:
e.running = false
}

View File

@@ -5,10 +5,6 @@ type AppConfig interface {
GetWidth() int
GetHeight() int
GetTitle() string
GetMinWidth() int
GetMinHeight() int
GetMaxWidth() int
GetMaxHeight() int
GetResizable() bool
GetHTML() string
GetDisableInspector() bool

View File

@@ -6,8 +6,6 @@ import "github.com/wailsapp/wails/lib/messages"
type EventManager interface {
PushEvent(*messages.EventData)
Emit(eventName string, optionalData ...interface{})
OnMultiple(eventName string, callback func(...interface{}), counter uint)
Once(eventName string, callback func(...interface{}))
On(eventName string, callback func(...interface{}))
Start(Renderer)
Shutdown()

View File

@@ -22,10 +22,6 @@ type Renderer interface {
// Window Runtime
SetColour(string) error
SetMinSize(width, height int)
SetMaxSize(width, height int)
Fullscreen()
UnFullscreen()
SetTitle(title string)

View File

@@ -1,4 +1,4 @@
package interfaces
// Runtime interface
type Runtime interface{}
type Runtime interface {}

View File

@@ -186,18 +186,6 @@ func (h *Bridge) SetColour(colour string) error {
return nil
}
// SetMinSize is unsupported for Bridge but required
// for the Renderer interface
func (h *Bridge) SetMinSize(width, height int) {
h.log.Warn("SetMinSize() unsupported in bridge mode")
}
// SetMaxSize is unsupported for Bridge but required
// for the Renderer interface
func (h *Bridge) SetMaxSize(width, height int) {
h.log.Warn("SetMaxSize() unsupported in bridge mode")
}
// Fullscreen is unsupported for Bridge but required
// for the Renderer interface
func (h *Bridge) Fullscreen() {

File diff suppressed because one or more lines are too long

View File

@@ -3,9 +3,8 @@ package renderer
import (
"time"
"github.com/wailsapp/wails/runtime"
"github.com/gorilla/websocket"
"github.com/leaanthony/mewn"
"github.com/wailsapp/wails/lib/interfaces"
"github.com/wailsapp/wails/lib/logger"
)
@@ -59,7 +58,8 @@ func (s *session) start(firstSession bool) {
s.log.Infof("Connected to frontend.")
go s.writePump()
s.evalJS(runtime.WailsJS, wailsRuntimeMessage)
wailsRuntime := mewn.String("../../runtime/assets/wails.js")
s.evalJS(wailsRuntime, wailsRuntimeMessage)
// Inject bindings
for _, binding := range s.bindingCache {

File diff suppressed because one or more lines are too long

View File

@@ -8,9 +8,8 @@ import (
"sync"
"time"
"github.com/wailsapp/wails/runtime"
"github.com/go-playground/colors"
"github.com/leaanthony/mewn"
"github.com/wailsapp/wails/lib/interfaces"
"github.com/wailsapp/wails/lib/logger"
"github.com/wailsapp/wails/lib/messages"
@@ -30,7 +29,6 @@ type WebView struct {
config interfaces.AppConfig
eventManager interfaces.EventManager
bindingCache []string
maximumSizeSet bool
}
// NewWebView returns a new WebView struct
@@ -54,37 +52,10 @@ func (w *WebView) Initialise(config interfaces.AppConfig, ipc interfaces.IPCMana
// Save the config
w.config = config
width := config.GetWidth()
height := config.GetHeight()
// Clamp width and height
minWidth, minHeight := config.GetMinWidth(), config.GetMinHeight()
maxWidth, maxHeight := config.GetMaxWidth(), config.GetMaxHeight()
setMinSize := minWidth != -1 && minHeight != -1
setMaxSize := maxWidth != -1 && maxHeight != -1
if setMinSize {
if width < minWidth {
width = minWidth
}
if height < minHeight {
height = minHeight
}
}
if setMaxSize {
if width > maxWidth {
width = maxWidth
}
if height > maxHeight {
height = maxHeight
}
}
// Create the WebView instance
w.window = wv.NewWebview(wv.Settings{
Width: width,
Height: height,
Width: config.GetWidth(),
Height: config.GetHeight(),
Title: config.GetTitle(),
Resizable: config.GetResizable(),
URL: config.GetHTML(),
@@ -93,38 +64,16 @@ func (w *WebView) Initialise(config interfaces.AppConfig, ipc interfaces.IPCMana
w.ipc.Dispatch(message, w.callback)
},
})
fmt.Println("Control")
// Set minimum and maximum sizes
if setMinSize {
w.SetMinSize(minWidth, minHeight)
}
if setMaxSize {
w.SetMaxSize(maxWidth, maxHeight)
fmt.Println("Max")
}
// Set minimum and maximum sizes
if setMinSize {
w.SetMinSize(minWidth, minHeight)
}
if setMaxSize {
w.SetMaxSize(maxWidth, maxHeight)
}
// SignalManager.OnExit(w.Exit)
// Set colour
color := config.GetColour()
if color != "" {
err := w.SetColour(color)
if err != nil {
return err
}
err := w.SetColour(config.GetColour())
if err != nil {
return err
}
w.log.Info("Initialised")
return nil
}
@@ -234,8 +183,8 @@ func (w *WebView) Run() error {
}
// Runtime assets
w.log.DebugFields("Injecting wails JS runtime", logger.Fields{"js": runtime.WailsJS})
w.evalJS(runtime.WailsJS)
wailsRuntime := mewn.String("../../runtime/assets/wails.js")
w.evalJS(wailsRuntime)
// Ping the wait channel when the wails runtime is loaded
w.eventManager.On("wails:loaded", func(...interface{}) {
@@ -258,9 +207,10 @@ func (w *WebView) Run() error {
w.injectCSS(w.config.GetCSS())
} else {
// Use default wails css
w.log.Debug("Injecting Default Wails CSS")
defaultCSS := mewn.String("../../runtime/assets/wails.css")
w.log.Debug("Injecting Default Wails CSS: " + runtime.WailsCSS)
w.injectCSS(runtime.WailsCSS)
w.injectCSS(defaultCSS)
}
// Inject user JS
@@ -306,9 +256,6 @@ func (w *WebView) SelectFile(title string, filter string) string {
wg.Done()
})
}()
defer w.focus() // Ensure the main window is put back into focus afterwards
wg.Wait()
return result
}
@@ -327,9 +274,6 @@ func (w *WebView) SelectDirectory() string {
wg.Done()
})
}()
defer w.focus() // Ensure the main window is put back into focus afterwards
wg.Wait()
return result
}
@@ -348,20 +292,10 @@ func (w *WebView) SelectSaveFile(title string, filter string) string {
wg.Done()
})
}()
defer w.focus() // Ensure the main window is put back into focus afterwards
wg.Wait()
return result
}
// focus puts the main window into focus
func (w *WebView) focus() {
w.window.Dispatch(func() {
w.window.Focus()
})
}
// callback sends a callback to the frontend
func (w *WebView) callback(data string) error {
callbackCMD := fmt.Sprintf("window.wails._.Callback('%s');", data)
@@ -403,37 +337,11 @@ func (w *WebView) NotifyEvent(event *messages.EventData) error {
return w.evalJS(message)
}
// SetMinSize sets the minimum size of a resizable window
func (w *WebView) SetMinSize(width, height int) {
if w.config.GetResizable() == false {
w.log.Warn("Cannot call SetMinSize() - App.Resizable = false")
return
}
w.window.Dispatch(func() {
w.window.SetMinSize(width, height)
})
}
// SetMaxSize sets the maximum size of a resizable window
func (w *WebView) SetMaxSize(width, height int) {
if w.config.GetResizable() == false {
w.log.Warn("Cannot call SetMaxSize() - App.Resizable = false")
return
}
w.maximumSizeSet = true
w.window.Dispatch(func() {
w.window.SetMaxSize(width, height)
})
}
// Fullscreen makes the main window go fullscreen
func (w *WebView) Fullscreen() {
if w.config.GetResizable() == false {
w.log.Warn("Cannot call Fullscreen() - App.Resizable = false")
return
} else if w.maximumSizeSet {
w.log.Warn("Cannot call Fullscreen() - Maximum size of window set")
return
}
w.window.Dispatch(func() {
w.window.SetFullscreen(true)

View File

@@ -65,18 +65,6 @@ static inline void CgoWebViewSetTitle(void *w, char *title) {
webview_set_title((struct webview *)w, title);
}
static inline void CgoWebViewFocus(void *w) {
webview_focus((struct webview *)w);
}
static inline void CgoWebViewMinSize(void *w, int width, int height) {
webview_minsize((struct webview *)w, width, height);
}
static inline void CgoWebViewMaxSize(void *w, int width, int height) {
webview_maxsize((struct webview *)w, width, height);
}
static inline void CgoWebViewSetFullscreen(void *w, int fullscreen) {
webview_set_fullscreen((struct webview *)w, fullscreen);
}
@@ -182,16 +170,6 @@ type WebView interface {
// SetTitle() changes window title. This method must be called from the main
// thread only. See Dispatch() for more details.
SetTitle(title string)
// Focus() puts the main window into focus
Focus()
// SetMinSize() sets the minimum size of the window
SetMinSize(width, height int)
// SetMaxSize() sets the maximum size of the window
SetMaxSize(width, height int)
// SetFullscreen() controls window full-screen mode. This method must be
// called from the main thread only. See Dispatch() for more details.
SetFullscreen(fullscreen bool)
@@ -329,18 +307,6 @@ func (w *webview) SetColor(r, g, b, a uint8) {
C.CgoWebViewSetColor(w.w, C.uint8_t(r), C.uint8_t(g), C.uint8_t(b), C.uint8_t(a))
}
func (w *webview) Focus() {
C.CgoWebViewFocus(w.w)
}
func (w *webview) SetMinSize(width, height int) {
C.CgoWebViewMinSize(w.w, C.int(width), C.int(height))
}
func (w *webview) SetMaxSize(width, height int) {
C.CgoWebViewMaxSize(w.w, C.int(width), C.int(height))
}
func (w *webview) SetFullscreen(fullscreen bool) {
C.CgoWebViewSetFullscreen(w.w, C.int(boolToInt(fullscreen)))
}
@@ -387,9 +353,7 @@ func _webviewDispatchGoCallback(index unsafe.Pointer) {
f = fns[uintptr(index)]
delete(fns, uintptr(index))
m.Unlock()
if f != nil {
f()
}
f()
}
//export _webviewExternalInvokeCallback
@@ -405,7 +369,5 @@ func _webviewExternalInvokeCallback(w unsafe.Pointer, data unsafe.Pointer) {
}
}
m.Unlock()
if cb != nil {
cb(wv, C.GoString((*C.char)(data)))
}
cb(wv, C.GoString((*C.char)(data)))
}

View File

@@ -54,11 +54,6 @@ extern "C"
int ready;
int js_busy;
int should_exit;
int min_width;
int min_height;
int max_width;
int max_height;
};
#elif defined(WEBVIEW_WINAPI)
#define CINTERFACE
@@ -80,11 +75,6 @@ struct webview_priv
DWORD saved_style;
DWORD saved_ex_style;
RECT saved_rect;
int min_width;
int min_height;
int max_width;
int max_height;
};
#elif defined(WEBVIEW_COCOA)
#import <Cocoa/Cocoa.h>
@@ -178,9 +168,6 @@ struct webview_priv
WEBVIEW_API int webview_eval(struct webview *w, const char *js);
WEBVIEW_API int webview_inject_css(struct webview *w, const char *css);
WEBVIEW_API void webview_set_title(struct webview *w, const char *title);
WEBVIEW_API void webview_focus(struct webview *w);
WEBVIEW_API void webview_minsize(struct webview *w, int width, int height);
WEBVIEW_API void webview_maxsize(struct webview *w, int width, int height);
WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen);
WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g,
uint8_t b, uint8_t a);
@@ -342,12 +329,6 @@ struct webview_priv
w->priv.should_exit = 0;
w->priv.queue = g_async_queue_new();
w->priv.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
w->priv.min_width = -1;
w->priv.min_height = -1;
w->priv.max_width = -1;
w->priv.max_height = -1;
gtk_window_set_title(GTK_WINDOW(w->priv.window), w->title);
if (w->resizable)
@@ -415,49 +396,6 @@ struct webview_priv
gtk_window_set_title(GTK_WINDOW(w->priv.window), title);
}
WEBVIEW_API void webview_focus(struct webview *w)
{
gtk_window_present(GTK_WINDOW(w->priv.window));
}
WEBVIEW_API void webview_minsize(struct webview *w, int width, int height) {
w->priv.min_width = width;
w->priv.min_height = height;
GdkGeometry hints;
GdkWindowHints usedHints = (GdkWindowHints) GDK_HINT_MIN_SIZE;
hints.min_width = w->priv.min_width;
hints.min_height = w->priv.min_height;
if (w->priv.max_width != -1) {
hints.max_width = w->priv.max_width;
hints.max_height = w->priv.max_height;
usedHints = (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
}
gtk_window_set_geometry_hints(GTK_WINDOW(w->priv.window), w->priv.window, &hints, usedHints);
}
WEBVIEW_API void webview_maxsize(struct webview *w, int width, int height) {
w->priv.max_width = width;
w->priv.max_height = height;
GdkGeometry hints;
GdkWindowHints usedHints = (GdkWindowHints) GDK_HINT_MAX_SIZE;
if (w->priv.min_width != -1) {
hints.min_width = w->priv.min_width;
hints.min_height = w->priv.min_height;
usedHints = (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
}
hints.max_width = w->priv.max_width;
hints.max_height = w->priv.max_height;
gtk_window_set_geometry_hints(GTK_WINDOW(w->priv.window), w->priv.window, &hints, usedHints);
}
WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen)
{
if (fullscreen)
@@ -1393,39 +1331,7 @@ struct webview_priv
case WM_CREATE:
w = (struct webview *)((CREATESTRUCT *)lParam)->lpCreateParams;
w->priv.hwnd = hwnd;
return EmbedBrowserObject(w);
case WM_GETMINMAXINFO:
{
if (w != NULL) {
// get pixel density
HDC hDC = GetDC(NULL);
double DPIScaleX = GetDeviceCaps(hDC, 88)/96.0;
double DPIScaleY = GetDeviceCaps(hDC, 90)/96.0;
ReleaseDC(NULL, hDC);
RECT rcClient, rcWind;
POINT ptDiff;
GetClientRect(hwnd, &rcClient);
GetWindowRect(hwnd, &rcWind);
int widthExtra = (rcWind.right - rcWind.left) - rcClient.right;
int heightExtra = (rcWind.bottom - rcWind.top) - rcClient.bottom;
LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam;
if (w->priv.min_width != -1) {
lpMMI->ptMinTrackSize.x = w->priv.min_width * DPIScaleX + widthExtra;
lpMMI->ptMinTrackSize.y = w->priv.min_height * DPIScaleY + heightExtra;
}
if (w->priv.max_width != -1) {
lpMMI->ptMaxTrackSize.x = w->priv.max_width * DPIScaleX + widthExtra;
lpMMI->ptMaxTrackSize.y = w->priv.max_height * DPIScaleY + heightExtra;
}
}
return 0;
}
case WM_DESTROY:
UnEmbedBrowserObject(w);
PostQuitMessage(0);
@@ -1490,9 +1396,6 @@ struct webview_priv
WEBVIEW_API int webview_init(struct webview *w)
{
w->priv.min_width = -1;
w->priv.max_width = -1;
WNDCLASSEX wc;
HINSTANCE hInstance;
DWORD style;
@@ -1738,21 +1641,6 @@ struct webview_priv
#endif
}
WEBVIEW_API void webview_focus(struct webview *w)
{
SetFocus(w->priv.hwnd);
}
WEBVIEW_API void webview_minsize(struct webview *w, int width, int height) {
w->priv.min_width = width;
w->priv.min_height = height;
}
WEBVIEW_API void webview_maxsize(struct webview *w, int width, int height) {
w->priv.max_width = width;
w->priv.max_height = height;
}
WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen)
{
if (w->priv.is_fullscreen == !!fullscreen)
@@ -2320,29 +2208,6 @@ struct webview_priv
[w->priv.window setTitle:nsTitle];
}
WEBVIEW_API void webview_focus(struct webview *w)
{
[w->priv.window makeKeyWindow];
}
WEBVIEW_API void webview_minsize(struct webview *w, int width, int height) {
NSSize size;
size.width = width;
size.height = height;
[w->priv.window setMinSize:size];
}
WEBVIEW_API void webview_maxsize(struct webview *w, int width, int height) {
NSSize size;
size.width = width;
size.height = height;
[w->priv.window setMaxSize:size];
NSButton *button = [w->priv.window standardWindowButton:NSWindowZoomButton];
[button performSelectorOnMainThread:@selector(setEnabled:) withObject:NO
waitUntilDone:NO];
}
WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen)
{
int b = ((([w->priv.window styleMask] & NSWindowStyleMaskFullScreen) ==
@@ -2497,4 +2362,4 @@ struct webview_priv
}
#endif
#endif /* WEBVIEW_H */
#endif /* WEBVIEW_H */

3
package-lock.json generated
View File

@@ -1,3 +0,0 @@
{
"lockfileVersion": 1
}

View File

@@ -1,15 +0,0 @@
package runtime
import _ "embed"
//go:embed assets/bridge.js
var BridgeJS []byte
//go:embed assets/wails.js
var WailsJS string
//go:embed assets/wails.css
var WailsCSS string
//go:embed js/runtime/init.js
var InitJS []byte

File diff suppressed because one or more lines are too long

View File

@@ -19,16 +19,6 @@ func (r *Events) On(eventName string, callback func(optionalData ...interface{})
r.eventManager.On(eventName, callback)
}
// Once pass through
func (r *Events) Once(eventName string, callback func(optionalData ...interface{})) {
r.eventManager.Once(eventName, callback)
}
// OnMultiple pass through
func (r *Events) OnMultiple(eventName string, callback func(optionalData ...interface{}), counter uint) {
r.eventManager.OnMultiple(eventName, callback, counter)
}
// Emit pass through
func (r *Events) Emit(eventName string, optionalData ...interface{}) {
r.eventManager.Emit(eventName, optionalData...)

View File

@@ -1,9 +1,9 @@
/*
_ __ _ __
_ __ _ __
| | / /___ _(_) /____
| | /| / / __ `/ / / ___/
| |/ |/ / /_/ / / (__ )
|__/|__/\__,_/_/_/____/
| |/ |/ / /_/ / / (__ )
|__/|__/\__,_/_/_/____/
The lightweight framework for web-like apps
(c) Lea Anthony 2019-present
*/
@@ -21,20 +21,6 @@ import * as Store from './store';
window.wails = window.wails || {};
window.backend = {};
// On webkit2gtk >= 2.32, the external object is not passed to the window context.
// However, IE will throw a strict mode error if window.external is assigned to
// so we need to make sure that line of code isn't reached in IE
// Using !window.external transpiles to `window.external = window.external || ...`
// so we have to use an explicit if statement to prevent webpack from optimizing the code.
if (window.external == undefined) {
window.external = {
invoke: function(x) {
window.webkit.messageHandlers.external.postMessage(x);
}
};
}
// Setup internal calls
var internal = {
NewBinding,
@@ -75,7 +61,7 @@ window.onerror = function (msg, url, lineNo, columnNo, error) {
};
// Use firebug?
if( window.usefirebug ) {
if( window.usefirebug ) {
InjectFirebug();
}
@@ -85,4 +71,4 @@ Emit('wails:loaded');
// Nothing to init in production
export function Init(callback) {
callback();
}
}

View File

@@ -2681,18 +2681,26 @@
"dev": true
},
"elliptic": {
"version": "6.5.4",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
"integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz",
"integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==",
"dev": true,
"requires": {
"bn.js": "^4.11.9",
"brorand": "^1.1.0",
"bn.js": "^4.4.0",
"brorand": "^1.0.1",
"hash.js": "^1.0.0",
"hmac-drbg": "^1.0.1",
"inherits": "^2.0.4",
"minimalistic-assert": "^1.0.1",
"minimalistic-crypto-utils": "^1.0.1"
"hmac-drbg": "^1.0.0",
"inherits": "^2.0.1",
"minimalistic-assert": "^1.0.0",
"minimalistic-crypto-utils": "^1.0.0"
},
"dependencies": {
"bn.js": {
"version": "4.11.9",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
"dev": true
}
}
},
"emoji-regex": {
@@ -6582,9 +6590,9 @@
"dev": true
},
"y18n": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz",
"integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
"dev": true
},
"yallist": {

View File

@@ -451,9 +451,9 @@
}
},
"y18n": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz",
"integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
"integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
"dev": true
},
"yargs": {

View File

@@ -67,16 +67,6 @@ func (r *Window) SetColour(colour string) error {
return r.renderer.SetColour(colour)
}
// SetMinSize sets the minimum size of a resizable window
func (r *Window) SetMinSize(width, height int) {
r.renderer.SetMinSize(width, height)
}
// SetMaxSize sets the maximum size of a resizable window
func (r *Window) SetMaxSize(width, height int) {
r.renderer.SetMaxSize(width, height)
}
// Fullscreen makes the window fullscreen
func (r *Window) Fullscreen() {
r.renderer.Fullscreen()

View File

@@ -8,6 +8,38 @@ import (
"path/filepath"
)
// Default target to run when none is specified
// If not set, running mage will list available targets
// var Default = Build
/*
# Build runtime
echo "**** Building Runtime ****"
cd runtime/js
npm install
npm run build
cd ../..
echo "**** Packing Assets ****"
cd cmd
mewn
cd ..
cd lib/renderer
mewn
cd ../..
echo "**** Installing Wails locally ****"
cd cmd/wails
go install
cd ../..
echo "**** Tidying the mods! ****"
go mod tidy
echo "**** WE ARE DONE! ****"
*/
func runCommand(command string, args ...string) {
cmd := exec.Command(command, args...)
output, err := cmd.CombinedOutput()
@@ -16,6 +48,7 @@ func runCommand(command string, args ...string) {
log.Println(string(output))
log.Fatal(err)
}
cmd.Run()
fmt.Println(string(output))
}
@@ -27,26 +60,26 @@ func main() {
// Build Runtime
fmt.Println("**** Building Runtime ****")
runtimeDir, _ := filepath.Abs(filepath.Join(dir, "..", "runtime", "js"))
err := os.Chdir(runtimeDir)
if err != nil {
log.Fatal(err)
}
os.Chdir(runtimeDir)
runCommand("npm", "install")
runCommand("npm", "run", "build")
// Pack assets
fmt.Println("**** Packing Assets ****")
rendererDir, _ := filepath.Abs(filepath.Join(dir, "..", "lib", "renderer"))
os.Chdir(rendererDir)
runCommand("mewn")
cmdDir, _ := filepath.Abs(filepath.Join(dir, "..", "cmd"))
os.Chdir(cmdDir)
runCommand("mewn")
// Install Wails
fmt.Println("**** Installing Wails locally ****")
execDir, _ := filepath.Abs(filepath.Join(dir, "..", "cmd", "wails"))
err = os.Chdir(execDir)
if err != nil {
log.Fatal(err)
}
os.Chdir(execDir)
runCommand("go", "install")
baseDir, _ := filepath.Abs(filepath.Join(dir, ".."))
err = os.Chdir(baseDir)
if err != nil {
log.Fatal(err)
}
os.Chdir(baseDir)
runCommand("go", "mod", "tidy")
}

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash
echo "**** Checking if Wails passes unit tests ****"
if ! go test ./lib/... ./runtime/... ./cmd/...
if ! go test ./...
then
echo ""
echo "ERROR: Unit tests failed!"
@@ -15,6 +15,15 @@ npm install
npm run build
cd ../..
echo "**** Packing Assets ****"
cd cmd
mewn
cd ..
cd lib/renderer
mewn
cd ../..
cd cmd/wails
echo "**** Checking if Wails compiles ****"
if ! go build .

View File

@@ -16,6 +16,7 @@ cd runtime/js
npm run build
cd ../..
mewn
git add cmd/version.go
git commit cmd/version.go -m "Bump to ${TAG}"

13
v2/.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,13 @@
{
"files.associations": {
"ios": "c",
"typeinfo": "c",
"sstream": "c",
"__functional_03": "c",
"functional": "c",
"__locale": "c",
"locale": "c",
"chrono": "c",
"system_error": "c"
}
}

40
v2/NOTES.md Normal file
View File

@@ -0,0 +1,40 @@
# Packing linux
* create app, app.desktop, app.png (512x512)
* chmod +x app!
* ./linuxdeploy-x86_64.AppImage --appdir AppDir -i react.png -d react.desktop -e react --output appimage
# Wails Doctor
Tested on:
* Debian 8
* Ubuntu 20.04
* Ubuntu 19.10
* Solus 4.1
* Centos 8
* Gentoo
* OpenSUSE/leap
* Fedora 31
### Development
Add a new package manager processor here: `v2/internal/system/packagemanager/`. IsAvailable should work even if the package is installed.
Add your new package manager to the list of package managers in `v2/internal/system/packagemanager/packagemanager.go`:
```
var db = map[string]PackageManager{
"eopkg": NewEopkg(),
"apt": NewApt(),
"yum": NewYum(),
"pacman": NewPacman(),
"emerge": NewEmerge(),
"zypper": NewZypper(),
}
```
## Gentoo
* Setup docker image using: emerge-webrsync -x -v

5
v2/README.md Normal file
View File

@@ -0,0 +1,5 @@
# Wails v2 ALPHA
This branch contains WORK IN PROGRESS! There are no guarantees. Use at your peril!
This document will be updated as progress is made.

View File

@@ -0,0 +1,119 @@
package build
import (
"fmt"
"io"
"runtime"
"strings"
"time"
"github.com/leaanthony/clir"
"github.com/leaanthony/slicer"
"github.com/wailsapp/wails/v2/pkg/clilogger"
"github.com/wailsapp/wails/v2/pkg/commands/build"
)
// AddBuildSubcommand adds the `build` command for the Wails application
func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
outputType := "desktop"
validTargetTypes := slicer.String([]string{"desktop", "hybrid", "server"})
command := app.NewSubCommand("build", "Builds the application")
// Setup target type flag
description := "Type of application to build. Valid types: " + validTargetTypes.Join(",")
command.StringFlag("t", description, &outputType)
// Setup production flag
production := false
command.BoolFlag("production", "Build in production mode", &production)
// Setup pack flag
pack := false
command.BoolFlag("package", "Create a platform specific package", &pack)
compilerCommand := "go"
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &compilerCommand)
// Setup Platform flag
platform := runtime.GOOS
command.StringFlag("platform", "Platform to target", &platform)
// Quiet Build
quiet := false
command.BoolFlag("q", "Suppress output to console", &quiet)
// ldflags to pass to `go`
ldflags := ""
command.StringFlag("ldflags", "optional ldflags", &ldflags)
// Log to file
logFile := ""
command.StringFlag("l", "Log to file", &logFile)
// Retain assets
keepAssets := false
command.BoolFlag("k", "Keep generated assets", &keepAssets)
command.Action(func() error {
// Create logger
logger := clilogger.New(w)
logger.Mute(quiet)
// Validate output type
if !validTargetTypes.Contains(outputType) {
return fmt.Errorf("output type '%s' is not valid", outputType)
}
if !quiet {
app.PrintBanner()
}
task := fmt.Sprintf("Building %s Application", strings.Title(outputType))
logger.Println(task)
logger.Println(strings.Repeat("-", len(task)))
// Setup mode
mode := build.Debug
if production {
mode = build.Production
}
// Create BuildOptions
buildOptions := &build.Options{
Logger: logger,
OutputType: outputType,
Mode: mode,
Pack: pack,
Platform: platform,
LDFlags: ldflags,
Compiler: compilerCommand,
KeepAssets: keepAssets,
}
return doBuild(buildOptions)
})
}
// doBuild is our main build command
func doBuild(buildOptions *build.Options) error {
// Start Time
start := time.Now()
outputFilename, err := build.Build(buildOptions)
if err != nil {
return err
}
// Output stats
elapsed := time.Since(start)
buildOptions.Logger.Println("")
buildOptions.Logger.Println(fmt.Sprintf("Built '%s' in %s.", outputFilename, elapsed.Round(time.Millisecond).String()))
buildOptions.Logger.Println("")
return nil
}

View File

@@ -0,0 +1,123 @@
package debug
import (
"fmt"
"github.com/wailsapp/wails/v2/internal/shell"
"io"
"os"
"runtime"
"strings"
"time"
"github.com/leaanthony/clir"
"github.com/leaanthony/slicer"
"github.com/wailsapp/wails/v2/pkg/clilogger"
"github.com/wailsapp/wails/v2/pkg/commands/build"
)
// AddSubcommand adds the `debug` command for the Wails application
func AddSubcommand(app *clir.Cli, w io.Writer) error {
outputType := "desktop"
validTargetTypes := slicer.String([]string{"desktop", "hybrid", "server"})
command := app.NewSubCommand("debug", "Builds the application then runs delve on the binary")
// Setup target type flag
description := "Type of application to build. Valid types: " + validTargetTypes.Join(",")
command.StringFlag("t", description, &outputType)
compilerCommand := "go"
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &compilerCommand)
quiet := false
command.BoolFlag("q", "Suppress output to console", &quiet)
// ldflags to pass to `go`
ldflags := ""
command.StringFlag("ldflags", "optional ldflags", &ldflags)
// Log to file
logFile := ""
command.StringFlag("l", "Log to file", &logFile)
command.Action(func() error {
// Create logger
logger := clilogger.New(w)
logger.Mute(quiet)
// Validate output type
if !validTargetTypes.Contains(outputType) {
return fmt.Errorf("output type '%s' is not valid", outputType)
}
if !quiet {
app.PrintBanner()
}
task := fmt.Sprintf("Building %s Application", strings.Title(outputType))
logger.Println(task)
logger.Println(strings.Repeat("-", len(task)))
// Setup mode
mode := build.Debug
// Create BuildOptions
buildOptions := &build.Options{
Logger: logger,
OutputType: outputType,
Mode: mode,
Pack: false,
Platform: runtime.GOOS,
LDFlags: ldflags,
Compiler: compilerCommand,
KeepAssets: false,
}
outputFilename, err := doDebugBuild(buildOptions)
if err != nil {
return err
}
// Check delve exists
delveExists := shell.CommandExists("dlv")
if !delveExists {
return fmt.Errorf("cannot launch delve (Is it installed?)")
}
// Get cwd
cwd, err := os.Getwd()
if err != nil {
return err
}
// Launch delve
println("Launching Delve on port 2345...")
command := shell.CreateCommand(cwd, "dlv", "--listen=:2345", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", outputFilename)
return command.Run()
})
return nil
}
// doDebugBuild is our main build command
func doDebugBuild(buildOptions *build.Options) (string, error) {
// Start Time
start := time.Now()
outputFilename, err := build.Build(buildOptions)
if err != nil {
return "", err
}
// Output stats
elapsed := time.Since(start)
buildOptions.Logger.Println("")
buildOptions.Logger.Println(fmt.Sprintf("Built '%s' in %s.", outputFilename, elapsed.Round(time.Millisecond).String()))
buildOptions.Logger.Println("")
return outputFilename, nil
}

View File

@@ -0,0 +1,270 @@
package dev
import (
"fmt"
"io"
"os"
"os/signal"
"runtime"
"strings"
"syscall"
"time"
"github.com/fsnotify/fsnotify"
"github.com/leaanthony/clir"
"github.com/leaanthony/slicer"
"github.com/wailsapp/wails/v2/internal/fs"
"github.com/wailsapp/wails/v2/internal/process"
"github.com/wailsapp/wails/v2/pkg/clilogger"
"github.com/wailsapp/wails/v2/pkg/commands/build"
)
// AddSubcommand adds the `dev` command for the Wails application
func AddSubcommand(app *clir.Cli, w io.Writer) error {
command := app.NewSubCommand("dev", "Development mode")
outputType := "desktop"
validTargetTypes := slicer.String([]string{"desktop", "hybrid", "server"})
// Setup target type flag
description := "Type of application to develop. Valid types: " + validTargetTypes.Join(",")
command.StringFlag("t", description, &outputType)
// Passthrough ldflags
ldflags := ""
command.StringFlag("ldflags", "optional ldflags", &ldflags)
// compiler command
compilerCommand := "go"
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &compilerCommand)
// extensions to trigger rebuilds
extensions := "go"
command.StringFlag("m", "Extensions to trigger rebuilds (comma separated) eg go,js,css,html", &extensions)
command.Action(func() error {
// Validate inputs
if !validTargetTypes.Contains(outputType) {
return fmt.Errorf("output type '%s' is not valid", outputType)
}
// Create logger
logger := clilogger.New(w)
app.PrintBanner()
// TODO: Check you are in a project directory
watcher, err := fsnotify.NewWatcher()
if err != nil {
return err
}
defer watcher.Close()
var debugBinaryProcess *process.Process = nil
var buildFrontend bool = true
var extensionsThatTriggerARebuild = strings.Split(extensions, ",")
// Setup signal handler
quitChannel := make(chan os.Signal, 1)
signal.Notify(quitChannel, os.Interrupt, os.Kill, syscall.SIGTERM)
debounceQuit := make(chan bool, 1)
// Do initial build
logger.Println("Building application for development...")
debugBinaryProcess = restartApp(logger, outputType, ldflags, compilerCommand, buildFrontend, debugBinaryProcess)
go debounce(100*time.Millisecond, watcher.Events, debounceQuit, func(event fsnotify.Event) {
// logger.Println("event: %+v", event)
// Check for new directories
if event.Op&fsnotify.Create == fsnotify.Create {
// If this is a folder, add it to our watch list
if fs.DirExists(event.Name) {
if !strings.Contains(event.Name, "node_modules") {
err := watcher.Add(event.Name)
if err != nil {
logger.Fatal("%s", err.Error())
}
logger.Println("Watching directory: %s", event.Name)
}
}
return
}
// Check for file writes
if event.Op&fsnotify.Write == fsnotify.Write {
// logger.Println("modified file: %s", event.Name)
var rebuild bool = false
// Iterate all file patterns
for _, pattern := range extensionsThatTriggerARebuild {
rebuild = strings.HasSuffix(event.Name, pattern)
if err != nil {
logger.Fatal(err.Error())
}
if rebuild {
// Only build frontend when the file isn't a Go file
buildFrontend = !strings.HasSuffix(event.Name, "go")
break
}
}
if !rebuild {
logger.Println("Filename change: %s did not match extension list %s", event.Name, extensions)
return
}
if buildFrontend {
logger.Println("Full rebuild triggered: %s updated", event.Name)
} else {
logger.Println("Partial build triggered: %s updated", event.Name)
}
// Do a rebuild
// Try and build the app
newBinaryProcess := restartApp(logger, outputType, ldflags, compilerCommand, buildFrontend, debugBinaryProcess)
// If we have a new process, save it
if newBinaryProcess != nil {
debugBinaryProcess = newBinaryProcess
}
}
})
// Get project dir
dir, err := os.Getwd()
if err != nil {
return err
}
// Get all subdirectories
dirs, err := fs.GetSubdirectories(dir)
if err != nil {
return err
}
// Setup a watcher for non-node_modules directories
dirs.Each(func(dir string) {
if strings.Contains(dir, "node_modules") {
return
}
logger.Println("Watching directory: %s", dir)
err = watcher.Add(dir)
if err != nil {
logger.Fatal(err.Error())
}
})
// Wait until we get a quit signal
quit := false
for quit == false {
select {
case <-quitChannel:
println()
// Notify debouncer to quit
debounceQuit <- true
quit = true
}
}
// Kill the current program if running
if debugBinaryProcess != nil {
err := debugBinaryProcess.Kill()
if err != nil {
return err
}
}
logger.Println("Development mode exited")
return nil
})
return nil
}
// Credit: https://drailing.net/2018/01/debounce-function-for-golang/
func debounce(interval time.Duration, input chan fsnotify.Event, quitChannel chan bool, cb func(arg fsnotify.Event)) {
var item fsnotify.Event
timer := time.NewTimer(interval)
exit:
for {
select {
case item = <-input:
timer.Reset(interval)
case <-timer.C:
if item.Name != "" {
cb(item)
}
case <-quitChannel:
break exit
}
}
}
func restartApp(logger *clilogger.CLILogger, outputType string, ldflags string, compilerCommand string, buildFrontend bool, debugBinaryProcess *process.Process) *process.Process {
appBinary, err := buildApp(logger, outputType, ldflags, compilerCommand, buildFrontend)
println()
if err != nil {
logger.Println("[ERROR] Build Failed: %s", err.Error())
return nil
}
logger.Println("Build new binary: %s", appBinary)
// Kill existing binary if need be
if debugBinaryProcess != nil {
killError := debugBinaryProcess.Kill()
if killError != nil {
logger.Fatal("Unable to kill debug binary (PID: %d)!", debugBinaryProcess.PID())
}
debugBinaryProcess = nil
}
// TODO: Generate `backend.js`
// Start up new binary
newProcess := process.NewProcess(logger, appBinary)
err = newProcess.Start()
if err != nil {
// Remove binary
deleteError := fs.DeleteFile(appBinary)
if deleteError != nil {
logger.Fatal("Unable to delete app binary: " + appBinary)
}
logger.Fatal("Unable to start application: %s", err.Error())
}
return newProcess
}
func buildApp(logger *clilogger.CLILogger, outputType string, ldflags string, compilerCommand string, buildFrontend bool) (string, error) {
// Create random output file
outputFile := fmt.Sprintf("debug-%d", time.Now().Unix())
// Create BuildOptions
buildOptions := &build.Options{
Logger: logger,
OutputType: outputType,
Mode: build.Debug,
Pack: false,
Platform: runtime.GOOS,
LDFlags: ldflags,
Compiler: compilerCommand,
OutputFile: outputFile,
IgnoreFrontend: !buildFrontend,
}
return build.Build(buildOptions)
}

View File

@@ -0,0 +1,154 @@
package doctor
import (
"fmt"
"io"
"log"
"os"
"runtime"
"strings"
"text/tabwriter"
"github.com/leaanthony/clir"
"github.com/wailsapp/wails/v2/internal/system"
"github.com/wailsapp/wails/v2/internal/system/packagemanager"
"github.com/wailsapp/wails/v2/pkg/clilogger"
)
// AddSubcommand adds the `doctor` command for the Wails application
func AddSubcommand(app *clir.Cli, w io.Writer) error {
command := app.NewSubCommand("doctor", "Diagnose your environment")
command.Action(func() error {
logger := clilogger.New(w)
app.PrintBanner()
logger.Print("Scanning system - please wait...")
// Get system info
info, err := system.GetInfo()
if err != nil {
return err
}
logger.Println("Done.")
// Start a new tabwriter
w := new(tabwriter.Writer)
w.Init(os.Stdout, 8, 8, 0, '\t', 0)
// Write out the system information
fmt.Fprintf(w, "\n")
fmt.Fprintf(w, "System\n")
fmt.Fprintf(w, "------\n")
fmt.Fprintf(w, "%s\t%s\n", "OS:", info.OS.Name)
fmt.Fprintf(w, "%s\t%s\n", "Version: ", info.OS.Version)
fmt.Fprintf(w, "%s\t%s\n", "ID:", info.OS.ID)
// Exit early if PM not found
if info.PM == nil {
fmt.Fprintf(w, "\n%s\t%s", "Package Manager:", "Not Found")
w.Flush()
println()
return nil
}
fmt.Fprintf(w, "%s\t%s\n", "Package Manager: ", info.PM.Name())
// Output Go Information
fmt.Fprintf(w, "%s\t%s\n", "Go Version:", runtime.Version())
fmt.Fprintf(w, "%s\t%s\n", "Platform:", runtime.GOOS)
fmt.Fprintf(w, "%s\t%s\n", "Architecture:", runtime.GOARCH)
// Output Dependencies Status
var dependenciesMissing = []string{}
var externalPackages = []*packagemanager.Dependancy{}
var dependenciesAvailableRequired = 0
var dependenciesAvailableOptional = 0
fmt.Fprintf(w, "\n")
fmt.Fprintf(w, "Dependency\tPackage Name\tStatus\tVersion\n")
fmt.Fprintf(w, "----------\t------------\t------\t-------\n")
// Loop over dependencies
for _, dependency := range info.Dependencies {
name := dependency.Name
if dependency.Optional {
name += "*"
}
packageName := "Unknown"
status := "Not Found"
// If we found the package
if dependency.PackageName != "" {
packageName = dependency.PackageName
// If it's installed, update the status
if dependency.Installed {
status = "Installed"
} else {
// Generate meaningful status text
status = "Available"
if dependency.Optional {
dependenciesAvailableOptional++
} else {
dependenciesAvailableRequired++
}
}
} else {
if !dependency.Optional {
dependenciesMissing = append(dependenciesMissing, dependency.Name)
}
if dependency.External {
externalPackages = append(externalPackages, dependency)
}
}
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", name, packageName, status, dependency.Version)
}
fmt.Fprintf(w, "\n")
fmt.Fprintf(w, "* - Optional Dependency\n")
w.Flush()
logger.Println("")
logger.Println("Diagnosis")
logger.Println("---------\n")
// Generate an appropriate diagnosis
if len(dependenciesMissing) == 0 && dependenciesAvailableRequired == 0 {
logger.Println("Your system is ready for Wails development!")
}
if dependenciesAvailableRequired != 0 {
log.Println("Install required packages using: " + info.Dependencies.InstallAllRequiredCommand())
}
if dependenciesAvailableOptional != 0 {
log.Println("Install optional packages using: " + info.Dependencies.InstallAllOptionalCommand())
}
if len(externalPackages) > 0 {
for _, p := range externalPackages {
if p.Optional {
print("[Optional] ")
}
log.Println("Install " + p.Name + ": " + p.InstallCommand)
}
}
if len(dependenciesMissing) != 0 {
// TODO: Check if apps are available locally and if so, adjust the diagnosis
log.Println("Fatal:")
log.Println("Required dependencies missing: " + strings.Join(dependenciesMissing, " "))
log.Println("Please read this article on how to resolve this: https://wails.app/guides/resolving-missing-packages")
}
log.Println("")
return nil
})
return nil
}

View File

@@ -0,0 +1,91 @@
package generate
import (
"io"
"time"
"github.com/leaanthony/clir"
"github.com/wailsapp/wails/v2/pkg/clilogger"
"github.com/wailsapp/wails/v2/pkg/parser"
)
// AddSubcommand adds the `dev` command for the Wails application
func AddSubcommand(app *clir.Cli, w io.Writer) error {
command := app.NewSubCommand("generate", "Code Generation Tools")
// Backend API
backendAPI := command.NewSubCommand("module", "Generates a JS module for the frontend to interface with the backend")
// Quiet Init
quiet := false
backendAPI.BoolFlag("q", "Supress output to console", &quiet)
backendAPI.Action(func() error {
// Create logger
logger := clilogger.New(w)
logger.Mute(quiet)
app.PrintBanner()
logger.Print("Generating Javascript module for Go code...")
// Start Time
start := time.Now()
p, err := parser.GenerateWailsFrontendPackage()
if err != nil {
return err
}
logger.Println("done.")
logger.Println("")
elapsed := time.Since(start)
packages := p.Packages
// Print report
for _, pkg := range p.Packages {
if pkg.ShouldGenerate() {
logPackage(pkg, logger)
}
}
logger.Println("%d packages parsed in %s.", len(packages), elapsed)
return nil
})
return nil
}
func logPackage(pkg *parser.Package, logger *clilogger.CLILogger) {
logger.Println("Processed Go package '" + pkg.Gopackage.Name + "' as '" + pkg.Name + "'")
for _, strct := range pkg.Structs() {
logger.Println("")
logger.Println(" Processed struct '" + strct.Name + "'")
if strct.IsBound {
for _, method := range strct.Methods {
logger.Println(" Bound method '" + method.Name + "'")
}
}
if strct.IsUsedAsData {
for _, field := range strct.Fields {
if !field.Ignored {
logger.Print(" Processed ")
if field.IsOptional {
logger.Print("optional ")
}
logger.Println("field '" + field.Name + "' as '" + field.JSName() + "'")
}
}
}
}
logger.Println("")
// logger.Println(" Original Go Package Path:", pkg.Gopackage.PkgPath)
// logger.Println(" Original Go Package Path:", pkg.Gopackage.PkgPath)
}

View File

@@ -0,0 +1,182 @@
package initialise
import (
"fmt"
"io"
"strings"
"time"
"github.com/leaanthony/clir"
"github.com/pkg/errors"
"github.com/wailsapp/wails/v2/internal/templates"
"github.com/wailsapp/wails/v2/pkg/clilogger"
"github.com/wailsapp/wails/v2/pkg/git"
)
// AddSubcommand adds the `init` command for the Wails application
func AddSubcommand(app *clir.Cli, w io.Writer) error {
// Load the template shortnames
validShortNames, err := templates.TemplateShortNames()
if err != nil {
return err
}
command := app.NewSubCommand("init", "Initialise a new Wails project")
// Setup template name flag
templateName := "vanilla"
description := "Name of template to use. Valid tempates: " + validShortNames.Join(" ")
command.StringFlag("t", description, &templateName)
// Setup project name
projectName := ""
command.StringFlag("n", "Name of project", &projectName)
// Setup project directory
projectDirectory := ""
command.StringFlag("d", "Project directory", &projectDirectory)
// Quiet Init
quiet := false
command.BoolFlag("q", "Supress output to console", &quiet)
initGit := false
gitInstalled := git.IsInstalled()
if gitInstalled {
// Git Init
command.BoolFlag("g", "Initialise git repository", &initGit)
}
// VSCode project files
vscode := false
command.BoolFlag("vscode", "Generate VSCode project files", &vscode)
// List templates
list := false
command.BoolFlag("l", "List templates", &list)
command.Action(func() error {
// Create logger
logger := clilogger.New(w)
logger.Mute(quiet)
// Are we listing templates?
if list {
app.PrintBanner()
err := templates.OutputList(logger)
logger.Println("")
return err
}
// Validate output type
if !validShortNames.Contains(templateName) {
logger.Print(fmt.Sprintf("[ERROR] Template '%s' is not valid", templateName))
logger.Println("")
command.PrintHelp()
return nil
}
// Validate name
if len(projectName) == 0 {
logger.Println("ERROR: Project name required")
logger.Println("")
command.PrintHelp()
return nil
}
if !quiet {
app.PrintBanner()
}
task := fmt.Sprintf("Initialising Project %s", strings.Title(projectName))
logger.Println(task)
logger.Println(strings.Repeat("-", len(task)))
// Create Template Options
options := &templates.Options{
ProjectName: projectName,
TargetDir: projectDirectory,
TemplateName: templateName,
Logger: logger,
GenerateVSCode: vscode,
InitGit: initGit,
}
// Try to discover author details from git config
err := findAuthorDetails(options)
if err != nil {
return err
}
return initProject(options)
})
return nil
}
// initProject is our main init command
func initProject(options *templates.Options) error {
// Start Time
start := time.Now()
// Install the template
err := templates.Install(options)
if err != nil {
return err
}
if options.InitGit {
err = initGit(options)
if err != nil {
return err
}
}
// Output stats
elapsed := time.Since(start)
options.Logger.Println("")
options.Logger.Println("Project Name: " + options.ProjectName)
options.Logger.Println("Project Directory: " + options.TargetDir)
options.Logger.Println("Project Template: " + options.TemplateName)
if options.GenerateVSCode {
options.Logger.Println("VSCode config files generated.")
}
if options.InitGit {
options.Logger.Println("Git repository initialised.")
}
options.Logger.Println("")
options.Logger.Println(fmt.Sprintf("Initialised project '%s' in %s.", options.ProjectName, elapsed.Round(time.Millisecond).String()))
options.Logger.Println("")
return nil
}
func initGit(options *templates.Options) error {
err := git.InitRepo(options.TargetDir)
if err != nil {
return errors.Wrap(err, "Unable to initialise git repository:")
}
return nil
}
func findAuthorDetails(options *templates.Options) error {
if git.IsInstalled() {
name, err := git.Name()
if err != nil {
return err
}
options.AuthorName = strings.TrimSpace(name)
email, err := git.Email()
if err != nil {
return err
}
options.AuthorEmail = strings.TrimSpace(email)
}
return nil
}

55
v2/cmd/wails/main.go Normal file
View File

@@ -0,0 +1,55 @@
package main
import (
"os"
"github.com/leaanthony/clir"
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/build"
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/debug"
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/dev"
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/doctor"
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/generate"
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/initialise"
)
func fatal(message string) {
println(message)
os.Exit(1)
}
func main() {
var err error
app := clir.NewCli("Wails", "Go/HTML Application Framework", version)
build.AddBuildSubcommand(app, os.Stdout)
err = initialise.AddSubcommand(app, os.Stdout)
if err != nil {
fatal(err.Error())
}
err = debug.AddSubcommand(app, os.Stdout)
if err != nil {
fatal(err.Error())
}
err = doctor.AddSubcommand(app, os.Stdout)
if err != nil {
fatal(err.Error())
}
err = dev.AddSubcommand(app, os.Stdout)
if err != nil {
fatal(err.Error())
}
err = generate.AddSubcommand(app, os.Stdout)
if err != nil {
fatal(err.Error())
}
err = app.Run()
if err != nil {
println("\n\nERROR: " + err.Error())
}
}

3
v2/cmd/wails/version.go Normal file
View File

@@ -0,0 +1,3 @@
package main
var version = "v2.0.0-alpha.11"

28
v2/go.mod Normal file
View File

@@ -0,0 +1,28 @@
module github.com/wailsapp/wails/v2
go 1.15
require (
github.com/davecgh/go-spew v1.1.1
github.com/fatih/structtag v1.2.0
github.com/fsnotify/fsnotify v1.4.9
github.com/imdario/mergo v0.3.11
github.com/jackmordaunt/icns v1.0.0
github.com/leaanthony/clir v1.0.4
github.com/leaanthony/gosod v0.0.4
github.com/leaanthony/slicer v1.5.0
github.com/matryer/is v1.4.0
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/olekukonko/tablewriter v0.0.4
github.com/pkg/errors v0.9.1
github.com/tdewolff/minify v2.3.6+incompatible
github.com/tdewolff/parse v2.3.4+incompatible // indirect
github.com/tdewolff/test v1.0.6 // indirect
github.com/xyproto/xpm v1.2.1
golang.org/x/net v0.0.0-20200822124328-c89045814202
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c
golang.org/x/tools v0.0.0-20200902012652-d1954cc86c82
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
nhooyr.io/websocket v1.8.6
)

134
v2/go.sum Normal file
View File

@@ -0,0 +1,134 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/jackmordaunt/icns v1.0.0 h1:RYSxplerf/l/DUd09AHtITwckkv/mqjVv4DjYdPmAMQ=
github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/klauspost/compress v1.10.3 h1:OP96hzwJVBIHYU52pVTI6CczrxPvrGfgqF9N5eTO0Q8=
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leaanthony/clir v1.0.4 h1:Dov2y9zWJmZr7CjaCe86lKa4b5CSxskGAt2yBkoDyiU=
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
github.com/leaanthony/gosod v0.0.4 h1:v4hepo4IyL8E8c9qzDsvYcA0KGh7Npf8As74K5ibQpI=
github.com/leaanthony/gosod v0.0.4/go.mod h1:nGMCb1PJfXwBDbOAike78jEYlpqge+xUKFf0iBKjKxU=
github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/tdewolff/minify v2.3.6+incompatible h1:2hw5/9ZvxhWLvBUnHE06gElGYz+Jv9R4Eys0XUzItYo=
github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs=
github.com/tdewolff/parse v2.3.4+incompatible h1:x05/cnGwIMf4ceLuDMBOdQ1qGniMoxpP46ghf0Qzh38=
github.com/tdewolff/parse v2.3.4+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ=
github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/xyproto/xpm v1.2.1 h1:trdvGjjWBsOOKzBBUPT6JvaIQM3acJEEYfbxN7M96wg=
github.com/xyproto/xpm v1.2.1/go.mod h1:cMnesLsD0PBXLgjDfTDEaKr8XyTFsnP1QycSqRw7BiY=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9 h1:L2auWcuQIvxz9xSEqzESnV/QN/gNRXNApHi3fYwl2w0=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200902012652-d1954cc86c82 h1:shxDsb9Dz27xzk3A0DxP0JuJnZMpKrdg8+E14eiUAX4=
golang.org/x/tools v0.0.0-20200902012652-d1954cc86c82/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k=
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=

12
v2/internal/app/debug.go Normal file
View File

@@ -0,0 +1,12 @@
// +build debug
package app
// Init initialises the application for a debug environment
func (a *App) Init() error {
// Indicate debug mode
a.debug = true
// Enable dev tools
a.options.DevTools = true
return nil
}

View File

@@ -0,0 +1,44 @@
// +build !desktop,!hybrid,!server
package app
// This is the default application that will get run if the user compiles using `go build`.
// The reason we want to prevent that is that the `wails build` command does a lot of behind
// the scenes work such as asset compilation. If we allow `go build`, the state of these assets
// will be unknown and the application will not work as expected.
import (
"github.com/wailsapp/wails/v2/internal/logger"
"os"
"github.com/wailsapp/wails/v2/pkg/options"
)
// App defines a Wails application structure
type App struct {
Title string
Width int
Height int
Resizable bool
// Indicates if the app is running in debug mode
debug bool
logger *logger.Logger
}
// CreateApp returns a null application
func CreateApp(_ *options.App) (*App, error) {
return &App{}, nil
}
// Run the application
func (a *App) Run() error {
println(`FATAL: This application was built using "go build". This is unsupported. Please compile using "wails build".`)
os.Exit(1)
return nil
}
// Bind the dummy interface
func (a *App) Bind(_ interface{}) {
}

226
v2/internal/app/desktop.go Normal file
View File

@@ -0,0 +1,226 @@
// +build desktop,!server
package app
import (
"github.com/wailsapp/wails/v2/internal/binding"
"github.com/wailsapp/wails/v2/internal/ffenestri"
"github.com/wailsapp/wails/v2/internal/logger"
"github.com/wailsapp/wails/v2/internal/menumanager"
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
"github.com/wailsapp/wails/v2/internal/runtime"
"github.com/wailsapp/wails/v2/internal/servicebus"
"github.com/wailsapp/wails/v2/internal/signal"
"github.com/wailsapp/wails/v2/internal/subsystem"
"github.com/wailsapp/wails/v2/pkg/options"
)
// App defines a Wails application structure
type App struct {
window *ffenestri.Application
servicebus *servicebus.ServiceBus
logger *logger.Logger
signal *signal.Manager
options *options.App
// Subsystems
log *subsystem.Log
runtime *subsystem.Runtime
event *subsystem.Event
binding *subsystem.Binding
call *subsystem.Call
menu *subsystem.Menu
dispatcher *messagedispatcher.Dispatcher
menuManager *menumanager.Manager
// Indicates if the app is in debug mode
debug bool
// This is our binding DB
bindings *binding.Bindings
// Application Stores
loglevelStore *runtime.Store
appconfigStore *runtime.Store
// Startup/Shutdown
startupCallback func(*runtime.Runtime)
shutdownCallback func()
}
// Create App
func CreateApp(appoptions *options.App) (*App, error) {
// Merge default options
options.MergeDefaults(appoptions)
// Set up logger
myLogger := logger.New(appoptions.Logger)
myLogger.SetLogLevel(appoptions.LogLevel)
// Create the menu manager
menuManager := menumanager.NewManager()
// Process the application menu
menuManager.SetApplicationMenu(options.GetApplicationMenu(appoptions))
// Process context menus
contextMenus := options.GetContextMenus(appoptions)
for _, contextMenu := range contextMenus {
menuManager.AddContextMenu(contextMenu)
}
// Process tray menus
trayMenus := options.GetTrayMenus(appoptions)
for _, trayMenu := range trayMenus {
menuManager.AddTrayMenu(trayMenu)
}
window := ffenestri.NewApplicationWithConfig(appoptions, myLogger, menuManager)
result := &App{
window: window,
servicebus: servicebus.New(myLogger),
logger: myLogger,
bindings: binding.NewBindings(myLogger),
menuManager: menuManager,
startupCallback: appoptions.Startup,
shutdownCallback: appoptions.Shutdown,
}
result.options = appoptions
// Initialise the app
err := result.Init()
return result, err
}
// Run the application
func (a *App) Run() error {
var err error
// Setup signal handler
signalsubsystem, err := signal.NewManager(a.servicebus, a.logger)
if err != nil {
return err
}
a.signal = signalsubsystem
a.signal.Start()
// Start the service bus
a.servicebus.Debug()
err = a.servicebus.Start()
if err != nil {
return err
}
runtimesubsystem, err := subsystem.NewRuntime(a.servicebus, a.logger, a.startupCallback, a.shutdownCallback)
if err != nil {
return err
}
a.runtime = runtimesubsystem
err = a.runtime.Start()
if err != nil {
return err
}
// Application Stores
a.loglevelStore = a.runtime.GoRuntime().Store.New("wails:loglevel", a.options.LogLevel)
a.appconfigStore = a.runtime.GoRuntime().Store.New("wails:appconfig", a.options)
// Start the binding subsystem
bindingsubsystem, err := subsystem.NewBinding(a.servicebus, a.logger, a.bindings, a.runtime.GoRuntime())
if err != nil {
return err
}
a.binding = bindingsubsystem
err = a.binding.Start()
if err != nil {
return err
}
// Start the logging subsystem
log, err := subsystem.NewLog(a.servicebus, a.logger, a.loglevelStore)
if err != nil {
return err
}
a.log = log
err = a.log.Start()
if err != nil {
return err
}
// create the dispatcher
dispatcher, err := messagedispatcher.New(a.servicebus, a.logger)
if err != nil {
return err
}
a.dispatcher = dispatcher
err = dispatcher.Start()
if err != nil {
return err
}
// Start the eventing subsystem
event, err := subsystem.NewEvent(a.servicebus, a.logger)
if err != nil {
return err
}
a.event = event
err = a.event.Start()
if err != nil {
return err
}
// Start the menu subsystem
menusubsystem, err := subsystem.NewMenu(a.servicebus, a.logger, a.menuManager)
if err != nil {
return err
}
a.menu = menusubsystem
err = a.menu.Start()
if err != nil {
return err
}
// Start the call subsystem
call, err := subsystem.NewCall(a.servicebus, a.logger, a.bindings.DB(), a.runtime.GoRuntime())
if err != nil {
return err
}
a.call = call
err = a.call.Start()
if err != nil {
return err
}
// Dump bindings as a debug
bindingDump, err := a.bindings.ToJSON()
if err != nil {
return err
}
result := a.window.Run(dispatcher, bindingDump, a.debug)
a.logger.Trace("Ffenestri.Run() exited")
err = a.servicebus.Stop()
if err != nil {
return err
}
return result
}
// Bind a struct to the application by passing in
// a pointer to it
func (a *App) Bind(structPtr interface{}) {
// Add the struct to the bindings
err := a.bindings.Add(structPtr)
if err != nil {
a.logger.Fatal("Error during binding: " + err.Error())
}
}

205
v2/internal/app/hybrid.go Normal file
View File

@@ -0,0 +1,205 @@
// +build !server,!desktop,hybrid
package app
import (
"os"
"path/filepath"
"github.com/leaanthony/clir"
"github.com/wailsapp/wails/v2/internal/binding"
"github.com/wailsapp/wails/v2/internal/ffenestri"
"github.com/wailsapp/wails/v2/internal/logger"
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
"github.com/wailsapp/wails/v2/internal/servicebus"
"github.com/wailsapp/wails/v2/internal/subsystem"
"github.com/wailsapp/wails/v2/internal/webserver"
)
// Config defines the Application's configuration
type Config struct {
Title string // Title is the value to be displayed in the title bar
Width int // Width is the desired window width
Height int // Height is the desired window height
DevTools bool // DevTools enables or disables the browser development tools
Resizable bool // Resizable when False prevents window resizing
ServerEnabled bool // ServerEnabled when True allows remote connections
}
// App defines a Wails application structure
type App struct {
config Config
window *ffenestri.Application
webserver *webserver.WebServer
binding *subsystem.Binding
call *subsystem.Call
event *subsystem.Event
log *subsystem.Log
runtime *subsystem.Runtime
bindings *binding.Bindings
logger *logger.Logger
dispatcher *messagedispatcher.Dispatcher
servicebus *servicebus.ServiceBus
debug bool
}
// Create App
func CreateApp(options *Options) *App {
// Merge default options
options.mergeDefaults()
// Set up logger
myLogger := logger.New(os.Stdout)
myLogger.SetLogLevel(logger.INFO)
window := ffenestri.NewApplicationWithConfig(&ffenestri.Config{
Title: options.Title,
Width: options.Width,
Height: options.Height,
MinWidth: options.MinWidth,
MinHeight: options.MinHeight,
MaxWidth: options.MaxWidth,
MaxHeight: options.MaxHeight,
StartHidden: options.StartHidden,
DevTools: options.DevTools,
Resizable: !options.DisableResize,
Fullscreen: options.Fullscreen,
}, myLogger)
app := &App{
window: window,
webserver: webserver.NewWebServer(myLogger),
servicebus: servicebus.New(myLogger),
logger: myLogger,
bindings: binding.NewBindings(myLogger),
}
// Initialise the app
app.Init()
return app
}
// Run the application
func (a *App) Run() error {
// Default app options
var port = 8080
var ip = "localhost"
var suppressLogging = false
// Create CLI
cli := clir.NewCli(filepath.Base(os.Args[0]), "Desktop/Server Build", "")
// Setup flags
cli.IntFlag("p", "Port to serve on", &port)
cli.StringFlag("i", "IP to serve on", &ip)
cli.BoolFlag("q", "Suppress logging", &suppressLogging)
// Setup main action
cli.Action(func() error {
// Set IP + Port
a.webserver.SetPort(port)
a.webserver.SetIP(ip)
a.webserver.SetBindings(a.bindings)
// Log information (if we aren't suppressing it)
if !suppressLogging {
cli.PrintBanner()
a.logger.Info("Running server at %s", a.webserver.URL())
}
a.servicebus.Start()
log, err := subsystem.NewLog(a.servicebus, a.logger)
if err != nil {
return err
}
a.log = log
a.log.Start()
dispatcher, err := messagedispatcher.New(a.servicebus, a.logger)
if err != nil {
return err
}
a.dispatcher = dispatcher
a.dispatcher.Start()
// Start the runtime
runtime, err := subsystem.NewRuntime(a.servicebus, a.logger)
if err != nil {
return err
}
a.runtime = runtime
a.runtime.Start()
// Start the binding subsystem
binding, err := subsystem.NewBinding(a.servicebus, a.logger, a.bindings, runtime.GoRuntime())
if err != nil {
return err
}
a.binding = binding
a.binding.Start()
// Start the eventing subsystem
event, err := subsystem.NewEvent(a.servicebus, a.logger)
if err != nil {
return err
}
a.event = event
a.event.Start()
// Start the call subsystem
call, err := subsystem.NewCall(a.servicebus, a.logger, a.bindings.DB())
if err != nil {
return err
}
a.call = call
a.call.Start()
// Required so that the WailsInit functions are fired!
runtime.GoRuntime().Events.Emit("wails:loaded")
// Set IP + Port
a.webserver.SetPort(port)
a.webserver.SetIP(ip)
// Log information (if we aren't suppressing it)
if !suppressLogging {
cli.PrintBanner()
println("Running server at " + a.webserver.URL())
}
// Dump bindings as a debug
bindingDump, err := a.bindings.ToJSON()
if err != nil {
return err
}
go func() {
if err := a.webserver.Start(dispatcher, event); err != nil {
a.logger.Error("Webserver failed to start %s", err)
}
}()
result := a.window.Run(dispatcher, bindingDump)
a.servicebus.Stop()
return result
})
return cli.Run()
}
// Bind a struct to the application by passing in
// a pointer to it
func (a *App) Bind(structPtr interface{}) {
// Add the struct to the bindings
err := a.bindings.Add(structPtr)
if err != nil {
a.logger.Fatal("Error during binding: " + err.Error())
}
}

View File

@@ -0,0 +1,11 @@
// +build !debug
package app
import "github.com/wailsapp/wails/v2/pkg/logger"
// Init initialises the application for a production environment
func (a *App) Init() error {
a.logger.SetLogLevel(logger.ERROR)
return nil
}

160
v2/internal/app/server.go Normal file
View File

@@ -0,0 +1,160 @@
// +build server,!desktop
package app
import (
"os"
"path/filepath"
"github.com/leaanthony/clir"
"github.com/wailsapp/wails/v2/internal/binding"
"github.com/wailsapp/wails/v2/internal/logger"
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
"github.com/wailsapp/wails/v2/internal/servicebus"
"github.com/wailsapp/wails/v2/internal/subsystem"
"github.com/wailsapp/wails/v2/internal/webserver"
)
// App defines a Wails application structure
type App struct {
binding *subsystem.Binding
call *subsystem.Call
event *subsystem.Event
log *subsystem.Log
runtime *subsystem.Runtime
bindings *binding.Bindings
logger *logger.Logger
dispatcher *messagedispatcher.Dispatcher
servicebus *servicebus.ServiceBus
webserver *webserver.WebServer
debug bool
}
// Create App
func CreateApp(options *Options) *App {
options.mergeDefaults()
// We ignore the inputs (for now)
// TODO: Allow logger output override on CLI
myLogger := logger.New(os.Stdout)
myLogger.SetLogLevel(logger.TRACE)
result := &App{
bindings: binding.NewBindings(myLogger),
logger: myLogger,
servicebus: servicebus.New(myLogger),
webserver: webserver.NewWebServer(myLogger),
}
// Initialise app
result.Init()
return result
}
// Run the application
func (a *App) Run() error {
// Default app options
var port = 8080
var ip = "localhost"
var supressLogging = false
var debugMode = false
// Create CLI
cli := clir.NewCli(filepath.Base(os.Args[0]), "Server Build", "")
// Setup flags
cli.IntFlag("p", "Port to serve on", &port)
cli.StringFlag("i", "IP to serve on", &ip)
cli.BoolFlag("d", "Debug mode", &debugMode)
cli.BoolFlag("q", "Supress logging", &supressLogging)
// Setup main action
cli.Action(func() error {
// Set IP + Port
a.webserver.SetPort(port)
a.webserver.SetIP(ip)
a.webserver.SetBindings(a.bindings)
// Log information (if we aren't supressing it)
if !supressLogging {
cli.PrintBanner()
a.logger.Info("Running server at %s", a.webserver.URL())
}
if debugMode {
a.servicebus.Debug()
}
a.servicebus.Start()
log, err := subsystem.NewLog(a.servicebus, a.logger)
if err != nil {
return err
}
a.log = log
a.log.Start()
dispatcher, err := messagedispatcher.New(a.servicebus, a.logger)
if err != nil {
return err
}
a.dispatcher = dispatcher
a.dispatcher.Start()
// Start the runtime
runtime, err := subsystem.NewRuntime(a.servicebus, a.logger)
if err != nil {
return err
}
a.runtime = runtime
a.runtime.Start()
// Start the binding subsystem
binding, err := subsystem.NewBinding(a.servicebus, a.logger, a.bindings, runtime.GoRuntime())
if err != nil {
return err
}
a.binding = binding
a.binding.Start()
// Start the eventing subsystem
event, err := subsystem.NewEvent(a.servicebus, a.logger)
if err != nil {
return err
}
a.event = event
a.event.Start()
// Start the call subsystem
call, err := subsystem.NewCall(a.servicebus, a.logger, a.bindings.DB())
if err != nil {
return err
}
a.call = call
a.call.Start()
// Required so that the WailsInit functions are fired!
runtime.GoRuntime().Events.Emit("wails:loaded")
if err := a.webserver.Start(dispatcher, event); err != nil {
a.logger.Error("Webserver failed to start %s", err)
return err
}
return nil
})
return cli.Run()
}
// Bind a struct to the application by passing in
// a pointer to it
func (a *App) Bind(structPtr interface{}) {
// Add the struct to the bindings
err := a.bindings.Add(structPtr)
if err != nil {
a.logger.Fatal("Error during binding: " + err.Error())
}
}

View File

@@ -0,0 +1,112 @@
package assetdb
import (
"fmt"
"strings"
"unsafe"
)
// AssetDB is a database for assets encoded as byte slices
type AssetDB struct {
db map[string][]byte
}
// NewAssetDB creates a new AssetDB and initialises a blank db
func NewAssetDB() *AssetDB {
return &AssetDB{
db: make(map[string][]byte),
}
}
// AddAsset saves the given byte slice under the given name
func (a *AssetDB) AddAsset(name string, data []byte) {
a.db[name] = data
}
// Remove removes the named asset
func (a *AssetDB) Remove(name string) {
delete(a.db, name)
}
// Asset retrieves the byte slice for the given name
func (a *AssetDB) Read(name string) ([]byte, error) {
result := a.db[name]
if result == nil {
return nil, fmt.Errorf("asset '%s' not found", name)
}
return result, nil
}
// AssetAsString returns the asset as a string.
// It also returns a boolean indicating whether the asset existed or not.
func (a *AssetDB) String(name string) (string, error) {
asset, err := a.Read(name)
if err != nil {
return "", err
}
return *(*string)(unsafe.Pointer(&asset)), nil
}
func (a *AssetDB) Dump() {
fmt.Printf("Assets:\n")
for k, _ := range a.db {
fmt.Println(k)
}
}
// Serialize converts the entire database to a file that when compiled will
// reconstruct the AssetDB during init()
// name: name of the asset.AssetDB instance
// pkg: package name placed at the top of the file
func (a *AssetDB) Serialize(name, pkg string) string {
var cdata strings.Builder
// Set buffer size to 4k
cdata.Grow(4096)
// Write header
header := `// DO NOT EDIT - Generated automatically
package %s
import "github.com/wailsapp/wails/v2/internal/assetdb"
var (
%s *assetdb.AssetDB = assetdb.NewAssetDB()
)
// AssetsDB is a clean interface to the assetdb.AssetDB struct
type AssetsDB interface {
Read(string) ([]byte, error)
String(string) (string, error)
}
// Assets returns the asset database
func Assets() AssetsDB {
return %s
}
func init() {
`
cdata.WriteString(fmt.Sprintf(header, pkg, name, name))
for aname, bytes := range a.db {
cdata.WriteString(fmt.Sprintf("\t%s.AddAsset(\"%s\", []byte{",
name,
aname))
l := len(bytes)
if l == 0 {
cdata.WriteString("0x00})\n")
continue
}
// Convert each byte to hex
for _, b := range bytes[:l-1] {
cdata.WriteString(fmt.Sprintf("0x%x, ", b))
}
cdata.WriteString(fmt.Sprintf("0x%x})\n", bytes[l-1]))
}
cdata.WriteString(`}`)
return cdata.String()
}

View File

@@ -0,0 +1,70 @@
package assetdb
import "testing"
import "github.com/matryer/is"
func TestExistsAsBytes(t *testing.T) {
is := is.New(t)
var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33}
db := NewAssetDB()
db.AddAsset("hello", helloworld)
result, err := db.Read("hello")
is.True(err == nil)
is.Equal(result, helloworld)
}
func TestNotExistsAsBytes(t *testing.T) {
is := is.New(t)
var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33}
db := NewAssetDB()
db.AddAsset("hello4", helloworld)
result, err := db.Read("hello")
is.True(err != nil)
is.True(result == nil)
}
func TestExistsAsString(t *testing.T) {
is := is.New(t)
var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33}
db := NewAssetDB()
db.AddAsset("hello", helloworld)
result, err := db.String("hello")
// Ensure it exists
is.True(err == nil)
// Ensure the string is the same as the byte slice
is.Equal(result, "Hello, World!")
}
func TestNotExistsAsString(t *testing.T) {
is := is.New(t)
var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33}
db := NewAssetDB()
db.AddAsset("hello", helloworld)
result, err := db.String("help")
// Ensure it doesn't exist
is.True(err != nil)
// Ensure the string is blank
is.Equal(result, "")
}

View File

@@ -0,0 +1,176 @@
// +build !desktop
package assetdb
import (
"errors"
"io"
"net/http"
"os"
"path"
"sort"
"strings"
"time"
)
var errWhence = errors.New("Seek: invalid whence")
var errOffset = errors.New("Seek: invalid offset")
// Open implements the http.FileSystem interface for the AssetDB
func (a *AssetDB) Open(name string) (http.File, error) {
if name == "/" || name == "" {
return &Entry{name: "/", dir: true, db: a}, nil
}
if data, ok := a.db[name]; ok {
return &Entry{name: name, data: data, size: len(data)}, nil
} else {
for n, _ := range a.db {
if strings.HasPrefix(n, name+"/") {
return &Entry{name: name, db: a, dir: true}, nil
}
}
}
return &Entry{}, os.ErrNotExist
}
// readdir returns the directory entries for the requested directory
func (a *AssetDB) readdir(name string) ([]os.FileInfo, error) {
dir := name
var ents []string
fim := make(map[string]os.FileInfo)
for fn, data := range a.db {
if strings.HasPrefix(fn, dir) {
pieces := strings.Split(fn[len(dir)+1:], "/")
if len(pieces) == 1 {
fim[pieces[0]] = FI{name: pieces[0], dir: false, size: len(data)}
ents = append(ents, pieces[0])
} else {
fim[pieces[0]] = FI{name: pieces[0], dir: true, size: -1}
ents = append(ents, pieces[0])
}
}
}
if len(ents) == 0 {
return nil, os.ErrNotExist
}
sort.Strings(ents)
var list []os.FileInfo
for _, dir := range ents {
list = append(list, fim[dir])
}
return list, nil
}
// Entry implements the http.File interface to allow for
// use in the http.FileSystem implementation of AssetDB
type Entry struct {
name string
data []byte
dir bool
size int
db *AssetDB
off int
}
// Close is a noop
func (e Entry) Close() error {
return nil
}
// Read fills the slice provided returning how many bytes were written
// and any errors encountered
func (e *Entry) Read(p []byte) (n int, err error) {
if e.off >= e.size {
return 0, io.EOF
}
numout := len(p)
if numout > e.size {
numout = e.size
}
for i := 0; i < numout; i++ {
p[i] = e.data[e.off+i]
}
e.off += numout
n = int(numout)
err = nil
return
}
// Seek seeks to the specified offset from the location specified by whence
func (e *Entry) Seek(offset int64, whence int) (int64, error) {
switch whence {
default:
return 0, errWhence
case io.SeekStart:
offset += 0
case io.SeekCurrent:
offset += int64(e.off)
case io.SeekEnd:
offset += int64(e.size)
}
if offset < 0 {
return 0, errOffset
}
e.off = int(offset)
return offset, nil
}
// Readdir returns the directory entries inside this entry if it is a directory
func (e Entry) Readdir(count int) ([]os.FileInfo, error) {
ents := []os.FileInfo{}
if !e.dir {
return ents, errors.New("Not a directory")
}
return e.db.readdir(e.name)
}
// Stat returns information about this directory entry
func (e Entry) Stat() (os.FileInfo, error) {
return FI{e.name, e.size, e.dir}, nil
}
// FI is the AssetDB implementation of os.FileInfo.
type FI struct {
name string
size int
dir bool
}
// IsDir returns true if this is a directory
func (fi FI) IsDir() bool {
return fi.dir
}
// ModTime always returns now
func (fi FI) ModTime() time.Time {
return time.Time{}
}
// Mode returns the file as readonly and directories
// as world writeable and executable
func (fi FI) Mode() os.FileMode {
if fi.IsDir() {
return 0755 | os.ModeDir
}
return 0444
}
// Name returns the name of this object without
// any leading slashes
func (fi FI) Name() string {
return path.Base(fi.name)
}
// Size returns the size of this item
func (fi FI) Size() int64 {
return int64(fi.size)
}
// Sys returns nil
func (fi FI) Sys() interface{} {
return nil
}

View File

@@ -0,0 +1,108 @@
package assetdb
import (
"fmt"
"os"
"testing"
"github.com/matryer/is"
)
func TestOpenLeadingSlash(t *testing.T) {
is := is.New(t)
var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33}
db := NewAssetDB()
db.AddAsset("/hello", helloworld)
file, err := db.Open("/hello")
// Ensure it does exist
is.True(err == nil)
buff := make([]byte, len(helloworld))
n, err := file.Read(buff)
fmt.Printf("Error %v\n", err)
is.True(err == nil)
is.Equal(n, len(helloworld))
result := string(buff)
// Ensure the string is blank
is.Equal(result, string(helloworld))
}
func TestOpen(t *testing.T) {
is := is.New(t)
var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33}
db := NewAssetDB()
db.AddAsset("/hello", helloworld)
file, err := db.Open("/hello")
// Ensure it does exist
is.True(err == nil)
buff := make([]byte, len(helloworld))
n, err := file.Read(buff)
is.True(err == nil)
is.Equal(n, len(helloworld))
result := string(buff)
// Ensure the string is blank
is.Equal(result, string(helloworld))
}
func TestReaddir(t *testing.T) {
is := is.New(t)
var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33}
db := NewAssetDB()
db.AddAsset("/hello", helloworld)
db.AddAsset("/directory/hello", helloworld)
db.AddAsset("/directory/subdirectory/hello", helloworld)
dir, err := db.Open("/doesntexist")
is.True(err == os.ErrNotExist)
ents, err := dir.Readdir(-1)
is.Equal([]os.FileInfo{}, ents)
dir, err = db.Open("/")
is.True(dir != nil)
is.True(err == nil)
ents, err = dir.Readdir(-1)
is.True(err == nil)
is.Equal(3, len(ents))
}
func TestReaddirSubdirectory(t *testing.T) {
is := is.New(t)
var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33}
db := NewAssetDB()
db.AddAsset("/hello", helloworld)
db.AddAsset("/directory/hello", helloworld)
db.AddAsset("/directory/subdirectory/hello", helloworld)
expected := []os.FileInfo{
FI{name: "hello", dir: false, size: len(helloworld)},
FI{name: "subdirectory", dir: true, size: -1},
}
dir, err := db.Open("/directory")
is.True(dir != nil)
is.True(err == nil)
ents, err := dir.Readdir(-1)
is.Equal(expected, ents)
// Check sub-subdirectory
dir, err = db.Open("/directory/subdirectory")
is.True(dir != nil)
is.True(err == nil)
ents, err = dir.Readdir(-1)
is.True(err == nil)
is.Equal([]os.FileInfo{FI{name: "hello", size: len(helloworld)}}, ents)
}

9
v2/internal/bind/bind.go Normal file
View File

@@ -0,0 +1,9 @@
package bind
func IsStructPointer(value interface{}) bool {
switch t := value.(type) {
default:
println(t)
}
return false
}

50
v2/internal/binding/binding.go Executable file
View File

@@ -0,0 +1,50 @@
package binding
import (
"fmt"
"strings"
"github.com/wailsapp/wails/v2/internal/logger"
)
type Bindings struct {
db *DB
logger logger.CustomLogger
}
// NewBindings returns a new Bindings object
func NewBindings(logger *logger.Logger) *Bindings {
return &Bindings{
db: newDB(),
logger: logger.CustomLogger("Bindings"),
}
}
// Add the given struct methods to the Bindings
func (b *Bindings) Add(structPtr interface{}) error {
methods, err := getMethods(structPtr)
if err != nil {
return fmt.Errorf("cannot bind value to app: %s", err.Error())
}
for _, method := range methods {
splitName := strings.Split(method.Name, ".")
packageName := splitName[0]
structName := splitName[1]
methodName := splitName[2]
// Add it as a regular method
b.db.AddMethod(packageName, structName, methodName, method)
}
return nil
}
func (b *Bindings) DB() *DB {
return b.db
}
func (b *Bindings) ToJSON() (string, error) {
return b.db.ToJSON()
}

View File

@@ -0,0 +1,97 @@
package binding
import (
"encoding/json"
"fmt"
"reflect"
)
// BoundMethod defines all the data related to a Go method that is
// bound to the Wails application
type BoundMethod struct {
Name string `json:"name"`
Inputs []*Parameter `json:"inputs,omitempty"`
Outputs []*Parameter `json:"outputs,omitempty"`
Comments string `json:"comments,omitempty"`
Method reflect.Value `json:"-"`
}
// InputCount returns the number of inputs this bound method has
func (b *BoundMethod) InputCount() int {
return len(b.Inputs)
}
// OutputCount returns the number of outputs this bound method has
func (b *BoundMethod) OutputCount() int {
return len(b.Outputs)
}
// ParseArgs method converts the input json into the types expected by the method
func (b *BoundMethod) ParseArgs(args []json.RawMessage) ([]interface{}, error) {
result := make([]interface{}, b.InputCount())
for index, arg := range args {
typ := b.Inputs[index].reflectType
inputValue := reflect.New(typ).Interface()
err := json.Unmarshal(arg, inputValue)
if err != nil {
return nil, err
}
if inputValue == nil {
result[index] = reflect.Zero(typ).Interface()
} else {
result[index] = reflect.ValueOf(inputValue).Elem().Interface()
}
}
return result, nil
}
// Call will attempt to call this bound method with the given args
func (b *BoundMethod) Call(args []interface{}) (interface{}, error) {
// Check inputs
expectedInputLength := len(b.Inputs)
actualInputLength := len(args)
if expectedInputLength != actualInputLength {
return nil, fmt.Errorf("%s takes %d inputs. Received %d", b.Name, expectedInputLength, actualInputLength)
}
/** Convert inputs to reflect values **/
// Create slice for the input arguments to the method call
callArgs := make([]reflect.Value, expectedInputLength)
// Iterate over given arguments
for index, arg := range args {
// Save the converted argument
callArgs[index] = reflect.ValueOf(arg)
}
// Do the call
callResults := b.Method.Call(callArgs)
//** Check results **//
var returnValue interface{}
var err error
switch b.OutputCount() {
case 1:
// Loop over results and determine if the result
// is an error or not
for _, result := range callResults {
interfac := result.Interface()
temp, ok := interfac.(error)
if ok {
err = temp
} else {
returnValue = interfac
}
}
case 2:
returnValue = callResults[0].Interface()
if temp, ok := callResults[1].Interface().(error); ok {
err = temp
}
}
return returnValue, err
}

104
v2/internal/binding/db.go Normal file
View File

@@ -0,0 +1,104 @@
package binding
import (
"encoding/json"
"sync"
"unsafe"
)
// DB is our database of method bindings
type DB struct {
// map[packagename] -> map[structname] -> map[methodname]*method
store map[string]map[string]map[string]*BoundMethod
// This uses fully qualified method names as a shortcut for store traversal.
// It used for performance gains at runtime
methodMap map[string]*BoundMethod
// Lock to ensure sync access to the data
lock sync.RWMutex
}
func newDB() *DB {
return &DB{
store: make(map[string]map[string]map[string]*BoundMethod),
methodMap: make(map[string]*BoundMethod),
}
}
// GetMethodFromStore returns the method for the given package/struct/method names
// nil is returned if any one of those does not exist
func (d *DB) GetMethodFromStore(packageName string, structName string, methodName string) *BoundMethod {
// Lock the db whilst processing and unlock on return
d.lock.RLock()
defer d.lock.RUnlock()
structMap, exists := d.store[packageName]
if !exists {
return nil
}
methodMap, exists := structMap[structName]
if !exists {
return nil
}
return methodMap[methodName]
}
// GetMethod returns the method for the given qualified method name
// qualifiedMethodName is "packagename.structname.methodname"
func (d *DB) GetMethod(qualifiedMethodName string) *BoundMethod {
// Lock the db whilst processing and unlock on return
d.lock.RLock()
defer d.lock.RUnlock()
return d.methodMap[qualifiedMethodName]
}
// AddMethod adds the given method definition to the db using the given qualified path: packageName.structName.methodName
func (d *DB) AddMethod(packageName string, structName string, methodName string, methodDefinition *BoundMethod) {
// TODO: Validate inputs?
// Lock the db whilst processing and unlock on return
d.lock.Lock()
defer d.lock.Unlock()
// Get the map associated with the package name
structMap, exists := d.store[packageName]
if !exists {
// Create a new map for this packagename
d.store[packageName] = make(map[string]map[string]*BoundMethod)
structMap = d.store[packageName]
}
// Get the map associated with the struct name
methodMap, exists := structMap[structName]
if !exists {
// Create a new map for this packagename
structMap[structName] = make(map[string]*BoundMethod)
methodMap = structMap[structName]
}
// Store the method definition
methodMap[methodName] = methodDefinition
// Store in the methodMap
key := packageName + "." + structName + "." + methodName
d.methodMap[key] = methodDefinition
}
// ToJSON converts the method map to JSON
func (d *DB) ToJSON() (string, error) {
// Lock the db whilst processing and unlock on return
d.lock.RLock()
defer d.lock.RUnlock()
bytes, err := json.Marshal(&d.store)
// Return zero copy string as this string will be read only
return *(*string)(unsafe.Pointer(&bytes)), err
}

View File

@@ -0,0 +1,28 @@
package binding
import "reflect"
// Parameter defines a Go method parameter
type Parameter struct {
Name string `json:"name,omitempty"`
TypeName string `json:"type"`
reflectType reflect.Type
}
func newParameter(Name string, Type reflect.Type) *Parameter {
return &Parameter{
Name: Name,
TypeName: Type.String(),
reflectType: Type,
}
}
// IsType returns true if the given
func (p *Parameter) IsType(typename string) bool {
return p.TypeName == typename
}
// IsError returns true if the parameter type is an error
func (p *Parameter) IsError() bool {
return p.IsType("error")
}

97
v2/internal/binding/reflect.go Executable file
View File

@@ -0,0 +1,97 @@
package binding
import (
"fmt"
"reflect"
"runtime"
)
// isStructPtr returns true if the value given is a
// pointer to a struct
func isStructPtr(value interface{}) bool {
return reflect.ValueOf(value).Kind() == reflect.Ptr &&
reflect.ValueOf(value).Elem().Kind() == reflect.Struct
}
// isFunction returns true if the given value is a function
func isFunction(value interface{}) bool {
return reflect.ValueOf(value).Kind() == reflect.Func
}
// isStructPtr returns true if the value given is a struct
func isStruct(value interface{}) bool {
return reflect.ValueOf(value).Kind() == reflect.Struct
}
func getMethods(value interface{}) ([]*BoundMethod, error) {
// Create result placeholder
var result []*BoundMethod
// Check type
if !isStructPtr(value) {
if isStruct(value) {
name := reflect.ValueOf(value).Type().Name()
return nil, fmt.Errorf("%s is a struct, not a pointer to a struct", name)
}
if isFunction(value) {
name := runtime.FuncForPC(reflect.ValueOf(value).Pointer()).Name()
return nil, fmt.Errorf("%s is a function, not a pointer to a struct. Wails v2 has deprecated the binding of functions. Please wrap your functions up in a struct and bind a pointer to that struct.", name)
}
return nil, fmt.Errorf("not a pointer to a struct.")
}
// Process Struct
structType := reflect.TypeOf(value)
structValue := reflect.ValueOf(value)
baseName := structType.String()[1:]
// Process Methods
for i := 0; i < structType.NumMethod(); i++ {
methodDef := structType.Method(i)
methodName := methodDef.Name
fullMethodName := baseName + "." + methodName
method := structValue.MethodByName(methodName)
// Create new method
boundMethod := &BoundMethod{
Name: fullMethodName,
Inputs: nil,
Outputs: nil,
Comments: "",
Method: method,
}
// Iterate inputs
methodType := method.Type()
inputParamCount := methodType.NumIn()
var inputs []*Parameter
for inputIndex := 0; inputIndex < inputParamCount; inputIndex++ {
input := methodType.In(inputIndex)
thisParam := newParameter("", input)
inputs = append(inputs, thisParam)
}
boundMethod.Inputs = inputs
// Iterate outputs
// TODO: Determine what to do about limiting return types
// especially around errors.
outputParamCount := methodType.NumOut()
var outputs []*Parameter
for outputIndex := 0; outputIndex < outputParamCount; outputIndex++ {
output := methodType.Out(outputIndex)
thisParam := newParameter("", output)
outputs = append(outputs, thisParam)
}
boundMethod.Outputs = outputs
// Save method in result
result = append(result, boundMethod)
}
return result, nil
}

View File

@@ -0,0 +1,17 @@
package crypto
import (
"crypto/rand"
"fmt"
"log"
)
// RandomID returns a random ID as a string
func RandomID() string {
b := make([]byte, 16)
_, err := rand.Read(b)
if err != nil {
log.Fatal(err)
}
return fmt.Sprintf("%x", b)
}

View File

@@ -0,0 +1,13 @@
# 3rd Party Licenses
## vec
Homepage: https://github.com/rxi/vec
License: https://github.com/rxi/vec/blob/master/LICENSE
## json
Homepage: http://git.ozlabs.org/?p=ccan;a=tree;f=ccan/json;hb=HEAD
License: http://git.ozlabs.org/?p=ccan;a=blob;f=licenses/BSD-MIT;h=89de354795ec7a7cdab07c091029653d3618540d;hb=HEAD
## hashmap
Homepage: https://github.com/sheredom/hashmap.h
License: https://github.com/sheredom/hashmap.h/blob/master/LICENSE

View File

@@ -0,0 +1,95 @@
//
// Created by Lea Anthony on 6/1/21.
//
#include "common.h"
// Credit: https://stackoverflow.com/a/8465083
char* concat(const char *string1, const char *string2)
{
const size_t len1 = strlen(string1);
const size_t len2 = strlen(string2);
char *result = malloc(len1 + len2 + 1);
strcpy(result, string1);
memcpy(result + len1, string2, len2 + 1);
return result;
}
// 10k is more than enough for a log message
#define MAXMESSAGE 1024*10
char abortbuffer[MAXMESSAGE];
void ABORT(const char *message, ...) {
const char *temp = concat("FATAL: ", message);
va_list args;
va_start(args, message);
vsnprintf(abortbuffer, MAXMESSAGE, temp, args);
printf("%s\n", &abortbuffer[0]);
MEMFREE(temp);
va_end(args);
exit(1);
}
int freeHashmapItem(void *const context, struct hashmap_element_s *const e) {
free(e->data);
return -1;
}
const char* getJSONString(JsonNode *item, const char* key) {
// Get key
JsonNode *node = json_find_member(item, key);
const char *result = "";
if ( node != NULL && node->tag == JSON_STRING) {
result = node->string_;
}
return result;
}
void ABORT_JSON(JsonNode *node, const char* key) {
ABORT("Unable to read required key '%s' from JSON: %s\n", key, json_encode(node));
}
const char* mustJSONString(JsonNode *node, const char* key) {
const char* result = getJSONString(node, key);
if ( result == NULL ) {
ABORT_JSON(node, key);
}
return result;
}
JsonNode* mustJSONObject(JsonNode *node, const char* key) {
struct JsonNode* result = getJSONObject(node, key);
if ( result == NULL ) {
ABORT_JSON(node, key);
}
return result;
}
JsonNode* getJSONObject(JsonNode* node, const char* key) {
return json_find_member(node, key);
}
bool getJSONBool(JsonNode *item, const char* key, bool *result) {
JsonNode *node = json_find_member(item, key);
if ( node != NULL && node->tag == JSON_BOOL) {
*result = node->bool_;
return true;
}
return false;
}
bool getJSONInt(JsonNode *item, const char* key, int *result) {
JsonNode *node = json_find_member(item, key);
if ( node != NULL && node->tag == JSON_NUMBER) {
*result = (int) node->number_;
return true;
}
return false;
}
JsonNode* mustParseJSON(const char* JSON) {
JsonNode* parsedUpdate = json_decode(JSON);
if ( parsedUpdate == NULL ) {
ABORT("Unable to decode JSON: %s\n", JSON);
}
return parsedUpdate;
}

View File

@@ -0,0 +1,40 @@
//
// Created by Lea Anthony on 6/1/21.
//
#ifndef COMMON_H
#define COMMON_H
#define OBJC_OLD_DISPATCH_PROTOTYPES 1
#include <objc/objc-runtime.h>
#include <CoreGraphics/CoreGraphics.h>
#include <stdio.h>
#include <stdarg.h>
#include "string.h"
#include "hashmap.h"
#include "vec.h"
#include "json.h"
#define STREQ(a,b) strcmp(a, b) == 0
#define STREMPTY(string) strlen(string) == 0
#define STRCOPY(a) concat(a, "")
#define STR_HAS_CHARS(input) input != NULL && strlen(input) > 0
#define MEMFREE(input) free((void*)input); input = NULL;
#define FREE_AND_SET(variable, value) if( variable != NULL ) { MEMFREE(variable); } variable = value
// Credit: https://stackoverflow.com/a/8465083
char* concat(const char *string1, const char *string2);
void ABORT(const char *message, ...);
int freeHashmapItem(void *const context, struct hashmap_element_s *const e);
const char* getJSONString(JsonNode *item, const char* key);
const char* mustJSONString(JsonNode *node, const char* key);
JsonNode* getJSONObject(JsonNode* node, const char* key);
JsonNode* mustJSONObject(JsonNode *node, const char* key);
bool getJSONBool(JsonNode *item, const char* key, bool *result);
bool getJSONInt(JsonNode *item, const char* key, int *result);
JsonNode* mustParseJSON(const char* JSON);
#endif //ASSETS_C_COMMON_H

View File

@@ -0,0 +1,99 @@
////
//// Created by Lea Anthony on 6/1/21.
////
//
#include "ffenestri_darwin.h"
#include "common.h"
#include "contextmenus_darwin.h"
#include "menu_darwin.h"
ContextMenu* NewContextMenu(const char* contextMenuJSON) {
ContextMenu* result = malloc(sizeof(ContextMenu));
JsonNode* processedJSON = json_decode(contextMenuJSON);
if( processedJSON == NULL ) {
ABORT("[NewTrayMenu] Unable to parse TrayMenu JSON: %s", contextMenuJSON);
}
// Save reference to this json
result->processedJSON = processedJSON;
result->ID = mustJSONString(processedJSON, "ID");
JsonNode* processedMenu = mustJSONObject(processedJSON, "ProcessedMenu");
result->menu = NewMenu(processedMenu);
result->nsmenu = NULL;
result->menu->menuType = ContextMenuType;
result->menu->parentData = result;
result->contextMenuData = NULL;
return result;
}
ContextMenu* GetContextMenuByID(ContextMenuStore* store, const char *contextMenuID) {
return (ContextMenu*)hashmap_get(&store->contextMenuMap, (char*)contextMenuID, strlen(contextMenuID));
}
void DeleteContextMenu(ContextMenu* contextMenu) {
// Free Menu
DeleteMenu(contextMenu->menu);
// Delete any context menu data we may have stored
if( contextMenu->contextMenuData != NULL ) {
MEMFREE(contextMenu->contextMenuData);
}
// Free JSON
if (contextMenu->processedJSON != NULL ) {
json_delete(contextMenu->processedJSON);
contextMenu->processedJSON = NULL;
}
// Free context menu
free(contextMenu);
}
int freeContextMenu(void *const context, struct hashmap_element_s *const e) {
DeleteContextMenu(e->data);
return -1;
}
void ShowContextMenu(ContextMenuStore* store, id mainWindow, const char *contextMenuID, const char *contextMenuData) {
// If no context menu ID was given, abort
if( contextMenuID == NULL ) {
return;
}
ContextMenu* contextMenu = GetContextMenuByID(store, contextMenuID);
// We don't need the ID now
MEMFREE(contextMenuID);
if( contextMenu == NULL ) {
// Free context menu data
if( contextMenuData != NULL ) {
MEMFREE(contextMenuData);
return;
}
}
// We need to store the context menu data. Free existing data if we have it
// and set to the new value.
FREE_AND_SET(contextMenu->contextMenuData, contextMenuData);
// Grab the content view and show the menu
id contentView = msg(mainWindow, s("contentView"));
// Get the triggering event
id menuEvent = msg(mainWindow, s("currentEvent"));
if( contextMenu->nsmenu == NULL ) {
// GetMenu creates the NSMenu
contextMenu->nsmenu = GetMenu(contextMenu->menu);
}
// Show popup
msg(c("NSMenu"), s("popUpContextMenu:withEvent:forView:"), contextMenu->nsmenu, menuEvent, contentView);
}

View File

@@ -0,0 +1,33 @@
////
//// Created by Lea Anthony on 6/1/21.
////
//
#ifndef CONTEXTMENU_DARWIN_H
#define CONTEXTMENU_DARWIN_H
#include "json.h"
#include "menu_darwin.h"
#include "contextmenustore_darwin.h"
typedef struct {
const char* ID;
id nsmenu;
Menu* menu;
JsonNode* processedJSON;
// Context menu data is given by the frontend when clicking a context menu.
// We send this to the backend when an item is selected
const char* contextMenuData;
} ContextMenu;
ContextMenu* NewContextMenu(const char* contextMenuJSON);
ContextMenu* GetContextMenuByID( ContextMenuStore* store, const char *contextMenuID);
void DeleteContextMenu(ContextMenu* contextMenu);
int freeContextMenu(void *const context, struct hashmap_element_s *const e);
void ShowContextMenu(ContextMenuStore* store, id mainWindow, const char *contextMenuID, const char *contextMenuData);
#endif //CONTEXTMENU_DARWIN_H

View File

@@ -0,0 +1,65 @@
#include "contextmenus_darwin.h"
#include "contextmenustore_darwin.h"
ContextMenuStore* NewContextMenuStore() {
ContextMenuStore* result = malloc(sizeof(ContextMenuStore));
// Allocate Context Menu Store
if( 0 != hashmap_create((const unsigned)4, &result->contextMenuMap)) {
ABORT("[NewContextMenus] Not enough memory to allocate contextMenuStore!");
}
return result;
}
void AddContextMenuToStore(ContextMenuStore* store, const char* contextMenuJSON) {
ContextMenu* newMenu = NewContextMenu(contextMenuJSON);
//TODO: check if there is already an entry for this menu
hashmap_put(&store->contextMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu);
}
ContextMenu* GetContextMenuFromStore(ContextMenuStore* store, const char* menuID) {
// Get the current menu
return hashmap_get(&store->contextMenuMap, menuID, strlen(menuID));
}
void UpdateContextMenuInStore(ContextMenuStore* store, const char* menuJSON) {
ContextMenu* newContextMenu = NewContextMenu(menuJSON);
// Get the current menu
ContextMenu *currentMenu = GetContextMenuFromStore(store, newContextMenu->ID);
if ( currentMenu == NULL ) {
ABORT("Attempted to update unknown context menu with ID '%s'.", newContextMenu->ID);
}
hashmap_remove(&store->contextMenuMap, newContextMenu->ID, strlen(newContextMenu->ID));
// Save the status bar reference
DeleteContextMenu(currentMenu);
hashmap_put(&store->contextMenuMap, newContextMenu->ID, strlen(newContextMenu->ID), newContextMenu);
}
void DeleteContextMenuStore(ContextMenuStore* store) {
// Guard against NULLs
if( store == NULL ) {
return;
}
// Delete context menus
if( hashmap_num_entries(&store->contextMenuMap) > 0 ) {
if (0 != hashmap_iterate_pairs(&store->contextMenuMap, freeContextMenu, NULL)) {
ABORT("[DeleteContextMenuStore] Failed to release contextMenuStore entries!");
}
}
// Free context menu hashmap
hashmap_destroy(&store->contextMenuMap);
}

View File

@@ -0,0 +1,27 @@
//
// Created by Lea Anthony on 7/1/21.
//
#ifndef CONTEXTMENUSTORE_DARWIN_H
#define CONTEXTMENUSTORE_DARWIN_H
#include "common.h"
typedef struct {
int dummy;
// This is our context menu store which keeps track
// of all instances of ContextMenus
struct hashmap_s contextMenuMap;
} ContextMenuStore;
ContextMenuStore* NewContextMenuStore();
void DeleteContextMenuStore(ContextMenuStore* store);
void UpdateContextMenuInStore(ContextMenuStore* store, const char* menuJSON);
void AddContextMenuToStore(ContextMenuStore* store, const char* contextMenuJSON);
#endif //CONTEXTMENUSTORE_DARWIN_H

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,185 @@
package ffenestri
import (
"github.com/wailsapp/wails/v2/internal/menumanager"
"runtime"
"strings"
"unsafe"
"github.com/wailsapp/wails/v2/internal/logger"
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
"github.com/wailsapp/wails/v2/pkg/options"
)
/*
#cgo linux CFLAGS: -DFFENESTRI_LINUX=1
#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0
#cgo darwin CFLAGS: -DFFENESTRI_DARWIN=1
#cgo darwin LDFLAGS: -framework WebKit -lobjc
#include <stdlib.h>
#include "ffenestri.h"
*/
import "C"
// Application is our main application object
type Application struct {
config *options.App
memory []unsafe.Pointer
// This is the main app pointer
app *C.struct_Application
// Manages menus
menuManager *menumanager.Manager
// Logger
logger logger.CustomLogger
}
func (a *Application) saveMemoryReference(mem unsafe.Pointer) {
a.memory = append(a.memory, mem)
}
func (a *Application) string2CString(str string) *C.char {
result := C.CString(str)
a.saveMemoryReference(unsafe.Pointer(result))
return result
}
func init() {
runtime.LockOSThread()
}
// NewApplicationWithConfig creates a new application based on the given config
func NewApplicationWithConfig(config *options.App, logger *logger.Logger, menuManager *menumanager.Manager) *Application {
return &Application{
config: config,
logger: logger.CustomLogger("Ffenestri"),
menuManager: menuManager,
}
}
// NewApplication creates a new Application with the default config
func NewApplication(logger *logger.Logger) *Application {
return &Application{
config: options.Default,
logger: logger.CustomLogger("Ffenestri"),
}
}
func (a *Application) freeMemory() {
for _, mem := range a.memory {
// fmt.Printf("Freeing memory: %+v\n", mem)
C.free(mem)
}
}
// bool2Cint converts a Go boolean to a C integer
func (a *Application) bool2Cint(value bool) C.int {
if value {
return C.int(1)
}
return C.int(0)
}
// dispatcher is the interface to send messages to
var dispatcher *messagedispatcher.DispatchClient
// Dispatcher is what we register out client with
type Dispatcher interface {
RegisterClient(client messagedispatcher.Client) *messagedispatcher.DispatchClient
}
// DispatchClient is the means for passing messages to the backend
type DispatchClient interface {
SendMessage(string)
}
func intToColour(colour int) (C.int, C.int, C.int, C.int) {
var alpha = C.int(colour & 0xFF)
var blue = C.int((colour >> 8) & 0xFF)
var green = C.int((colour >> 16) & 0xFF)
var red = C.int((colour >> 24) & 0xFF)
return red, green, blue, alpha
}
// Run the application
func (a *Application) Run(incomingDispatcher Dispatcher, bindings string, debug bool) error {
title := a.string2CString(a.config.Title)
width := C.int(a.config.Width)
height := C.int(a.config.Height)
resizable := a.bool2Cint(!a.config.DisableResize)
devtools := a.bool2Cint(a.config.DevTools)
fullscreen := a.bool2Cint(a.config.Fullscreen)
startHidden := a.bool2Cint(a.config.StartHidden)
logLevel := C.int(a.config.LogLevel)
app := C.NewApplication(title, width, height, resizable, devtools, fullscreen, startHidden, logLevel)
// Save app reference
a.app = (*C.struct_Application)(app)
// Set Min Window Size
minWidth := C.int(a.config.MinWidth)
minHeight := C.int(a.config.MinHeight)
C.SetMinWindowSize(a.app, minWidth, minHeight)
// Set Max Window Size
maxWidth := C.int(a.config.MaxWidth)
maxHeight := C.int(a.config.MaxHeight)
C.SetMaxWindowSize(a.app, maxWidth, maxHeight)
// Set debug if needed
C.SetDebug(app, a.bool2Cint(debug))
// TODO: Move frameless to Linux options
// if a.config.Frameless {
// C.DisableFrame(a.app)
// }
if a.config.RGBA != 0 {
r, g, b, alpha := intToColour(a.config.RGBA)
C.SetColour(a.app, r, g, b, alpha)
}
// Escape bindings so C doesn't freak out
bindings = strings.ReplaceAll(bindings, `"`, `\"`)
// Set bindings
C.SetBindings(app, a.string2CString(bindings))
// save the dispatcher in a package variable so that the C callbacks
// can access it
dispatcher = incomingDispatcher.RegisterClient(newClient(a))
// Process platform settings
err := a.processPlatformSettings()
if err != nil {
return err
}
// Check we could initialise the application
if app != nil {
// Yes - Save memory reference and run app, cleaning up afterwards
a.saveMemoryReference(unsafe.Pointer(app))
C.Run(app, 0, nil)
} else {
// Oh no! We couldn't initialise the application
a.logger.Fatal("Cannot initialise Application.")
}
a.freeMemory()
return nil
}
// messageFromWindowCallback is called by any messages sent in
// webkit to window.external.invoke. It relays the message on to
// the dispatcher.
//export messageFromWindowCallback
func messageFromWindowCallback(data *C.char) {
dispatcher.DispatchMessage(C.GoString(data))
}

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