Compare commits

...

79 Commits

Author SHA1 Message Date
Lea Anthony
695f78861d [v2] v2.0.0-alpha.67 2021-06-21 19:28:51 +10:00
Lea Anthony
46ad4f4d18 [windows] Support SetPosition 2021-06-21 19:21:25 +10:00
Lea Anthony
2fc2d63e2d [v2] Remove SetColour 2021-06-21 18:05:45 +10:00
Lea Anthony
d137859d12 [windows] Support fullscreen config + api & unfullscreen api 2021-06-21 16:54:33 +10:00
Lea Anthony
09cf223aa2 [windows] Workaround webview2 bug being blank. Reduced flashing at start. 2021-06-21 15:48:24 +10:00
Lea Anthony
909da72eb2 [windows] Support StartHidden flag 2021-06-21 15:39:26 +10:00
Lea Anthony
2a06e2e577 [windows] Change location of application data 2021-06-21 15:27:14 +10:00
Lea Anthony
7f841ab85b [windows] hideWindowOnClose partial solution 2021-06-21 15:08:52 +10:00
Lea Anthony
a2d95e1b99 [v2] Update default template 2021-06-21 14:49:08 +10:00
Lea Anthony
d06f563bfe [windows] Fix application shutdown 2021-06-21 14:44:07 +10:00
Lea Anthony
c53d44b3ec [windows] Temporarily use common-dialog fork 2021-06-21 14:24:42 +10:00
Lea Anthony
5e51f426fa [windows] Fix app size, disable devtools in production build 2021-06-21 14:12:05 +10:00
Lea Anthony
193d9e8ed8 [windows] Better handle closing dialogs 2021-06-21 14:11:30 +10:00
Lea Anthony
2d03d355c2 [v2] Vanilla template fix (no drag) 2021-06-21 14:10:13 +10:00
Lea Anthony
185b7fed63 [windows] Lint fixes 2021-06-21 09:58:10 +10:00
Lea Anthony
ee6ad0bb27 [windows] Support frameless 2021-06-21 09:44:45 +10:00
Lea Anthony
3644f4ae1e [windows] Support drag 2021-06-21 09:04:14 +10:00
Lea Anthony
28d87a8e58 [windows] Improve Save Dialog 2021-06-20 16:09:22 +10:00
Lea Anthony
cf7d31e432 [windows] Improve Dialog Message API 2021-06-20 16:09:22 +10:00
Lea Anthony
fd40faabe8 [v2] Update build directory template. Update vanilla template. 2021-06-20 15:09:03 +10:00
Lea Anthony
d521f80dcd [windows] Improve Dialog API. Major refactor. 2021-06-20 13:48:30 +10:00
Lea Anthony
102a8cc5a6 [windows] Support Dialog API 2021-06-19 16:29:49 +10:00
Lea Anthony
e90f5361be [windows] Support webview2 runtime installation strategies 2021-06-15 21:25:08 +10:00
Lea Anthony
afe677d39d [windows] Update SDK scripts/files 2021-06-15 20:08:54 +10:00
Lea Anthony
58e6ce10ad [windows] Support disabling window icon 2021-06-14 12:00:47 +10:00
Lea Anthony
b0c522a59a [windows] Support translucent windows 2021-06-14 11:36:41 +10:00
Lea Anthony
62fc489001 [windows] Remove default app title 2021-06-14 11:04:24 +10:00
Lea Anthony
a269fc9e8c [windows] Support transparent webview 2021-06-13 20:47:01 +10:00
Lea Anthony
7cd6d109d4 [windows] Add missing files 2021-06-12 07:32:03 +10:00
Lea Anthony
1f8a2bb9b1 [windows] Update WebView2 to 1.0.864.35 2021-06-12 07:31:47 +10:00
Lea Anthony
eb2ac99067 [mac] fix compilation bug 2021-06-12 06:56:15 +10:00
Lea Anthony
79147c612e [v2] Big tidy up! 2021-06-12 06:49:38 +10:00
Lea Anthony
3d75ba174b [v2] If using -compiler flag, add go version to filename. 2021-06-11 15:24:42 +10:00
Lea Anthony
3933c5ab02 [windows] Better error message 2021-06-09 12:13:27 +10:00
Lea Anthony
aa5ff6ed2e [v2] Update vanilla template with @wails/runtime v1.3.20 2021-06-06 12:29:49 +10:00
Lea Anthony
407269b0d5 [v2] Update bridge assets. @wails/runtime v1.3.20 2021-06-06 12:21:26 +10:00
Lea Anthony
67a72cc693 [v2] Update debme for CopyFile() fix 2021-06-06 12:08:09 +10:00
Lea Anthony
955fe1d583 [v2] Better app icon 2021-06-06 11:35:35 +10:00
Lea Anthony
82bce89086 [mac] Update branding 2021-06-05 16:02:03 +10:00
Lea Anthony
c13257b9e9 [v2] v2.0.0-alpha.66 2021-06-05 14:37:12 +10:00
Lea Anthony
3f773f80ac [linux] Fix header signatures 2021-06-05 14:22:37 +10:00
Lea Anthony
5b23122b35 [v2] Make user + email discovery optional 2021-06-05 14:18:42 +10:00
Lea Anthony
d5cbfa6749 [linux] Support wails build and wails dev 2021-06-04 20:36:56 +10:00
Lea Anthony
3ad92192a9 [linux] Add linux runtime to wails dev 2021-06-04 20:34:55 +10:00
Lea Anthony
466676d99f [linux] Create Linux runtime 2021-06-04 20:32:40 +10:00
Lea Anthony
a1d5412465 [v2] Remove redundant apps package 2021-06-03 21:32:19 +10:00
Lea Anthony
9fdd5148ca [mac] Update runtime to use window.wailsInvoke 2021-06-03 21:01:14 +10:00
Lea Anthony
ac957b27cb [v1] Upgrade vanilla template to use runtime v1.3.19 2021-06-03 21:00:13 +10:00
Lea Anthony
20bc332720 [v1] Fix vanilla template package-lock.json 2021-06-03 20:33:25 +10:00
Lea Anthony
d2507660c2 [linux] Get CLI working. yum->dnf. doctor improvements. 2021-06-02 20:02:45 +10:00
Lea Anthony
64264c6378 [v2] Add README to vanilla template 2021-06-01 21:40:35 +10:00
Lea Anthony
ddadcdc18f [v2] Rebuild runtime 2021-05-31 20:09:04 +10:00
Lea Anthony
4738a0e0a8 [v2] Remove common.js 2021-05-31 20:08:11 +10:00
Lea Anthony
d2e4a0b0d2 [windows] Support wails dev 2021-05-31 20:01:40 +10:00
Lea Anthony
9f365ed85e [windows] Support rollup in vanilla template 2021-05-30 20:05:07 +10:00
Lea Anthony
5e733657c2 [v2] Updated runtime 2021-05-30 20:03:28 +10:00
Lea Anthony
93d9b61366 [windows] Fix bridge payload for 'wails dev' 2021-05-30 20:03:01 +10:00
Lea Anthony
b5d289bda9 [v2] Published @wails/runtime v1.3.14 2021-05-30 11:24:15 +10:00
Lea Anthony
319b7a3755 [v2] Change import to require for bridge for compatibility reasons 2021-05-30 11:22:40 +10:00
Lea Anthony
410d23b4d9 [windows] wails doctor docker support Better output 2021-05-30 11:06:38 +10:00
Lea Anthony
003e505c4a [mac] detect upx 2021-05-30 10:19:27 +10:00
Lea Anthony
22f09772d3 [mac] better wails doctor 2021-05-30 10:18:36 +10:00
Lea Anthony
a300172adc [windows] Better wails doctor installation details 2021-05-30 09:41:47 +10:00
Lea Anthony
1eba408f64 [windows] Better wails doctor diagnostics 2021-05-30 09:34:07 +10:00
Lea Anthony
be39b293b5 [mac] better wails doctor 2021-05-26 21:18:52 +10:00
Travis McLane
31cf04a944 fix shadowed err (#718) 2021-05-19 05:55:05 +10:00
Lea Anthony
f5912d29b6 Updated README.md 2021-05-18 21:29:03 +10:00
Lea Anthony
caad3a6b00 [windows] add icon to main window 2021-05-18 21:25:34 +10:00
Lea Anthony
08f4476087 Support for upx and more go:embed. 2021-05-18 21:25:16 +10:00
Lea Anthony
46ea3e6074 Better handling of process in wails dev 2021-05-18 21:22:52 +10:00
Lea Anthony
8be2a39daf [windows] Generate syso file for windows builds 2021-05-17 19:51:43 +10:00
Lea Anthony
7591b45ffa [windows] fix for no windows config 2021-05-17 19:50:12 +10:00
Travis McLane
f5056e7232 hack: enable builds on non-Windows 2021-05-16 13:51:14 +10:00
Alexander Hudek
101d344303 Merge pull request #715
* Fixed multi-line tags being minified incorrectly. Fixed self closing …

* Improved html whitespace minification fix.
2021-05-16 13:22:44 +10:00
Lea Anthony
6ab1a4adb0 Support passing arguments when using wails dev 2021-05-14 14:22:25 +10:00
Lea Anthony
5a30425091 [windows] Fix broken WebView2Loader.dll 2021-05-14 09:09:52 +10:00
Lea Anthony
e9deb248f9 Move assets -> build dir. Bundle assets in CLI binary. 2021-05-13 20:12:19 +10:00
Lea Anthony
7d0ff8b1a2 [windows] Updated webview.dll 2021-05-13 20:03:39 +10:00
Alexander Hudek
8399cc1e57 Fix width and height being set to zero when no max width and max height is set. (#709) 2021-05-13 18:49:53 +10:00
145 changed files with 6415 additions and 1649 deletions

2
.gitignore vendored
View File

@@ -28,4 +28,6 @@ v2/test/kitchensink/frontend/public
v2/test/kitchensink/build/darwin/desktop/kitchensink
v2/test/kitchensink/frontend/package.json.md5
/v2/internal/ffenestri/windows/test/cmake-build-debug/
!v2/internal/ffenestri/windows/x64/webview2.dll
!v2/internal/ffenestri/windows/x64/WebView2Loader.dll
.idea/

View File

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

View File

@@ -0,0 +1,54 @@
# Build
The build command processes the Wails project and generates an application binary.
## Usage
`wails build <flags>`
### Flags
| Flag | Details | Default |
| :------------- | :----------- | :------ |
| -clean | Clean the bin directory before building | |
| -compiler path/to/compiler | Use a different go compiler, eg go1.15beta1 | go |
| -ldflags "custom ld flags" | Use given ldflags | |
| -o path/to/binary | Compile to given path/filename | |
| -k | Keep generated assets | |
| -package | Create a platform specific package | |
| -production | Compile in production mode: -ldflags="-w -s" + "-h windows" on Windows | |
| -tags | Build tags to pass to Go compiler (quoted and space separated) | |
| -upx | Compress final binary with UPX (if installed) | |
| -upxflags "custom flags" | Flags to pass to upx | |
| -v int | Verbosity level (0 - silent, 1 - default, 2 - verbose) | 1 |
## The Build Process
The build process is as follows:
- The flags are processed, and an Options struct built containing the build context.
- The type of target is determined, and a custom build process is followed for target.
### Desktop Target
- The frontend dependencies are installed. The command is read from the project file `wails.json` under the key `frontend:install` and executed in the `frontend` directory. If this is not defined, it is ignored.
- The frontend is then built. This command is read from the project file `wails.json` under the key `frontend:install` and executed in the `frontend` directory. If this is not defined, it is ignored.
- The project directory is checked to see if the `build` directory exists. If not, it is created and default project assets are copied to it.
- An asset bundle is then created by reading the `html` key from `wails.json` and loading the referenced file. This is then parsed, looking for local Javascript and CSS references. Those files are in turn loaded into memory, converted to C data and saved into the asset bundle located at `build/assets.h`, which also includes the original HTML.
- The application icon is then processed: if there is no `build/appicon.png`, a default icon is copied. On Windows, an `app.ico` file is generated from this png. On Mac, `icons.icns` is generated.
- If there are icons in the `build/tray` directory, these are processed, converted to C data and saved as `build/trayicons.h`, ready for the compilation step.
- If there are icons in the `build/dialog` directory, these are processed, converted to C data and saved as `build/userdialogicons.h`, ready for the compilation step.
- If the `-package` flag is given for a Windows target, the Windows assets in the `build/windows` directory are processed: manifest + icons compiled to a `.syso` file (deleted after compilation).
- If we are building a universal binary for Mac, the application is compiled for both `arm64` and `amd64`. The `lipo` tool is then executed to create the universal binary.
- If we are not building a universal binary for Mac, the application is built using `go build`, using build tags to indicate type of application and build mode (debug/production).
- If the `-upx` flag was provided, `upx` is invoked to compress the binary. Custom flags may be provided using the `-upxflags` flag.
- If the `package` flag is given for a non Windows target, the application is bundled for the platform. On Mac, this creates a `.app` with the processed icons, the `Info.plist` in `build/darwin` and the compiled binary.
### Server Target
TBD
### Hybrid Target
TBD

View File

@@ -36,7 +36,10 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &compilerCommand)
compress := false
command.BoolFlag("compress", "Compress final binary", &compress)
command.BoolFlag("upx", "Compress final binary with UPX (if installed)", &compress)
compressFlags := ""
command.StringFlag("upxflags", "Flags to pass to upx", &compressFlags)
// Setup Platform flag
platform := runtime.GOOS
@@ -66,6 +69,9 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
cleanBuildDirectory := false
command.BoolFlag("clean", "Clean the build directory before building", &cleanBuildDirectory)
webview2 := "download"
command.StringFlag("webview2", "WebView2 installer strategy: download,embed,browser,error.", &webview2)
command.Action(func() error {
quiet := verbosity == 0
@@ -95,6 +101,7 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
"darwin/amd64",
"darwin/arm64",
"darwin/universal",
"linux",
//"linux/amd64",
//"linux/arm-7",
"windows",
@@ -118,6 +125,25 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
}
}
// Webview2 installer strategy (download by default)
wv2rtstrategy := ""
webview2 = strings.ToLower(webview2)
if webview2 != "" {
validWV2Runtime := slicer.String([]string{"download", "embed", "browser", "error"})
if !validWV2Runtime.Contains(webview2) {
return fmt.Errorf("invalid option for flag 'webview2': %s", webview2)
}
// These are the build tags associated with the strategies
switch webview2 {
case "embed":
wv2rtstrategy = "wv2runtime.embed"
case "error":
wv2rtstrategy = "wv2runtime.error"
case "browser":
wv2rtstrategy = "wv2runtime.browser"
}
}
// Create BuildOptions
buildOptions := &build.Options{
Logger: logger,
@@ -131,7 +157,9 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
KeepAssets: keepAssets,
Verbosity: verbosity,
Compress: compress,
CompressFlags: compressFlags,
UserTags: userTags,
WebView2Strategy: wv2rtstrategy,
}
// Calculate platform and arch

View File

@@ -0,0 +1,22 @@
# Dev
The dev command allows you to develop your application through a standard browser.
## Usage
`wails dev <flags>`
### Flags
| Flag | Details | Default |
| :------------- | :----------- | :------ |
| -compiler path/to/compiler | Use a different go compiler, eg go1.15beta1 | go |
| -ldflags "custom ld flags" | Use given ldflags | |
| -e list,of,extensions | File extensions to trigger rebuilds | go |
| -w | Show warnings | false |
| -v int | Verbosity level (0 - silent, 1 - default, 2 - verbose) | 1 |
| -loglevel | Loglevel to pass to the application - Trace, Debug, Info, Warning, Error | Debug |
## How it works
The project is built using a special mode that starts a webserver and starts listening to port 34115. When the frontend project is run independently, so long as the JS is wrapped with the runtime method `ready`, then the frontend will connect to the backend code via websockets. The interface should be present in your browser, and you should be able to interact with the backend as you would in a desktop app.

View File

@@ -3,6 +3,7 @@ package dev
import (
"fmt"
"io"
"log"
"os"
"os/signal"
"path/filepath"
@@ -57,6 +58,10 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
showWarnings := false
command.BoolFlag("w", "Show warnings", &showWarnings)
// Verbosity
verbosity := 1
command.IntFlag("v", "Verbosity level (0 - silent, 1 - default, 2 - verbose)", &verbosity)
loglevel := ""
command.StringFlag("loglevel", "Loglevel to use - Trace, Debug, Info, Warning, Error", &loglevel)
@@ -72,7 +77,12 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
if err != nil {
return err
}
defer watcher.Close()
defer func(watcher *fsnotify.Watcher) {
err := watcher.Close()
if err != nil {
log.Fatal(err)
}
}(watcher)
var debugBinaryProcess *process.Process = nil
var extensionsThatTriggerARebuild = strings.Split(extensions, ",")
@@ -83,15 +93,22 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
debounceQuit := make(chan bool, 1)
var passthruArgs []string
//if len(os.Args) > 2 {
// passthruArgs = os.Args[2:]
//}
// Do initial build
logger.Println("Building application for development...")
newProcess, err := restartApp(logger, "dev", ldflags, compilerCommand, debugBinaryProcess, loglevel)
newProcess, appBinary, err := restartApp(logger, ldflags, compilerCommand, debugBinaryProcess, loglevel, passthruArgs, verbosity)
if newProcess != nil {
debugBinaryProcess = newProcess
}
if err != nil {
return err
}
var newBinaryProcess *process.Process
go debounce(100*time.Millisecond, watcher.Events, debounceQuit, func(event fsnotify.Event) {
// logger.Println("event: %+v", event)
@@ -135,7 +152,7 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
// Do a rebuild
// Try and build the app
newBinaryProcess, err := restartApp(logger, "dev", ldflags, compilerCommand, debugBinaryProcess, loglevel)
newBinaryProcess, _, err = restartApp(logger, ldflags, compilerCommand, debugBinaryProcess, loglevel, passthruArgs, verbosity)
if err != nil {
fmt.Printf("Error during build: %s", err.Error())
return
@@ -197,6 +214,12 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
}
}
// Remove dev binary
err = os.Remove(appBinary)
if err != nil {
return err
}
LogGreen("Development mode exited")
return nil
@@ -224,14 +247,14 @@ exit:
}
}
func restartApp(logger *clilogger.CLILogger, outputType string, ldflags string, compilerCommand string, debugBinaryProcess *process.Process, loglevel string) (*process.Process, error) {
func restartApp(logger *clilogger.CLILogger, ldflags string, compilerCommand string, debugBinaryProcess *process.Process, loglevel string, passthruArgs []string, verbosity int) (*process.Process, string, error) {
appBinary, err := buildApp(logger, outputType, ldflags, compilerCommand)
appBinary, err := buildApp(logger, ldflags, compilerCommand, verbosity)
println()
if err != nil {
LogRed("Build error - continuing to run current version")
LogDarkYellow(err.Error())
return nil, nil
return nil, "", nil
}
// Kill existing binary if need be
@@ -247,8 +270,12 @@ func restartApp(logger *clilogger.CLILogger, outputType string, ldflags string,
// TODO: Generate `backend.js`
// Start up new binary
newProcess := process.NewProcess(logger, appBinary, "-loglevel", loglevel)
// Start up new binary with correct args
var args = []string{"-loglevel", loglevel}
if len(passthruArgs) > 0 {
args = append(args, passthruArgs...)
}
newProcess := process.NewProcess(logger, appBinary, args...)
err = newProcess.Start()
if err != nil {
// Remove binary
@@ -259,18 +286,21 @@ func restartApp(logger *clilogger.CLILogger, outputType string, ldflags string,
logger.Fatal("Unable to start application: %s", err.Error())
}
return newProcess, nil
return newProcess, appBinary, nil
}
func buildApp(logger *clilogger.CLILogger, outputType string, ldflags string, compilerCommand string) (string, error) {
func buildApp(logger *clilogger.CLILogger, ldflags string, compilerCommand string, verbosity int) (string, error) {
// Create random output file
outputFile := fmt.Sprintf("dev-%d", time.Now().Unix())
outputFile := "wailsdev"
if runtime.GOOS == "windows" {
outputFile += ".exe"
}
// Create BuildOptions
buildOptions := &build.Options{
Logger: logger,
OutputType: outputType,
OutputType: "dev",
Mode: build.Debug,
Pack: false,
Platform: runtime.GOOS,
@@ -278,6 +308,7 @@ func buildApp(logger *clilogger.CLILogger, outputType string, ldflags string, co
Compiler: compilerCommand,
OutputFile: outputFile,
IgnoreFrontend: true,
Verbosity: verbosity,
}
return build.Build(buildOptions)

View File

@@ -3,7 +3,6 @@ package doctor
import (
"fmt"
"io"
"log"
"os"
"runtime"
"strings"
@@ -25,11 +24,13 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
logger := clilogger.New(w)
app.PrintBanner()
logger.Print("Scanning system - please wait...")
logger.Print("Scanning system - Please wait (this may take a long time)...")
// Get system info
info, err := system.GetInfo()
if err != nil {
logger.Println("Failed.")
return err
}
logger.Println("Done.")
@@ -39,25 +40,22 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
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 {
w.Flush()
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)
// Exit early if PM not found
if info.PM != nil {
fmt.Fprintf(w, "%s\t%s\n", "Package Manager: ", info.PM.Name())
}
// Output Dependencies Status
var dependenciesMissing = []string{}
var externalPackages = []*packagemanager.Dependancy{}
@@ -67,12 +65,14 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
fmt.Fprintf(w, "Dependency\tPackage Name\tStatus\tVersion\n")
fmt.Fprintf(w, "----------\t------------\t------\t-------\n")
hasOptionalDependencies := false
// Loop over dependencies
for _, dependency := range info.Dependencies {
name := dependency.Name
if dependency.Optional {
name += "*"
name = "*" + name
hasOptionalDependencies = true
}
packageName := "Unknown"
status := "Not Found"
@@ -107,44 +107,48 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
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")
if hasOptionalDependencies {
fmt.Fprintf(w, "\n")
fmt.Fprintf(w, "* - Optional Dependency\n")
}
w.Flush()
logger.Println("")
logger.Println("Diagnosis")
logger.Println("---------\n")
logger.Println("---------")
// Generate an appropriate diagnosis
if len(dependenciesMissing) == 0 && dependenciesAvailableRequired == 0 {
logger.Println("Your system is ready for Wails development!")
} else {
logger.Println("Your system has missing dependencies!\n")
}
if dependenciesAvailableRequired != 0 {
log.Println("Install required packages using: " + info.Dependencies.InstallAllRequiredCommand())
logger.Println("Required package(s) installation details: \n" + 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)
}
logger.Println("Optional package(s) installation details: \n" + info.Dependencies.InstallAllOptionalCommand())
}
//
//if len(externalPackages) > 0 {
// for _, p := range externalPackages {
// if p.Optional {
// print("[Optional] ")
// }
// logger.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")
logger.Println("Fatal:")
logger.Println("Required dependencies missing: " + strings.Join(dependenciesMissing, " "))
logger.Println("Please read this article on how to resolve this: https://wails.app/guides/resolving-missing-packages")
}
log.Println("")
logger.Println("")
return nil
})

View File

@@ -2,6 +2,7 @@ package initialise
import (
"fmt"
"github.com/wailsapp/wails/v2/pkg/buildassets"
"io"
"strings"
"time"
@@ -40,7 +41,7 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
// Quiet Init
quiet := false
command.BoolFlag("q", "Supress output to console", &quiet)
command.BoolFlag("q", "Suppress output to console", &quiet)
initGit := false
gitInstalled := git.IsInstalled()
@@ -106,10 +107,7 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
}
// Try to discover author details from git config
err := findAuthorDetails(options)
if err != nil {
return err
}
findAuthorDetails(options)
return initProject(options)
})
@@ -129,6 +127,12 @@ func initProject(options *templates.Options) error {
return err
}
// Install the default assets
err = buildassets.Install(options.TargetDir, options.ProjectName)
if err != nil {
return err
}
if options.InitGit {
err = initGit(options)
if err != nil {
@@ -164,20 +168,18 @@ func initGit(options *templates.Options) error {
return nil
}
func findAuthorDetails(options *templates.Options) error {
// findAuthorDetails tries to find the user's name and email
// from gitconfig. If it finds them, it stores them in the project options
func findAuthorDetails(options *templates.Options) {
if git.IsInstalled() {
name, err := git.Name()
if err != nil {
return err
if err == nil {
options.AuthorName = strings.TrimSpace(name)
}
options.AuthorName = strings.TrimSpace(name)
email, err := git.Email()
if err != nil {
return err
if err == nil {
options.AuthorEmail = strings.TrimSpace(email)
}
options.AuthorEmail = strings.TrimSpace(email)
}
return nil
}

View File

@@ -0,0 +1,16 @@
# README
## About
This template uses vanilla JS / HTML and CSS. [Rollup](https://rollupjs.org/guide/en/) is used for processing and bundling the files.
## Building
To build this project in debug mode, use `wails build`. For production, use `wails build -production`.
To generate a platform native package, add the `-package` flag.
## Live Development
To run in live development mode, run `wails dev` in the project directory. In another terminal, go into the `frontend`
directory and run `npm run dev`. The frontend dev server will run on http://localhost:5000. Connect to this
in your browser and connect to your application.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
{
"name": "vanilla",
"version": "1.0.0",
"description": "Vanilla Wails v2 template",
"main": "src/main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "rollup -c",
"dev": "rollup -c -w",
"start": "sirv dist"
},
"author": "{{.AuthorName}}",
"license": "ISC",
"dependencies": {
"@rollup/plugin-commonjs": "^19.0.0",
"@rollup/plugin-image": "^2.0.6",
"@rollup/plugin-node-resolve": "^13.0.0",
"@rollup/plugin-url": "^6.0.0",
"@wails/runtime": "^1.3.20",
"rollup": "^2.50.4",
"rollup-plugin-copy": "^3.4.0",
"rollup-plugin-livereload": "^2.0.0",
"rollup-plugin-postcss": "^4.0.0",
"rollup-plugin-terser": "^7.0.2",
"sirv-cli": "^1.0.12"
}
}

View File

@@ -0,0 +1,103 @@
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';
import postcss from 'rollup-plugin-postcss';
import image from '@rollup/plugin-image';
import url from '@rollup/plugin-url';
import copy from 'rollup-plugin-copy';
const production = !process.env.ROLLUP_WATCH;
export default {
input: 'src/main.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'dist/main.js'
},
onwarn: handleRollupWarning,
plugins: [
image(),
copy({
targets: [
{ src: 'src/index.html', dest: 'dist' },
{ src: 'src/main.css', dest: 'dist' },
]
}),
// Embed binary files
url({
include: ['**/*.woff', '**/*.woff2'],
limit: Infinity,
}),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration -
// consult the documentation for details:
// https://github.com/rollup/plugins/tree/master/packages/commonjs
resolve({
browser: true,
}),
commonjs(),
// PostCSS preprocessing
postcss({
extensions: ['.css', '.scss'],
extract: true,
minimize: false,
use: [
['sass', {
includePaths: [
'./src',
'./node_modules'
]
}]
],
}),
// In dev mode, call `npm run start` once
// the bundle has been generated
!production && serve(),
// Watch the `public` directory and refresh the
// browser on changes when not in production
!production && livereload('dist'),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser()
],
watch: {
clearScreen: false
}
};
function handleRollupWarning(warning) {
console.error('ERROR: ' + warning.toString());
}
function serve() {
let server;
function toExit() {
if (server) server.kill(0);
}
return {
writeBundle() {
if (server) return;
server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
stdio: ['ignore', 'inherit', 'inherit'],
shell: true
});
process.on('SIGTERM', toExit);
process.on('exit', toExit);
}
};
}

View File

@@ -6,8 +6,8 @@
<body data-wails-drag>
<div id="logo"></div>
<div id="input">
<input id="name" type="text"></input>
<div id="input" data-wails-no-drag>
<input id="name" type="text">
<button onclick="greet()">Greet</button>
</div>
<div id="result"></div>

View File

@@ -1,16 +1,21 @@
// Get input + focus
let nameElement = document.getElementById("name");
nameElement.focus();
// Setup the greet function
window.greet = function () {
import {ready} from '@wails/runtime';
// Get name
let name = nameElement.value;
ready( () => {
// Get input + focus
let nameElement = document.getElementById("name");
nameElement.focus();
// Call Basic.Greet(name)
window.backend.main.Basic.Greet(name).then((result) => {
// Update result with data back from Basic.Greet()
document.getElementById("result").innerText = result;
});
}
// Setup the greet function
window.greet = function () {
// Get name
let name = nameElement.value;
// Call Basic.Greet(name)
window.backend.main.Basic.Greet(name).then((result) => {
// Update result with data back from Basic.Greet()
document.getElementById("result").innerText = result;
});
};
});

View File

@@ -1,6 +1,7 @@
package main
import (
"github.com/wailsapp/wails/v2/pkg/options/windows"
"log"
"github.com/wailsapp/wails/v2"
@@ -16,10 +17,25 @@ func main() {
app := NewBasic()
err := wails.Run(&options.App{
Title: "{{.ProjectName}}",
Width: 800,
Height: 600,
DisableResize: true,
Title: "{{.ProjectName}}",
Width: 800,
Height: 600,
MinWidth: 400,
MinHeight: 400,
MaxWidth: 1280,
MaxHeight: 1024,
DisableResize: false,
Fullscreen: false,
Frameless: false,
StartHidden: false,
HideWindowOnClose: false,
DevTools: false,
RGBA: 0x000000FF,
Windows: &windows.Options{
WebviewIsTransparent: true,
WindowBackgroundIsTranslucent: true,
DisableWindowIcon: true,
},
Mac: &mac.Options{
WebviewIsTransparent: true,
WindowBackgroundIsTranslucent: true,

View File

@@ -1,7 +1,9 @@
{
"name": "{{.ProjectName}}",
"outputfilename": "{{.BinaryName}}",
"html": "frontend/src/index.html",
"html": "frontend/dist/index.html",
"frontend:build": "npm run build",
"frontend:install": "npm ci",
"author": {
"name": "{{.AuthorName}}",
"email": "{{.AuthorEmail}}"

View File

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

View File

@@ -10,10 +10,13 @@ require (
github.com/imdario/mergo v0.3.11
github.com/jackmordaunt/icns v1.0.0
github.com/leaanthony/clir v1.0.4
github.com/leaanthony/debme v1.1.2
github.com/leaanthony/debme v1.2.1
github.com/leaanthony/go-ansi-parser v1.0.1
github.com/leaanthony/go-common-file-dialog v1.0.2
github.com/leaanthony/gosod v1.0.1
github.com/leaanthony/slicer v1.5.0
github.com/leaanthony/webview2runtime v1.1.0
github.com/leaanthony/winicon v0.0.0-20200606125418-4419cea822a0
github.com/matryer/is v1.4.0
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/olekukonko/tablewriter v0.0.4
@@ -24,7 +27,7 @@ require (
github.com/wzshiming/ctc v1.2.3
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/sys v0.0.0-20210611083646-a4fc73990273
golang.org/x/tools v0.0.0-20200902012652-d1954cc86c82
nhooyr.io/websocket v1.8.6
)

View File

@@ -10,6 +10,8 @@ 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-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
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=
@@ -29,6 +31,8 @@ github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgj
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/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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=
@@ -42,14 +46,20 @@ github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs
github.com/leaanthony/clir v1.0.4 h1:Dov2y9zWJmZr7CjaCe86lKa4b5CSxskGAt2yBkoDyiU=
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
github.com/leaanthony/debme v1.1.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
github.com/leaanthony/debme v1.1.2 h1:dGeQuj0+xPIlDQzGIjmAU52+yRg85u5pWaaqrdLBjD0=
github.com/leaanthony/debme v1.1.2/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4=
github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM=
github.com/leaanthony/go-common-file-dialog v1.0.2 h1:uJ2zXCxP4GwbpR/k/y6unuNbSJn3WTjt4rvHolX3Eys=
github.com/leaanthony/go-common-file-dialog v1.0.2/go.mod h1:TGhEc9eSJgRsupZ+iH1ZgAOnEo9zp05cRH2j08RPrF0=
github.com/leaanthony/gosod v1.0.1 h1:F+4c3DmEBfigi7oAswCV2RpQ+k4DcNbhuCZUGdBHacQ=
github.com/leaanthony/gosod v1.0.1/go.mod h1:W8RyeSFBXu7RpIxPGEJfW4moSyGGEjlJMLV25wEbAdU=
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/leaanthony/webview2runtime v1.1.0 h1:N0pv55ift8XtqozIp4PNOtRCJ/Qdd/qzx80lUpalS4c=
github.com/leaanthony/webview2runtime v1.1.0/go.mod h1:hH9GnWCve3DYzNaPOcPbhHQ7fodXR1QJNsnwixid4Tk=
github.com/leaanthony/winicon v0.0.0-20200606125418-4419cea822a0 h1:FPGYnfxuuxqCZhrGq8nKjthEcYHgHmFbyY953Xv9cNI=
github.com/leaanthony/winicon v0.0.0-20200606125418-4419cea822a0/go.mod h1:en5xhijl92aphrJdmRPlh4NI1L6wq3gEm0LpXAPghjU=
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=
@@ -92,6 +102,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
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/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw=
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
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=
@@ -106,8 +118,8 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200107162124-548cf772de50/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/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/sys v0.0.0-20210611083646-a4fc73990273 h1:faDu4veV+8pcThn4fewv6TVlNCezafGoC1gM/mxQLbQ=
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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=

View File

@@ -5,6 +5,7 @@ import (
"syscall"
)
// Init is called at the start of the application
func Init() error {
status, r, err := syscall.NewLazyDLL("user32.dll").NewProc("SetProcessDPIAware").Call()
if status == 0 {

View File

@@ -103,8 +103,17 @@ func CreateApp(appoptions *options.App) (*App, error) {
// Initialise the app
err := result.Init()
if err != nil {
return nil, err
}
return result, err
// Preflight Checks
err = result.PreflightChecks(appoptions)
if err != nil {
return nil, err
}
return result, nil
}

View File

@@ -125,7 +125,7 @@ func (a *App) Run() error {
return err
}
runtimesubsystem, err := subsystem.NewRuntime(ctx, a.servicebus, a.logger, a.startupCallback)
runtimesubsystem, err := subsystem.NewRuntime(ctx, a.servicebus, a.logger, a.startupCallback, nil)
if err != nil {
return err
}

View File

@@ -0,0 +1,9 @@
//+build !windows
package app
import "github.com/wailsapp/wails/v2/pkg/options"
func (a *App) PreflightChecks(options *options.App) error {
return nil
}

View File

@@ -0,0 +1,19 @@
//+build windows
package app
import (
"github.com/wailsapp/wails/v2/internal/ffenestri/windows/wv2runtime"
"github.com/wailsapp/wails/v2/pkg/options"
)
func (a *App) PreflightChecks(options *options.App) error {
// Process the webview2 runtime situation. We can pass a strategy in via the `webview2` flag for `wails build`.
// This will determine how wv2runtime.Process will handle a lack of valid runtime.
err := wv2runtime.Process()
if err != nil {
return err
}
return nil
}

View File

@@ -79,7 +79,7 @@ func (a *App) Run() error {
// Default app options
var port = 8080
var ip = "localhost"
var supressLogging = false
var SuppressLogging = false
var debugMode = false
// Create CLI
@@ -89,7 +89,7 @@ func (a *App) Run() error {
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)
cli.BoolFlag("q", "Suppress logging", &SuppressLogging)
// Setup main action
cli.Action(func() error {
@@ -98,8 +98,8 @@ func (a *App) Run() error {
a.webserver.SetPort(port)
a.webserver.SetIP(ip)
a.webserver.SetBindings(a.bindings)
// Log information (if we aren't supressing it)
if !supressLogging {
// Log information (if we aren't Suppressing it)
if !SuppressLogging {
cli.PrintBanner()
a.logger.Info("Running server at %s", a.webserver.URL())
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -18,6 +18,12 @@ import (
//go:embed darwin.js
var darwinRuntime string
//go:embed windows.js
var windowsRuntime string
//go:embed linux.js
var linuxRuntime string
// session represents a single websocket session
type session struct {
bindings string
@@ -84,6 +90,10 @@ func (s *session) start(firstSession bool) {
switch runtime.GOOS {
case "darwin":
wailsRuntime = darwinRuntime
case "windows":
wailsRuntime = windowsRuntime
case "linux":
wailsRuntime = linuxRuntime
default:
log.Fatal("platform not supported")
}
@@ -92,7 +102,10 @@ func (s *session) start(firstSession bool) {
s.log.Info(bindingsMessage)
bootstrapMessage := bindingsMessage + wailsRuntime
s.sendMessage("b" + bootstrapMessage)
err := s.sendMessage("b" + bootstrapMessage)
if err != nil {
s.log.Error(err.Error())
}
// Send menus
traymenus, err := s.menumanager.GetTrayMenus()
@@ -101,7 +114,10 @@ func (s *session) start(firstSession bool) {
}
for _, trayMenu := range traymenus {
s.sendMessage("TS" + trayMenu)
err := s.sendMessage("TS" + trayMenu)
if err != nil {
s.log.Error(err.Error())
}
}
for {
@@ -130,7 +146,10 @@ func (s *session) start(firstSession bool) {
// Shutdown
func (s *session) Shutdown() {
s.conn.Close()
err := s.conn.Close()
if err != nil {
s.log.Error(err.Error())
}
s.done = true
s.log.Info("session %v exit", s.Identifier())
}
@@ -146,10 +165,16 @@ func (s *session) writePump() {
s.Shutdown()
return
case msg, ok := <-s.writeChan:
s.conn.SetWriteDeadline(time.Now().Add(1 * time.Second))
err := s.conn.SetWriteDeadline(time.Now().Add(1 * time.Second))
if err != nil {
s.log.Error(err.Error())
}
if !ok {
s.log.Debug("writeChan was closed!")
s.conn.WriteMessage(websocket.CloseMessage, []byte{})
err := s.conn.WriteMessage(websocket.CloseMessage, []byte{})
if err != nil {
s.log.Error(err.Error())
}
return
}

File diff suppressed because one or more lines are too long

View File

@@ -20,7 +20,7 @@ import (
#cgo darwin LDFLAGS: -framework WebKit -lobjc
#cgo windows CXXFLAGS: -std=c++11
#cgo windows,amd64 LDFLAGS: -L./windows/x64 -lwebview -lWebView2Loader -lgdi32 -lole32 -lShlwapi -luser32 -loleaut32
#cgo windows,amd64 LDFLAGS: -L./windows/x64 -lWebView2Loader -lgdi32 -lole32 -lShlwapi -luser32 -loleaut32 -ldwmapi
#include <stdlib.h>
#include "ffenestri.h"
@@ -130,7 +130,6 @@ func (a *Application) Run(incomingDispatcher Dispatcher, bindings string, debug
// Set debug if needed
C.SetDebug(app, a.bool2Cint(debug))
// TODO: Move frameless to Linux options
if a.config.Frameless {
C.DisableFrame(a.app)
}

View File

@@ -47,6 +47,7 @@ extern void AddContextMenu(struct Application*, char *contextMenuJSON);
extern void UpdateContextMenu(struct Application*, char *contextMenuJSON);
extern void WebviewIsTransparent(struct Application*);
extern void WindowBackgroundIsTranslucent(struct Application*);
extern void* GetWindowHandle(struct Application*);
#ifdef __cplusplus
}

View File

@@ -1,3 +1,5 @@
// +build !windows
package ffenestri
/*
@@ -6,14 +8,16 @@ package ffenestri
import "C"
import (
"runtime"
"strconv"
"strings"
"github.com/wailsapp/wails/v2/pkg/options/dialog"
"github.com/wailsapp/wails/v2/internal/logger"
)
// Client is our implentation of messageDispatcher.Client
// Client is our implementation of messageDispatcher.Client
type Client struct {
app *Application
logger logger.CustomLogger
@@ -122,17 +126,72 @@ func (c *Client) WindowSetColour(colour int) {
C.SetColour(c.app.app, r, g, b, a)
}
// OpenDialog will open a dialog with the given title and filter
func (c *Client) OpenDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
// OpenFileDialog will open a dialog with the given title and filter
func (c *Client) OpenFileDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
filters := []string{}
if runtime.GOOS == "darwin" {
for _, filter := range dialogOptions.Filters {
filters = append(filters, strings.Split(filter.Pattern, ",")...)
}
}
C.OpenDialog(c.app.app,
c.app.string2CString(callbackID),
c.app.string2CString(dialogOptions.Title),
c.app.string2CString(dialogOptions.Filters),
c.app.string2CString(strings.Join(filters, ";")),
c.app.string2CString(dialogOptions.DefaultFilename),
c.app.string2CString(dialogOptions.DefaultDirectory),
c.app.bool2Cint(dialogOptions.AllowFiles),
c.app.bool2Cint(dialogOptions.AllowDirectories),
c.app.bool2Cint(dialogOptions.AllowMultiple),
c.app.bool2Cint(false),
c.app.bool2Cint(dialogOptions.ShowHiddenFiles),
c.app.bool2Cint(dialogOptions.CanCreateDirectories),
c.app.bool2Cint(dialogOptions.ResolvesAliases),
c.app.bool2Cint(dialogOptions.TreatPackagesAsDirectories),
)
}
// OpenDirectoryDialog will open a dialog with the given title and filter
func (c *Client) OpenDirectoryDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
filters := []string{}
if runtime.GOOS == "darwin" {
for _, filter := range dialogOptions.Filters {
filters = append(filters, strings.Split(filter.Pattern, ",")...)
}
}
C.OpenDialog(c.app.app,
c.app.string2CString(callbackID),
c.app.string2CString(dialogOptions.Title),
c.app.string2CString(strings.Join(filters, ";")),
c.app.string2CString(dialogOptions.DefaultFilename),
c.app.string2CString(dialogOptions.DefaultDirectory),
c.app.bool2Cint(false), // Files
c.app.bool2Cint(true), // Directories
c.app.bool2Cint(false), // Multiple
c.app.bool2Cint(dialogOptions.ShowHiddenFiles),
c.app.bool2Cint(dialogOptions.CanCreateDirectories),
c.app.bool2Cint(dialogOptions.ResolvesAliases),
c.app.bool2Cint(dialogOptions.TreatPackagesAsDirectories),
)
}
// OpenMultipleFilesDialog will open a dialog with the given title and filter
func (c *Client) OpenMultipleFilesDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
filters := []string{}
if runtime.GOOS == "darwin" {
for _, filter := range dialogOptions.Filters {
filters = append(filters, strings.Split(filter.Pattern, ",")...)
}
}
C.OpenDialog(c.app.app,
c.app.string2CString(callbackID),
c.app.string2CString(dialogOptions.Title),
c.app.string2CString(strings.Join(filters, ";")),
c.app.string2CString(dialogOptions.DefaultFilename),
c.app.string2CString(dialogOptions.DefaultDirectory),
c.app.bool2Cint(dialogOptions.AllowFiles),
c.app.bool2Cint(dialogOptions.AllowDirectories),
c.app.bool2Cint(true),
c.app.bool2Cint(dialogOptions.ShowHiddenFiles),
c.app.bool2Cint(dialogOptions.CanCreateDirectories),
c.app.bool2Cint(dialogOptions.ResolvesAliases),
@@ -142,10 +201,16 @@ func (c *Client) OpenDialog(dialogOptions *dialog.OpenDialog, callbackID string)
// SaveDialog will open a dialog with the given title and filter
func (c *Client) SaveDialog(dialogOptions *dialog.SaveDialog, callbackID string) {
filters := []string{}
if runtime.GOOS == "darwin" {
for _, filter := range dialogOptions.Filters {
filters = append(filters, strings.Split(filter.Pattern, ",")...)
}
}
C.SaveDialog(c.app.app,
c.app.string2CString(callbackID),
c.app.string2CString(dialogOptions.Title),
c.app.string2CString(dialogOptions.Filters),
c.app.string2CString(strings.Join(filters, ";")),
c.app.string2CString(dialogOptions.DefaultFilename),
c.app.string2CString(dialogOptions.DefaultDirectory),
c.app.bool2Cint(dialogOptions.ShowHiddenFiles),

View File

@@ -0,0 +1,319 @@
// +build windows
package ffenestri
/*
#include "ffenestri.h"
*/
import "C"
import (
"encoding/json"
"github.com/leaanthony/go-common-file-dialog/cfd"
"golang.org/x/sys/windows"
"log"
"strconv"
"syscall"
"github.com/wailsapp/wails/v2/pkg/options/dialog"
"github.com/wailsapp/wails/v2/internal/logger"
)
// Client is our implementation of messageDispatcher.Client
type Client struct {
app *Application
logger logger.CustomLogger
}
func newClient(app *Application) *Client {
return &Client{
app: app,
logger: app.logger,
}
}
// Quit the application
func (c *Client) Quit() {
c.app.logger.Trace("Got shutdown message")
C.Quit(c.app.app)
}
// NotifyEvent will pass on the event message to the frontend
func (c *Client) NotifyEvent(message string) {
eventMessage := `window.wails._.Notify(` + strconv.Quote(message) + `);`
c.app.logger.Trace("eventMessage = %+v", eventMessage)
C.ExecJS(c.app.app, c.app.string2CString(eventMessage))
}
// CallResult contains the result of the call from JS
func (c *Client) CallResult(message string) {
callbackMessage := `window.wails._.Callback(` + strconv.Quote(message) + `);`
c.app.logger.Trace("callbackMessage = %+v", callbackMessage)
C.ExecJS(c.app.app, c.app.string2CString(callbackMessage))
}
// WindowSetTitle sets the window title to the given string
func (c *Client) WindowSetTitle(title string) {
C.SetTitle(c.app.app, c.app.string2CString(title))
}
// WindowFullscreen will set the window to be fullscreen
func (c *Client) WindowFullscreen() {
C.Fullscreen(c.app.app)
}
// WindowUnFullscreen will unfullscreen the window
func (c *Client) WindowUnFullscreen() {
C.UnFullscreen(c.app.app)
}
// WindowShow will show the window
func (c *Client) WindowShow() {
C.Show(c.app.app)
}
// WindowHide will hide the window
func (c *Client) WindowHide() {
C.Hide(c.app.app)
}
// WindowCenter will hide the window
func (c *Client) WindowCenter() {
C.Center(c.app.app)
}
// WindowMaximise will maximise the window
func (c *Client) WindowMaximise() {
C.Maximise(c.app.app)
}
// WindowMinimise will minimise the window
func (c *Client) WindowMinimise() {
C.Minimise(c.app.app)
}
// WindowUnmaximise will unmaximise the window
func (c *Client) WindowUnmaximise() {
C.Unmaximise(c.app.app)
}
// WindowUnminimise will unminimise the window
func (c *Client) WindowUnminimise() {
C.Unminimise(c.app.app)
}
// WindowPosition will position the window to x,y on the
// monitor that the window is mostly on
func (c *Client) WindowPosition(x int, y int) {
C.SetPosition(c.app.app, C.int(x), C.int(y))
}
// WindowSize will resize the window to the given
// width and height
func (c *Client) WindowSize(width int, height int) {
C.SetSize(c.app.app, C.int(width), C.int(height))
}
// WindowSetMinSize sets the minimum window size
func (c *Client) WindowSetMinSize(width int, height int) {
C.SetMinWindowSize(c.app.app, C.int(width), C.int(height))
}
// WindowSetMaxSize sets the maximum window size
func (c *Client) WindowSetMaxSize(width int, height int) {
C.SetMaxWindowSize(c.app.app, C.int(width), C.int(height))
}
// WindowSetColour sets the window colour
func (c *Client) WindowSetColour(colour int) {
r, g, b, a := intToColour(colour)
C.SetColour(c.app.app, r, g, b, a)
}
func convertFilters(filters []dialog.FileFilter) []cfd.FileFilter {
var result []cfd.FileFilter
for _, filter := range filters {
result = append(result, cfd.FileFilter(filter))
}
return result
}
func userCancelled(err error) bool {
return err.Error() == "cancelled by user"
}
// OpenFileDialog will open a dialog with the given title and filter
func (c *Client) OpenFileDialog(options *dialog.OpenDialog, callbackID string) {
config := cfd.DialogConfig{
Folder: options.DefaultDirectory,
FileFilters: convertFilters(options.Filters),
FileName: options.DefaultFilename,
}
thisdialog, err := cfd.NewOpenFileDialog(config)
if err != nil {
log.Fatal(err)
}
thisdialog.SetParentWindowHandle(uintptr(C.GetWindowHandle(c.app.app)))
defer func(thisdialog cfd.OpenFileDialog) {
err := thisdialog.Release()
if err != nil {
log.Fatal(err)
}
}(thisdialog)
result, err := thisdialog.ShowAndGetResult()
if err != nil && !userCancelled(err) {
log.Fatal(err)
}
resultJSON, err := json.Marshal([]string{result})
if err != nil {
log.Fatal(err)
}
dispatcher.DispatchMessage("DO" + callbackID + "|" + string(resultJSON))
}
// OpenDirectoryDialog will open a dialog with the given title and filter
func (c *Client) OpenDirectoryDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
config := cfd.DialogConfig{
Title: dialogOptions.Title,
Role: "PickFolder",
Folder: dialogOptions.DefaultDirectory,
}
thisDialog, err := cfd.NewSelectFolderDialog(config)
if err != nil {
log.Fatal()
}
thisDialog.SetParentWindowHandle(uintptr(C.GetWindowHandle(c.app.app)))
defer func(thisDialog cfd.SelectFolderDialog) {
err := thisDialog.Release()
if err != nil {
log.Fatal(err)
}
}(thisDialog)
result, err := thisDialog.ShowAndGetResult()
if err != nil && !userCancelled(err) {
log.Fatal(err)
}
resultJSON, err := json.Marshal(result)
dispatcher.DispatchMessage("DD" + callbackID + "|" + string(resultJSON))
}
// OpenMultipleFilesDialog will open a dialog with the given title and filter
func (c *Client) OpenMultipleFilesDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
config := cfd.DialogConfig{
Title: dialogOptions.Title,
Role: "OpenMultipleFiles",
FileFilters: convertFilters(dialogOptions.Filters),
FileName: dialogOptions.DefaultFilename,
Folder: dialogOptions.DefaultDirectory,
}
thisdialog, err := cfd.NewOpenMultipleFilesDialog(config)
if err != nil {
log.Fatal(err)
}
thisdialog.SetParentWindowHandle(uintptr(C.GetWindowHandle(c.app.app)))
defer func(thisdialog cfd.OpenMultipleFilesDialog) {
err := thisdialog.Release()
if err != nil {
log.Fatal(err)
}
}(thisdialog)
result, err := thisdialog.ShowAndGetResults()
if err != nil && !userCancelled(err) {
log.Fatal(err)
}
resultJSON, err := json.Marshal(result)
if err != nil {
log.Fatal(err)
}
dispatcher.DispatchMessage("D*" + callbackID + "|" + string(resultJSON))
}
// SaveDialog will open a dialog with the given title and filter
func (c *Client) SaveDialog(dialogOptions *dialog.SaveDialog, callbackID string) {
saveDialog, err := cfd.NewSaveFileDialog(cfd.DialogConfig{
Title: dialogOptions.Title,
Role: "SaveFile",
FileFilters: convertFilters(dialogOptions.Filters),
FileName: dialogOptions.DefaultFilename,
Folder: dialogOptions.DefaultDirectory,
})
if err != nil {
log.Fatal(err)
}
saveDialog.SetParentWindowHandle(uintptr(C.GetWindowHandle(c.app.app)))
err = saveDialog.Show()
if err != nil {
log.Fatal(err)
}
result, err := saveDialog.GetResult()
if err != nil && !userCancelled(err) {
log.Fatal(err)
}
dispatcher.DispatchMessage("DS" + callbackID + "|" + result)
}
// MessageDialog will open a message dialog with the given options
func (c *Client) MessageDialog(options *dialog.MessageDialog, callbackID string) {
title, err := syscall.UTF16PtrFromString(options.Title)
if err != nil {
log.Fatal(err)
}
message, err := syscall.UTF16PtrFromString(options.Message)
if err != nil {
log.Fatal(err)
}
var flags uint32
switch options.Type {
case dialog.InfoDialog:
flags = windows.MB_OK | windows.MB_ICONINFORMATION
case dialog.ErrorDialog:
flags = windows.MB_ICONERROR | windows.MB_OK
case dialog.QuestionDialog:
flags = windows.MB_YESNO
case dialog.WarningDialog:
flags = windows.MB_OK | windows.MB_ICONWARNING
}
button, _ := windows.MessageBox(windows.HWND(C.GetWindowHandle(c.app.app)), message, title, flags|windows.MB_SYSTEMMODAL)
// This maps MessageBox return values to strings
responses := []string{"", "Ok", "Cancel", "Abort", "Retry", "Ignore", "Yes", "No", "", "", "Try Again", "Continue"}
result := "Error"
if int(button) < len(responses) {
result = responses[button]
}
dispatcher.DispatchMessage("DM" + callbackID + "|" + result)
}
// DarkModeEnabled sets the application to use dark mode
func (c *Client) DarkModeEnabled(callbackID string) {
C.DarkModeEnabled(c.app.app, c.app.string2CString(callbackID))
}
// SetApplicationMenu sets the application menu
func (c *Client) SetApplicationMenu(applicationMenuJSON string) {
C.SetApplicationMenu(c.app.app, c.app.string2CString(applicationMenuJSON))
}
// SetTrayMenu sets the tray menu
func (c *Client) SetTrayMenu(trayMenuJSON string) {
C.SetTrayMenu(c.app.app, c.app.string2CString(trayMenuJSON))
}
// UpdateTrayMenuLabel updates a tray menu label
func (c *Client) UpdateTrayMenuLabel(JSON string) {
C.UpdateTrayMenuLabel(c.app.app, c.app.string2CString(JSON))
}
// UpdateContextMenu will update the current context menu
func (c *Client) UpdateContextMenu(contextMenuJSON string) {
C.UpdateContextMenu(c.app.app, c.app.string2CString(contextMenuJSON))
}
// DeleteTrayMenuByID will remove a tray menu based on the given id
func (c *Client) DeleteTrayMenuByID(id string) {
C.DeleteTrayMenuByID(c.app.app, c.app.string2CString(id))
}

View File

@@ -983,7 +983,7 @@ void SaveDialog(struct Application *app, char *callbackID, char *title, char *fi
);
}
const char *invoke = "window.external={invoke:function(x){window.webkit.messageHandlers.external.postMessage(x);}};";
const char *invoke = "window.wailsInvoke=function(message){window.webkit.messageHandlers.external.postMessage(message);};window.wailsDrag=function(message){window.webkit.messageHandlers.windowDrag.postMessage(message);};window.wailsContextMenuMessage=function(message){window.webkit.messageHandlers.contextMenu.postMessage(message);};";
// DisableFrame disables the window frame
void DisableFrame(struct Application *app)

View File

@@ -2,6 +2,7 @@
#ifndef __FFENESTRI_LINUX_H__
#define __FFENESTRI_LINUX_H__
#include "common.h"
#include "gtk/gtk.h"
#include "webkit2/webkit2.h"
#include <time.h>
@@ -11,9 +12,10 @@
#include <stdarg.h>
// References to assets
extern const unsigned char *assets[];
extern const unsigned char runtime;
extern const char *icon[];
#include "icon.h"
#include "assets.h"
// Constants
#define PRIMARY_MOUSE_BUTTON 1
@@ -23,17 +25,6 @@ extern const char *icon[];
// MAIN DEBUG FLAG
int debug;
// Credit: https://stackoverflow.com/a/8465083
char *concat(const char *s1, const char *s2)
{
const size_t len1 = strlen(s1);
const size_t len2 = strlen(s2);
char *result = malloc(len1 + len2 + 1);
memcpy(result, s1, len1);
memcpy(result + len1, s2, len2 + 1);
return result;
}
// Debug works like sprintf but mutes if the global debug flag is true
// Credit: https://stackoverflow.com/a/20639708
void Debug(char *message, ...)
@@ -312,17 +303,17 @@ void SetMaxWindowSize(struct Application *app, int maxWidth, int maxHeight)
}
// SetColour sets the colour of the webview to the given colour string
int SetColour(struct Application *app, const char *colourString)
void SetColour(struct Application *app, int red, int green, int blue, int alpha)
{
GdkRGBA rgba;
gboolean result = gdk_rgba_parse(&rgba, colourString);
if (result == FALSE)
{
return 0;
}
// Debug("Setting webview colour to: %s", colourString);
webkit_web_view_get_background_color((WebKitWebView *)(app->webView), &rgba);
return 1;
// GdkRGBA rgba;
// rgba.
// gboolean result = gdk_rgba_parse(&rgba, colourString);
// if (result == FALSE)
// {
// return 0;
// }
// // Debug("Setting webview colour to: %s", colourString);
// webkit_web_view_get_background_color((WebKitWebView *)(app->webView), &rgba);
}
// DisableFrame disables the window frame
@@ -523,6 +514,11 @@ static void load_finished_cb(WebKitWebView *webView,
Debug("Binding Methods");
syncEval(app, app->bindings);
// Setup IPC commands
Debug("Setting up IPC methods");
const char *invoke = "window.wailsInvoke=function(message){window.webkit.messageHandlers.external.postMessage(message);};window.wailsDrag=function(message){window.webkit.messageHandlers.windowDrag.postMessage(message);};window.wailsContextMenuMessage=function(message){window.webkit.messageHandlers.contextMenu.postMessage(message);};";
syncEval(app, invoke);
// Runtime
Debug("Setting up Wails runtime");
syncEval(app, &runtime);
@@ -824,7 +820,7 @@ void Show(struct Application *app) {
// maximiseInternal maximises the main window
void maximiseInternal(struct Application *app) {
gtk_window_maximize(GTK_WIDGET(app->mainWindow));
gtk_window_maximize(GTK_WINDOW(app->mainWindow));
}
// Maximise places the maximiseInternal method onto the main thread for execution
@@ -841,7 +837,7 @@ void Maximise(struct Application *app) {
// unmaximiseInternal unmaximises the main window
void unmaximiseInternal(struct Application *app) {
gtk_window_unmaximize(GTK_WIDGET(app->mainWindow));
gtk_window_unmaximize(GTK_WINDOW(app->mainWindow));
}
// Unmaximise places the unmaximiseInternal method onto the main thread for execution
@@ -857,6 +853,21 @@ void Unmaximise(struct Application *app) {
}
void DarkModeEnabled(struct Application* app, char *callbackID) {}
void SetApplicationMenu(struct Application* app, const char *menuJSON) {}
void AddTrayMenu(struct Application* app, const char *menuTrayJSON) {}
void SetTrayMenu(struct Application* app, const char *menuTrayJSON) {}
void DeleteTrayMenuByID(struct Application* app, const char *id) {}
void UpdateTrayMenuLabel(struct Application* app, const char* JSON) {}
void AddContextMenu(struct Application* app, char *contextMenuJSON) {}
void UpdateContextMenu(struct Application* app, char *contextMenuJSON) {}
void WebviewIsTransparent(struct Application* app) {}
void WindowBackgroundIsTranslucent(struct Application* app) {}
void OpenDialog(struct Application* app, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int allowFiles, int allowDirs, int allowMultiple, int showHiddenFiles, int canCreateDirectories, int resolvesAliases, int treatPackagesAsDirectories) {}
void SaveDialog(struct Application* app, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int showHiddenFiles, int canCreateDirectories, int treatPackagesAsDirectories) {}
void MessageDialog(struct Application* app, char *callbackID, char *type, char *title, char *message, char *icon, char *button1, char *button2, char *button3, char *button4, char *defaultButton, char *cancelButton) {}
// minimiseInternal minimises the main window
void minimiseInternal(struct Application *app) {
gtk_window_iconify(app->mainWindow);

View File

@@ -0,0 +1,17 @@
package ffenestri
/*
#cgo linux CFLAGS: -DFFENESTRI_LINUX=1
#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0
#include "ffenestri.h"
#include "ffenestri_linux.h"
*/
import "C"
func (a *Application) processPlatformSettings() error {
return nil
}

View File

@@ -0,0 +1,6 @@
#ifndef FFENESTRI_LINUX_H
#define FFENESTRI_LINUX_H
#endif

View File

@@ -9,12 +9,15 @@
#include <locale>
#include <codecvt>
#include "windows/WebView2.h"
#include <winuser.h>
#include "effectstructs_windows.h"
#include <Shlobj.h>
int debug = 0;
DWORD mainThread;
#define WS_EX_NOREDIRECTIONBITMAP 0x00200000L
// --- Assets
extern const unsigned char runtime;
extern const unsigned char *defaultDialogIcons[];
@@ -59,6 +62,7 @@ struct Application *NewApplication(const char *title, int width, int height, int
result->hideWindowOnClose = hideWindowOnClose;
result->webviewIsTranparent = false;
result->windowBackgroundIsTranslucent = false;
result->disableWindowIcon = false;
// Min/Max Width/Height
result->minWidth = 0;
@@ -81,9 +85,16 @@ struct Application *NewApplication(const char *title, int width, int height, int
// Startup url
result->startupURL = nullptr;
// Used to remember the window location when going fullscreen
result->previousPlacement = { sizeof(result->previousPlacement) };
return result;
}
void* GetWindowHandle(struct Application *app) {
return (void*)app->window;
}
void SetMinWindowSize(struct Application* app, int minWidth, int minHeight) {
app->minWidth = (LONG)minWidth;
app->minHeight = (LONG)minHeight;
@@ -107,6 +118,7 @@ void performShutdown(struct Application *app) {
messageFromWindowCallback("WC");
}
// Credit: https://gist.github.com/ysc3839/b08d2bff1c7dacde529bed1d37e85ccf
void enableTranslucentBackground(struct Application *app) {
HMODULE hUser = GetModuleHandleA("user32.dll");
if (hUser)
@@ -130,11 +142,22 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_CLOSE: {
DestroyWindow( app->window );
break;
}
case WM_DESTROY: {
DestroyApplication(app);
if( app->hideWindowOnClose ) {
Hide(app);
} else {
PostQuitMessage(0);
}
break;
}
case WM_SIZE: {
if ( app == NULL ) {
return 0;
}
if( app->webviewController != nullptr) {
RECT bounds;
GetClientRect(app->window, &bounds);
@@ -195,8 +218,8 @@ void execJS(struct Application* app, const char *script) {
void loadAssets(struct Application* app) {
// patch window.external.invoke
std::string initialCode = std::string("window.external={invoke:s=>window.chrome.webview.postMessage(s)};");
// setup window.wailsInvoke
std::string initialCode = std::string("window.wailsInvoke=function(m){window.chrome.webview.postMessage(m)};");
// Load bindings
initialCode += std::string(app->bindings);
@@ -224,7 +247,7 @@ void loadAssets(struct Application* app) {
initialCode += std::string("wails._.DisableDefaultContextMenu();");
}
initialCode += std::string("window.external.invoke('completed');");
initialCode += std::string("window.wailsInvoke('completed');");
// Keep a copy of the code
app->initialCode = new char[initialCode.length()+1];
@@ -243,6 +266,26 @@ void completed(struct Application* app) {
delete[] app->initialCode;
app->initialCode = nullptr;
// Process whether window should show by default
int startVisibility = SW_SHOWNORMAL;
if ( app->startHidden == 1 ) {
startVisibility = SW_HIDE;
}
// Fix for webview2 bug: https://github.com/MicrosoftEdge/WebView2Feedback/issues/1077
// Will be fixed in next stable release
app->webviewController->put_IsVisible(false);
app->webviewController->put_IsVisible(true);
// Private setTitle as we're on the main thread
if( app->frame == 1) {
setTitle(app, app->title);
}
ShowWindow(app->window, startVisibility);
UpdateWindow(app->window);
SetFocus(app->window);
if( app->startupURL == nullptr ) {
messageFromWindowCallback("SS");
return;
@@ -262,31 +305,73 @@ bool initWebView2(struct Application *app, int debugEnabled, messageCallback cb)
std::atomic_flag flag = ATOMIC_FLAG_INIT;
flag.test_and_set();
// char currentExePath[MAX_PATH];
// GetModuleFileNameA(NULL, currentExePath, MAX_PATH);
// char *currentExeName = PathFindFileNameA(currentExePath);
// std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> wideCharConverter;
// auto exeName = wideCharConverter.from_bytes(currentExeName);
//
// PWSTR path;
// HRESULT appDataResult = SHGetFolderPathAndSubDir(app->window, CSIDL_LOCAL_APPDATA, nullptr, SHGFP_TYPE_CURRENT, exeName.c_str(), path);
// if ( appDataResult == false ) {
// path = nullptr;
// }
//
char currentExePath[MAX_PATH];
GetModuleFileNameA(NULL, currentExePath, MAX_PATH);
char *currentExeName = PathFindFileNameA(currentExePath);
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> wideCharConverter;
std::wstring userDataFolder =
wideCharConverter.from_bytes(std::getenv("APPDATA"));
std::wstring currentExeNameW = wideCharConverter.from_bytes(currentExeName);
ICoreWebView2Controller *controller;
ICoreWebView2* webview;
HRESULT res = CreateCoreWebView2EnvironmentWithOptions(
nullptr, nullptr, nullptr,
nullptr, (userDataFolder + L"/" + currentExeNameW).c_str(), nullptr,
new wv2ComHandler(app, app->window, cb,
[&](ICoreWebView2Controller *webviewController) {
controller = webviewController;
controller->get_CoreWebView2(&webview);
webview->AddRef();
ICoreWebView2Settings* settings;
webview->get_Settings(&settings);
if ( debugEnabled == 0 ) {
settings->put_AreDefaultContextMenusEnabled(FALSE);
}
// Fix for invisible webview
if( app->startHidden ) {}
flag.clear();
}));
if (!SUCCEEDED(res))
{
switch (res)
{
case HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND):
{
MessageBox(
app->window,
L"Couldn't find Edge installation. "
"Do you have a version installed that's compatible with this "
"WebView2 SDK version?",
nullptr, MB_OK);
}
break;
case HRESULT_FROM_WIN32(ERROR_FILE_EXISTS):
{
MessageBox(
app->window, L"User data folder cannot be created because a file with the same name already exists.", nullptr, MB_OK);
}
break;
case E_ACCESSDENIED:
{
MessageBox(
app->window, L"Unable to create user data folder, Access Denied.", nullptr, MB_OK);
}
break;
case E_FAIL:
{
MessageBox(
app->window, L"Edge runtime unable to start", nullptr, MB_OK);
}
break;
default:
{
MessageBox(app->window, L"Failed to create WebView2 environment", nullptr, MB_OK);
}
}
}
if (res != S_OK) {
CoUninitialize();
return false;
@@ -304,8 +389,8 @@ bool initWebView2(struct Application *app, int debugEnabled, messageCallback cb)
GetClientRect(app->window, &bounds);
app->webviewController->put_Bounds(bounds);
// Callback hack
app->webview->AddScriptToExecuteOnDocumentCreated(L"window.chrome.webview.postMessage('I');", nullptr);
// Let the backend know we have initialised
app->webview->AddScriptToExecuteOnDocumentCreated(L"window.chrome.webview.postMessage('initialised');", nullptr);
// Load the HTML
LPCWSTR html = (LPCWSTR) cstrToLPWSTR((char*)assets[0]);
app->webview->Navigate(html);
@@ -320,64 +405,148 @@ void initialCallback(std::string message) {
void Run(struct Application* app, int argc, char **argv) {
WNDCLASSEX wc;
HINSTANCE hInstance = GetModuleHandle(NULL);
ZeroMemory(&wc, sizeof(WNDCLASSEX));
// Register the window class.
const wchar_t CLASS_NAME[] = L"Ffenestri";
WNDCLASSEX wc = { };
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.hInstance = hInstance;
wc.lpszClassName = (LPCWSTR)"ffenestri";
wc.lpfnWndProc = WndProc;
wc.hInstance = GetModuleHandle(NULL);
wc.lpszClassName = CLASS_NAME;
// TODO: Menu
// wc.lpszMenuName = nullptr;
if( app->disableWindowIcon == false ) {
wc.hIcon = LoadIcon(wc.hInstance, MAKEINTRESOURCE(100));
wc.hIconSm = LoadIcon(wc.hInstance, MAKEINTRESOURCE(100));
}
// Configure translucency
DWORD dwExStyle = 0;
if ( app->windowBackgroundIsTranslucent) {
dwExStyle = WS_EX_NOREDIRECTIONBITMAP;
wc.hbrBackground = CreateSolidBrush(RGB(255,255,255));
}
RegisterClassEx(&wc);
// Process window style
DWORD windowStyle = WS_OVERLAPPEDWINDOW | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
// Process window resizable
DWORD windowStyle = WS_OVERLAPPEDWINDOW;
if (app->resizable == 0) {
windowStyle &= ~WS_MAXIMIZEBOX;
windowStyle &= ~WS_THICKFRAME;
}
if ( app->frame == 0 ) {
windowStyle = WS_POPUP;
windowStyle &= ~WS_OVERLAPPEDWINDOW;
windowStyle &= ~WS_CAPTION;
windowStyle |= WS_POPUP;
}
RegisterClassEx(&wc);
app->window = CreateWindow((LPCWSTR)"ffenestri", (LPCWSTR)"", windowStyle, CW_USEDEFAULT,
CW_USEDEFAULT, app->width, app->height, NULL, NULL,
hInstance, NULL);
// Create the window.
app->window = CreateWindowEx(
dwExStyle, // Optional window styles.
CLASS_NAME, // Window class
L"", // Window text
windowStyle, // Window style
// Private setTitle as we're on the main thread
setTitle(app, app->title);
// Size and position
CW_USEDEFAULT, CW_USEDEFAULT, app->width, app->height,
NULL, // Parent window
NULL, // Menu
wc.hInstance, // Instance handle
NULL // Additional application data
);
if (app->window == NULL)
{
return;
}
if ( app->fullscreen ) {
fullscreen(app);
}
// Credit: https://stackoverflow.com/a/35482689
if( app->disableWindowIcon && app->frame == 1 ) {
int extendedStyle = GetWindowLong(app->window, GWL_EXSTYLE);
SetWindowLong(app->window, GWL_EXSTYLE, extendedStyle | WS_EX_DLGMODALFRAME);
SetWindowPos(nullptr, nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
}
if ( app->windowBackgroundIsTranslucent ) {
// Enable the translucent background effect
enableTranslucentBackground(app);
// Setup transparency of main window. This allows the blur to show through.
SetLayeredWindowAttributes(app->window,RGB(255,255,255),0,LWA_COLORKEY);
}
// Store application pointer in window handle
SetWindowLongPtr(app->window, GWLP_USERDATA, (LONG_PTR)app);
// Process whether window should show by default
int startVisibility = SW_SHOWNORMAL;
if ( app->startHidden == 1 ) {
startVisibility = SW_HIDE;
}
// TODO: Make configurable
// COREWEBVIEW2_COLOR wvColor;
// wvColor.A = 255;
// std::weak_ptr<ICoreWebView2Controller2> controller2 = app->webviewController->query<ICoreWebView2Controller2>();
// controller2->put_DefaultBackgroundColor(wvColor);
if( app->windowBackgroundIsTranslucent ) {
enableTranslucentBackground(app);
}
// private center() as we are on main thread
center(app);
ShowWindow(app->window, startVisibility);
UpdateWindow(app->window);
SetFocus(app->window);
// Add webview2
initWebView2(app, 1, initialCallback);
initWebView2(app, debug, initialCallback);
if( app->webviewIsTranparent ) {
wchar_t szBuff[64];
ICoreWebView2Controller2 *wc2;
wc2 = nullptr;
app->webviewController->QueryInterface(IID_ICoreWebView2Controller2, (void**)&wc2);
COREWEBVIEW2_COLOR wvColor;
wvColor.R = app->backgroundColour.R;
wvColor.G = app->backgroundColour.G;
wvColor.B = app->backgroundColour.B;
wvColor.A = app->backgroundColour.A == 0 ? 0 : 255;
if( app->windowBackgroundIsTranslucent ) {
wvColor.A = 0;
}
HRESULT result = wc2->put_DefaultBackgroundColor(wvColor);
if (!SUCCEEDED(result))
{
switch (result)
{
case HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND):
{
MessageBox(
app->window,
L"Couldn't find Edge installation. "
"Do you have a version installed that's compatible with this "
"WebView2 SDK version?",
nullptr, MB_OK);
}
break;
case HRESULT_FROM_WIN32(ERROR_FILE_EXISTS):
{
MessageBox(
app->window, L"User data folder cannot be created because a file with the same name already exists.", nullptr, MB_OK);
}
break;
case E_ACCESSDENIED:
{
MessageBox(
app->window, L"Unable to create user data folder, Access Denied.", nullptr, MB_OK);
}
break;
case E_FAIL:
{
MessageBox(
app->window, L"Edge runtime unable to start", nullptr, MB_OK);
}
break;
default:
{
MessageBox(app->window, L"Failed to create WebView2 environment", nullptr, MB_OK);
}
}
}
}
// Main event loop
MSG msg;
@@ -399,9 +568,6 @@ void Run(struct Application* app, int argc, char **argv) {
}
}
void DestroyApplication(struct Application* app) {
PostQuitMessage(0);
}
void SetDebug(struct Application* app, int flag) {
debug = flag;
}
@@ -432,6 +598,10 @@ void Show(struct Application* app) {
);
}
void DisableWindowIcon(struct Application* app) {
app->disableWindowIcon = true;
}
void center(struct Application* app) {
HMONITOR currentMonitor = MonitorFromWindow(app->window, MONITOR_DEFAULTTONEAREST);
@@ -537,25 +707,46 @@ void ToggleMinimise(struct Application* app) {
}
void SetColour(struct Application* app, int red, int green, int blue, int alpha) {
// TBD
app->backgroundColour.R = red;
app->backgroundColour.G = green;
app->backgroundColour.B = blue;
app->backgroundColour.A = alpha;
}
void SetSize(struct Application* app, int width, int height) {
// TBD
if( app->maxWidth > 0 && width > app->maxWidth ) {
width = app->maxWidth;
}
if ( app->maxHeight > 0 && height > app->maxHeight ) {
height = app->maxHeight;
}
SetWindowPos(app->window, nullptr, 0, 0, width, height, SWP_NOMOVE);
}
void setPosition(struct Application* app, int x, int y) {
// TBD
HMONITOR currentMonitor = MonitorFromWindow(app->window, MONITOR_DEFAULTTONEAREST);
MONITORINFO info = {0};
info.cbSize = sizeof(info);
GetMonitorInfoA(currentMonitor, &info);
RECT workRect = info.rcWork;
LONG newX = workRect.left + x;
LONG newY = workRect.top + y;
SetWindowPos(app->window, HWND_TOP, newX, newY, 0, 0, SWP_NOSIZE);
}
void SetPosition(struct Application* app, int x, int y) {
// ON_MAIN_THREAD(
// setPosition(app, x, y);
// );
ON_MAIN_THREAD(
setPosition(app, x, y);
);
}
void Quit(struct Application* app) {
DestroyWindow(app->window);
// Override the hide window on close flag
app->hideWindowOnClose = 0;
ON_MAIN_THREAD(
DestroyWindow(app->window);
);
}
@@ -572,13 +763,47 @@ void SetTitle(struct Application* app, const char *title) {
);
}
void fullscreen(struct Application* app) {
// Ensure we aren't in fullscreen
if (app->isFullscreen) return;
app->isFullscreen = true;
app->previousWindowStyle = GetWindowLong(app->window, GWL_STYLE);
MONITORINFO mi = { sizeof(mi) };
if (GetWindowPlacement(app->window, &(app->previousPlacement)) && GetMonitorInfo(MonitorFromWindow(app->window, MONITOR_DEFAULTTOPRIMARY), &mi)) {
SetWindowLong(app->window, GWL_STYLE, app->previousWindowStyle & ~WS_OVERLAPPEDWINDOW);
SetWindowPos(app->window, HWND_TOP,
mi.rcMonitor.left,
mi.rcMonitor.top,
mi.rcMonitor.right - mi.rcMonitor.left,
mi.rcMonitor.bottom - mi.rcMonitor.top,
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
}
}
void Fullscreen(struct Application* app) {
ON_MAIN_THREAD(
fullscreen(app);
show(app);
);
}
void unfullscreen(struct Application* app) {
if (app->isFullscreen) {
SetWindowLong(app->window, GWL_STYLE, app->previousWindowStyle);
SetWindowPlacement(app->window, &(app->previousPlacement));
SetWindowPos(app->window, NULL, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
app->isFullscreen = false;
}
}
void UnFullscreen(struct Application* app) {
}
void ToggleFullscreen(struct Application* app) {
ON_MAIN_THREAD(
unfullscreen(app);
);
}
void DisableFrame(struct Application* app) {

View File

@@ -5,16 +5,21 @@ import "C"
/*
#cgo windows CXXFLAGS: -std=c++11
#cgo windows,amd64 LDFLAGS: -L./windows/x64 -lwebview -lWebView2Loader -lgdi32 -lole32 -lShlwapi -luser32 -loleaut32
#cgo windows,amd64 LDFLAGS: -lgdi32 -lole32 -lShlwapi -luser32 -loleaut32 -ldwmapi
#include "ffenestri.h"
extern void DisableWindowIcon(struct Application* app);
*/
import "C"
func (a *Application) processPlatformSettings() error {
config := a.config.Windows
if config == nil {
return nil
}
// Check if the webview should be transparent
if config.WebviewIsTransparent {
@@ -25,6 +30,10 @@ func (a *Application) processPlatformSettings() error {
C.WindowBackgroundIsTranslucent(a.app)
}
if config.DisableWindowIcon {
C.DisableWindowIcon(a.app)
}
//// Process menu
////applicationMenu := options.GetApplicationMenu(a.config)
//applicationMenu := a.menuManager.GetApplicationMenuJSON()

View File

@@ -45,6 +45,12 @@ struct Application{
bool webviewIsTranparent;
bool windowBackgroundIsTranslucent;
COREWEBVIEW2_COLOR backgroundColour;
bool disableWindowIcon;
// Used by fullscreen/unfullscreen
bool isFullscreen;
WINDOWPLACEMENT previousPlacement;
DWORD previousWindowStyle;
// placeholders
char* bindings;
@@ -59,6 +65,8 @@ typedef std::function<void(ICoreWebView2Controller *)> comHandlerCallback;
void center(struct Application*);
void setTitle(struct Application* app, const char *title);
void fullscreen(struct Application* app);
void unfullscreen(struct Application* app);
char* LPWSTRToCstr(LPWSTR input);
// called when the DOM is ready
@@ -69,7 +77,9 @@ void completed(struct Application* app);
// Callback
extern "C" {
void DisableWindowIcon(struct Application* app);
void messageFromWindowCallback(const char *);
void* GetWindowHandle(struct Application*);
}
#endif

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
These files were generated using the scripts in the [webview](https://github.com/webview/webview) project and compressed using UPX.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,144 @@
// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef __core_webview2_environment_options_h__
#define __core_webview2_environment_options_h__
#include <objbase.h>
#include <wrl/implements.h>
#include "webview2.h"
#define CORE_WEBVIEW_TARGET_PRODUCT_VERSION L"91.0.864.35"
#define COREWEBVIEW2ENVIRONMENTOPTIONS_STRING_PROPERTY(p) \
public: \
HRESULT STDMETHODCALLTYPE get_##p(LPWSTR* value) override { \
if (!value) \
return E_POINTER; \
*value = m_##p.Copy(); \
if ((*value == nullptr) && (m_##p.Get() != nullptr)) \
return HRESULT_FROM_WIN32(GetLastError()); \
return S_OK; \
} \
HRESULT STDMETHODCALLTYPE put_##p(LPCWSTR value) override { \
LPCWSTR result = m_##p.Set(value); \
if ((result == nullptr) && (value != nullptr)) \
return HRESULT_FROM_WIN32(GetLastError()); \
return S_OK; \
} \
\
protected: \
AutoCoMemString m_##p;
#define COREWEBVIEW2ENVIRONMENTOPTIONS_BOOL_PROPERTY(p) \
public: \
HRESULT STDMETHODCALLTYPE get_##p(BOOL* value) override { \
if (!value) \
return E_POINTER; \
*value = m_##p; \
return S_OK; \
} \
HRESULT STDMETHODCALLTYPE put_##p(BOOL value) override { \
m_##p = value; \
return S_OK; \
} \
\
protected: \
BOOL m_##p = FALSE;
// This is a base COM class that implements ICoreWebView2EnvironmentOptions.
template <typename allocate_fn_t,
allocate_fn_t allocate_fn,
typename deallocate_fn_t,
deallocate_fn_t deallocate_fn>
class CoreWebView2EnvironmentOptionsBase
: public Microsoft::WRL::Implements<
Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
ICoreWebView2EnvironmentOptions> {
public:
CoreWebView2EnvironmentOptionsBase() {
// Initialize the target compatible browser version value to the version of
// the browser binaries corresponding to this version of the SDK.
m_TargetCompatibleBrowserVersion.Set(CORE_WEBVIEW_TARGET_PRODUCT_VERSION);
}
protected:
~CoreWebView2EnvironmentOptionsBase(){};
class AutoCoMemString {
public:
AutoCoMemString() {}
~AutoCoMemString() { Release(); }
void Release() {
if (m_string) {
deallocate_fn(m_string);
m_string = nullptr;
}
}
LPCWSTR Set(LPCWSTR str) {
Release();
if (str) {
m_string = MakeCoMemString(str);
}
return m_string;
}
LPCWSTR Get() { return m_string; }
LPWSTR Copy() {
if (m_string)
return MakeCoMemString(m_string);
return nullptr;
}
protected:
LPWSTR MakeCoMemString(LPCWSTR source) {
const size_t length = wcslen(source);
const size_t bytes = (length + 1) * sizeof(*source);
// Ensure we didn't overflow during our size calculation.
if (bytes <= length) {
return nullptr;
}
wchar_t* result = reinterpret_cast<wchar_t*>(allocate_fn(bytes));
if (result)
memcpy(result, source, bytes);
return result;
}
LPWSTR m_string = nullptr;
};
COREWEBVIEW2ENVIRONMENTOPTIONS_STRING_PROPERTY(AdditionalBrowserArguments)
COREWEBVIEW2ENVIRONMENTOPTIONS_STRING_PROPERTY(Language)
COREWEBVIEW2ENVIRONMENTOPTIONS_STRING_PROPERTY(TargetCompatibleBrowserVersion)
COREWEBVIEW2ENVIRONMENTOPTIONS_BOOL_PROPERTY(
AllowSingleSignOnUsingOSPrimaryAccount)
};
template <typename allocate_fn_t,
allocate_fn_t allocate_fn,
typename deallocate_fn_t,
deallocate_fn_t deallocate_fn>
class CoreWebView2EnvironmentOptionsBaseClass
: public Microsoft::WRL::RuntimeClass<
Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
CoreWebView2EnvironmentOptionsBase<allocate_fn_t,
allocate_fn,
deallocate_fn_t,
deallocate_fn>> {
public:
CoreWebView2EnvironmentOptionsBaseClass() {}
protected:
~CoreWebView2EnvironmentOptionsBaseClass() override{};
};
typedef CoreWebView2EnvironmentOptionsBaseClass<decltype(&::CoTaskMemAlloc),
::CoTaskMemAlloc,
decltype(&::CoTaskMemFree),
::CoTaskMemFree>
CoreWebView2EnvironmentOptions;
#endif // __core_webview2_environment_options_h__

View File

@@ -0,0 +1,11 @@
# Build
This script will download the given webview2 sdk version and copy out the files necessary for building Wails apps.
## Prerequistes
- nuget
## Usage
`updatesdk.bat <version>`

View File

@@ -0,0 +1 @@
The version of WebView2 used: 1.0.864.35

View File

@@ -0,0 +1,18 @@
@echo off
IF %1.==. GOTO NoVersion
nuget install microsoft.web.webview2 -Version %1 -OutputDirectory . >NUL || goto :eof
echo Downloaded microsoft.web.webview2.%1
set sdk_version=%1
set native_dir="%~dp0\microsoft.web.webview2.%sdk_version%\build\native"
copy "%native_dir%\include\*.h" .. >NUL
copy "%native_dir%\x64\WebView2Loader.dll" "..\x64" >NUL
@rd /S /Q "microsoft.web.webview2.%sdk_version%"
del /s version.txt >nul 2>&1
echo The version of WebView2 SDK used: %sdk_version% > sdkversion.txt
echo SDK updated to %sdk_version%
goto :eof
:NoVersion
echo Please provide a version number, EG: 1.0.664.37
goto :eof

View File

@@ -1,7 +0,0 @@
cmake_minimum_required(VERSION 3.19)
project(test C)
set(CMAKE_C_STANDARD 99)
set(SOURCES ../../ffenestri_windows.cpp)
add_executable(test ${SOURCES} main.c)

View File

@@ -1 +0,0 @@
g++ main.c ..\..\ffenestri_windows.cpp -lgdi32 -std=c++11

View File

@@ -0,0 +1,23 @@
// +build wv2runtime.browser
package wv2runtime
import (
"fmt"
"github.com/leaanthony/webview2runtime"
)
func doInstallationStrategy(installStatus installationStatus) error {
confirmed, err := webview2runtime.Confirm("This application requires the WebView2 runtime. Press OK to open the download page. Minimum version required: "+minimumRuntimeVersion, "Missing Requirements")
if err != nil {
return err
}
if confirmed {
err = webview2runtime.OpenInstallerDownloadWebpage()
if err != nil {
return err
}
}
return fmt.Errorf("webview2 runtime not installed")
}

View File

@@ -0,0 +1,35 @@
// +build !wv2runtime.error
// +build !wv2runtime.browser
// +build !wv2runtime.embed
package wv2runtime
import (
"fmt"
"github.com/leaanthony/webview2runtime"
)
func doInstallationStrategy(installStatus installationStatus) error {
message := "The WebView2 runtime is required. "
if installStatus == needsUpdating {
message = "The Webview2 runtime needs updating. "
}
message += "Press Ok to download and install. Note: The installer will download silently so please wait."
confirmed, err := webview2runtime.Confirm(message, "Missing Requirements")
if err != nil {
return err
}
if !confirmed {
return fmt.Errorf("webview2 runtime not installed")
}
installedCorrectly, err := webview2runtime.InstallUsingBootstrapper()
if err != nil {
_ = webview2runtime.Error(err.Error(), "Error")
return err
}
if !installedCorrectly {
err = webview2runtime.Error("The runtime failed to install correctly. Please try again.", "Error")
return err
}
return nil
}

View File

@@ -0,0 +1,33 @@
// +build wv2runtime.embed
package wv2runtime
import (
"fmt"
"github.com/leaanthony/webview2runtime"
)
func doInstallationStrategy(installStatus installationStatus) error {
message := "The WebView2 runtime is required. "
if installStatus == needsUpdating {
message = "The Webview2 runtime needs updating. "
}
message += "Press Ok to install."
confirmed, err := webview2runtime.Confirm(message, "Missing Requirements")
if err != nil {
return err
}
if !confirmed {
return fmt.Errorf("webview2 runtime not installed")
}
installedCorrectly, err := webview2runtime.InstallUsingEmbeddedBootstrapper()
if err != nil {
_ = webview2runtime.Error(err.Error(), "Error")
return err
}
if !installedCorrectly {
err = webview2runtime.Error("The runtime failed to install correctly. Please try again.", "Error")
return err
}
return nil
}

View File

@@ -0,0 +1,13 @@
// +build wv2runtime.error
package wv2runtime
import (
"fmt"
"github.com/leaanthony/webview2runtime"
)
func doInstallationStrategy(installStatus installationStatus) error {
_ = webview2runtime.Error("The WebView2 runtime is required to run this application. Please contact your system administrator.", "Error")
return fmt.Errorf("webview2 runtime not installed")
}

View File

@@ -0,0 +1,34 @@
package wv2runtime
import (
"github.com/leaanthony/webview2runtime"
)
const minimumRuntimeVersion string = "91.0.864.48"
type installationStatus int
const (
needsInstalling installationStatus = iota
needsUpdating
installed
)
func Process() error {
installStatus := needsInstalling
installedVersion := webview2runtime.GetInstalledVersion()
if installedVersion != nil {
installStatus = installed
updateRequired, err := installedVersion.IsOlderThan(minimumRuntimeVersion)
if err != nil {
_ = webview2runtime.Error(err.Error(), "Error")
return err
}
// Installed and does not require updating
if !updateRequired {
return nil
}
installStatus = needsUpdating
}
return doInstallationStrategy(installStatus)
}

View File

@@ -1,9 +1,8 @@
// +build windows
package x64
import _ "embed"
//go:embed webview.dll
var WebView2 []byte
//go:embed WebView2Loader.dll
var WebView2Loader []byte

View File

@@ -66,21 +66,20 @@ class wv2ComHandler
completed(app);
return S_OK;
}
switch(m[0]) {
// Standard message for backend
case 'S':
printf("--> Message to backend: %s\n", &m[1]);
messageFromWindowCallback(&m[1]);
break;
// DOM Initialised
case 'I':
else if (strcmp(m, "initialised") == 0) {
loadAssets(app);
break;
default:
printf("----> Unknown message type: %c\n", m[0]);
return S_OK;
}
else if (strcmp(m, "wails-drag") == 0) {
// We don't drag in fullscreen mode
if (!app->isFullscreen) {
ReleaseCapture();
SendMessage(this->window, WM_NCLBUTTONDOWN, HTCAPTION, 0);
}
return S_OK;
}
else {
messageFromWindowCallback(m);
}
delete[] m;
return S_OK;

View File

@@ -52,21 +52,13 @@ func (a *Asset) AsString() string {
return a.Data
}
// AsCHexData processes the asset data so it may be used by C
func (a *Asset) AsCHexData() string {
// This will be our final string to hexify
dataString := a.Data
func (a *Asset) minifiedData() (string, error) {
switch a.Type {
case AssetTypes.HTML:
// Escape HTML
var re = regexp.MustCompile(`\s{2,}`)
result := re.ReplaceAllString(a.Data, ``)
result = strings.ReplaceAll(result, "\n", "")
result = strings.ReplaceAll(result, "\r\n", "")
result = strings.ReplaceAll(result, "\n", "")
var re = regexp.MustCompile(`[\s]+`)
result := re.ReplaceAllString(a.Data, ` `)
// Inject wailsloader code
result = strings.Replace(result, `</body>`, `<script id='wailsloader'>window.wailsloader = { html: true, runtime: false, userjs: false, usercss: false };var self=document.querySelector('#wailsloader');self.parentNode.removeChild(self);</script></body>`, 1)
@@ -75,7 +67,7 @@ func (a *Asset) AsCHexData() string {
urlString := strings.ReplaceAll(url.String(), "/", "%2f")
// Save Data uRI string
dataString = "data:text/html;charset=utf-8," + urlString
return "data:text/html;charset=utf-8," + urlString, nil
case AssetTypes.CSS:
@@ -91,19 +83,28 @@ func (a *Asset) AsCHexData() string {
result = strings.ReplaceAll(result, `'`, `\'`)
result = strings.ReplaceAll(result, ` {`, `{`)
result = strings.ReplaceAll(result, `: `, `:`)
dataString = fmt.Sprintf("window.wails._.InjectCSS(\"%s\");", result)
return fmt.Sprintf("window.wails._.InjectCSS(\"%s\");", result), nil
case AssetTypes.JS:
m := minify.New()
m.AddFunc("application/javascript", js.Minify)
var err error
dataString, err = m.String("application/javascript", a.Data+";")
result, err := m.String("application/javascript", a.Data+";")
if err != nil {
log.Fatal(err)
return "", err
}
a.Data = dataString
return result, nil
default:
return "", fmt.Errorf("minification for asset type %s not implemented", a.Type)
}
}
// AsCHexData processes the asset data so it may be used by C
func (a *Asset) AsCHexData() string {
dataString, err := a.minifiedData()
if err != nil {
log.Fatal(err)
}
// Get byte data of the string
bytes := *(*[]byte)(unsafe.Pointer(&dataString))

View File

@@ -0,0 +1,53 @@
package html
import "testing"
func TestAsset_minifiedData(t *testing.T) {
type fields struct {
Type string
Path string
Data string
}
tests := []struct {
name string
fields fields
want string
wantErr bool
}{
{
name: "multi-line tag",
fields: fields{
Type: AssetTypes.HTML,
Path: "foo.html",
Data: "<link\n rel=\"stylesheet\"\n href=\"src/foo.css\"\n>\n",
},
want: "data:text/html;charset=utf-8,%3Clink%20rel=%22stylesheet%22%20href=%22src%2ffoo.css%22%20%3E%20",
},
{
name: "multi-line tag no spaces",
fields: fields{
Type: AssetTypes.HTML,
Path: "foo.html",
Data: "<link\nrel=\"stylesheet\"\nhref=\"src/foo.css\"\n>\n",
},
want: "data:text/html;charset=utf-8,%3Clink%20rel=%22stylesheet%22%20href=%22src%2ffoo.css%22%20%3E%20",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
a := &Asset{
Type: tt.fields.Type,
Path: tt.fields.Path,
Data: tt.fields.Data,
}
got, err := a.minifiedData()
if (err != nil) != tt.wantErr {
t.Errorf("Asset.minifiedData() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("Asset.minifiedData() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -84,7 +84,7 @@ func (a *AssetBundle) processHTML(htmldata string) error {
}
//process the token according to the token type...
if tokenType == html.StartTagToken {
if tokenType == html.StartTagToken || tokenType == html.SelfClosingTagToken {
//get the token
token := tokenizer.Token()

View File

@@ -0,0 +1,73 @@
package html
import (
"testing"
)
func TestNewAssetBundle(t *testing.T) {
tests := []struct {
name string
pathToHTML string
wantAssets []string
wantErr bool
}{
{
name: "basic html",
pathToHTML: "testdata/basic.html",
wantAssets: []string{
AssetTypes.HTML,
AssetTypes.FAVICON,
AssetTypes.JS,
AssetTypes.CSS,
},
wantErr: false,
},
{
name: "self closing tags",
pathToHTML: "testdata/self_closing.html",
wantAssets: []string{
AssetTypes.HTML,
AssetTypes.FAVICON,
AssetTypes.JS,
AssetTypes.CSS,
},
wantErr: false,
},
{
name: "multi-line tags",
pathToHTML: "testdata/self_closing.html",
wantAssets: []string{
AssetTypes.HTML,
AssetTypes.FAVICON,
AssetTypes.JS,
AssetTypes.CSS,
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := NewAssetBundle(tt.pathToHTML)
if (err != nil) != tt.wantErr {
t.Errorf("NewAssetBundle() error = %v, wantErr %v", err, tt.wantErr)
return
}
if len(got.assets) != len(tt.wantAssets) {
t.Errorf("NewAssetBundle() len(assets) = %d, want %d",
len(got.assets), len(tt.wantAssets))
}
for i := range tt.wantAssets {
if i >= len(got.assets) {
t.Errorf("NewAssetBundle() missing assets[%d].Type = %s",
i, tt.wantAssets[i])
} else {
if got.assets[i].Type != tt.wantAssets[i] {
t.Errorf("NewAssetBundle() assets[%d].Type = %s, want %s",
i, got.assets[i].Type, tt.wantAssets[i])
}
}
}
})
}
}

14
v2/internal/html/testdata/basic.html vendored Normal file
View File

@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg"></link>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script type="text/javascript" src="src/bundle.js"></script>
<link rel="stylesheet" href="src/style.css"></link>
<title>Vite App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>

View File

@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script type="text/javascript" src="src/bundle.js"></script>
<link
rel="stylesheet"
href="src/style.css"
/>
<title>Vite App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>

View File

@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script type="text/javascript" src="src/bundle.js"></script>
<link rel="stylesheet" href="src/style.css" />
<title>Vite App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>

View File

@@ -0,0 +1 @@
window.alert("I am JS!");

View File

@@ -0,0 +1,8 @@
<svg version="1.1"
baseProfile="full"
width="300" height="200"
xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" fill="blue" />
</svg>

After

Width:  |  Height:  |  Size: 172 B

View File

@@ -0,0 +1,3 @@
.body {
background: blue;
}

View File

@@ -14,7 +14,9 @@ type Client interface {
Quit()
NotifyEvent(message string)
CallResult(message string)
OpenDialog(dialogOptions *dialog.OpenDialog, callbackID string)
OpenFileDialog(dialogOptions *dialog.OpenDialog, callbackID string)
OpenMultipleFilesDialog(dialogOptions *dialog.OpenDialog, callbackID string)
OpenDirectoryDialog(dialogOptions *dialog.OpenDialog, callbackID string)
SaveDialog(dialogOptions *dialog.SaveDialog, callbackID string)
MessageDialog(dialogOptions *dialog.MessageDialog, callbackID string)
WindowSetTitle(title string)

View File

@@ -32,13 +32,29 @@ func dialogMessageParser(message string) (*parsedMessage, error) {
switch dialogType {
case 'O':
var data []string
var data string
topic = "dialog:openselected:" + callbackID
err := json.Unmarshal([]byte(payloadData), &data)
if err != nil {
return nil, err
}
responseMessage = &parsedMessage{Topic: topic, Data: data}
case 'D':
var data string
topic = "dialog:opendirectoryselected:" + callbackID
err := json.Unmarshal([]byte(payloadData), &data)
if err != nil {
return nil, err
}
responseMessage = &parsedMessage{Topic: topic, Data: data}
case '*':
var data []string
topic = "dialog:openmultipleselected:" + callbackID
err := json.Unmarshal([]byte(payloadData), &data)
if err != nil {
return nil, err
}
responseMessage = &parsedMessage{Topic: topic, Data: data}
case 'S':
topic = "dialog:saveselected:" + callbackID
responseMessage = &parsedMessage{Topic: topic, Data: payloadData}

View File

@@ -422,7 +422,35 @@ func (d *Dispatcher) processDialogMessage(result *servicebus.Message) {
// TODO: Work out what we mean in a multi window environment...
// For now we will just pick the first one
for _, client := range d.clients {
client.frontend.OpenDialog(dialogOptions, callbackID)
client.frontend.OpenFileDialog(dialogOptions, callbackID)
}
case "openmultiple":
dialogOptions, ok := result.Data().(*dialog.OpenDialog)
if !ok {
d.logger.Error("Invalid data for 'dialog:select:openmultiple' : %#v", result.Data())
return
}
// This is hardcoded in the sender too
callbackID := splitTopic[3]
// TODO: Work out what we mean in a multi window environment...
// For now we will just pick the first one
for _, client := range d.clients {
client.frontend.OpenMultipleFilesDialog(dialogOptions, callbackID)
}
case "directory":
dialogOptions, ok := result.Data().(*dialog.OpenDialog)
if !ok {
d.logger.Error("Invalid data for 'dialog:select:directory' : %#v", result.Data())
return
}
// This is hardcoded in the sender too
callbackID := splitTopic[3]
// TODO: Work out what we mean in a multi window environment...
// For now we will just pick the first one
for _, client := range d.clients {
client.frontend.OpenDirectoryDialog(dialogOptions, callbackID)
}
case "save":
dialogOptions, ok := result.Data().(*dialog.SaveDialog)

View File

@@ -39,12 +39,7 @@ func (p *Process) Start() error {
go func(cmd *exec.Cmd, running *bool, logger *clilogger.CLILogger, exitChannel chan bool) {
logger.Println("Starting process (PID: %d)", cmd.Process.Pid)
err := cmd.Wait()
if err != nil {
if err.Error() != "signal: killed" {
logger.Fatal("Fatal error from app: " + err.Error())
}
}
_ = cmd.Wait()
logger.Println("Exiting process (PID: %d)", cmd.Process.Pid)
*running = false
exitChannel <- true
@@ -59,6 +54,13 @@ func (p *Process) Kill() error {
return nil
}
err := p.cmd.Process.Kill()
if err != nil {
return err
}
err = p.cmd.Process.Release()
if err != nil {
return err
}
// Wait for command to exit properly
<-p.exitChannel

View File

@@ -25,8 +25,8 @@ type Project struct {
// The path to the project directory
Path string
// Assets directory
AssetsDir string `json:"assetsdir"`
// Build directory
BuildDir string `json:"builddir"`
// The output filename
OutputFilename string `json:"outputfilename"`
@@ -76,8 +76,8 @@ func Load(projectPath string) (*Project, error) {
}
// Set default assets directory if none given
if result.AssetsDir == "" {
result.AssetsDir = filepath.Join(result.Path, "assets")
if result.BuildDir == "" {
result.BuildDir = filepath.Join(result.Path, "build")
}
// Fix up OutputFilename

View File

@@ -0,0 +1,12 @@
package assets
import _ "embed"
//go:embed desktop_darwin.js
var desktopDarwinJS string
//go:embed desktop_windows.js
var desktopWindowsJS string
//go:embed wails.js
var wailsJS string

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -10,9 +10,11 @@ import (
// Dialog defines all Dialog related operations
type Dialog interface {
Open(dialogOptions *dialogoptions.OpenDialog) []string
Save(dialogOptions *dialogoptions.SaveDialog) string
Message(dialogOptions *dialogoptions.MessageDialog) string
OpenFile(dialogOptions *dialogoptions.OpenDialog) (string, error)
OpenMultipleFiles(dialogOptions *dialogoptions.OpenDialog) ([]string, error)
OpenDirectory(dialogOptions *dialogoptions.OpenDialog) (string, error)
SaveFile(dialogOptions *dialogoptions.SaveDialog) (string, error)
Message(dialogOptions *dialogoptions.MessageDialog) (string, error)
}
// dialog exposes the Dialog interface
@@ -27,6 +29,7 @@ func newDialog(bus *servicebus.ServiceBus) Dialog {
}
}
// processTitleAndFilter return the title and filter from the given params.
// title is the first string, filter is the second
func (r *dialog) processTitleAndFilter(params ...string) (string, string) {
@@ -44,8 +47,33 @@ func (r *dialog) processTitleAndFilter(params ...string) (string, string) {
return title, filter
}
// Open prompts the user to select a file
func (r *dialog) Open(dialogOptions *dialogoptions.OpenDialog) []string {
// OpenDirectory prompts the user to select a directory
func (r *dialog) OpenDirectory(dialogOptions *dialogoptions.OpenDialog) (string, error) {
// Create unique dialog callback
uniqueCallback := crypto.RandomID()
// Subscribe to the respose channel
responseTopic := "dialog:opendirectoryselected:" + uniqueCallback
dialogResponseChannel, err := r.bus.Subscribe(responseTopic)
if err != nil {
return "", fmt.Errorf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
}
message := "dialog:select:directory:" + uniqueCallback
r.bus.Publish(message, dialogOptions)
// Wait for result
var result = <-dialogResponseChannel
// Delete subscription to response topic
r.bus.UnSubscribe(responseTopic)
return result.Data().(string), nil
}
// OpenFile prompts the user to select a file
func (r *dialog) OpenFile(dialogOptions *dialogoptions.OpenDialog) (string, error) {
// Create unique dialog callback
uniqueCallback := crypto.RandomID()
@@ -54,23 +82,54 @@ func (r *dialog) Open(dialogOptions *dialogoptions.OpenDialog) []string {
responseTopic := "dialog:openselected:" + uniqueCallback
dialogResponseChannel, err := r.bus.Subscribe(responseTopic)
if err != nil {
fmt.Printf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
return "", fmt.Errorf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
}
message := "dialog:select:open:" + uniqueCallback
r.bus.Publish(message, dialogOptions)
// Wait for result
var result *servicebus.Message = <-dialogResponseChannel
var result = <-dialogResponseChannel
// Delete subscription to response topic
r.bus.UnSubscribe(responseTopic)
return result.Data().([]string)
files := result.Data().([]string)
res := ""
if len(files) > 0 {
res = files[0]
}
return res, nil
}
// Save prompts the user to select a file
func (r *dialog) Save(dialogOptions *dialogoptions.SaveDialog) string {
// OpenMultipleFiles prompts the user to select a file
func (r *dialog) OpenMultipleFiles(dialogOptions *dialogoptions.OpenDialog) ([]string, error) {
// Create unique dialog callback
uniqueCallback := crypto.RandomID()
// Subscribe to the respose channel
responseTopic := "dialog:openmultipleselected:" + uniqueCallback
dialogResponseChannel, err := r.bus.Subscribe(responseTopic)
if err != nil {
return nil, fmt.Errorf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
}
message := "dialog:select:openmultiple:" + uniqueCallback
r.bus.Publish(message, dialogOptions)
// Wait for result
var result = <-dialogResponseChannel
// Delete subscription to response topic
r.bus.UnSubscribe(responseTopic)
return result.Data().([]string), nil
}
// SaveFile prompts the user to select a file
func (r *dialog) SaveFile(dialogOptions *dialogoptions.SaveDialog) (string, error) {
// Create unique dialog callback
uniqueCallback := crypto.RandomID()
@@ -79,23 +138,23 @@ func (r *dialog) Save(dialogOptions *dialogoptions.SaveDialog) string {
responseTopic := "dialog:saveselected:" + uniqueCallback
dialogResponseChannel, err := r.bus.Subscribe(responseTopic)
if err != nil {
fmt.Printf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
return "", fmt.Errorf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
}
message := "dialog:select:save:" + uniqueCallback
r.bus.Publish(message, dialogOptions)
// Wait for result
var result *servicebus.Message = <-dialogResponseChannel
var result = <-dialogResponseChannel
// Delete subscription to response topic
r.bus.UnSubscribe(responseTopic)
return result.Data().(string)
return result.Data().(string), nil
}
// Message show a message to the user
func (r *dialog) Message(dialogOptions *dialogoptions.MessageDialog) string {
func (r *dialog) Message(dialogOptions *dialogoptions.MessageDialog) (string, error) {
// Create unique dialog callback
uniqueCallback := crypto.RandomID()
@@ -104,17 +163,17 @@ func (r *dialog) Message(dialogOptions *dialogoptions.MessageDialog) string {
responseTopic := "dialog:messageselected:" + uniqueCallback
dialogResponseChannel, err := r.bus.Subscribe(responseTopic)
if err != nil {
fmt.Printf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
return "", fmt.Errorf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
}
message := "dialog:select:message:" + uniqueCallback
r.bus.Publish(message, dialogOptions)
// Wait for result
var result *servicebus.Message = <-dialogResponseChannel
var result = <-dialogResponseChannel
// Delete subscription to response topic
r.bus.UnSubscribe(responseTopic)
return result.Data().(string)
return result.Data().(string), nil
}

View File

@@ -10,20 +10,6 @@ The lightweight framework for web-like apps
/* jshint esversion: 6 */
import { SetBindings } from './bindings';
import { Init } from './main';
import {RaiseError} from '../desktop/darwin';
// Setup global error handler
window.onerror = function (msg, url, lineNo, columnNo, error) {
const errorMessage = {
message: msg,
url: url,
line: lineNo,
column: columnNo,
error: JSON.stringify(error),
stack: function() { return JSON.stringify(new Error().stack); }(),
};
RaiseError(errorMessage);
};
// Initialise the Runtime
Init();

View File

@@ -15,7 +15,7 @@ import * as Dialog from './dialog';
import { On, Once, OnMultiple, Emit, Notify } from './events';
import { Callback, SystemCall } from './calls';
import { AddScript, InjectCSS, DisableDefaultContextMenu } from './utils';
import { AddIPCListener } from 'ipc';
import { AddIPCListener, SendMessage } from 'ipc';
import * as Platform from 'platform';
import * as Store from './store';
import * as Tray from './tray';
@@ -47,6 +47,7 @@ export function Init() {
// Init,
AddIPCListener,
SystemCall,
SendMessage,
},
Store,
};

View File

@@ -13,60 +13,53 @@ The lightweight framework for web-like apps
* Initialises platform specific code
*/
// import * as common from './common';
const common = require('./common');
export const System = {
...common,
Platform: () => "darwin",
}
AppType: 'desktop',
Platform: () => 'darwin',
};
export function SendMessage(message) {
window.webkit.messageHandlers.external.postMessage(message);
}
export function RaiseError(message) {
window.webkit.messageHandlers.error.postMessage(message);
window.wailsInvoke(message);
}
export function Init() {
// Setup drag handler
// Based on code from: https://github.com/patr0nus/DeskGap
window.addEventListener('mousedown', function (e) {
let currentElement = e.target;
while (currentElement != null) {
if (currentElement.hasAttribute('data-wails-no-drag')) {
break;
} else if (currentElement.hasAttribute('data-wails-drag')) {
window.webkit.messageHandlers.windowDrag.postMessage(null);
break;
}
currentElement = currentElement.parentElement;
}
});
// Setup drag handler
// Based on code from: https://github.com/patr0nus/DeskGap
window.addEventListener('mousedown', function (e) {
let currentElement = e.target;
while (currentElement != null) {
if (currentElement.hasAttribute('data-wails-no-drag')) {
break;
} else if (currentElement.hasAttribute('data-wails-drag')) {
window.wailsDrag(null);
break;
}
currentElement = currentElement.parentElement;
}
});
// Setup context menu hook
window.addEventListener('contextmenu', function (e) {
let currentElement = e.target;
let contextMenuId;
while (currentElement != null) {
contextMenuId = currentElement.dataset['wails-context-menu-id'];
if (contextMenuId != null) {
break;
}
currentElement = currentElement.parentElement;
}
if (contextMenuId != null || window.disableWailsDefaultContextMenu) {
e.preventDefault();
}
if( contextMenuId != null ) {
let contextData = currentElement.dataset['wails-context-menu-data'];
let message = {
id: contextMenuId,
data: contextData || "",
};
window.webkit.messageHandlers.contextMenu.postMessage(JSON.stringify(message));
}
});
// Setup context menu hook
window.addEventListener('contextmenu', function (e) {
let currentElement = e.target;
let contextMenuId;
while (currentElement != null) {
contextMenuId = currentElement.dataset['wails-context-menu-id'];
if (contextMenuId != null) {
break;
}
currentElement = currentElement.parentElement;
}
if (contextMenuId != null || window.disableWailsDefaultContextMenu) {
e.preventDefault();
}
if( contextMenuId != null ) {
let contextData = currentElement.dataset['wails-context-menu-data'];
let message = {
id: contextMenuId,
data: contextData || '',
};
window.wailsContextMenuMessage(JSON.stringify(message));
}
});
}

View File

@@ -14,28 +14,52 @@ The lightweight framework for web-like apps
*/
export const System = {
...common,
Platform: () => "linux",
}
AppType: 'desktop',
Platform: () => 'linux',
};
export function SendMessage(message) {
window.webkit.messageHandlers.external.postMessage(message);
window.wailsInvoke(message);
}
export function Init() {
// Setup drag handler
// Based on code from: https://github.com/patr0nus/DeskGap
window.addEventListener('mousedown', function (e) {
let currentElement = e.target;
while (currentElement != null) {
if (currentElement.hasAttribute('data-wails-no-drag')) {
break;
} else if (currentElement.hasAttribute('data-wails-drag')) {
window.webkit.messageHandlers.windowDrag.postMessage(null);
break;
}
currentElement = currentElement.parentElement;
}
});
// Setup drag handler
// Based on code from: https://github.com/patr0nus/DeskGap
window.addEventListener('mousedown', function (e) {
let currentElement = e.target;
while (currentElement != null) {
if (currentElement.hasAttribute('data-wails-no-drag')) {
break;
} else if (currentElement.hasAttribute('data-wails-drag')) {
window.wailsDrag(null);
break;
}
currentElement = currentElement.parentElement;
}
});
// Setup context menu hook
window.addEventListener('contextmenu', function (e) {
let currentElement = e.target;
let contextMenuId;
while (currentElement != null) {
contextMenuId = currentElement.dataset['wails-context-menu-id'];
if (contextMenuId != null) {
break;
}
currentElement = currentElement.parentElement;
}
if (contextMenuId != null || window.disableWailsDefaultContextMenu) {
e.preventDefault();
}
if( contextMenuId != null ) {
let contextData = currentElement.dataset['wails-context-menu-data'];
let message = {
id: contextMenuId,
data: contextData || '',
};
window.wailsContextMenuMessage(JSON.stringify(message));
}
});
}

View File

@@ -13,20 +13,13 @@ The lightweight framework for web-like apps
* Initialises platform specific code
*/
// import * as common from './common';
const common = require('./common');
export const System = {
...common,
AppType: 'desktop',
Platform: () => 'windows',
};
export function SendMessage(message) {
window.chrome.webview.postMessage('S'+message);
}
export function RaiseError(message) {
window.chrome.webview.postMessage('E'+message);
window.wailsInvoke(message);
}
export function Init() {
@@ -39,7 +32,7 @@ export function Init() {
if (currentElement.hasAttribute('data-wails-no-drag')) {
break;
} else if (currentElement.hasAttribute('data-wails-drag')) {
window.chrome.webview.postMessage('wails-drag');
window.wailsInvoke('wails-drag');
break;
}
currentElement = currentElement.parentElement;
@@ -66,7 +59,7 @@ export function Init() {
id: contextMenuId,
data: contextData || '',
};
window.chrome.webview.postMessage('C'+JSON.stringify(message));
window.wailsInvoke('C'+JSON.stringify(message));
}
});
}

View File

@@ -677,8 +677,8 @@
function add_css() {
var style = element("style");
style.id = "svelte-9nqyfr-style";
style.textContent = ".wails-reconnect-overlay.svelte-9nqyfr{position:fixed;top:0;left:0;width:100%;height:100%;backdrop-filter:blur(20px) saturate(160%) contrast(45%) brightness(140%);z-index:999999\n }.wails-reconnect-overlay-content.svelte-9nqyfr{position:relative;top:50%;transform:translateY(-50%);margin:0;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC8AAAAuCAMAAACPpbA7AAAAflBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAAAAAAAAAAAABAQEEBAQAAAAAAAAEBAQAAAADAwMAAAABAQEAAAAAAAAAAAAAAAAAAAACAgICAgIBAQEAAAAAAAAAAAAAAAAAAAACAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQWCC3waAAAAKXRSTlMALgUMIBk0+xEqJs70Xhb3lu3EjX2EZTlv5eHXvbarQj3cdmpXSqOeUDwaqNAAAAKCSURBVEjHjZTntqsgEIUPVVCwtxg1vfD+L3hHRe8K6snZf+KKn8OewvzsSSeXLruLnz+KHs0gr6DkT3xsRkU6VVn4Ha/UxLe1Z4y64i847sykPBh/AvQ7ry3eFN70oKrfcBJYvm/tQ1qxP4T3emXPeXAkvodPUvtdjbhk+Ft4c0hslTiXVOzxOJ15NWUblQhRsdu3E1AfCjj3Gdm18zSOsiH8Lk4TB480ksy62fiqNo4OpyU8O21l6+hyRtS6z8r1pHlmle5sR1/WXS6Mq2Nl+YeKt3vr+vdH/q4O68tzXuwkiZmngYb4R8Co1jh0+Ww2UTyWxBvtyxLO7QVjO3YOD/lWZpbXDGellFG2Mws58mMnjVZSn7p+XvZ6IF4nn02OJZV0aTO22arp/DgLPtrgpVoi6TPbZm4XQBjY159w02uO0BDdYsfrOEi0M2ulRXlCIPAOuN1NOVhi+riBR3dgwQplYsZRZJLXq23Mlo5njkbY0rZFu3oiNIYG2kqsbVz67OlNuZZIOlfxHDl0UpyRX86z/OYC/3qf1A1xTrMp/PWWM4ePzf8DDp1nesQRpcFk7BlwdzN08ZIALJpCaciQXO0f6k4dnuT/Ewg4l7qSTNzm2SykdHn6GJ12mWc6aCNj/g1cTXpB8YFfr0uVc96aFkkqiIiX4nO+salKwGtIkvfB+Ja8DxMeD3hIXP5mTOYPB4eVT0+32I5ykvPZjesnkGgIREgYnmLrPb0PdV3hoLup2TjcGBPM4mgsfF5BrawZR4/GpzYQzQfrUZCf0TCWYo2DqhdhTJBQ6j4xqmmLN5LjdRIY8LWExiFUsSrza/nmFBqw3I9tEZB9h0lIQSO9if8DkISDAj8CDawAAAAASUVORK5CYII=);background-repeat:no-repeat;background-position:center\n }.wails-reconnect-overlay-loadingspinner.svelte-9nqyfr{pointer-events:none;width:2.5em;height:2.5em;border:.4em solid transparent;border-color:#f00 #eee0 #f00 #eee0;border-radius:50%;animation:svelte-9nqyfr-loadingspin 1s linear infinite;margin:auto;padding:2.5em\n }@keyframes svelte-9nqyfr-loadingspin{100%{transform:rotate(360deg)}}";
style.id = "svelte-1m56lfo-style";
style.textContent = ".wails-reconnect-overlay.svelte-1m56lfo{position:fixed;top:0;left:0;width:100%;height:100%;backdrop-filter:blur(20px) saturate(160%) contrast(45%) brightness(140%);z-index:999999\n }.wails-reconnect-overlay-content.svelte-1m56lfo{position:relative;top:50%;transform:translateY(-50%);margin:0;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEsAAAA7CAMAAAAEsocZAAAC91BMVEUAAACzQ0PjMjLkMjLZLS7XLS+vJCjkMjKlEx6uGyHjMDGiFx7GJyrAISjUKy3mMzPlMjLjMzOsGyDKJirkMjK6HyXmMjLgMDC6IiLcMjLULC3MJyrRKSy+IibmMzPmMjK7ISXlMjLIJimzHSLkMjKtGiHZLC7BIifgMDCpGSDFIivcLy+yHSKoGR+eFBzNKCvlMjKxHSPkMTKxHSLmMjLKJyq5ICXDJCe6ISXdLzDkMjLmMzPFJSm2HyTlMTLhMDGyHSKUEBmhFx24HyTCJCjHJijjMzOiFh7mMjJ6BhDaLDCuGyOKABjnMzPGJinJJiquHCGEChSmGB/pMzOiFh7VKy3OKCu1HiSvHCLjMTLMKCrBIyeICxWxHCLDIyjSKizBIyh+CBO9ISa6ISWDChS9Iie1HyXVLC7FJSrLKCrlMjLiMTGPDhicFRywGyKXFBuhFx1/BxO7IiXkMTGeFBx8BxLkMTGnGR/GJCi4ICWsGyGJDxXSLS2yGiHSKi3CJCfnMzPQKiyECRTKJiq6ISWUERq/Iye0HiPDJCjGJSm6ICaPDxiTEBrdLy+3HyXSKiy0HyOQEBi4ICWhFh1+CBO9IieODhfSKyzWLC2LDhh8BxHKKCq7ISWaFBzkMzPqNDTTLC3EJSiHDBacExyvGyO1HyTPKCy+IieoGSC7ISaVEhrMKCvQKyusGyG0HiKACBPIJSq/JCaABxR5BRLEJCnkMzPJJinEJimPDRZ2BRKqHx/jMjLnMzPgMDHULC3NKSvQKSzsNDTWLS7SKyy3HyTKJyrDJSjbLzDYLC6mGB/GJSnVLC61HiPLKCrHJSm/Iye8Iia6ICWzHSKxHCLaLi/PKSupGR+7ICXpMzPbLi/IJinJJSmsGyGrGiCkFx6PDheJCxaFChXBIyfAIieSDxmBCBPlMjLeLzDdLzC5HySMDRe+ISWvGyGcFBzSKSzPJyvMJyrEJCjDIyefFRyWERriMDHUKiy/ISaZExv0NjbwNTXuNDTrMzMI0c+yAAAAu3RSTlMAA8HR/gwGgAj+MEpGCsC+hGpjQjYnIxgWBfzx7urizMrFqqB1bF83KhsR/fz8+/r5+fXv7unZ1tC+t6mmopqKdW1nYVpVRjUeHhIQBPr59/b28/Hx8ODg3NvUw8O/vKeim5aNioiDgn1vZWNjX1xUU1JPTUVFPT08Mi4qJyIh/Pv7+/n4+Pf39fT08/Du7efn5uXj4uHa19XNwsG/vrq2tbSuramlnpyYkpGNiIZ+enRraGVjVVBKOzghdjzRsAAABJVJREFUWMPtllVQG1EYhTc0ASpoobS0FCulUHd3oUjd3d3d3d3d3d2b7CYhnkBCCHGDEIK7Vh56d0NpOgwkYfLQzvA9ZrLfnPvfc+8uVEst/yheBJup3Nya2MjU6pa/jWLZtxjXpZFtVB4uVNI6m5gIruNkVFebqIb5Ug2ym4TIEM/gtUOGbg613oBzjAzZFrZ+lXu/3TIiMXXS5M6HTvrNHeLpZLEh6suGNW9fzZ9zd/qVi2eOHygqi5cDE5GUrJocONgzyqo0UXNSUlKSEhMztFqtXq9vNxImAmS3g7Y6QlbjdBWVGW36jt4wDGTUXjUsafh5zJWRkdFuZGtWGnCRmg+HasiGMUClTTzW0ZuVgLlGDIPM4Lhi0IrVq+tv2hS21fNrSONQgpM9DsJ4t3fM9PkvJuKj2ZjrZwvILKvaSTgciUSirjt6dOfOpyd169bDb9rMOwF9Hj4OD100gY0YXYb299bjzMrqj9doNByJWlVXFB9DT5dmJuvy+cq83JyuS6ayEYSHulKL8dmFnBkrCeZlHKMrC5XRhXGCZB2Ty1fkleRQaMCFT2DBsEafzRFJu7/2MicbKynPhQUDLiZwMWLJZKNLzoLbJBYVcurSmbmn+rcyJ8vCMgmlmaW6gnwun/+3C96VpAUuET1ZgRR36r2xWlnYSnf3oKABA14uXDDvydxHs6cpTV1p3hlJ2rJCiUjIZCByItXg8sHJijuvT64CuMTABUYvb6NN1Jdp1PH7D7f3bo2eS5KvW4RJr7atWT5w4MBBg9zdBw9+37BS7QIoFS5WnIaj12dr1DEXFgdvr4fh4eFl+u/wz8uf3jjHic8s4DL2Dal0IANyUBeCRCcwOBJV26JsjSpGwHVuSai69jvqD+jr56OgtKy0zAAK5mLTVBKVKL5tNthGAR9JneJQ/bFsHNzy+U7IlCYROxtMpIjR0ceoQVnowracLLpAQWETqV361bPoFo3cEbz2zYLZM7t3HWXcxmiBOgttS1ycWkTXMWh4mGigdug9DFdttqCFgTN6nD0q1XEVSoCxEjyFCi2eNC6Z69MRVIImJ6JQSf5gcFVCuF+aDhCa1F6MJFDaiNBQAh2TMfWBjhmLsAxUjG/fmjs0qjJck8D0GPBcuUuZW1LS/tIsPzqmQt17PvZQknlwnf4tHDBc+7t5VV3QQCkdc+Ur8/hdrz0but0RCumWiYbiKmLJ7EVbRomj4Q7+y5wsaXvfTGFpQcHB7n2WbG4MGdniw2Tm8xl5Yhr7MrSYHQ3uampz10aWyHyuzxvqaW/6W4MjXAUD3QV2aw97ZxhGjxCohYf5TpTHMXU1BbsAuoFnkRygVieIGAbqiF7rrH4rfWpKJouBCtyHJF8ctEyGubBa+C6NsMYEUonJFITHZqWBxXUA12Dv76Tf/PgOBmeNiiLG1pcKo1HAq8jLpY4JU1yWEixVNaOgoRJAKBSZHTZTU+wJOMtUDZvlVITC6FTlksyrEBoPHXpxxbzdaqzigUtVDkJVIOtVQ9UEOR4VGUh/kHWq0edJ6CxnZ+eePXva2bnY/cF/I1RLLf8vvwDANdMSMegxcAAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-position:center\n }.wails-reconnect-overlay-loadingspinner.svelte-1m56lfo{pointer-events:none;width:2.5em;height:2.5em;border:.4em solid transparent;border-color:#f00 #eee0 #f00 #eee0;border-radius:50%;animation:svelte-1m56lfo-loadingspin 1s linear infinite;margin:auto;padding:2.5em\n }@keyframes svelte-1m56lfo-loadingspin{100%{transform:rotate(360deg)}}";
append(document.head, style);
}
@@ -691,8 +691,8 @@
return {
c() {
div2 = element("div");
div2.innerHTML = `<div class="wails-reconnect-overlay-content svelte-9nqyfr"><div class="wails-reconnect-overlay-loadingspinner svelte-9nqyfr"></div></div>`;
attr(div2, "class", "wails-reconnect-overlay svelte-9nqyfr");
div2.innerHTML = `<div class="wails-reconnect-overlay-content svelte-1m56lfo"><div class="wails-reconnect-overlay-loadingspinner svelte-1m56lfo"></div></div>`;
attr(div2, "class", "wails-reconnect-overlay svelte-1m56lfo");
},
m(target, anchor) {
insert(target, div2, anchor);
@@ -782,7 +782,7 @@
class Overlay extends SvelteComponent {
constructor(options) {
super();
if (!document.getElementById("svelte-9nqyfr-style")) add_css();
if (!document.getElementById("svelte-1m56lfo-style")) add_css();
init(this, options, instance, create_fragment, safe_not_equal, {});
}
}
@@ -1543,154 +1543,142 @@
function StartWebsocket(userCallback) {
callback = userCallback;
callback = userCallback;
window.onbeforeunload = function() {
if( websocket ) {
websocket.onclose = function () { };
websocket.close();
websocket = null;
}
};
window.onbeforeunload = function() {
if( websocket ) {
websocket.onclose = function () { };
websocket.close();
websocket = null;
}
};
// ...and attempt to connect
connect();
// ...and attempt to connect
connect();
}
function setupIPCBridge() {
// darwin
window.webkit = {
messageHandlers: {
external: {
postMessage: (message) => {
websocket.send(message);
}
},
windowDrag: {
postMessage: () => {
// Ignore window drag events
}
}
}
};
window.wailsInvoke = (message) => {
websocket.send(message);
};
}
// Handles incoming websocket connections
function handleConnect() {
log('Connected to backend');
setupIPCBridge();
hideOverlay();
clearInterval(connectTimer);
websocket.onclose = handleDisconnect;
websocket.onmessage = handleMessage;
log('Connected to backend');
setupIPCBridge();
hideOverlay();
clearInterval(connectTimer);
websocket.onclose = handleDisconnect;
websocket.onmessage = handleMessage;
}
// Handles websocket disconnects
function handleDisconnect() {
log('Disconnected from backend');
websocket = null;
showOverlay();
connect();
log('Disconnected from backend');
websocket = null;
showOverlay();
connect();
}
// Try to connect to the backend every 1s (default value).
function connect() {
connectTimer = setInterval(function () {
if (websocket == null) {
websocket = new WebSocket('ws://' + window.location.hostname + ':34115/bridge');
websocket.onopen = handleConnect;
websocket.onerror = function (e) {
e.stopImmediatePropagation();
e.stopPropagation();
e.preventDefault();
websocket = null;
return false;
};
}
}, 1000);
connectTimer = setInterval(function () {
if (websocket == null) {
websocket = new WebSocket('ws://' + window.location.hostname + ':34115/bridge');
websocket.onopen = handleConnect;
websocket.onerror = function (e) {
e.stopImmediatePropagation();
e.stopPropagation();
e.preventDefault();
websocket = null;
return false;
};
}
}, 1000);
}
// Adds a script to the Dom.
// Removes it if second parameter is true.
function addScript(script, remove) {
const s = document.createElement('script');
s.setAttribute('type', 'text/javascript');
s.textContent = script;
document.head.appendChild(s);
const s = document.createElement('script');
s.setAttribute('type', 'text/javascript');
s.textContent = script;
document.head.appendChild(s);
// Remove internal messages from the DOM
if (remove) {
s.parentNode.removeChild(s);
}
// Remove internal messages from the DOM
if (remove) {
s.parentNode.removeChild(s);
}
}
function handleMessage(message) {
// As a bridge we ignore js and css injections
switch (message.data[0]) {
// Wails library - inject!
case 'b':
message = message.data.slice(1);
addScript(message);
log('Loaded Wails Runtime');
// As a bridge we ignore js and css injections
switch (message.data[0]) {
// Wails library - inject!
case 'b':
message = message.data.slice(1);
addScript(message);
log('Loaded Wails Runtime');
// We need to now send a message to the backend telling it
// we have loaded (System Start)
window.webkit.messageHandlers.external.postMessage("SS");
// We need to now send a message to the backend telling it
// we have loaded (System Start)
window.wailsInvoke('SS');
// Now wails runtime is loaded, wails for the ready event
// and callback to the main app
// window.wails.Events.On('wails:loaded', function () {
if (callback) {
log('Notifying application');
callback(window.wails);
}
// });
break;
// Notifications
case 'n':
window.wails._.Notify(message.data.slice(1));
break;
// // Binding
// case 'b':
// const binding = message.data.slice(1);
// //log("Binding: " + binding)
// window.wails._.NewBinding(binding);
// break;
// // Call back
case 'c':
const callbackData = message.data.slice(1);
window.wails._.Callback(callbackData);
break;
// Tray
case 'T':
const trayMessage = message.data.slice(1);
switch (trayMessage[0]) {
case 'S':
// Set tray
const trayJSON = trayMessage.slice(1);
let tray = JSON.parse(trayJSON);
setTray(tray);
break;
case 'U':
// Update label
const updateTrayLabelJSON = trayMessage.slice(1);
let trayLabelData = JSON.parse(updateTrayLabelJSON);
updateTrayLabel(trayLabelData);
break;
case 'D':
// Delete Tray Menu
const id = trayMessage.slice(1);
deleteTrayMenu(id);
break;
default:
log('Unknown tray message: ' + message.data);
}
break;
// Now wails runtime is loaded, wails for the ready event
// and callback to the main app
// window.wails.Events.On('wails:loaded', function () {
if (callback) {
log('Notifying application');
callback(window.wails);
}
// });
break;
// Notifications
case 'n':
window.wails._.Notify(message.data.slice(1));
break;
// // Binding
// case 'b':
// const binding = message.data.slice(1);
// //log("Binding: " + binding)
// window.wails._.NewBinding(binding);
// break;
// // Call back
case 'c':
const callbackData = message.data.slice(1);
window.wails._.Callback(callbackData);
break;
// Tray
case 'T':
const trayMessage = message.data.slice(1);
switch (trayMessage[0]) {
case 'S':
// Set tray
const trayJSON = trayMessage.slice(1);
let tray = JSON.parse(trayJSON);
setTray(tray);
break
case 'U':
// Update label
const updateTrayLabelJSON = trayMessage.slice(1);
let trayLabelData = JSON.parse(updateTrayLabelJSON);
updateTrayLabel(trayLabelData);
break
case 'D':
// Delete Tray Menu
const id = trayMessage.slice(1);
deleteTrayMenu(id);
break
default:
log('Unknown tray message: ' + message.data);
}
break;
default:
log('Unknown message: ' + message.data);
}
default:
log('Unknown message: ' + message.data);
}
}
/*

View File

@@ -9,7 +9,7 @@ The lightweight framework for web-like apps
*/
/* jshint esversion: 6 */
import bridge from './bridge';
const bridge = require('./bridge');
/**
* ready will execute the callback when Wails has loaded

View File

@@ -1,6 +1,6 @@
{
"name": "@wails/runtime",
"version": "1.2.24",
"version": "1.3.15",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@wails/runtime",
"version": "1.3.13",
"version": "1.3.20",
"description": "Wails V2 Javascript runtime library",
"main": "main.js",
"types": "runtime.d.ts",

View File

@@ -29,7 +29,7 @@
top: 50%;
transform: translateY(-50%);
margin: 0;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC8AAAAuCAMAAACPpbA7AAAAflBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAAAAAAAAAAAABAQEEBAQAAAAAAAAEBAQAAAADAwMAAAABAQEAAAAAAAAAAAAAAAAAAAACAgICAgIBAQEAAAAAAAAAAAAAAAAAAAACAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQWCC3waAAAAKXRSTlMALgUMIBk0+xEqJs70Xhb3lu3EjX2EZTlv5eHXvbarQj3cdmpXSqOeUDwaqNAAAAKCSURBVEjHjZTntqsgEIUPVVCwtxg1vfD+L3hHRe8K6snZf+KKn8OewvzsSSeXLruLnz+KHs0gr6DkT3xsRkU6VVn4Ha/UxLe1Z4y64i847sykPBh/AvQ7ry3eFN70oKrfcBJYvm/tQ1qxP4T3emXPeXAkvodPUvtdjbhk+Ft4c0hslTiXVOzxOJ15NWUblQhRsdu3E1AfCjj3Gdm18zSOsiH8Lk4TB480ksy62fiqNo4OpyU8O21l6+hyRtS6z8r1pHlmle5sR1/WXS6Mq2Nl+YeKt3vr+vdH/q4O68tzXuwkiZmngYb4R8Co1jh0+Ww2UTyWxBvtyxLO7QVjO3YOD/lWZpbXDGellFG2Mws58mMnjVZSn7p+XvZ6IF4nn02OJZV0aTO22arp/DgLPtrgpVoi6TPbZm4XQBjY159w02uO0BDdYsfrOEi0M2ulRXlCIPAOuN1NOVhi+riBR3dgwQplYsZRZJLXq23Mlo5njkbY0rZFu3oiNIYG2kqsbVz67OlNuZZIOlfxHDl0UpyRX86z/OYC/3qf1A1xTrMp/PWWM4ePzf8DDp1nesQRpcFk7BlwdzN08ZIALJpCaciQXO0f6k4dnuT/Ewg4l7qSTNzm2SykdHn6GJ12mWc6aCNj/g1cTXpB8YFfr0uVc96aFkkqiIiX4nO+salKwGtIkvfB+Ja8DxMeD3hIXP5mTOYPB4eVT0+32I5ykvPZjesnkGgIREgYnmLrPb0PdV3hoLup2TjcGBPM4mgsfF5BrawZR4/GpzYQzQfrUZCf0TCWYo2DqhdhTJBQ6j4xqmmLN5LjdRIY8LWExiFUsSrza/nmFBqw3I9tEZB9h0lIQSO9if8DkISDAj8CDawAAAAASUVORK5CYII=);
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEsAAAA7CAMAAAAEsocZAAAC91BMVEUAAACzQ0PjMjLkMjLZLS7XLS+vJCjkMjKlEx6uGyHjMDGiFx7GJyrAISjUKy3mMzPlMjLjMzOsGyDKJirkMjK6HyXmMjLgMDC6IiLcMjLULC3MJyrRKSy+IibmMzPmMjK7ISXlMjLIJimzHSLkMjKtGiHZLC7BIifgMDCpGSDFIivcLy+yHSKoGR+eFBzNKCvlMjKxHSPkMTKxHSLmMjLKJyq5ICXDJCe6ISXdLzDkMjLmMzPFJSm2HyTlMTLhMDGyHSKUEBmhFx24HyTCJCjHJijjMzOiFh7mMjJ6BhDaLDCuGyOKABjnMzPGJinJJiquHCGEChSmGB/pMzOiFh7VKy3OKCu1HiSvHCLjMTLMKCrBIyeICxWxHCLDIyjSKizBIyh+CBO9ISa6ISWDChS9Iie1HyXVLC7FJSrLKCrlMjLiMTGPDhicFRywGyKXFBuhFx1/BxO7IiXkMTGeFBx8BxLkMTGnGR/GJCi4ICWsGyGJDxXSLS2yGiHSKi3CJCfnMzPQKiyECRTKJiq6ISWUERq/Iye0HiPDJCjGJSm6ICaPDxiTEBrdLy+3HyXSKiy0HyOQEBi4ICWhFh1+CBO9IieODhfSKyzWLC2LDhh8BxHKKCq7ISWaFBzkMzPqNDTTLC3EJSiHDBacExyvGyO1HyTPKCy+IieoGSC7ISaVEhrMKCvQKyusGyG0HiKACBPIJSq/JCaABxR5BRLEJCnkMzPJJinEJimPDRZ2BRKqHx/jMjLnMzPgMDHULC3NKSvQKSzsNDTWLS7SKyy3HyTKJyrDJSjbLzDYLC6mGB/GJSnVLC61HiPLKCrHJSm/Iye8Iia6ICWzHSKxHCLaLi/PKSupGR+7ICXpMzPbLi/IJinJJSmsGyGrGiCkFx6PDheJCxaFChXBIyfAIieSDxmBCBPlMjLeLzDdLzC5HySMDRe+ISWvGyGcFBzSKSzPJyvMJyrEJCjDIyefFRyWERriMDHUKiy/ISaZExv0NjbwNTXuNDTrMzMI0c+yAAAAu3RSTlMAA8HR/gwGgAj+MEpGCsC+hGpjQjYnIxgWBfzx7urizMrFqqB1bF83KhsR/fz8+/r5+fXv7unZ1tC+t6mmopqKdW1nYVpVRjUeHhIQBPr59/b28/Hx8ODg3NvUw8O/vKeim5aNioiDgn1vZWNjX1xUU1JPTUVFPT08Mi4qJyIh/Pv7+/n4+Pf39fT08/Du7efn5uXj4uHa19XNwsG/vrq2tbSuramlnpyYkpGNiIZ+enRraGVjVVBKOzghdjzRsAAABJVJREFUWMPtllVQG1EYhTc0ASpoobS0FCulUHd3oUjd3d3d3d3d3d2b7CYhnkBCCHGDEIK7Vh56d0NpOgwkYfLQzvA9ZrLfnPvfc+8uVEst/yheBJup3Nya2MjU6pa/jWLZtxjXpZFtVB4uVNI6m5gIruNkVFebqIb5Ug2ym4TIEM/gtUOGbg613oBzjAzZFrZ+lXu/3TIiMXXS5M6HTvrNHeLpZLEh6suGNW9fzZ9zd/qVi2eOHygqi5cDE5GUrJocONgzyqo0UXNSUlKSEhMztFqtXq9vNxImAmS3g7Y6QlbjdBWVGW36jt4wDGTUXjUsafh5zJWRkdFuZGtWGnCRmg+HasiGMUClTTzW0ZuVgLlGDIPM4Lhi0IrVq+tv2hS21fNrSONQgpM9DsJ4t3fM9PkvJuKj2ZjrZwvILKvaSTgciUSirjt6dOfOpyd169bDb9rMOwF9Hj4OD100gY0YXYb299bjzMrqj9doNByJWlVXFB9DT5dmJuvy+cq83JyuS6ayEYSHulKL8dmFnBkrCeZlHKMrC5XRhXGCZB2Ty1fkleRQaMCFT2DBsEafzRFJu7/2MicbKynPhQUDLiZwMWLJZKNLzoLbJBYVcurSmbmn+rcyJ8vCMgmlmaW6gnwun/+3C96VpAUuET1ZgRR36r2xWlnYSnf3oKABA14uXDDvydxHs6cpTV1p3hlJ2rJCiUjIZCByItXg8sHJijuvT64CuMTABUYvb6NN1Jdp1PH7D7f3bo2eS5KvW4RJr7atWT5w4MBBg9zdBw9+37BS7QIoFS5WnIaj12dr1DEXFgdvr4fh4eFl+u/wz8uf3jjHic8s4DL2Dal0IANyUBeCRCcwOBJV26JsjSpGwHVuSai69jvqD+jr56OgtKy0zAAK5mLTVBKVKL5tNthGAR9JneJQ/bFsHNzy+U7IlCYROxtMpIjR0ceoQVnowracLLpAQWETqV361bPoFo3cEbz2zYLZM7t3HWXcxmiBOgttS1ycWkTXMWh4mGigdug9DFdttqCFgTN6nD0q1XEVSoCxEjyFCi2eNC6Z69MRVIImJ6JQSf5gcFVCuF+aDhCa1F6MJFDaiNBQAh2TMfWBjhmLsAxUjG/fmjs0qjJck8D0GPBcuUuZW1LS/tIsPzqmQt17PvZQknlwnf4tHDBc+7t5VV3QQCkdc+Ur8/hdrz0but0RCumWiYbiKmLJ7EVbRomj4Q7+y5wsaXvfTGFpQcHB7n2WbG4MGdniw2Tm8xl5Yhr7MrSYHQ3uampz10aWyHyuzxvqaW/6W4MjXAUD3QV2aw97ZxhGjxCohYf5TpTHMXU1BbsAuoFnkRygVieIGAbqiF7rrH4rfWpKJouBCtyHJF8ctEyGubBa+C6NsMYEUonJFITHZqWBxXUA12Dv76Tf/PgOBmeNiiLG1pcKo1HAq8jLpY4JU1yWEixVNaOgoRJAKBSZHTZTU+wJOMtUDZvlVITC6FTlksyrEBoPHXpxxbzdaqzigUtVDkJVIOtVQ9UEOR4VGUh/kHWq0edJ6CxnZ+eePXva2bnY/cF/I1RLLf8vvwDANdMSMegxcAAAAABJRU5ErkJggg==);
background-repeat: no-repeat;
background-position: center
}

View File

@@ -1,616 +1,8 @@
{
"name": "bridge",
"version": "1.0.0",
"lockfileVersion": 2,
"lockfileVersion": 1,
"requires": true,
"packages": {
"": {
"name": "bridge",
"version": "1.0.0",
"license": "ISC",
"devDependencies": {
"@rollup/plugin-commonjs": "^17.1.0",
"@rollup/plugin-node-resolve": "^11.1.1",
"rollup": "^2.38.5",
"rollup-plugin-svelte": "^7.1.0",
"rollup-plugin-terser": "^7.0.2",
"svelte": "^3.32.2"
}
},
"node_modules/@babel/code-frame": {
"version": "7.12.13",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz",
"integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==",
"dev": true,
"dependencies": {
"@babel/highlight": "^7.12.13"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
"integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==",
"dev": true
},
"node_modules/@babel/highlight": {
"version": "7.12.13",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz",
"integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==",
"dev": true,
"dependencies": {
"@babel/helper-validator-identifier": "^7.12.11",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
}
},
"node_modules/@rollup/plugin-commonjs": {
"version": "17.1.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-17.1.0.tgz",
"integrity": "sha512-PoMdXCw0ZyvjpCMT5aV4nkL0QywxP29sODQsSGeDpr/oI49Qq9tRtAsb/LbYbDzFlOydVEqHmmZWFtXJEAX9ew==",
"dev": true,
"dependencies": {
"@rollup/pluginutils": "^3.1.0",
"commondir": "^1.0.1",
"estree-walker": "^2.0.1",
"glob": "^7.1.6",
"is-reference": "^1.2.1",
"magic-string": "^0.25.7",
"resolve": "^1.17.0"
},
"engines": {
"node": ">= 8.0.0"
}
},
"node_modules/@rollup/plugin-commonjs/node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"dev": true
},
"node_modules/@rollup/plugin-node-resolve": {
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.1.1.tgz",
"integrity": "sha512-zlBXR4eRS+2m79TsUZWhsd0slrHUYdRx4JF+aVQm+MI0wsKdlpC2vlDVjmlGvtZY1vsefOT9w3JxvmWSBei+Lg==",
"dev": true,
"dependencies": {
"@rollup/pluginutils": "^3.1.0",
"@types/resolve": "1.17.1",
"builtin-modules": "^3.1.0",
"deepmerge": "^4.2.2",
"is-module": "^1.0.0",
"resolve": "^1.19.0"
},
"engines": {
"node": ">= 10.0.0"
}
},
"node_modules/@rollup/pluginutils": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
"integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==",
"dev": true,
"dependencies": {
"@types/estree": "0.0.39",
"estree-walker": "^1.0.1",
"picomatch": "^2.2.2"
},
"engines": {
"node": ">= 8.0.0"
}
},
"node_modules/@types/estree": {
"version": "0.0.39",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
"integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
"dev": true
},
"node_modules/@types/node": {
"version": "14.14.25",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.25.tgz",
"integrity": "sha512-EPpXLOVqDvisVxtlbvzfyqSsFeQxltFbluZNRndIb8tr9KiBnYNLzrc1N3pyKUCww2RNrfHDViqDWWE1LCJQtQ==",
"dev": true
},
"node_modules/@types/resolve": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
"integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"dependencies": {
"color-convert": "^1.9.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true
},
"node_modules/builtin-modules": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz",
"integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"dependencies": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"dependencies": {
"color-name": "1.1.3"
}
},
"node_modules/color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
"node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
},
"node_modules/commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
"dev": true
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
"node_modules/deepmerge": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true,
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/estree-walker": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
"integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==",
"dev": true
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true
},
"node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"node_modules/glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
}
},
"node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.1"
},
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"node_modules/is-core-module": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz",
"integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==",
"dev": true,
"dependencies": {
"has": "^1.0.3"
}
},
"node_modules/is-module": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
"integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
"dev": true
},
"node_modules/is-reference": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
"integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
"dev": true,
"dependencies": {
"@types/estree": "*"
}
},
"node_modules/jest-worker": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
"integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==",
"dev": true,
"dependencies": {
"@types/node": "*",
"merge-stream": "^2.0.0",
"supports-color": "^7.0.0"
},
"engines": {
"node": ">= 10.13.0"
}
},
"node_modules/jest-worker/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/jest-worker/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true
},
"node_modules/magic-string": {
"version": "0.25.7",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
"integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
"dev": true,
"dependencies": {
"sourcemap-codec": "^1.4.4"
}
},
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
"dev": true
},
"node_modules/minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"dependencies": {
"wrappy": "1"
}
},
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/path-parse": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
"dev": true
},
"node_modules/picomatch": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
"dev": true,
"engines": {
"node": ">=8.6"
}
},
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"dev": true,
"dependencies": {
"safe-buffer": "^5.1.0"
}
},
"node_modules/require-relative": {
"version": "0.8.7",
"resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz",
"integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=",
"dev": true
},
"node_modules/resolve": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz",
"integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==",
"dev": true,
"dependencies": {
"is-core-module": "^2.1.0",
"path-parse": "^1.0.6"
}
},
"node_modules/rollup": {
"version": "2.38.5",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.38.5.tgz",
"integrity": "sha512-VoWt8DysFGDVRGWuHTqZzT02J0ASgjVq/hPs9QcBOGMd7B+jfTr/iqMVEyOi901rE3xq+Deq66GzIT1yt7sGwQ==",
"dev": true,
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
"node": ">=10.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.1"
}
},
"node_modules/rollup-plugin-svelte": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/rollup-plugin-svelte/-/rollup-plugin-svelte-7.1.0.tgz",
"integrity": "sha512-vopCUq3G+25sKjwF5VilIbiY6KCuMNHP1PFvx2Vr3REBNMDllKHFZN2B9jwwC+MqNc3UPKkjXnceLPEjTjXGXg==",
"dev": true,
"dependencies": {
"require-relative": "^0.8.7",
"rollup-pluginutils": "^2.8.2"
},
"engines": {
"node": ">=10"
}
},
"node_modules/rollup-plugin-terser": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz",
"integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.10.4",
"jest-worker": "^26.2.1",
"serialize-javascript": "^4.0.0",
"terser": "^5.0.0"
}
},
"node_modules/rollup-pluginutils": {
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
"integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
"dev": true,
"dependencies": {
"estree-walker": "^0.6.1"
}
},
"node_modules/rollup-pluginutils/node_modules/estree-walker": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
"integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
"dev": true
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"dev": true
},
"node_modules/serialize-javascript": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
"integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
"dev": true,
"dependencies": {
"randombytes": "^2.1.0"
}
},
"node_modules/source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
"dev": true,
"engines": {
"node": ">= 8"
}
},
"node_modules/source-map-support": {
"version": "0.5.19",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
"integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
"dev": true,
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"node_modules/source-map-support/node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/sourcemap-codec": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
"dev": true
},
"node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"dependencies": {
"has-flag": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/svelte": {
"version": "3.32.2",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.32.2.tgz",
"integrity": "sha512-Zxh1MQQl/+vnToKbU1Per+PoMN8Jb2MeKJcGxiOsCGR677hXw7jkMfbnNXq33+dxIzV/HfA4xtoSPJrqeB0VUg==",
"dev": true,
"engines": {
"node": ">= 8"
}
},
"node_modules/terser": {
"version": "5.5.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.5.1.tgz",
"integrity": "sha512-6VGWZNVP2KTUcltUQJ25TtNjx/XgdDsBDKGt8nN0MpydU36LmbPPcMBd2kmtZNNGVVDLg44k7GKeHHj+4zPIBQ==",
"dev": true,
"dependencies": {
"commander": "^2.20.0",
"source-map": "~0.7.2",
"source-map-support": "~0.5.19"
},
"bin": {
"terser": "bin/terser"
},
"engines": {
"node": ">=10"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
}
},
"dependencies": {
"@babel/code-frame": {
"version": "7.12.13",

View File

@@ -10,8 +10,8 @@ The lightweight framework for web-like apps
/* jshint esversion: 6 */
import {setTray, hideOverlay, showOverlay, updateTrayLabel, deleteTrayMenu} from "./store";
import {log} from "./log";
import {setTray, hideOverlay, showOverlay, updateTrayLabel, deleteTrayMenu} from './store';
import {log} from './log';
let websocket = null;
let callback = null;
@@ -19,152 +19,140 @@ let connectTimer;
export function StartWebsocket(userCallback) {
callback = userCallback;
callback = userCallback;
window.onbeforeunload = function() {
if( websocket ) {
websocket.onclose = function () { };
websocket.close();
websocket = null;
}
}
window.onbeforeunload = function() {
if( websocket ) {
websocket.onclose = function () { };
websocket.close();
websocket = null;
}
};
// ...and attempt to connect
connect();
// ...and attempt to connect
connect();
}
function setupIPCBridge() {
// darwin
window.webkit = {
messageHandlers: {
external: {
postMessage: (message) => {
websocket.send(message);
}
},
windowDrag: {
postMessage: () => {
// Ignore window drag events
}
}
}
};
window.wailsInvoke = (message) => {
websocket.send(message);
};
}
// Handles incoming websocket connections
function handleConnect() {
log('Connected to backend');
setupIPCBridge();
hideOverlay();
clearInterval(connectTimer);
websocket.onclose = handleDisconnect;
websocket.onmessage = handleMessage;
log('Connected to backend');
setupIPCBridge();
hideOverlay();
clearInterval(connectTimer);
websocket.onclose = handleDisconnect;
websocket.onmessage = handleMessage;
}
// Handles websocket disconnects
function handleDisconnect() {
log('Disconnected from backend');
websocket = null;
showOverlay();
connect();
log('Disconnected from backend');
websocket = null;
showOverlay();
connect();
}
// Try to connect to the backend every 1s (default value).
function connect() {
connectTimer = setInterval(function () {
if (websocket == null) {
websocket = new WebSocket('ws://' + window.location.hostname + ':34115/bridge');
websocket.onopen = handleConnect;
websocket.onerror = function (e) {
e.stopImmediatePropagation();
e.stopPropagation();
e.preventDefault();
websocket = null;
return false;
};
}
}, 1000);
connectTimer = setInterval(function () {
if (websocket == null) {
websocket = new WebSocket('ws://' + window.location.hostname + ':34115/bridge');
websocket.onopen = handleConnect;
websocket.onerror = function (e) {
e.stopImmediatePropagation();
e.stopPropagation();
e.preventDefault();
websocket = null;
return false;
};
}
}, 1000);
}
// Adds a script to the Dom.
// Removes it if second parameter is true.
function addScript(script, remove) {
const s = document.createElement('script');
s.setAttribute('type', 'text/javascript');
s.textContent = script;
document.head.appendChild(s);
const s = document.createElement('script');
s.setAttribute('type', 'text/javascript');
s.textContent = script;
document.head.appendChild(s);
// Remove internal messages from the DOM
if (remove) {
s.parentNode.removeChild(s);
}
// Remove internal messages from the DOM
if (remove) {
s.parentNode.removeChild(s);
}
}
function handleMessage(message) {
// As a bridge we ignore js and css injections
switch (message.data[0]) {
// Wails library - inject!
case 'b':
message = message.data.slice(1)
addScript(message);
log('Loaded Wails Runtime');
// As a bridge we ignore js and css injections
switch (message.data[0]) {
// Wails library - inject!
case 'b':
message = message.data.slice(1);
addScript(message);
log('Loaded Wails Runtime');
// We need to now send a message to the backend telling it
// we have loaded (System Start)
window.webkit.messageHandlers.external.postMessage("SS");
// We need to now send a message to the backend telling it
// we have loaded (System Start)
window.wailsInvoke('SS');
// Now wails runtime is loaded, wails for the ready event
// and callback to the main app
// window.wails.Events.On('wails:loaded', function () {
if (callback) {
log('Notifying application');
callback(window.wails);
}
// });
break;
// Notifications
case 'n':
window.wails._.Notify(message.data.slice(1));
break;
// // Binding
// case 'b':
// const binding = message.data.slice(1);
// //log("Binding: " + binding)
// window.wails._.NewBinding(binding);
// break;
// // Call back
case 'c':
const callbackData = message.data.slice(1);
window.wails._.Callback(callbackData);
break;
// Tray
case 'T':
const trayMessage = message.data.slice(1);
switch (trayMessage[0]) {
case 'S':
// Set tray
const trayJSON = trayMessage.slice(1);
let tray = JSON.parse(trayJSON);
setTray(tray);
break;
case 'U':
// Update label
const updateTrayLabelJSON = trayMessage.slice(1);
let trayLabelData = JSON.parse(updateTrayLabelJSON);
updateTrayLabel(trayLabelData);
break;
case 'D':
// Delete Tray Menu
const id = trayMessage.slice(1);
deleteTrayMenu(id);
break;
default:
log('Unknown tray message: ' + message.data);
}
break;
// Now wails runtime is loaded, wails for the ready event
// and callback to the main app
// window.wails.Events.On('wails:loaded', function () {
if (callback) {
log('Notifying application');
callback(window.wails);
}
// });
break;
// Notifications
case 'n':
window.wails._.Notify(message.data.slice(1));
break;
// // Binding
// case 'b':
// const binding = message.data.slice(1);
// //log("Binding: " + binding)
// window.wails._.NewBinding(binding);
// break;
// // Call back
case 'c':
const callbackData = message.data.slice(1);
window.wails._.Callback(callbackData);
break;
// Tray
case 'T':
const trayMessage = message.data.slice(1);
switch (trayMessage[0]) {
case 'S':
// Set tray
const trayJSON = trayMessage.slice(1);
let tray = JSON.parse(trayJSON)
setTray(tray)
break
case 'U':
// Update label
const updateTrayLabelJSON = trayMessage.slice(1);
let trayLabelData = JSON.parse(updateTrayLabelJSON)
updateTrayLabel(trayLabelData)
break
case 'D':
// Delete Tray Menu
const id = trayMessage.slice(1);
deleteTrayMenu(id)
break
default:
log('Unknown tray message: ' + message.data);
}
break;
default:
log('Unknown message: ' + message.data);
}
default:
log('Unknown message: ' + message.data);
}
}

View File

@@ -16,7 +16,7 @@ func main() {
sourceDir := fs.RelativePath("../../../internal/runtime/js")
platforms := []string{"darwin", "windows"}
platforms := []string{"darwin", "windows", "linux"}
for _, platform := range platforms {
println("Building JS Runtime for " + platform)

View File

@@ -23,7 +23,6 @@ type Window interface {
SetPosition(x int, y int)
Fullscreen()
UnFullscreen()
SetColour(colour int)
}
// Window exposes the Windows interface
@@ -66,11 +65,6 @@ func (w *window) Center() {
w.bus.Publish("window:center", "")
}
// SetColour sets the window colour to the given int
func (w *window) SetColour(colour int) {
w.bus.Publish("window:setcolour", colour)
}
// Show shows the window if hidden
func (w *window) Show() {
w.bus.Publish("window:show", "")

View File

@@ -140,7 +140,10 @@ func (c *Call) processSystemCall(payload *message.CallMessage, clientID string)
if err != nil {
c.logger.Error("Error decoding: %s", err)
}
result := c.runtime.Dialog.Open(dialogOptions)
result, err := c.runtime.Dialog.OpenFile(dialogOptions)
if err != nil {
c.logger.Error("Error: %s", err)
}
c.sendResult(result, payload, clientID)
case "Dialog.Save":
dialogOptions := new(dialog.SaveDialog)
@@ -148,7 +151,10 @@ func (c *Call) processSystemCall(payload *message.CallMessage, clientID string)
if err != nil {
c.logger.Error("Error decoding: %s", err)
}
result := c.runtime.Dialog.Save(dialogOptions)
result, err := c.runtime.Dialog.SaveFile(dialogOptions)
if err != nil {
c.logger.Error("Error: %s", err)
}
c.sendResult(result, payload, clientID)
case "Dialog.Message":
dialogOptions := new(dialog.MessageDialog)
@@ -156,7 +162,10 @@ func (c *Call) processSystemCall(payload *message.CallMessage, clientID string)
if err != nil {
c.logger.Error("Error decoding: %s", err)
}
result := c.runtime.Dialog.Message(dialogOptions)
result, err := c.runtime.Dialog.Message(dialogOptions)
if err != nil {
c.logger.Error("Error: %s", err)
}
c.sendResult(result, payload, clientID)
default:
c.logger.Error("Unknown system call: %+v", callName)

View File

@@ -3,12 +3,11 @@ package subsystem
import (
"context"
"fmt"
"strings"
"sync"
"github.com/wailsapp/wails/v2/internal/logger"
"github.com/wailsapp/wails/v2/internal/runtime"
"github.com/wailsapp/wails/v2/internal/servicebus"
"strings"
"sync"
)
// Runtime is the Runtime subsystem. It handles messages with topics starting

View File

@@ -1,5 +0,0 @@
package apps
func Find() []Apps {
}

View File

@@ -9,23 +9,23 @@ import (
"github.com/wailsapp/wails/v2/internal/shell"
)
// Yum represents the Yum manager
type Yum struct {
// Dnf represents the Dnf manager
type Dnf struct {
name string
osid string
}
// NewYum creates a new Yum instance
func NewYum(osid string) *Yum {
return &Yum{
name: "yum",
// NewDnf creates a new Dnf instance
func NewDnf(osid string) *Dnf {
return &Dnf{
name: "dnf",
osid: osid,
}
}
// Packages returns the libraries that we need for Wails to compile
// They will potentially differ on different distributions or versions
func (y *Yum) Packages() packagemap {
func (y *Dnf) Packages() packagemap {
return packagemap{
"libgtk-3": []*Package{
{Name: "gtk3-devel", SystemPackage: true, Library: true},
@@ -43,6 +43,9 @@ func (y *Yum) Packages() packagemap {
"npm": []*Package{
{Name: "npm", SystemPackage: true},
},
"upx": []*Package{
{Name: "upx", SystemPackage: true, Optional: true},
},
"docker": []*Package{
{
SystemPackage: false,
@@ -57,16 +60,16 @@ func (y *Yum) Packages() packagemap {
}
// Name returns the name of the package manager
func (y *Yum) Name() string {
func (y *Dnf) Name() string {
return y.name
}
// PackageInstalled tests if the given package name is installed
func (y *Yum) PackageInstalled(pkg *Package) (bool, error) {
func (y *Dnf) PackageInstalled(pkg *Package) (bool, error) {
if pkg.SystemPackage == false {
return false, nil
}
stdout, _, err := shell.RunCommand(".", "yum", "info", "installed", pkg.Name)
stdout, _, err := shell.RunCommand(".", "dnf", "info", "installed", pkg.Name)
if err != nil {
_, ok := err.(*exec.ExitError)
if ok {
@@ -87,11 +90,11 @@ func (y *Yum) PackageInstalled(pkg *Package) (bool, error) {
}
// PackageAvailable tests if the given package is available for installation
func (y *Yum) PackageAvailable(pkg *Package) (bool, error) {
func (y *Dnf) PackageAvailable(pkg *Package) (bool, error) {
if pkg.SystemPackage == false {
return false, nil
}
stdout, _, err := shell.RunCommand(".", "yum", "info", pkg.Name)
stdout, _, err := shell.RunCommand(".", "dnf", "info", pkg.Name)
// We add a space to ensure we get a full match, not partial match
if err != nil {
_, ok := err.(*exec.ExitError)
@@ -111,14 +114,14 @@ func (y *Yum) PackageAvailable(pkg *Package) (bool, error) {
}
// InstallCommand returns the package manager specific command to install a package
func (y *Yum) InstallCommand(pkg *Package) string {
func (y *Dnf) InstallCommand(pkg *Package) string {
if pkg.SystemPackage == false {
return pkg.InstallCommand[y.osid]
}
return "sudo yum install " + pkg.Name
return "sudo dnf install " + pkg.Name
}
func (y *Yum) getPackageVersion(pkg *Package, output string) {
func (y *Dnf) getPackageVersion(pkg *Package, output string) {
splitOutput := strings.Split(output, " ")
if len(splitOutput) > 0 {
pkg.Version = splitOutput[1]

View File

@@ -9,12 +9,11 @@ import (
"github.com/wailsapp/wails/v2/internal/shell"
)
// A list of package manager commands
var pmcommands = []string{
"eopkg",
"apt",
"yum",
"dnf",
"pacman",
"emerge",
"zypper",
@@ -38,8 +37,8 @@ func newPackageManager(pmname string, osid string) PackageManager {
return NewEopkg(osid)
case "apt":
return NewApt(osid)
case "yum":
return NewYum(osid)
case "dnf":
return NewDnf(osid)
case "pacman":
return NewPacman(osid)
case "emerge":
@@ -77,7 +76,7 @@ func Dependancies(p PackageManager) (DependencyList, error) {
if installed {
dependency.Installed = true
dependency.Version = pkg.Version
if !pkg.Library {
if !pkg.SystemPackage {
dependency.Version = AppVersion(name)
}
} else {

View File

@@ -21,7 +21,6 @@ type PackageManager interface {
InstallCommand(*Package) string
}
// Dependancy represents a system package that we require
type Dependancy struct {
Name string
@@ -36,20 +35,13 @@ type Dependancy struct {
// DependencyList is a list of Dependency instances
type DependencyList []*Dependancy
// InstallAllRequiredCommand returns the command you need to use to install all required dependencies
func (d DependencyList) InstallAllRequiredCommand() string {
result := ""
for _, dependency := range d {
if dependency.PackageName != "" {
if !dependency.Installed && !dependency.Optional {
if result == "" {
result = dependency.InstallCommand
} else {
result += " " + dependency.PackageName
}
}
if !dependency.Installed && !dependency.Optional {
result += " - " + dependency.Name + ": " + dependency.InstallCommand + "\n"
}
}
@@ -61,17 +53,10 @@ func (d DependencyList) InstallAllOptionalCommand() string {
result := ""
for _, dependency := range d {
if dependency.PackageName != "" {
if !dependency.Installed && dependency.Optional {
if result == "" {
result = dependency.InstallCommand
} else {
result += " " + dependency.PackageName
}
}
if !dependency.Installed && dependency.Optional {
result += " - " + dependency.Name + ": " + dependency.InstallCommand + "\n"
}
}
return result
}

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