mirror of
https://github.com/taigrr/wails.git
synced 2026-04-04 06:02:43 -07:00
Compare commits
131 Commits
v2.0.0-alp
...
v2-alpha-m
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52554009ce | ||
|
|
9f89a4a58a | ||
|
|
5585d72c1c | ||
|
|
7748cc2497 | ||
|
|
60f9a02143 | ||
|
|
899e522c74 | ||
|
|
be87d73da8 | ||
|
|
00639677f5 | ||
|
|
3c25a73ae8 | ||
|
|
344103739f | ||
|
|
c2b8247fbb | ||
|
|
03cdfad418 | ||
|
|
3fe4c5455a | ||
|
|
a6b95b23c9 | ||
|
|
2616d87922 | ||
|
|
f983649bc6 | ||
|
|
15ed02b78c | ||
|
|
2cb93b4b4b | ||
|
|
7e0ad801b0 | ||
|
|
ccdfa9a8be | ||
|
|
85e04d8094 | ||
|
|
e7d4ec5836 | ||
|
|
7fdbb0372c | ||
|
|
72f6f08f11 | ||
|
|
d16d5bdcd4 | ||
|
|
22d0e4ff8f | ||
|
|
c001a5f3cb | ||
|
|
43ab0e084f | ||
|
|
954470250e | ||
|
|
5ab5246aa0 | ||
|
|
abbbdda102 | ||
|
|
d270cc2ffa | ||
|
|
d6cdd1df82 | ||
|
|
3c0da9fd15 | ||
|
|
c9f93cd313 | ||
|
|
78c43d23b6 | ||
|
|
322f6b9b64 | ||
|
|
88bbfcb7f1 | ||
|
|
cae9827841 | ||
|
|
414b0149f2 | ||
|
|
33e4ec3e80 | ||
|
|
c46182923c | ||
|
|
5d2242f7a4 | ||
|
|
6204e63c56 | ||
|
|
4468edc939 | ||
|
|
b54a94135d | ||
|
|
e4d70f94b1 | ||
|
|
70418783a8 | ||
|
|
d9aa125a15 | ||
|
|
dacea399ab | ||
|
|
a78b9a5b9b | ||
|
|
36cd6af6df | ||
|
|
1e9807189c | ||
|
|
d54834d501 | ||
|
|
ac06e6728d | ||
|
|
227c316cb0 | ||
|
|
2c2ce66ec4 | ||
|
|
9a99b47f07 | ||
|
|
505bb51a27 | ||
|
|
6ade38e0ff | ||
|
|
6551e1b499 | ||
|
|
20f82cbde4 | ||
|
|
1ee9cf41e2 | ||
|
|
1cd38d12f9 | ||
|
|
0b71d64931 | ||
|
|
4954655ad4 | ||
|
|
8db91df185 | ||
|
|
ac4c17ca09 | ||
|
|
604dc6ace3 | ||
|
|
627aa06786 | ||
|
|
e718fb8333 | ||
|
|
c5d9fd1a0d | ||
|
|
63117fd519 | ||
|
|
a7c5064a33 | ||
|
|
f20ce7411d | ||
|
|
a7c04ac891 | ||
|
|
01de76a32e | ||
|
|
a861aa36b9 | ||
|
|
af593ef47a | ||
|
|
b98ab1f5b5 | ||
|
|
5ff3a286cf | ||
|
|
58dc917fb7 | ||
|
|
e00d65d468 | ||
|
|
dbcf4058e5 | ||
|
|
b558246d52 | ||
|
|
c3c88f5e27 | ||
|
|
31468aa177 | ||
|
|
6923ea301b | ||
|
|
ec8d8e4587 | ||
|
|
32591465f3 | ||
|
|
1c5c26e04a | ||
|
|
83baf4c6bb | ||
|
|
c383a61036 | ||
|
|
9d9c3d971a | ||
|
|
8acfeba3e1 | ||
|
|
09bae529de | ||
|
|
38c507a605 | ||
|
|
b7cd36921e | ||
|
|
de255729e6 | ||
|
|
3ac1dcc8d9 | ||
|
|
1d6cce7c52 | ||
|
|
c2ac4961ef | ||
|
|
8e84bdfa8d | ||
|
|
316e4de8e2 | ||
|
|
d83fd1c2b4 | ||
|
|
619d8cc05e | ||
|
|
244b3dc2b4 | ||
|
|
1a69d93d32 | ||
|
|
5ba85f2817 | ||
|
|
76f19f0752 | ||
|
|
5b10ee4b40 | ||
|
|
72b1e58218 | ||
|
|
7eb0718c9c | ||
|
|
ca8d41dd3b | ||
|
|
179d26b1c4 | ||
|
|
9786053324 | ||
|
|
aee395020f | ||
|
|
f377c94ba3 | ||
|
|
c5f1bd4449 | ||
|
|
e11dc0e080 | ||
|
|
0ea135a546 | ||
|
|
ccda8c5760 | ||
|
|
8a5287794e | ||
|
|
3e28bfe717 | ||
|
|
06ebe5f51f | ||
|
|
f02c140709 | ||
|
|
b80a64b0ee | ||
|
|
5d2cc81123 | ||
|
|
b86d2fe8cd | ||
|
|
fee14babbc | ||
|
|
f06ffb62de |
4
.github/workflows/latest-pre.yml
vendored
4
.github/workflows/latest-pre.yml
vendored
@@ -1,8 +1,10 @@
|
||||
name: latest pre-release
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
tags:
|
||||
- '**-pre**'
|
||||
- '**-pre**'
|
||||
jobs:
|
||||
|
||||
build:
|
||||
|
||||
29
.github/workflows/runtime.yml
vendored
Normal file
29
.github/workflows/runtime.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
name: Runtime
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- v2-alpha
|
||||
paths:
|
||||
- 'v2/internal/frontend/runtime/**'
|
||||
jobs:
|
||||
rebuild-runtime:
|
||||
name: Rebuild the runtime
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14.17.6
|
||||
cache: 'npm'
|
||||
cache-dependency-path: v2/internal/frontend/runtime/package-lock.json
|
||||
- run: npm install
|
||||
working-directory: v2/internal/frontend/runtime
|
||||
- run: npm run build
|
||||
working-directory: v2/internal/frontend/runtime
|
||||
|
||||
- name: Commit changes
|
||||
uses: devops-infra/action-commit-push@master
|
||||
with:
|
||||
github_token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
commit_prefix: "[AUTO]"
|
||||
commit_message: "The runtime was rebuilt"
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build linux || darwin || !windows
|
||||
// +build linux darwin !windows
|
||||
|
||||
package wails
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build windows || !linux || !darwin
|
||||
// +build windows !linux !darwin
|
||||
|
||||
package wails
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,3 +1,4 @@
|
||||
//go:build dev
|
||||
// +build dev
|
||||
|
||||
package main
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build dev
|
||||
// +build dev
|
||||
|
||||
package main
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package cmd
|
||||
|
||||
1
go.sum
1
go.sum
@@ -79,7 +79,6 @@ golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
|
||||
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package interfaces
|
||||
|
||||
// Runtime interface
|
||||
type Runtime interface {}
|
||||
type Runtime interface{}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -2,4 +2,5 @@
|
||||
|
||||
This branch contains WORK IN PROGRESS! There are no guarantees. Use at your peril!
|
||||
|
||||
This document will be updated as progress is made.
|
||||
This document will be updated as progress is made.
|
||||
|
||||
|
||||
@@ -12,8 +12,6 @@ import (
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/system"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/shell"
|
||||
|
||||
"github.com/leaanthony/clir"
|
||||
"github.com/leaanthony/slicer"
|
||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||
@@ -29,13 +27,9 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
||||
|
||||
command := app.NewSubCommand("build", "Builds the application")
|
||||
|
||||
// Setup production flag
|
||||
production := false
|
||||
command.BoolFlag("production", "Build in production mode", &production)
|
||||
|
||||
// Setup pack flag
|
||||
pack := false
|
||||
command.BoolFlag("package", "Create a platform specific package", &pack)
|
||||
// Setup noPackage flag
|
||||
noPackage := false
|
||||
command.BoolFlag("noPackage", "Skips platform specific packaging", &noPackage)
|
||||
|
||||
compilerCommand := "go"
|
||||
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &compilerCommand)
|
||||
@@ -62,11 +56,6 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
||||
tags := ""
|
||||
command.StringFlag("tags", "tags to pass to Go compiler (quoted and space separated)", &tags)
|
||||
|
||||
// Retain assets
|
||||
keepAssets := false
|
||||
command.BoolFlag("k", "Keep generated assets", &keepAssets)
|
||||
|
||||
// Retain assets
|
||||
outputFilename := ""
|
||||
command.StringFlag("o", "Output filename", &outputFilename)
|
||||
|
||||
@@ -77,8 +66,11 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
||||
webview2 := "download"
|
||||
command.StringFlag("webview2", "WebView2 installer strategy: download,embed,browser,error.", &webview2)
|
||||
|
||||
runDelve := false
|
||||
command.BoolFlag("delve", "Runs the built binary in delve for debugging", &runDelve)
|
||||
skipFrontend := false
|
||||
command.BoolFlag("s", "Skips building the frontend", &skipFrontend)
|
||||
|
||||
forceBuild := false
|
||||
command.BoolFlag("f", "Force build application", &forceBuild)
|
||||
|
||||
command.Action(func() error {
|
||||
|
||||
@@ -97,12 +89,6 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
||||
app.PrintBanner()
|
||||
}
|
||||
|
||||
// Setup mode
|
||||
mode := build.Debug
|
||||
if production {
|
||||
mode = build.Production
|
||||
}
|
||||
|
||||
// Check platform
|
||||
validPlatformArch := slicer.String([]string{
|
||||
"darwin",
|
||||
@@ -158,34 +144,29 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
||||
}
|
||||
}
|
||||
|
||||
// If we want to use delve we need to compile in DEBUG mode
|
||||
if runDelve {
|
||||
mode = build.Debug
|
||||
}
|
||||
|
||||
// Create BuildOptions
|
||||
buildOptions := &build.Options{
|
||||
Logger: logger,
|
||||
OutputType: outputType,
|
||||
OutputFile: outputFilename,
|
||||
CleanBuildDirectory: cleanBuildDirectory,
|
||||
Mode: mode,
|
||||
Pack: pack,
|
||||
Mode: build.Production,
|
||||
Pack: !noPackage,
|
||||
LDFlags: ldflags,
|
||||
Compiler: compilerCommand,
|
||||
KeepAssets: keepAssets,
|
||||
Verbosity: verbosity,
|
||||
ForceBuild: forceBuild,
|
||||
IgnoreFrontend: skipFrontend,
|
||||
Compress: compress,
|
||||
CompressFlags: compressFlags,
|
||||
UserTags: userTags,
|
||||
WebView2Strategy: wv2rtstrategy,
|
||||
RunDelve: runDelve,
|
||||
}
|
||||
|
||||
// Calculate platform and arch
|
||||
platformSplit := strings.Split(platform, "/")
|
||||
buildOptions.Platform = platformSplit[0]
|
||||
if system.IsAppleSilicon() {
|
||||
if system.IsAppleSilicon {
|
||||
buildOptions.Arch = "arm64"
|
||||
} else {
|
||||
buildOptions.Arch = runtime.GOARCH
|
||||
@@ -194,28 +175,20 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
||||
buildOptions.Arch = platformSplit[1]
|
||||
}
|
||||
|
||||
println("Build arch =", buildOptions.Arch)
|
||||
|
||||
// Start a new tabwriter
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 8, 8, 0, '\t', 0)
|
||||
|
||||
buildModeText := "debug"
|
||||
if production {
|
||||
buildModeText = "production"
|
||||
}
|
||||
|
||||
// Write out the system information
|
||||
fmt.Fprintf(w, "\n")
|
||||
fmt.Fprintf(w, "App Type: \t%s\n", buildOptions.OutputType)
|
||||
fmt.Fprintf(w, "Platform: \t%s\n", buildOptions.Platform)
|
||||
fmt.Fprintf(w, "Arch: \t%s\n", buildOptions.Arch)
|
||||
fmt.Fprintf(w, "Compiler: \t%s\n", compilerPath)
|
||||
fmt.Fprintf(w, "Skip Frontend: \t%t\n", skipFrontend)
|
||||
fmt.Fprintf(w, "Compress: \t%t\n", buildOptions.Compress)
|
||||
fmt.Fprintf(w, "Build Mode: \t%s\n", buildModeText)
|
||||
fmt.Fprintf(w, "Package: \t%t\n", buildOptions.Pack)
|
||||
fmt.Fprintf(w, "Clean Build Dir: \t%t\n", buildOptions.CleanBuildDirectory)
|
||||
fmt.Fprintf(w, "KeepAssets: \t%t\n", buildOptions.KeepAssets)
|
||||
fmt.Fprintf(w, "LDFlags: \t\"%s\"\n", buildOptions.LDFlags)
|
||||
fmt.Fprintf(w, "Tags: \t[%s]\n", strings.Join(buildOptions.UserTags, ","))
|
||||
if len(buildOptions.OutputFile) > 0 {
|
||||
@@ -245,40 +218,5 @@ func doBuild(buildOptions *build.Options) error {
|
||||
buildOptions.Logger.Println(fmt.Sprintf("Built '%s' in %s.", outputFilename, elapsed.Round(time.Millisecond).String()))
|
||||
buildOptions.Logger.Println("")
|
||||
|
||||
if buildOptions.RunDelve {
|
||||
// Check delve exists
|
||||
delveExists := shell.CommandExists("dlv")
|
||||
if !delveExists {
|
||||
return fmt.Errorf("cannot launch delve (Is it installed?)")
|
||||
}
|
||||
|
||||
// Get cwd
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Launch delve
|
||||
buildOptions.Logger.Println("Launching Delve on port 2345...")
|
||||
cmdArgs := slicer.String([]string{"--listen=:2345", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", outputFilename})
|
||||
if buildOptions.Verbosity == build.VERBOSE {
|
||||
buildOptions.Logger.Println("\tRunning: dlv %s", cmdArgs.Join(" "))
|
||||
}
|
||||
stdout, stderr, err := shell.RunCommand(cwd, "dlv", cmdArgs.AsSlice()...)
|
||||
if buildOptions.Verbosity == build.VERBOSE || err != nil {
|
||||
trimstdout := strings.TrimSpace(stdout)
|
||||
if trimstdout != "" {
|
||||
buildOptions.Logger.Println(trimstdout)
|
||||
}
|
||||
trimstderr := strings.TrimSpace(stderr)
|
||||
if trimstderr != "" {
|
||||
buildOptions.Logger.Println(trimstderr)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2,8 +2,11 @@ package dev
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leaanthony/slicer"
|
||||
"github.com/wailsapp/wails/v2/internal/project"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
@@ -12,6 +15,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/browser"
|
||||
"github.com/wailsapp/wails/v2/internal/colour"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
@@ -37,6 +41,14 @@ func LogDarkYellow(message string, args ...interface{}) {
|
||||
println(colour.DarkYellow(text))
|
||||
}
|
||||
|
||||
func sliceToMap(input []string) map[string]struct{} {
|
||||
result := map[string]struct{}{}
|
||||
for _, value := range input {
|
||||
result[value] = struct{}{}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// AddSubcommand adds the `dev` command for the Wails application
|
||||
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
|
||||
@@ -50,20 +62,35 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
compilerCommand := "go"
|
||||
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &compilerCommand)
|
||||
|
||||
// extensions to trigger rebuilds
|
||||
extensions := "go"
|
||||
command.StringFlag("e", "Extensions to trigger rebuilds (comma separated) eg go,js,css,html", &extensions)
|
||||
assetDir := ""
|
||||
command.StringFlag("assetdir", "Serve assets from the given directory", &assetDir)
|
||||
|
||||
// extensions to trigger rebuilds
|
||||
showWarnings := false
|
||||
command.BoolFlag("w", "Show warnings", &showWarnings)
|
||||
// extensions to trigger rebuilds of application
|
||||
extensions := "go"
|
||||
command.StringFlag("e", "Extensions to trigger rebuilds (comma separated) eg go", &extensions)
|
||||
|
||||
openBrowser := false
|
||||
command.BoolFlag("browser", "Open application in browser", &openBrowser)
|
||||
|
||||
noreload := false
|
||||
command.BoolFlag("noreload", "Disable reload on asset change", &noreload)
|
||||
|
||||
wailsjsdir := ""
|
||||
command.StringFlag("wailsjsdir", "Directory to generate the Wails JS modules", &wailsjsdir)
|
||||
|
||||
// tags to pass to `go`
|
||||
tags := ""
|
||||
command.StringFlag("tags", "tags to pass to Go compiler (quoted and space separated)", &tags)
|
||||
|
||||
// Verbosity
|
||||
verbosity := 1
|
||||
command.IntFlag("v", "Verbosity level (0 - silent, 1 - default, 2 - verbose)", &verbosity)
|
||||
command.IntFlag("v", "Verbosity level (0 - silent, 1 - standard, 2 - verbose)", &verbosity)
|
||||
|
||||
loglevel := ""
|
||||
command.StringFlag("loglevel", "Loglevel to use - Trace, Debug, Info, Warning, Error", &loglevel)
|
||||
command.StringFlag("loglevel", "Loglevel to use - Trace, Dev, Info, Warning, Error", &loglevel)
|
||||
|
||||
forceBuild := false
|
||||
command.BoolFlag("f", "Force build application", &forceBuild)
|
||||
|
||||
command.Action(func() error {
|
||||
|
||||
@@ -71,7 +98,65 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
logger := clilogger.New(w)
|
||||
app.PrintBanner()
|
||||
|
||||
// TODO: Check you are in a project directory
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
projectConfig, err := project.Load(cwd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if projectConfig.AssetDirectory == "" && assetDir == "" {
|
||||
return fmt.Errorf("No asset directory provided. Please use -assetdir to indicate which directory contains your built assets.")
|
||||
}
|
||||
|
||||
if assetDir == "" && projectConfig.AssetDirectory != "" {
|
||||
assetDir = projectConfig.AssetDirectory
|
||||
}
|
||||
|
||||
if assetDir != projectConfig.AssetDirectory {
|
||||
projectConfig.AssetDirectory = filepath.ToSlash(assetDir)
|
||||
err := projectConfig.Save()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if wailsjsdir == "" && projectConfig.WailsJSDir != "" {
|
||||
wailsjsdir = projectConfig.WailsJSDir
|
||||
}
|
||||
|
||||
if wailsjsdir == "" {
|
||||
wailsjsdir = "./frontend"
|
||||
}
|
||||
|
||||
if wailsjsdir != projectConfig.WailsJSDir {
|
||||
projectConfig.WailsJSDir = filepath.ToSlash(wailsjsdir)
|
||||
err := projectConfig.Save()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
buildOptions := &build.Options{
|
||||
Logger: logger,
|
||||
OutputType: "dev",
|
||||
Mode: build.Dev,
|
||||
Arch: runtime.GOARCH,
|
||||
Pack: true,
|
||||
Platform: runtime.GOOS,
|
||||
LDFlags: ldflags,
|
||||
Compiler: compilerCommand,
|
||||
ForceBuild: forceBuild,
|
||||
IgnoreFrontend: false,
|
||||
Verbosity: verbosity,
|
||||
WailsJSDir: wailsjsdir,
|
||||
}
|
||||
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
@@ -85,13 +170,12 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
}(watcher)
|
||||
|
||||
var debugBinaryProcess *process.Process = nil
|
||||
var extensionsThatTriggerARebuild = strings.Split(extensions, ",")
|
||||
var extensionsThatTriggerARebuild = sliceToMap(strings.Split(extensions, ","))
|
||||
|
||||
// Setup signal handler
|
||||
quitChannel := make(chan os.Signal, 1)
|
||||
signal.Notify(quitChannel, os.Interrupt, os.Kill, syscall.SIGTERM)
|
||||
|
||||
debounceQuit := make(chan bool, 1)
|
||||
exitCodeChannel := make(chan int, 1)
|
||||
|
||||
var passthruArgs []string
|
||||
//if len(os.Args) > 2 {
|
||||
@@ -100,70 +184,26 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
|
||||
// Do initial build
|
||||
logger.Println("Building application for development...")
|
||||
newProcess, appBinary, err := restartApp(logger, ldflags, compilerCommand, debugBinaryProcess, loglevel, passthruArgs, verbosity)
|
||||
newProcess, appBinary, err := restartApp(logger, buildOptions, debugBinaryProcess, loglevel, passthruArgs, assetDir, false, exitCodeChannel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if newProcess != nil {
|
||||
debugBinaryProcess = newProcess
|
||||
}
|
||||
|
||||
// open browser
|
||||
if openBrowser {
|
||||
err = browser.OpenURL("http://localhost:34115")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
// Check for new directories
|
||||
if event.Op&fsnotify.Create == fsnotify.Create {
|
||||
// If this is a folder, add it to our watch list
|
||||
if fs.DirExists(event.Name) {
|
||||
if !strings.Contains(event.Name, "node_modules") {
|
||||
err := watcher.Add(event.Name)
|
||||
if err != nil {
|
||||
logger.Fatal("%s", err.Error())
|
||||
}
|
||||
LogGreen("[New Directory] Watching new directory: %s", event.Name)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Check for file writes
|
||||
if event.Op&fsnotify.Write == fsnotify.Write {
|
||||
|
||||
var rebuild bool = false
|
||||
|
||||
// Iterate all file patterns
|
||||
for _, pattern := range extensionsThatTriggerARebuild {
|
||||
if strings.HasSuffix(event.Name, pattern) {
|
||||
rebuild = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !rebuild {
|
||||
if showWarnings {
|
||||
LogDarkYellow("[File change] %s did not match extension list (%s)", event.Name, extensions)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
LogGreen("[Attempting rebuild] %s updated", event.Name)
|
||||
|
||||
// Do a rebuild
|
||||
|
||||
// Try and build the app
|
||||
newBinaryProcess, _, err = restartApp(logger, ldflags, compilerCommand, debugBinaryProcess, loglevel, passthruArgs, verbosity)
|
||||
if err != nil {
|
||||
fmt.Printf("Error during build: %s", err.Error())
|
||||
return
|
||||
}
|
||||
// If we have a new process, save it
|
||||
if newBinaryProcess != nil {
|
||||
debugBinaryProcess = newBinaryProcess
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
// Get project dir
|
||||
projectDir, err := os.Getwd()
|
||||
@@ -188,20 +228,88 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
if strings.HasPrefix(dir, filepath.Join(projectDir, "build")) {
|
||||
return
|
||||
}
|
||||
//println("Watching", dir)
|
||||
err = watcher.Add(dir)
|
||||
if err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
})
|
||||
|
||||
// Wait until we get a quit signal
|
||||
// Main Loop
|
||||
quit := false
|
||||
// Use 100ms debounce
|
||||
interval := 100 * time.Millisecond
|
||||
timer := time.NewTimer(interval)
|
||||
rebuild := false
|
||||
reload := false
|
||||
for quit == false {
|
||||
//reload := false
|
||||
select {
|
||||
case exitCode := <-exitCodeChannel:
|
||||
if exitCode == 0 {
|
||||
quit = true
|
||||
}
|
||||
case item := <-watcher.Events:
|
||||
// Check for file writes
|
||||
if item.Op&fsnotify.Write == fsnotify.Write {
|
||||
// Ignore directories
|
||||
if fs.DirExists(item.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Iterate all file patterns
|
||||
ext := filepath.Ext(item.Name)
|
||||
if ext != "" {
|
||||
ext = ext[1:]
|
||||
if _, exists := extensionsThatTriggerARebuild[ext]; exists {
|
||||
rebuild = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(item.Name, assetDir) {
|
||||
reload = true
|
||||
}
|
||||
timer.Reset(interval)
|
||||
}
|
||||
// Check for new directories
|
||||
if item.Op&fsnotify.Create == fsnotify.Create {
|
||||
// If this is a folder, add it to our watch list
|
||||
if fs.DirExists(item.Name) {
|
||||
//node_modules is BANNED!
|
||||
if !strings.Contains(item.Name, "node_modules") {
|
||||
err := watcher.Add(item.Name)
|
||||
if err != nil {
|
||||
logger.Fatal("%s", err.Error())
|
||||
}
|
||||
LogGreen("Added new directory to watcher: %s", item.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
case <-timer.C:
|
||||
if rebuild {
|
||||
rebuild = false
|
||||
LogGreen("[Rebuild triggered] files updated")
|
||||
// Try and build the app
|
||||
newBinaryProcess, _, err = restartApp(logger, buildOptions, debugBinaryProcess, loglevel, passthruArgs, assetDir, false, exitCodeChannel)
|
||||
if err != nil {
|
||||
LogRed("Error during build: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
// If we have a new process, save it
|
||||
if newBinaryProcess != nil {
|
||||
debugBinaryProcess = newBinaryProcess
|
||||
}
|
||||
}
|
||||
if reload {
|
||||
reload = false
|
||||
_, err = http.Get("http://localhost:34115/wails/reload")
|
||||
if err != nil {
|
||||
LogRed("Error during refresh: %s", err.Error())
|
||||
}
|
||||
}
|
||||
case <-quitChannel:
|
||||
LogGreen("\nCaught quit")
|
||||
// Notify debouncer to quit
|
||||
debounceQuit <- true
|
||||
quit = true
|
||||
}
|
||||
}
|
||||
@@ -228,30 +336,14 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Credit: https://drailing.net/2018/01/debounce-function-for-golang/
|
||||
func debounce(interval time.Duration, input chan fsnotify.Event, quitChannel chan bool, cb func(arg fsnotify.Event)) {
|
||||
var item fsnotify.Event
|
||||
timer := time.NewTimer(interval)
|
||||
exit:
|
||||
for {
|
||||
select {
|
||||
case item = <-input:
|
||||
timer.Reset(interval)
|
||||
case <-timer.C:
|
||||
if item.Name != "" {
|
||||
cb(item)
|
||||
}
|
||||
case <-quitChannel:
|
||||
break exit
|
||||
}
|
||||
}
|
||||
}
|
||||
func restartApp(logger *clilogger.CLILogger, buildOptions *build.Options, debugBinaryProcess *process.Process, loglevel string, passthruArgs []string, assetDir string, firstRun bool, exitCodeChannel chan int) (*process.Process, string, 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, ldflags, compilerCommand, verbosity)
|
||||
appBinary, err := build.Build(buildOptions)
|
||||
println()
|
||||
if err != nil {
|
||||
if firstRun {
|
||||
return nil, "", err
|
||||
}
|
||||
LogRed("Build error - continuing to run current version")
|
||||
LogDarkYellow(err.Error())
|
||||
return nil, "", nil
|
||||
@@ -268,15 +360,18 @@ func restartApp(logger *clilogger.CLILogger, ldflags string, compilerCommand str
|
||||
debugBinaryProcess = nil
|
||||
}
|
||||
|
||||
// TODO: Generate `backend.js`
|
||||
|
||||
// Start up new binary with correct args
|
||||
var args = []string{"-loglevel", loglevel}
|
||||
if len(passthruArgs) > 0 {
|
||||
args = append(args, passthruArgs...)
|
||||
args := slicer.StringSlicer{}
|
||||
args.Add("-loglevel", loglevel)
|
||||
if assetDir != "" {
|
||||
args.Add("-assetdir", assetDir)
|
||||
}
|
||||
newProcess := process.NewProcess(logger, appBinary, args...)
|
||||
err = newProcess.Start()
|
||||
|
||||
if len(passthruArgs) > 0 {
|
||||
args.AddSlice(passthruArgs)
|
||||
}
|
||||
newProcess := process.NewProcess(appBinary, args.AsSlice()...)
|
||||
err = newProcess.Start(exitCodeChannel)
|
||||
if err != nil {
|
||||
// Remove binary
|
||||
deleteError := fs.DeleteFile(appBinary)
|
||||
@@ -288,29 +383,3 @@ func restartApp(logger *clilogger.CLILogger, ldflags string, compilerCommand str
|
||||
|
||||
return newProcess, appBinary, nil
|
||||
}
|
||||
|
||||
func buildApp(logger *clilogger.CLILogger, ldflags string, compilerCommand string, verbosity int) (string, error) {
|
||||
|
||||
// Create random output file
|
||||
outputFile := "wailsdev"
|
||||
if runtime.GOOS == "windows" {
|
||||
outputFile += ".exe"
|
||||
}
|
||||
|
||||
// Create BuildOptions
|
||||
buildOptions := &build.Options{
|
||||
Logger: logger,
|
||||
OutputType: "dev",
|
||||
Mode: build.Debug,
|
||||
Pack: false,
|
||||
Platform: runtime.GOOS,
|
||||
LDFlags: ldflags,
|
||||
Compiler: compilerCommand,
|
||||
OutputFile: outputFile,
|
||||
IgnoreFrontend: true,
|
||||
Verbosity: verbosity,
|
||||
}
|
||||
|
||||
return build.Build(buildOptions)
|
||||
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
}
|
||||
logger.Println("Done.")
|
||||
|
||||
logger.Println("")
|
||||
|
||||
// Start a new tabwriter
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 8, 8, 0, '\t', 0)
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/wailsapp/wails/v2"
|
||||
)
|
||||
|
||||
// App struct
|
||||
type App struct {
|
||||
runtime *wails.Runtime
|
||||
runtime context.Context
|
||||
}
|
||||
|
||||
// NewApp creates a new App application struct
|
||||
@@ -17,14 +16,16 @@ func NewApp() *App {
|
||||
}
|
||||
|
||||
// startup is called at application startup
|
||||
func (b *App) startup(runtime *wails.Runtime) {
|
||||
func (b *App) startup(ctx context.Context) {
|
||||
// Perform your setup here
|
||||
b.runtime = runtime
|
||||
runtime.Window.SetTitle("{{.ProjectName}}")
|
||||
//TODO: move to new runtime layout
|
||||
|
||||
//b.runtime = runtime
|
||||
//runtime.Window.SetTitle("{{.ProjectName}}")
|
||||
}
|
||||
|
||||
// shutdown is called at application termination
|
||||
func (b *App) shutdown() {
|
||||
func (b *App) shutdown(ctx context.Context) {
|
||||
// Perform your teardown here
|
||||
}
|
||||
|
||||
|
||||
@@ -7,9 +7,7 @@ import (
|
||||
|
||||
"github.com/wailsapp/wails/v2"
|
||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -30,22 +28,15 @@ func main() {
|
||||
Frameless: false,
|
||||
StartHidden: false,
|
||||
HideWindowOnClose: false,
|
||||
DevTools: false,
|
||||
RGBA: 0x000000FF,
|
||||
RGBA: &options.RGBA{0, 0, 0, 255},
|
||||
Windows: &windows.Options{
|
||||
WebviewIsTransparent: true,
|
||||
WindowBackgroundIsTranslucent: true,
|
||||
DisableWindowIcon: true,
|
||||
WebviewIsTransparent: true,
|
||||
WindowIsTranslucent: true,
|
||||
DisableWindowIcon: true,
|
||||
},
|
||||
Mac: &mac.Options{
|
||||
WebviewIsTransparent: true,
|
||||
WindowBackgroundIsTranslucent: true,
|
||||
TitleBar: mac.TitleBarHiddenInset(),
|
||||
Menu: menu.DefaultMacMenu(),
|
||||
},
|
||||
LogLevel: logger.DEBUG,
|
||||
Startup: app.startup,
|
||||
Shutdown: app.shutdown,
|
||||
LogLevel: logger.DEBUG,
|
||||
OnStartup: app.startup,
|
||||
OnShutdown: app.shutdown,
|
||||
Bind: []interface{}{
|
||||
app,
|
||||
},
|
||||
|
||||
@@ -225,6 +225,15 @@ func Install(options *Options) (bool, error) {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}(tempdir)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// Remove the .git directory
|
||||
err = os.RemoveAll(filepath.Join(tempdir, ".git"))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
templateFS := os.DirFS(tempdir)
|
||||
template, err = parseTemplate(templateFS)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/wailsapp/wails/v2"
|
||||
)
|
||||
|
||||
// App application struct
|
||||
type App struct {
|
||||
runtime *wails.Runtime
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewApp creates a new App application struct
|
||||
@@ -17,13 +16,13 @@ func NewApp() *App {
|
||||
}
|
||||
|
||||
// startup is called at application startup
|
||||
func (b *App) startup(runtime *wails.Runtime) {
|
||||
func (b *App) startup(ctx context.Context) {
|
||||
// Perform your setup here
|
||||
b.runtime = runtime
|
||||
b.ctx = ctx
|
||||
}
|
||||
|
||||
// shutdown is called at application termination
|
||||
func (b *App) shutdown() {
|
||||
func (b *App) shutdown(ctx context.Context) {
|
||||
// Perform your teardown here
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
let greeting = "";
|
||||
|
||||
function greet() {
|
||||
window.backend.main.App.Greet(name).then((result) => {
|
||||
window.go.main.App.Greet(name).then((result) => {
|
||||
greeting = result;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"log"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options/windows"
|
||||
|
||||
"github.com/wailsapp/wails/v2"
|
||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
//go:embed frontend/dist
|
||||
var assets embed.FS
|
||||
|
||||
func main() {
|
||||
|
||||
// Create application with options
|
||||
app := NewApp()
|
||||
|
||||
err := wails.Run(&options.App{
|
||||
Title: "",
|
||||
Width: 800,
|
||||
Height: 600,
|
||||
MinWidth: 400,
|
||||
MinHeight: 400,
|
||||
MaxWidth: 1280,
|
||||
MaxHeight: 1024,
|
||||
DisableResize: false,
|
||||
Fullscreen: false,
|
||||
Frameless: false,
|
||||
StartHidden: false,
|
||||
HideWindowOnClose: false,
|
||||
RGBA: 0x000000FF,
|
||||
Assets: assets,
|
||||
Windows: &windows.Options{
|
||||
WebviewIsTransparent: true,
|
||||
WindowIsTranslucent: true,
|
||||
DisableWindowIcon: true,
|
||||
},
|
||||
LogLevel: logger.DEBUG,
|
||||
OnStartup: app.startup,
|
||||
OnShutdown: app.shutdown,
|
||||
Bind: []interface{}{
|
||||
app,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options/windows"
|
||||
|
||||
"github.com/wailsapp/wails/v2"
|
||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// Create application with options
|
||||
app := NewApp()
|
||||
|
||||
err := wails.Run(&options.App{
|
||||
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,
|
||||
TitleBar: mac.TitleBarHiddenInset(),
|
||||
Menu: menu.DefaultMacMenu(),
|
||||
},
|
||||
LogLevel: logger.DEBUG,
|
||||
Startup: app.startup,
|
||||
Shutdown: app.shutdown,
|
||||
Bind: []interface{}{
|
||||
app,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "{{.ProjectName}}",
|
||||
"outputfilename": "{{.BinaryName}}",
|
||||
"html": "frontend/dist/index.html",
|
||||
"frontend:build": "npm run build",
|
||||
"frontend:install": "npm install",
|
||||
"author": {
|
||||
"name": "{{.AuthorName}}",
|
||||
"email": "{{.AuthorEmail}}"
|
||||
}
|
||||
"name": "{{.ProjectName}}",
|
||||
"outputfilename": "{{.BinaryName}}",
|
||||
"assetdir": "frontend/dist",
|
||||
"frontend:build": "npm run build",
|
||||
"frontend:install": "npm install",
|
||||
"author": {
|
||||
"name": "{{.AuthorName}}",
|
||||
"email": "{{.AuthorEmail}}"
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
## 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.
|
||||
This template uses vanilla JS / HTML and CSS.
|
||||
|
||||
## 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.
|
||||
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.
|
||||
|
||||
## Building
|
||||
|
||||
For a production build, use `wails build`.
|
||||
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/wailsapp/wails/v2"
|
||||
)
|
||||
|
||||
// App struct
|
||||
type App struct {
|
||||
runtime *wails.Runtime
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewApp creates a new App application struct
|
||||
@@ -17,13 +16,13 @@ func NewApp() *App {
|
||||
}
|
||||
|
||||
// startup is called at application startup
|
||||
func (b *App) startup(runtime *wails.Runtime) {
|
||||
func (b *App) startup(ctx context.Context) {
|
||||
// Perform your setup here
|
||||
b.runtime = runtime
|
||||
b.ctx = ctx
|
||||
}
|
||||
|
||||
// shutdown is called at application termination
|
||||
func (b *App) shutdown() {
|
||||
func (b *App) shutdown(ctx context.Context) {
|
||||
// Perform your teardown here
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
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);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com),
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Binary file not shown.
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 551 436" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||
xml:space="preserve"
|
||||
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(1.27527,0,0,1.27527,104.01,410.563)">
|
||||
<path d="M0,-51.891L14.429,-51.891L13.043,-21.183L22.568,-51.891L34.226,-51.891L34.084,-21.183L42.365,-51.891L56.794,-51.891L38.526,0L25.198,0L25.34,-32.45L15.211,0L1.919,0L0,-51.891Z"
|
||||
style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1.27527,0,0,1.27527,224.985,367.503)">
|
||||
<path d="M0,15.639L5.793,15.639L5.971,-3.589L0,15.639ZM-20.187,33.765L-0.675,-18.126L16.42,-18.126L20.08,33.765L5.437,33.765L5.509,26.123L-3.057,26.123L-5.332,33.765L-20.187,33.765Z"
|
||||
style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(0.19929,-1.2596,-1.2596,-0.19929,332.323,396.949)">
|
||||
<path d="M-16.046,33.107L36.491,33.107L38.757,18.784L-13.785,18.82L-16.046,33.107Z"
|
||||
style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1.27527,0,0,1.27527,353.217,344.388)">
|
||||
<path d="M0,51.891L8.246,0L22.781,0L16.597,39.024L27.224,39.024L25.199,51.891L0,51.891Z"
|
||||
style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1.27527,0,0,1.27527,427.939,364.922)">
|
||||
<path d="M0,19.83C1.611,21.181 3.305,22.224 5.083,22.959C6.859,23.693 8.565,24.06 10.2,24.06C11.645,24.06 12.794,23.663 13.647,22.87C14.5,22.076 14.927,20.992 14.927,19.617C14.927,18.434 14.571,17.254 13.861,16.081C13.15,14.908 11.775,13.351 9.738,11.408C7.273,9.015 5.58,6.906 4.655,5.081C3.731,3.257 3.27,1.243 3.27,-0.96C3.27,-5.912 4.839,-9.846 7.979,-12.76C11.118,-15.674 15.377,-17.132 20.756,-17.132C22.936,-17.132 25.008,-16.889 26.975,-16.403C28.941,-15.917 30.943,-15.165 32.982,-14.146L30.92,-1.493C29.356,-2.583 27.834,-3.412 26.354,-3.981C24.872,-4.551 23.457,-4.835 22.106,-4.835C20.898,-4.835 19.943,-4.521 19.245,-3.894C18.546,-3.265 18.196,-2.406 18.196,-1.316C18.196,0.154 19.535,2.215 22.213,4.868C22.544,5.2 22.805,5.46 22.995,5.649C25.696,8.304 27.473,10.578 28.326,12.475C29.179,14.37 29.605,16.56 29.605,19.049C29.605,24.594 27.893,28.965 24.469,32.163C21.046,35.361 16.36,36.962 10.413,36.962C7.877,36.962 5.479,36.66 3.216,36.056C0.953,35.45 -0.948,34.615 -2.488,33.549L0,19.83Z"
|
||||
style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(-166.599,4.57132,4.57132,166.599,147.403,167.648)">
|
||||
<path d="M0.883,-0.081L0.121,0.081L0.256,-0.063L0.883,-0.081Z" style="fill:url(#_Linear1);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(-106.443,-16.0669,-16.0669,106.443,428.19,188.033)">
|
||||
<path d="M0.878,-0.285L-0.073,0.71L-1.186,0.542L0.015,0.207L-0.846,0.077L0.355,-0.258L-0.505,-0.388L0.649,-0.71L0.878,-0.285Z"
|
||||
style="fill:url(#_Linear2);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(-114.484,-162.408,-162.408,114.484,333.291,285.804)">
|
||||
<path d="M0.44,-0.04L0.44,-0.04L0.44,-0.04L0.265,-0.056L0.177,0.437L-0.311,-0.255L0.262,-0.437L0.568,-0.437L0.44,-0.04Z"
|
||||
style="fill:url(#_Linear3);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(61.6919,58.8091,58.8091,-61.6919,258.631,180.413)">
|
||||
<path d="M0.5,0L0.5,-0L0.5,0L0.5,0Z" style="fill:url(#_Linear4);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(238.126,298.893,298.893,-238.126,113.516,-150.536)">
|
||||
<path d="M0.622,-0.115L0.761,-0.115L0.806,-0.013L0.826,0.182L0.622,-0.115Z"
|
||||
style="fill:url(#_Linear5);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(-369.529,-97.4118,-97.4118,369.529,582.38,94.027)">
|
||||
<path d="M0.467,0.005L0.49,0.062L0.271,-0.062L0.467,0.005Z" style="fill:url(#_Linear6);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(-496.156,-53.9751,-53.9751,496.156,367.888,125.085)">
|
||||
<path d="M0.2,0.001L0.219,-0.018L0.614,0.012L0.519,0.089L0.282,0.068L0.2,0.135L0.463,0.194L0.374,0.266L0.138,0.186L0.138,0.186L0.138,0.186L0.047,0.033L-0.131,-0.266L0.2,0.001Z"
|
||||
style="fill:url(#_Linear7);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(185.076,176.427,176.427,-185.076,153.446,80.1488)">
|
||||
<path d="M0.735,-0L0.735,-0L0.735,0L0.735,-0Z" style="fill:url(#_Linear8);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,-3.46945e-18,-3.46945e-18,-1,0,-3.05761e-06)"><stop offset="0" style="stop-color:rgb(227,50,50);stop-opacity:1"/>
|
||||
<stop offset="1" style="stop-color:rgb(107,0,13);stop-opacity:1"/></linearGradient>
|
||||
<linearGradient id="_Linear2" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,-1,0,-2.75467e-06)"><stop offset="0" style="stop-color:rgb(227,50,50);stop-opacity:1"/>
|
||||
<stop offset="1" style="stop-color:rgb(107,0,13);stop-opacity:1"/></linearGradient>
|
||||
<linearGradient id="_Linear3" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,-1.11022e-16,-1.11022e-16,-1,0,-2.61861e-06)"><stop offset="0" style="stop-color:rgb(227,50,50);stop-opacity:1"/>
|
||||
<stop offset="1" style="stop-color:rgb(107,0,13);stop-opacity:1"/></linearGradient>
|
||||
<linearGradient id="_Linear4" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,-5.55112e-17,-5.55112e-17,-1,0,-1.57562e-06)"><stop offset="0" style="stop-color:rgb(227,50,50);stop-opacity:1"/>
|
||||
<stop offset="1" style="stop-color:rgb(107,0,13);stop-opacity:1"/></linearGradient>
|
||||
<linearGradient id="_Linear5" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(-0.801899,-0.59746,-0.59746,0.801899,1.3495,0.447457)"><stop offset="0" style="stop-color:rgb(227,50,50);stop-opacity:1"/>
|
||||
<stop offset="1" style="stop-color:rgb(107,0,13);stop-opacity:1"/></linearGradient>
|
||||
<linearGradient id="_Linear6" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,-2.77556e-17,-2.77556e-17,-1,0,-1.92826e-06)"><stop offset="0" style="stop-color:rgb(227,50,50);stop-opacity:1"/>
|
||||
<stop offset="1" style="stop-color:rgb(107,0,13);stop-opacity:1"/></linearGradient>
|
||||
<linearGradient id="_Linear7" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,-1,0,9.68429e-07)"><stop offset="0" style="stop-color:rgb(227,50,50);stop-opacity:1"/>
|
||||
<stop offset="1" style="stop-color:rgb(107,0,13);stop-opacity:1"/></linearGradient>
|
||||
<linearGradient id="_Linear8" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,-1,0,1.43665e-07)"><stop offset="0" style="stop-color:rgb(227,50,50);stop-opacity:1"/>
|
||||
<stop offset="1" style="stop-color:rgb(107,0,13);stop-opacity:1"/></linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.2 KiB |
File diff suppressed because one or more lines are too long
@@ -1,21 +1,16 @@
|
||||
// Get input + focus
|
||||
let nameElement = document.getElementById("name");
|
||||
nameElement.focus();
|
||||
|
||||
import {ready} from '@wails/runtime';
|
||||
// Setup the greet function
|
||||
window.greet = function () {
|
||||
|
||||
ready( () => {
|
||||
// Get input + focus
|
||||
let nameElement = document.getElementById("name");
|
||||
nameElement.focus();
|
||||
// Get name
|
||||
let name = nameElement.value;
|
||||
|
||||
// Setup the greet function
|
||||
window.greet = function () {
|
||||
|
||||
// Get name
|
||||
let name = nameElement.value;
|
||||
|
||||
// Call App.Greet(name)
|
||||
window.backend.main.App.Greet(name).then((result) => {
|
||||
// Update result with data back from App.Greet()
|
||||
document.getElementById("result").innerText = result;
|
||||
});
|
||||
};
|
||||
});
|
||||
// Call App.Greet(name)
|
||||
window.go.main.App.Greet(name).then((result) => {
|
||||
// Update result with data back from App.Greet()
|
||||
document.getElementById("result").innerText = result;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"log"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options/windows"
|
||||
|
||||
"github.com/wailsapp/wails/v2"
|
||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
||||
)
|
||||
|
||||
//go:embed frontend/src
|
||||
var assets embed.FS
|
||||
|
||||
func main() {
|
||||
|
||||
// Create application with options
|
||||
@@ -30,22 +32,16 @@ func main() {
|
||||
Frameless: false,
|
||||
StartHidden: false,
|
||||
HideWindowOnClose: false,
|
||||
DevTools: false,
|
||||
RGBA: 0x000000FF,
|
||||
RGBA: &options.RGBA{0, 0, 0, 255},
|
||||
Assets: assets,
|
||||
Windows: &windows.Options{
|
||||
WebviewIsTransparent: true,
|
||||
WindowBackgroundIsTranslucent: true,
|
||||
DisableWindowIcon: true,
|
||||
WebviewIsTransparent: false,
|
||||
WindowIsTranslucent: false,
|
||||
DisableWindowIcon: false,
|
||||
},
|
||||
Mac: &mac.Options{
|
||||
WebviewIsTransparent: true,
|
||||
WindowBackgroundIsTranslucent: true,
|
||||
TitleBar: mac.TitleBarHiddenInset(),
|
||||
Menu: menu.DefaultMacMenu(),
|
||||
},
|
||||
LogLevel: logger.DEBUG,
|
||||
Startup: app.startup,
|
||||
Shutdown: app.shutdown,
|
||||
LogLevel: logger.DEBUG,
|
||||
OnStartup: app.startup,
|
||||
OnShutdown: app.shutdown,
|
||||
Bind: []interface{}{
|
||||
app,
|
||||
},
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
{
|
||||
"name": "{{.ProjectName}}",
|
||||
"outputfilename": "{{.BinaryName}}",
|
||||
"html": "frontend/dist/index.html",
|
||||
"frontend:build": "npm run build",
|
||||
"frontend:install": "npm install",
|
||||
"author": {
|
||||
"name": "{{.AuthorName}}",
|
||||
"email": "{{.AuthorEmail}}"
|
||||
}
|
||||
"name": "{{.ProjectName}}",
|
||||
"outputfilename": "{{.BinaryName}}",
|
||||
"assetdir": "frontend/src",
|
||||
"author": {
|
||||
"name": "{{.AuthorName}}",
|
||||
"email": "{{.AuthorEmail}}"
|
||||
}
|
||||
}
|
||||
59
v2/go.mod
59
v2/go.mod
@@ -1,45 +1,86 @@
|
||||
module github.com/wailsapp/wails/v2
|
||||
|
||||
go 1.16
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/Masterminds/semver v1.5.0
|
||||
github.com/fatih/structtag v1.2.0
|
||||
github.com/fsnotify/fsnotify v1.4.9
|
||||
github.com/gabriel-vasile/mimetype v1.3.1
|
||||
github.com/go-git/go-billy/v5 v5.2.0 // indirect
|
||||
github.com/go-git/go-git/v5 v5.3.0
|
||||
github.com/gofiber/fiber/v2 v2.17.0
|
||||
github.com/gofiber/websocket/v2 v2.0.8
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/uuid v1.1.2 // indirect
|
||||
github.com/gorilla/websocket v1.4.1
|
||||
github.com/imdario/mergo v0.3.12
|
||||
github.com/jackmordaunt/icns v1.0.0
|
||||
github.com/klauspost/compress v1.11.3 // indirect
|
||||
github.com/klauspost/compress v1.12.2 // indirect
|
||||
github.com/leaanthony/clir v1.0.4
|
||||
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.3
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934
|
||||
github.com/leaanthony/gosod v1.0.1
|
||||
github.com/leaanthony/idgen v1.0.0
|
||||
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/leaanthony/winc v0.0.0-20210906113646-fd400754f6ba
|
||||
github.com/leaanthony/winicon v1.0.0
|
||||
github.com/matryer/is v1.4.0
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.4
|
||||
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/stretchr/testify v1.7.0 // indirect
|
||||
github.com/tc-hib/winres v0.1.5
|
||||
github.com/tdewolff/minify v2.3.6+incompatible
|
||||
github.com/tdewolff/parse v2.3.4+incompatible // indirect
|
||||
github.com/tdewolff/test v1.0.6 // indirect
|
||||
github.com/tidwall/sjson v1.1.7
|
||||
github.com/tkrajina/typescriptify-golang-structs v0.1.6
|
||||
github.com/wailsapp/wails v1.16.6
|
||||
github.com/wzshiming/ctc v1.2.3
|
||||
github.com/xyproto/xpm v1.2.1
|
||||
github.com/ztrue/tracerr v0.3.0
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect
|
||||
golang.org/x/mod v0.4.1 // indirect
|
||||
golang.org/x/net v0.0.0-20210326060303-6b1517762897
|
||||
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273
|
||||
golang.org/x/text v0.3.5 // indirect
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf
|
||||
golang.org/x/tools v0.1.0
|
||||
nhooyr.io/websocket v1.8.6
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Microsoft/go-winio v0.4.16 // indirect
|
||||
github.com/abadojack/whatlanggo v1.0.1 // indirect
|
||||
github.com/andybalholm/brotli v1.0.2 // indirect
|
||||
github.com/emirpasic/gods v1.12.0 // indirect
|
||||
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect
|
||||
github.com/go-git/gcfg v1.5.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.5 // indirect
|
||||
github.com/google/go-cmp v0.5.5 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 // indirect
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e // indirect
|
||||
github.com/mattn/go-runewidth v0.0.7 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect
|
||||
github.com/sergi/go-diff v1.1.0 // indirect
|
||||
github.com/sirupsen/logrus v1.4.1 // indirect
|
||||
github.com/tidwall/gjson v1.8.0 // indirect
|
||||
github.com/tidwall/match v1.0.3 // indirect
|
||||
github.com/tidwall/pretty v1.1.0 // indirect
|
||||
github.com/tkrajina/go-reflector v0.5.4 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.28.0 // indirect
|
||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||
github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
||||
golang.org/x/image v0.0.0-20201208152932-35266b937fa6 // indirect
|
||||
golang.org/x/text v0.3.6 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
)
|
||||
|
||||
110
v2/go.sum
110
v2/go.sum
@@ -1,10 +1,16 @@
|
||||
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||
github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
|
||||
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
|
||||
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
|
||||
github.com/abadojack/whatlanggo v1.0.1 h1:19N6YogDnf71CTHm3Mp2qhYfkRdyvbgwWdd2EPxJRG4=
|
||||
github.com/abadojack/whatlanggo v1.0.1/go.mod h1:66WiQbSbJBIlOZMsvbKe5m6pzQovxCH9B/K8tQB2uoc=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||
github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E=
|
||||
github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
@@ -15,11 +21,16 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab h1:9e2joQGp642wHGFP5m86SDptAavrdGBe8/x9DGEEAaI=
|
||||
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab/go.mod h1:smsv/h4PBEBaU0XDTY5UwJTpZv69fQ0FfcLJr21mA6Y=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
|
||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/gabriel-vasile/mimetype v1.3.1 h1:qevA6c2MtE1RorlScnixeG0VA1H4xrXyhyX3oWBynNQ=
|
||||
github.com/gabriel-vasile/mimetype v1.3.1/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
|
||||
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=
|
||||
@@ -36,9 +47,11 @@ github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbK
|
||||
github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
|
||||
github.com/go-git/go-git/v5 v5.3.0 h1:8WKMtJR2j8RntEXR/uvTKagfEt4GYlwQ7mntE4+0GWc=
|
||||
github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw=
|
||||
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-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
|
||||
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/colors v1.2.0/go.mod h1:miw1R2JIE19cclPxsXqNdzLZsk4DP4iF+m88bRc7kfM=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
@@ -51,11 +64,16 @@ github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
|
||||
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
|
||||
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||
github.com/gofiber/fiber/v2 v2.17.0 h1:qP3PkGUbBB0i9iQh5E057XI1yO5CZigUxZhyUFYAFoM=
|
||||
github.com/gofiber/fiber/v2 v2.17.0/go.mod h1:iftruuHGkRYGEXVISmdD7HTYWyfS2Bh+Dkfq4n/1Owg=
|
||||
github.com/gofiber/websocket/v2 v2.0.8 h1:Hb4y6IxYZVMO0segROODXJiXVgVD3a6i7wnfot8kM6k=
|
||||
github.com/gofiber/websocket/v2 v2.0.8/go.mod h1:fv8HSGQX09sauNv9g5Xq8GeGAaahLFYQKKb4ZdT0x2w=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
@@ -64,23 +82,33 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
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/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
|
||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/jackmordaunt/icns v1.0.0 h1:RYSxplerf/l/DUd09AHtITwckkv/mqjVv4DjYdPmAMQ=
|
||||
github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 h1:pdFFlHXY9tZXmJz+tRSm1DzYEH4ebha7cffmm607bMU=
|
||||
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kennygrant/sanitize v1.2.4/go.mod h1:LGsjYYtgxbetdg5owWB2mpgUL6e2nfw2eObZ0u0qvak=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.11.3 h1:dB4Bn0tN3wdCzQxnS8r06kV74qN/TAfaIS0bVE8h3jc=
|
||||
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.12.2 h1:2KCfW3I9M7nSc5wOqXAlW2v2U6v+w6cbjvbfp+OykW8=
|
||||
github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
@@ -97,26 +125,41 @@ github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQ
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM=
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3 h1:O0uGjKnWtdEADGrkg+TyAAbZylykMwwx/MNEXn9fp+Y=
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3/go.mod h1:TGhEc9eSJgRsupZ+iH1ZgAOnEo9zp05cRH2j08RPrF0=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934 h1:nK/JTPyJi5QRqYjVZjXgtN4/dhg2qtngoLxLDVn429k=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
|
||||
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/idgen v1.0.0 h1:IZreR+JGEzFV4yeVuBZA25gM0keUoFy+RDUldncQ+Jw=
|
||||
github.com/leaanthony/idgen v1.0.0/go.mod h1:4nBZnt8ml/f/ic/EVQuLxuj817RccT2fyrUaZFxrcVA=
|
||||
github.com/leaanthony/slicer v1.4.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
|
||||
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/spinner v0.5.3/go.mod h1:oHlrvWicr++CVV7ALWYi+qHk/XNA91D9IJ48IqmpVUo=
|
||||
github.com/leaanthony/synx v0.1.0/go.mod h1:Iz7eybeeG8bdq640iR+CwYb8p+9EOsgMWghkSRyZcqs=
|
||||
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/leaanthony/winc v0.0.0-20210906113646-fd400754f6ba h1:JalbOARv2XoT3RtJg7XGKKYcp7IndycC7pccLlfVRZI=
|
||||
github.com/leaanthony/winc v0.0.0-20210906113646-fd400754f6ba/go.mod h1:KEbMsKoznsebyGHwLk5LqkFOxL5uXSRdvpP4+avmAMs=
|
||||
github.com/leaanthony/wincursor v0.1.0/go.mod h1:7TVwwrzSH/2Y9gLOGH+VhA+bZhoWXBRgbGNTMk+yimE=
|
||||
github.com/leaanthony/winicon v1.0.0 h1:ZNt5U5dY71oEoKZ97UVwJRT4e+5xo5o/ieKuHuk8NqQ=
|
||||
github.com/leaanthony/winicon v1.0.0/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/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e h1:9MlwzLdW7QSDrhDjFlsEYmxpFyIoXmYRon3dt0io31k=
|
||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
@@ -128,21 +171,31 @@ github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
|
||||
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
|
||||
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
||||
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 h1:acNfDZXmm28D2Yg/c3ALnZStzNaZMSagpbr96vY6Zjc=
|
||||
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f h1:PgA+Olipyj258EIEYnpFFONrrCcAIWNUNoFhUfMqAGY=
|
||||
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f/go.mod h1:lHhJedqxCoHN+zMtwGNTXWmF0u9Jt363FYRhV6g0CdY=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba/go.mod h1:iLnlXG2Pakcii2CU0cbY07DRCSvpWNa7nFxtevhOChk=
|
||||
github.com/tc-hib/winres v0.1.5 h1:2dA5yfjdoEA3UyRaOC92HNMt3jap66pLzoW4MjpC/0M=
|
||||
github.com/tc-hib/winres v0.1.5/go.mod h1:pe6dOR40VOrGz8PkzreVKNvEKnlE8t4yR8A8naL+t7A=
|
||||
github.com/tdewolff/minify v2.3.6+incompatible h1:2hw5/9ZvxhWLvBUnHE06gElGYz+Jv9R4Eys0XUzItYo=
|
||||
github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs=
|
||||
github.com/tdewolff/parse v2.3.4+incompatible h1:x05/cnGwIMf4ceLuDMBOdQ1qGniMoxpP46ghf0Qzh38=
|
||||
@@ -157,10 +210,25 @@ github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8=
|
||||
github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tidwall/sjson v1.1.7 h1:sgVPwu/yygHJ2m1pJDLgGM/h+1F5odx5Q9ljG3imRm8=
|
||||
github.com/tidwall/sjson v1.1.7/go.mod h1:w/yG+ezBeTdUxiKs5NcPicO9diP38nk96QBAbIIGeFs=
|
||||
github.com/tkrajina/go-reflector v0.5.4 h1:dS9aJEa/eYNQU/fwsb5CSiATOxcNyA/gG/A7a582D5s=
|
||||
github.com/tkrajina/go-reflector v0.5.4/go.mod h1:9PyLgEOzc78ey/JmQQHbW8cQJ1oucLlNQsg8yFvkVk8=
|
||||
github.com/tkrajina/typescriptify-golang-structs v0.1.6 h1:AlUeArKYvOdsl0wL7VKtRDgBqT7Hvk87w7hYGrITcqg=
|
||||
github.com/tkrajina/typescriptify-golang-structs v0.1.6/go.mod h1:mfb2iqie4FjTKHfbjjCp08SRphjYaM7f2LdfUcNP7wY=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.9.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
|
||||
github.com/valyala/fasthttp v1.26.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA=
|
||||
github.com/valyala/fasthttp v1.28.0 h1:ruVmTmZaBR5i67NqnjvvH5gEv0zwHfWtbjoyW98iho4=
|
||||
github.com/valyala/fasthttp v1.28.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA=
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
github.com/wailsapp/wails v1.16.6 h1:iN0tP0O/Gwr8SKWwgH4t+IqDlMCGeVquWoHTegk8JlQ=
|
||||
github.com/wailsapp/wails v1.16.6/go.mod h1:aADbAvTzZrKGd4Td7d1l4Dp5Hx7lLJEvVH7guIHoDf8=
|
||||
github.com/wzshiming/ctc v1.2.3 h1:q+hW3IQNsjIlOFBTGZZZeIXTElFM4grF4spW/errh/c=
|
||||
github.com/wzshiming/ctc v1.2.3/go.mod h1:2tVAtIY7SUyraSk0JxvwmONNPFL4ARavPuEsg5+KA28=
|
||||
github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae h1:tpXvBXC3hpQBDCc9OojJZCQMVRAbT3TTdUMP8WguXkY=
|
||||
@@ -172,28 +240,37 @@ github.com/xyproto/xpm v1.2.1/go.mod h1:cMnesLsD0PBXLgjDfTDEaKr8XyTFsnP1QycSqRw7
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/ztrue/tracerr v0.3.0 h1:lDi6EgEYhPYPnKcjsYzmWw4EkFEoA/gfe+I9Y5f+h6Y=
|
||||
github.com/ztrue/tracerr v0.3.0/go.mod h1:qEalzze4VN9O8tnhBXScfCrmoJo10o8TN5ciKjm6Mww=
|
||||
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20201208152932-35266b937fa6 h1:nfeHNc1nAqecKCy2FCy4HY+soOOe5sDLJ/gZLbx6GYI=
|
||||
golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210326060303-6b1517762897 h1:KrsHThm5nFk34YtATK1LsThyGhGbGe1olrte/HInHvs=
|
||||
golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
|
||||
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I=
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -201,20 +278,27 @@ 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-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 h1:faDu4veV+8pcThn4fewv6TVlNCezafGoC1gM/mxQLbQ=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
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/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
@@ -228,6 +312,7 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/AlecAivazis/survey.v1 v1.8.4/go.mod h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -240,6 +325,7 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k=
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// +build debug
|
||||
//go:build dev
|
||||
// +build dev
|
||||
|
||||
package app
|
||||
|
||||
@@ -14,11 +15,6 @@ func (a *App) Init() error {
|
||||
// Indicate debug mode
|
||||
a.debug = true
|
||||
|
||||
if a.appType == "desktop" {
|
||||
// Enable dev tools
|
||||
a.options.DevTools = true
|
||||
}
|
||||
|
||||
// Set log levels
|
||||
loglevel := flag.String("loglevel", "debug", "Loglevel to use - Trace, Debug, Info, Warning, Error")
|
||||
flag.Parse()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build desktop && !server
|
||||
// +build desktop,!server
|
||||
|
||||
package app
|
||||
@@ -11,7 +12,6 @@ import (
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/menumanager"
|
||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||
"github.com/wailsapp/wails/v2/internal/runtime"
|
||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||
"github.com/wailsapp/wails/v2/internal/signal"
|
||||
"github.com/wailsapp/wails/v2/internal/subsystem"
|
||||
@@ -46,12 +46,8 @@ type App struct {
|
||||
// This is our binding DB
|
||||
bindings *binding.Bindings
|
||||
|
||||
// Application Stores
|
||||
loglevelStore *runtime.Store
|
||||
appconfigStore *runtime.Store
|
||||
|
||||
// Startup/Shutdown
|
||||
startupCallback func(*runtime.Runtime)
|
||||
// OnStartup/OnShutdown
|
||||
startupCallback func(ctx context.Context)
|
||||
shutdownCallback func()
|
||||
}
|
||||
|
||||
@@ -87,7 +83,7 @@ func CreateApp(appoptions *options.App) (*App, error) {
|
||||
window := ffenestri.NewApplicationWithConfig(appoptions, myLogger, menuManager)
|
||||
|
||||
// Create binding exemptions - Ugly hack. There must be a better way
|
||||
bindingExemptions := []interface{}{appoptions.Startup, appoptions.Shutdown}
|
||||
bindingExemptions := []interface{}{appoptions.OnStartup, appoptions.OnShutdown, appoptions.OnDomReady}
|
||||
|
||||
result := &App{
|
||||
appType: "desktop",
|
||||
@@ -96,8 +92,8 @@ func CreateApp(appoptions *options.App) (*App, error) {
|
||||
logger: myLogger,
|
||||
bindings: binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions),
|
||||
menuManager: menuManager,
|
||||
startupCallback: appoptions.Startup,
|
||||
shutdownCallback: appoptions.Shutdown,
|
||||
startupCallback: appoptions.OnStartup,
|
||||
shutdownCallback: appoptions.OnShutdown,
|
||||
}
|
||||
|
||||
result.options = appoptions
|
||||
@@ -145,12 +141,8 @@ func (a *App) Run() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Application Stores
|
||||
a.loglevelStore = a.runtime.GoRuntime().Store.New("wails:loglevel", a.options.LogLevel)
|
||||
a.appconfigStore = a.runtime.GoRuntime().Store.New("wails:appconfig", a.options)
|
||||
|
||||
// Start the logging subsystem
|
||||
log, err := subsystem.NewLog(a.servicebus, a.logger, a.loglevelStore)
|
||||
log, err := subsystem.NewLog(a.servicebus, a.logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -207,7 +199,7 @@ func (a *App) Run() error {
|
||||
}
|
||||
|
||||
// Start the call subsystem
|
||||
callSubsystem, err := subsystem.NewCall(ctx, a.servicebus, a.logger, a.bindings.DB(), a.runtime.GoRuntime())
|
||||
callSubsystem, err := subsystem.NewCall(ctx, a.servicebus, a.logger, a.bindings.DB())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -255,7 +247,7 @@ func (a *App) Run() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Shutdown callback
|
||||
// OnShutdown callback
|
||||
if a.shutdownCallback != nil {
|
||||
a.shutdownCallback()
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
//go:build dev
|
||||
// +build dev
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/wailsapp/wails/runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/bridge"
|
||||
@@ -14,7 +16,6 @@ import (
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||
"github.com/wailsapp/wails/v2/internal/runtime"
|
||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||
"github.com/wailsapp/wails/v2/internal/signal"
|
||||
"github.com/wailsapp/wails/v2/internal/subsystem"
|
||||
@@ -50,7 +51,7 @@ type App struct {
|
||||
loglevelStore *runtime.Store
|
||||
appconfigStore *runtime.Store
|
||||
|
||||
// Startup/Shutdown
|
||||
// OnStartup/OnShutdown
|
||||
startupCallback func(*runtime.Runtime)
|
||||
shutdownCallback func()
|
||||
|
||||
@@ -86,15 +87,15 @@ func CreateApp(appoptions *options.App) (*App, error) {
|
||||
}
|
||||
|
||||
// Create binding exemptions - Ugly hack. There must be a better way
|
||||
bindingExemptions := []interface{}{appoptions.Startup, appoptions.Shutdown}
|
||||
bindingExemptions := []interface{}{appoptions.OnStartup, appoptions.OnShutdown, appoptions.OnDomReady}
|
||||
|
||||
result := &App{
|
||||
appType: "dev",
|
||||
bindings: binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions),
|
||||
logger: myLogger,
|
||||
servicebus: servicebus.New(myLogger),
|
||||
startupCallback: appoptions.Startup,
|
||||
shutdownCallback: appoptions.Shutdown,
|
||||
startupCallback: appoptions.OnStartup,
|
||||
shutdownCallback: appoptions.OnShutdown,
|
||||
bridge: bridge.NewBridge(myLogger),
|
||||
menuManager: menuManager,
|
||||
}
|
||||
@@ -185,7 +186,7 @@ func (a *App) Run() error {
|
||||
}
|
||||
|
||||
// Start the call subsystem
|
||||
callSubsystem, err := subsystem.NewCall(ctx, a.servicebus, a.logger, a.bindings.DB(), a.runtime.GoRuntime())
|
||||
callSubsystem, err := subsystem.NewCall(ctx, a.servicebus, a.logger, a.bindings.DB())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -236,7 +237,7 @@ func (a *App) Run() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Shutdown callback
|
||||
// OnShutdown callback
|
||||
if a.shutdownCallback != nil {
|
||||
a.shutdownCallback()
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// +build !debug
|
||||
//go:build production
|
||||
// +build production
|
||||
|
||||
package app
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
//go:build server && !desktop
|
||||
// +build server,!desktop
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
@@ -12,7 +14,6 @@ import (
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||
"github.com/wailsapp/wails/v2/internal/runtime"
|
||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||
"github.com/wailsapp/wails/v2/internal/subsystem"
|
||||
"github.com/wailsapp/wails/v2/internal/webserver"
|
||||
@@ -26,7 +27,6 @@ type App struct {
|
||||
call *subsystem.Call
|
||||
event *subsystem.Event
|
||||
log *subsystem.Log
|
||||
runtime *subsystem.Runtime
|
||||
|
||||
options *options.App
|
||||
|
||||
@@ -38,12 +38,8 @@ type App struct {
|
||||
|
||||
debug bool
|
||||
|
||||
// Application Stores
|
||||
loglevelStore *runtime.Store
|
||||
appconfigStore *runtime.Store
|
||||
|
||||
// Startup/Shutdown
|
||||
startupCallback func(*runtime.Runtime)
|
||||
// OnStartup/OnShutdown
|
||||
startupCallback func(ctx context.Context)
|
||||
shutdownCallback func()
|
||||
}
|
||||
|
||||
@@ -63,8 +59,8 @@ func CreateApp(appoptions *options.App) (*App, error) {
|
||||
logger: myLogger,
|
||||
servicebus: servicebus.New(myLogger),
|
||||
webserver: webserver.NewWebServer(myLogger),
|
||||
startupCallback: appoptions.Startup,
|
||||
shutdownCallback: appoptions.Shutdown,
|
||||
startupCallback: appoptions.OnStartup,
|
||||
shutdownCallback: appoptions.OnShutdown,
|
||||
}
|
||||
|
||||
// Initialise app
|
||||
@@ -109,19 +105,15 @@ func (a *App) Run() error {
|
||||
}
|
||||
|
||||
// Start the runtime
|
||||
runtime, err := subsystem.NewRuntime(a.servicebus, a.logger, a.startupCallback, a.shutdownCallback)
|
||||
runtime, err := subsystem.NewRuntime(a.servicebus, a.logger, a.startupCallback)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.runtime = runtime
|
||||
a.runtime.Start()
|
||||
|
||||
// Application Stores
|
||||
a.loglevelStore = a.runtime.GoRuntime().Store.New("wails:loglevel", a.options.LogLevel)
|
||||
a.appconfigStore = a.runtime.GoRuntime().Store.New("wails:appconfig", a.options)
|
||||
|
||||
a.servicebus.Start()
|
||||
log, err := subsystem.NewLog(a.servicebus, a.logger, a.loglevelStore)
|
||||
log, err := subsystem.NewLog(a.servicebus, a.logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -135,7 +127,7 @@ func (a *App) Run() error {
|
||||
a.dispatcher.Start()
|
||||
|
||||
// Start the binding subsystem
|
||||
binding, err := subsystem.NewBinding(a.servicebus, a.logger, a.bindings, runtime.GoRuntime())
|
||||
binding, err := subsystem.NewBinding(a.servicebus, a.logger, a.bindings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
29
v2/internal/appng/app_default.go
Normal file
29
v2/internal/appng/app_default.go
Normal file
@@ -0,0 +1,29 @@
|
||||
//go:build !dev && !production && windows
|
||||
|
||||
package appng
|
||||
|
||||
import (
|
||||
"github.com/leaanthony/winc/w32"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// App defines a Wails application structure
|
||||
type App struct{}
|
||||
|
||||
func (a *App) Run() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateApp creates the app!
|
||||
func CreateApp(_ *options.App) (*App, error) {
|
||||
result := w32.MessageBox(0,
|
||||
`Wails applications will not build without the correct build tags.
|
||||
Please use "wails build" or press "OK" to open the documentation on how to use "go build"`,
|
||||
"Error",
|
||||
w32.MB_ICONERROR|w32.MB_OKCANCEL)
|
||||
if result == 1 {
|
||||
exec.Command("rundll32", "url.dll,FileProtocolHandler", "https://wails.io").Start()
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
166
v2/internal/appng/app_dev.go
Normal file
166
v2/internal/appng/app_dev.go
Normal file
@@ -0,0 +1,166 @@
|
||||
//go:build dev
|
||||
// +build dev
|
||||
|
||||
package appng
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/desktop"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/devserver"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/dispatcher"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/runtime"
|
||||
"github.com/wailsapp/wails/v2/internal/fs"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/menumanager"
|
||||
"github.com/wailsapp/wails/v2/internal/project"
|
||||
"github.com/wailsapp/wails/v2/internal/signal"
|
||||
pkglogger "github.com/wailsapp/wails/v2/pkg/logger"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// App defines a Wails application structure
|
||||
type App struct {
|
||||
frontend frontend.Frontend
|
||||
logger *logger.Logger
|
||||
signal *signal.Manager
|
||||
options *options.App
|
||||
|
||||
menuManager *menumanager.Manager
|
||||
|
||||
// Indicates if the app is in debug mode
|
||||
debug bool
|
||||
|
||||
// OnStartup/OnShutdown
|
||||
startupCallback func(ctx context.Context)
|
||||
shutdownCallback func(ctx context.Context)
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func (a *App) Run() error {
|
||||
err := a.frontend.Run(a.ctx)
|
||||
if a.shutdownCallback != nil {
|
||||
a.shutdownCallback(a.ctx)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateApp creates the app!
|
||||
func CreateApp(appoptions *options.App) (*App, error) {
|
||||
var err error
|
||||
|
||||
ctx := context.WithValue(context.Background(), "debug", true)
|
||||
|
||||
// Set up logger
|
||||
myLogger := logger.New(appoptions.Logger)
|
||||
myLogger.SetLogLevel(appoptions.LogLevel)
|
||||
|
||||
// Check for CLI Flags
|
||||
assetdir := flag.String("assetdir", "", "Directory to serve assets")
|
||||
loglevel := flag.String("loglevel", "debug", "Loglevel to use - Trace, Debug, Info, Warning, Error")
|
||||
flag.Parse()
|
||||
if assetdir != nil && *assetdir != "" {
|
||||
ctx = context.WithValue(ctx, "assetdir", *assetdir)
|
||||
}
|
||||
if loglevel != nil && *loglevel != "" {
|
||||
level, err := pkglogger.StringToLogLevel(*loglevel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
myLogger.SetLogLevel(level)
|
||||
}
|
||||
|
||||
// Attach logger to context
|
||||
ctx = context.WithValue(ctx, "logger", myLogger)
|
||||
|
||||
// Preflight checks
|
||||
err = PreflightChecks(appoptions, myLogger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Merge default options
|
||||
options.MergeDefaults(appoptions)
|
||||
|
||||
var menuManager *menumanager.Manager
|
||||
|
||||
// Process the application menu
|
||||
if appoptions.Menu != nil {
|
||||
// Create the menu manager
|
||||
menuManager = menumanager.NewManager()
|
||||
err = menuManager.SetApplicationMenu(appoptions.Menu)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Create binding exemptions - Ugly hack. There must be a better way
|
||||
bindingExemptions := []interface{}{appoptions.OnStartup, appoptions.OnShutdown, appoptions.OnDomReady}
|
||||
appBindings := binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions)
|
||||
|
||||
err = generateBindings(appBindings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
eventHandler := runtime.NewEvents(myLogger)
|
||||
ctx = context.WithValue(ctx, "events", eventHandler)
|
||||
messageDispatcher := dispatcher.NewDispatcher(myLogger, appBindings, eventHandler)
|
||||
|
||||
// Create the frontends and register to event handler
|
||||
desktopFrontend := desktop.NewFrontend(ctx, appoptions, myLogger, appBindings, messageDispatcher)
|
||||
appFrontend := devserver.NewFrontend(ctx, appoptions, myLogger, appBindings, messageDispatcher, menuManager, desktopFrontend)
|
||||
eventHandler.AddFrontend(appFrontend)
|
||||
eventHandler.AddFrontend(desktopFrontend)
|
||||
|
||||
result := &App{
|
||||
ctx: ctx,
|
||||
frontend: appFrontend,
|
||||
logger: myLogger,
|
||||
menuManager: menuManager,
|
||||
startupCallback: appoptions.OnStartup,
|
||||
shutdownCallback: appoptions.OnShutdown,
|
||||
debug: true,
|
||||
}
|
||||
|
||||
result.options = appoptions
|
||||
|
||||
return result, nil
|
||||
|
||||
}
|
||||
|
||||
func generateBindings(bindings *binding.Bindings) error {
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
projectConfig, err := project.Load(cwd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
targetDir := filepath.Join(projectConfig.WailsJSDir, "wailsjs", "go")
|
||||
err = os.RemoveAll(targetDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = fs.MkDirs(targetDir)
|
||||
modelsFile := filepath.Join(targetDir, "models.ts")
|
||||
err = bindings.WriteTS(modelsFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write backend method wrappers
|
||||
bindingsFilename := filepath.Join(targetDir, "bindings.js")
|
||||
err = bindings.GenerateBackendJS(bindingsFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
101
v2/internal/appng/app_production.go
Normal file
101
v2/internal/appng/app_production.go
Normal file
@@ -0,0 +1,101 @@
|
||||
//go:build production
|
||||
// +build production
|
||||
|
||||
package appng
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/desktop"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/dispatcher"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/runtime"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/menumanager"
|
||||
"github.com/wailsapp/wails/v2/internal/signal"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
// App defines a Wails application structure
|
||||
type App struct {
|
||||
frontend frontend.Frontend
|
||||
logger *logger.Logger
|
||||
signal *signal.Manager
|
||||
options *options.App
|
||||
|
||||
menuManager *menumanager.Manager
|
||||
|
||||
// Indicates if the app is in debug mode
|
||||
debug bool
|
||||
|
||||
// OnStartup/OnShutdown
|
||||
startupCallback func(ctx context.Context)
|
||||
shutdownCallback func(ctx context.Context)
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func (a *App) Run() error {
|
||||
err := a.frontend.Run(a.ctx)
|
||||
if a.shutdownCallback != nil {
|
||||
a.shutdownCallback(a.ctx)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateApp creates the app!
|
||||
func CreateApp(appoptions *options.App) (*App, error) {
|
||||
var err error
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Merge default options
|
||||
options.MergeDefaults(appoptions)
|
||||
|
||||
// Set up logger
|
||||
myLogger := logger.New(appoptions.Logger)
|
||||
myLogger.SetLogLevel(appoptions.LogLevel)
|
||||
|
||||
// Preflight Checks
|
||||
err = PreflightChecks(appoptions, myLogger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create the menu manager
|
||||
menuManager := menumanager.NewManager()
|
||||
|
||||
// Process the application menu
|
||||
if appoptions.Menu != nil {
|
||||
err = menuManager.SetApplicationMenu(appoptions.Menu)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Create binding exemptions - Ugly hack. There must be a better way
|
||||
bindingExemptions := []interface{}{appoptions.OnStartup, appoptions.OnShutdown, appoptions.OnDomReady}
|
||||
appBindings := binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions)
|
||||
eventHandler := runtime.NewEvents(myLogger)
|
||||
ctx = context.WithValue(ctx, "events", eventHandler)
|
||||
messageDispatcher := dispatcher.NewDispatcher(myLogger, appBindings, eventHandler)
|
||||
|
||||
appFrontend := desktop.NewFrontend(ctx, appoptions, myLogger, appBindings, messageDispatcher)
|
||||
eventHandler.AddFrontend(appFrontend)
|
||||
|
||||
result := &App{
|
||||
ctx: ctx,
|
||||
frontend: appFrontend,
|
||||
logger: myLogger,
|
||||
menuManager: menuManager,
|
||||
startupCallback: appoptions.OnStartup,
|
||||
shutdownCallback: appoptions.OnShutdown,
|
||||
debug: false,
|
||||
}
|
||||
|
||||
result.options = appoptions
|
||||
|
||||
result.ctx = context.WithValue(result.ctx, "debug", result.debug)
|
||||
|
||||
return result, nil
|
||||
|
||||
}
|
||||
27
v2/internal/appng/app_windows.go
Normal file
27
v2/internal/appng/app_windows.go
Normal file
@@ -0,0 +1,27 @@
|
||||
//go:build windows
|
||||
|
||||
package appng
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/wails/v2/internal/ffenestri/windows/wv2runtime"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
func PreflightChecks(options *options.App, logger *logger.Logger) error {
|
||||
|
||||
_ = options
|
||||
|
||||
// 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.
|
||||
installedVersion, err := wv2runtime.Process()
|
||||
if installedVersion != nil {
|
||||
logger.Debug("WebView2 Runtime installed: Name: '%s' Version:'%s' Location:'%s'. Minimum version required: %s.",
|
||||
installedVersion.Name, installedVersion.Version, installedVersion.Location, wv2runtime.MinimumRuntimeVersion)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
{
|
||||
"name": "backend",
|
||||
"name": "go",
|
||||
"version": "1.0.0",
|
||||
"description": "Package to wrap backend method calls",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"description": "Package to wrap your bound go methods",
|
||||
"main": "bindings.js",
|
||||
"types": "bindings.d.ts",
|
||||
"scripts": {},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
||||
@@ -2,12 +2,12 @@ package binding
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/tkrajina/typescriptify-golang-structs/typescriptify"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
)
|
||||
|
||||
@@ -15,15 +15,25 @@ type Bindings struct {
|
||||
db *DB
|
||||
logger logger.CustomLogger
|
||||
exemptions slicer.StringSlicer
|
||||
|
||||
// Typescript writer
|
||||
converter *typescriptify.TypeScriptify
|
||||
}
|
||||
|
||||
// NewBindings returns a new Bindings object
|
||||
func NewBindings(logger *logger.Logger, structPointersToBind []interface{}, exemptions []interface{}) *Bindings {
|
||||
result := &Bindings{
|
||||
db: newDB(),
|
||||
logger: logger.CustomLogger("Bindings"),
|
||||
db: newDB(),
|
||||
logger: logger.CustomLogger("Bindings"),
|
||||
converter: typescriptify.New(),
|
||||
}
|
||||
|
||||
// No backups
|
||||
result.converter.WithBackupDir("")
|
||||
|
||||
// Hack for TS compilation error
|
||||
result.converter.AddImport("export {};")
|
||||
|
||||
for _, exemption := range exemptions {
|
||||
if exemptions == nil {
|
||||
continue
|
||||
@@ -65,6 +75,11 @@ func (b *Bindings) Add(structPtr interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Bindings) WriteTS(filename string) error {
|
||||
println("WriteTS to:", filename)
|
||||
return b.converter.ConvertToFile(filename)
|
||||
}
|
||||
|
||||
func (b *Bindings) DB() *DB {
|
||||
return b.db
|
||||
}
|
||||
|
||||
@@ -4,20 +4,18 @@ import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"log"
|
||||
"github.com/wailsapp/wails/v2/internal/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/fs"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
)
|
||||
|
||||
//go:embed assets/package.json
|
||||
var packageJSON []byte
|
||||
|
||||
func (b *Bindings) GenerateBackendJS() {
|
||||
func (b *Bindings) GenerateBackendJS(targetfile string) error {
|
||||
|
||||
store := b.db.store
|
||||
var output bytes.Buffer
|
||||
@@ -26,7 +24,7 @@ func (b *Bindings) GenerateBackendJS() {
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
const backend = {`)
|
||||
const go = {`)
|
||||
output.WriteString("\n")
|
||||
|
||||
var sortedPackageNames slicer.StringSlicer
|
||||
@@ -84,7 +82,7 @@ const backend = {`)
|
||||
argsString := args.Join(", ")
|
||||
output.WriteString(fmt.Sprintf(" \"%s\": (%s) => {", methodName, argsString))
|
||||
output.WriteString("\n")
|
||||
output.WriteString(fmt.Sprintf(" return window.backend.%s.%s.%s(%s);", packageName, structName, methodName, argsString))
|
||||
output.WriteString(fmt.Sprintf(" return window.go.%s.%s.%s(%s);", packageName, structName, methodName, argsString))
|
||||
output.WriteString("\n")
|
||||
output.WriteString(fmt.Sprintf(" },"))
|
||||
output.WriteString("\n")
|
||||
@@ -100,35 +98,19 @@ const backend = {`)
|
||||
})
|
||||
|
||||
output.WriteString(`};
|
||||
export default backend;`)
|
||||
export default go;`)
|
||||
output.WriteString("\n")
|
||||
|
||||
// TODO: Make this configurable in wails.json
|
||||
dirname, err := fs.RelativeToCwd("frontend/src/backend")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if !fs.DirExists(dirname) {
|
||||
err := fs.MkDirs(dirname)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
packageJsonFile := filepath.Join(dirname, "package.json")
|
||||
dir := filepath.Dir(targetfile)
|
||||
packageJsonFile := filepath.Join(dir, "package.json")
|
||||
if !fs.FileExists(packageJsonFile) {
|
||||
err := os.WriteFile(packageJsonFile, packageJSON, 0755)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
filename := filepath.Join(dirname, "index.js")
|
||||
err = os.WriteFile(filename, output.Bytes(), 0755)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return os.WriteFile(targetfile, output.Bytes(), 0755)
|
||||
}
|
||||
|
||||
func goTypeToJSDocType(input string) string {
|
||||
@@ -150,6 +132,9 @@ func goTypeToJSDocType(input string) string {
|
||||
arrayType := goTypeToJSDocType(input[2:])
|
||||
return "Array.<" + arrayType + ">"
|
||||
default:
|
||||
if strings.ContainsRune(input, '.') {
|
||||
return strings.Split(input, ".")[1]
|
||||
}
|
||||
return "any"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,24 @@ func (b *Bindings) getMethods(value interface{}) ([]*BoundMethod, error) {
|
||||
for inputIndex := 0; inputIndex < inputParamCount; inputIndex++ {
|
||||
input := methodType.In(inputIndex)
|
||||
thisParam := newParameter("", input)
|
||||
|
||||
// Process struct pointer params
|
||||
if input.Kind() == reflect.Ptr {
|
||||
if input.Elem().Kind() == reflect.Struct {
|
||||
typ := input.Elem()
|
||||
a := reflect.New(typ)
|
||||
s := reflect.Indirect(a).Interface()
|
||||
b.converter.Add(s)
|
||||
}
|
||||
}
|
||||
|
||||
// Process struct params
|
||||
if input.Kind() == reflect.Struct {
|
||||
a := reflect.New(input)
|
||||
s := reflect.Indirect(a).Interface()
|
||||
b.converter.Add(s)
|
||||
}
|
||||
|
||||
inputs = append(inputs, thisParam)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/wails/v2/pkg/options/dialog"
|
||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||
)
|
||||
|
||||
type BridgeClient struct {
|
||||
@@ -27,30 +27,30 @@ func (b BridgeClient) Quit() {
|
||||
|
||||
func (b BridgeClient) NotifyEvent(message string) {
|
||||
b.session.sendMessage("n" + message)
|
||||
b.session.log.Info("NotifyEvent: %s", message)
|
||||
b.session.log.Info("Notify: %s", message)
|
||||
}
|
||||
|
||||
func (b BridgeClient) CallResult(message string) {
|
||||
b.session.sendMessage("c" + message)
|
||||
}
|
||||
|
||||
func (b BridgeClient) OpenFileDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
func (b BridgeClient) OpenFileDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) {
|
||||
// Handled by dialog_client
|
||||
}
|
||||
|
||||
func (b BridgeClient) OpenMultipleFilesDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
func (b BridgeClient) OpenMultipleFilesDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) {
|
||||
// Handled by dialog_client
|
||||
}
|
||||
|
||||
func (b BridgeClient) OpenDirectoryDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
func (b BridgeClient) OpenDirectoryDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) {
|
||||
// Handled by dialog_client
|
||||
}
|
||||
|
||||
func (b BridgeClient) SaveDialog(dialogOptions *dialog.SaveDialog, callbackID string) {
|
||||
func (b BridgeClient) SaveDialog(dialogOptions runtime.SaveDialogOptions, callbackID string) {
|
||||
// Handled by dialog_client
|
||||
}
|
||||
|
||||
func (b BridgeClient) MessageDialog(dialogOptions *dialog.MessageDialog, callbackID string) {
|
||||
func (b BridgeClient) MessageDialog(dialogOptions runtime.MessageDialogOptions, callbackID string) {
|
||||
// Handled by dialog_client
|
||||
}
|
||||
|
||||
@@ -118,8 +118,8 @@ func (b BridgeClient) DarkModeEnabled(callbackID string) {
|
||||
b.session.log.Info("DarkModeEnabled unsupported in Bridge mode")
|
||||
}
|
||||
|
||||
func (b BridgeClient) SetApplicationMenu(menuJSON string) {
|
||||
b.session.log.Info("SetApplicationMenu unsupported in Bridge mode")
|
||||
func (b BridgeClient) MenuSetApplicationMenu(menuJSON string) {
|
||||
b.session.log.Info("MenuSetApplicationMenu unsupported in Bridge mode")
|
||||
}
|
||||
|
||||
func (b BridgeClient) SetTrayMenu(trayMenuJSON string) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package bridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -11,7 +12,6 @@ import (
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/dialog"
|
||||
)
|
||||
|
||||
type DialogClient struct {
|
||||
@@ -37,17 +37,17 @@ func (d *DialogClient) NotifyEvent(message string) {
|
||||
func (d *DialogClient) CallResult(message string) {
|
||||
}
|
||||
|
||||
func (d *DialogClient) OpenDirectoryDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
func (d *DialogClient) OpenDirectoryDialog(options runtime.OpenDialogOptions, callbackID string) {
|
||||
}
|
||||
func (d *DialogClient) OpenFileDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
func (d *DialogClient) OpenFileDialog(options runtime.OpenDialogOptions, callbackID string) {
|
||||
}
|
||||
func (d *DialogClient) OpenMultipleFilesDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
func (d *DialogClient) OpenMultipleFilesDialog(options runtime.OpenDialogOptions, callbackID string) {
|
||||
}
|
||||
|
||||
func (d *DialogClient) SaveDialog(dialogOptions *dialog.SaveDialog, callbackID string) {
|
||||
func (d *DialogClient) SaveDialog(options runtime.SaveDialogOptions, callbackID string) {
|
||||
}
|
||||
|
||||
func (d *DialogClient) MessageDialog(dialogOptions *dialog.MessageDialog, callbackID string) {
|
||||
func (d *DialogClient) MessageDialog(options runtime.MessageDialogOptions, callbackID string) {
|
||||
|
||||
osa, err := exec.LookPath("osascript")
|
||||
if err != nil {
|
||||
@@ -58,23 +58,23 @@ func (d *DialogClient) MessageDialog(dialogOptions *dialog.MessageDialog, callba
|
||||
var btns slicer.StringSlicer
|
||||
defaultButton := ""
|
||||
cancelButton := ""
|
||||
for index, btn := range dialogOptions.Buttons {
|
||||
for index, btn := range options.Buttons {
|
||||
btns.Add(strconv.Quote(btn))
|
||||
if btn == dialogOptions.DefaultButton {
|
||||
if btn == options.DefaultButton {
|
||||
defaultButton = fmt.Sprintf("default button %d", index+1)
|
||||
}
|
||||
if btn == dialogOptions.CancelButton {
|
||||
if btn == options.CancelButton {
|
||||
cancelButton = fmt.Sprintf("cancel button %d", index+1)
|
||||
}
|
||||
}
|
||||
buttons := "{" + btns.Join(",") + "}"
|
||||
script := fmt.Sprintf("display dialog \"%s\" buttons %s %s %s with title \"%s\"", dialogOptions.Message, buttons, defaultButton, cancelButton, dialogOptions.Title)
|
||||
script := fmt.Sprintf("display dialog \"%s\" buttons %s %s %s with title \"%s\"", options.Message, buttons, defaultButton, cancelButton, options.Title)
|
||||
go func() {
|
||||
out, err := exec.Command(osa, "-e", script).Output()
|
||||
if err != nil {
|
||||
// Assume user has pressed cancel button
|
||||
if dialogOptions.CancelButton != "" {
|
||||
d.dispatcher.DispatchMessage("DM" + callbackID + "|" + dialogOptions.CancelButton)
|
||||
if options.CancelButton != "" {
|
||||
d.dispatcher.DispatchMessage("DM" + callbackID + "|" + options.CancelButton)
|
||||
return
|
||||
}
|
||||
d.log.Error("Dialog had bad exit code. If this was a Cancel button, add 'CancelButton' to the dialog.MessageDialog struct. Error: %s", err.Error())
|
||||
|
||||
7
v2/internal/ffenestri/README.md
Normal file
7
v2/internal/ffenestri/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## Windows
|
||||
|
||||
- Left and Right Win keys act the same
|
||||
- Accelerators will automatically add appropriate text into the menu items. This can be prevented by adding a tab
|
||||
character to the menu label
|
||||
- Tooltips + styling with font currently unsupported
|
||||
-
|
||||
@@ -46,7 +46,7 @@ extern void UpdateTrayMenuLabel(struct Application*, const char* JSON);
|
||||
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 WindowIsTranslucent(struct Application*);
|
||||
extern void* GetWindowHandle(struct Application*);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -8,11 +8,11 @@ package ffenestri
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
goruntime "runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options/dialog"
|
||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
)
|
||||
@@ -127,9 +127,9 @@ func (c *Client) WindowSetColour(colour int) {
|
||||
}
|
||||
|
||||
// OpenFileDialog will open a dialog with the given title and filter
|
||||
func (c *Client) OpenFileDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
func (c *Client) OpenFileDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) {
|
||||
filters := []string{}
|
||||
if runtime.GOOS == "darwin" {
|
||||
if goruntime.GOOS == "darwin" {
|
||||
for _, filter := range dialogOptions.Filters {
|
||||
filters = append(filters, strings.Split(filter.Pattern, ",")...)
|
||||
}
|
||||
@@ -150,11 +150,10 @@ func (c *Client) OpenFileDialog(dialogOptions *dialog.OpenDialog, callbackID str
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// OpenDirectoryDialog will open a dialog with the given title and filter
|
||||
func (c *Client) OpenDirectoryDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
func (c *Client) OpenDirectoryDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) {
|
||||
filters := []string{}
|
||||
if runtime.GOOS == "darwin" {
|
||||
if goruntime.GOOS == "darwin" {
|
||||
for _, filter := range dialogOptions.Filters {
|
||||
filters = append(filters, strings.Split(filter.Pattern, ",")...)
|
||||
}
|
||||
@@ -166,7 +165,7 @@ func (c *Client) OpenDirectoryDialog(dialogOptions *dialog.OpenDialog, callbackI
|
||||
c.app.string2CString(dialogOptions.DefaultFilename),
|
||||
c.app.string2CString(dialogOptions.DefaultDirectory),
|
||||
c.app.bool2Cint(false), // Files
|
||||
c.app.bool2Cint(true), // Directories
|
||||
c.app.bool2Cint(true), // Directories
|
||||
c.app.bool2Cint(false), // Multiple
|
||||
c.app.bool2Cint(dialogOptions.ShowHiddenFiles),
|
||||
c.app.bool2Cint(dialogOptions.CanCreateDirectories),
|
||||
@@ -176,9 +175,9 @@ func (c *Client) OpenDirectoryDialog(dialogOptions *dialog.OpenDialog, callbackI
|
||||
}
|
||||
|
||||
// OpenMultipleFilesDialog will open a dialog with the given title and filter
|
||||
func (c *Client) OpenMultipleFilesDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
func (c *Client) OpenMultipleFilesDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) {
|
||||
filters := []string{}
|
||||
if runtime.GOOS == "darwin" {
|
||||
if goruntime.GOOS == "darwin" {
|
||||
for _, filter := range dialogOptions.Filters {
|
||||
filters = append(filters, strings.Split(filter.Pattern, ",")...)
|
||||
}
|
||||
@@ -200,9 +199,9 @@ func (c *Client) OpenMultipleFilesDialog(dialogOptions *dialog.OpenDialog, callb
|
||||
}
|
||||
|
||||
// SaveDialog will open a dialog with the given title and filter
|
||||
func (c *Client) SaveDialog(dialogOptions *dialog.SaveDialog, callbackID string) {
|
||||
func (c *Client) SaveDialog(dialogOptions *runtime.SaveDialogOptions, callbackID string) {
|
||||
filters := []string{}
|
||||
if runtime.GOOS == "darwin" {
|
||||
if goruntime.GOOS == "darwin" {
|
||||
for _, filter := range dialogOptions.Filters {
|
||||
filters = append(filters, strings.Split(filter.Pattern, ",")...)
|
||||
}
|
||||
@@ -220,7 +219,7 @@ func (c *Client) SaveDialog(dialogOptions *dialog.SaveDialog, callbackID string)
|
||||
}
|
||||
|
||||
// MessageDialog will open a message dialog with the given options
|
||||
func (c *Client) MessageDialog(dialogOptions *dialog.MessageDialog, callbackID string) {
|
||||
func (c *Client) MessageDialog(dialogOptions runtime.MessageDialogOptions, callbackID string) {
|
||||
|
||||
// Sanity check button length
|
||||
if len(dialogOptions.Buttons) > 4 {
|
||||
|
||||
@@ -10,13 +10,12 @@ import "C"
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/leaanthony/go-common-file-dialog/cfd"
|
||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||
"golang.org/x/sys/windows"
|
||||
"log"
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options/dialog"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
)
|
||||
|
||||
@@ -131,7 +130,7 @@ func (c *Client) WindowSetColour(colour int) {
|
||||
C.SetColour(c.app.app, r, g, b, a)
|
||||
}
|
||||
|
||||
func convertFilters(filters []dialog.FileFilter) []cfd.FileFilter {
|
||||
func convertFilters(filters []runtime.FileFilter) []cfd.FileFilter {
|
||||
var result []cfd.FileFilter
|
||||
for _, filter := range filters {
|
||||
result = append(result, cfd.FileFilter(filter))
|
||||
@@ -140,7 +139,7 @@ func convertFilters(filters []dialog.FileFilter) []cfd.FileFilter {
|
||||
}
|
||||
|
||||
// OpenFileDialog will open a dialog with the given title and filter
|
||||
func (c *Client) OpenFileDialog(options *dialog.OpenDialog, callbackID string) {
|
||||
func (c *Client) OpenFileDialog(options runtime.OpenDialogOptions, callbackID string) {
|
||||
config := cfd.DialogConfig{
|
||||
Folder: options.DefaultDirectory,
|
||||
FileFilters: convertFilters(options.Filters),
|
||||
@@ -166,7 +165,7 @@ func (c *Client) OpenFileDialog(options *dialog.OpenDialog, callbackID string) {
|
||||
}
|
||||
|
||||
// OpenDirectoryDialog will open a dialog with the given title and filter
|
||||
func (c *Client) OpenDirectoryDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
func (c *Client) OpenDirectoryDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) {
|
||||
config := cfd.DialogConfig{
|
||||
Title: dialogOptions.Title,
|
||||
Role: "PickFolder",
|
||||
@@ -191,7 +190,7 @@ func (c *Client) OpenDirectoryDialog(dialogOptions *dialog.OpenDialog, callbackI
|
||||
}
|
||||
|
||||
// OpenMultipleFilesDialog will open a dialog with the given title and filter
|
||||
func (c *Client) OpenMultipleFilesDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
func (c *Client) OpenMultipleFilesDialog(dialogOptions runtime.OpenDialogOptions, callbackID string) {
|
||||
config := cfd.DialogConfig{
|
||||
Title: dialogOptions.Title,
|
||||
Role: "OpenMultipleFiles",
|
||||
@@ -222,7 +221,7 @@ func (c *Client) OpenMultipleFilesDialog(dialogOptions *dialog.OpenDialog, callb
|
||||
}
|
||||
|
||||
// SaveDialog will open a dialog with the given title and filter
|
||||
func (c *Client) SaveDialog(dialogOptions *dialog.SaveDialog, callbackID string) {
|
||||
func (c *Client) SaveDialog(dialogOptions runtime.SaveDialogOptions, callbackID string) {
|
||||
saveDialog, err := cfd.NewSaveFileDialog(cfd.DialogConfig{
|
||||
Title: dialogOptions.Title,
|
||||
Role: "SaveFile",
|
||||
@@ -246,7 +245,7 @@ func (c *Client) SaveDialog(dialogOptions *dialog.SaveDialog, callbackID string)
|
||||
}
|
||||
|
||||
// MessageDialog will open a message dialog with the given options
|
||||
func (c *Client) MessageDialog(options *dialog.MessageDialog, callbackID string) {
|
||||
func (c *Client) MessageDialog(options runtime.MessageDialogOptions, callbackID string) {
|
||||
|
||||
title, err := syscall.UTF16PtrFromString(options.Title)
|
||||
if err != nil {
|
||||
@@ -258,13 +257,13 @@ func (c *Client) MessageDialog(options *dialog.MessageDialog, callbackID string)
|
||||
}
|
||||
var flags uint32
|
||||
switch options.Type {
|
||||
case dialog.InfoDialog:
|
||||
case runtime.InfoDialog:
|
||||
flags = windows.MB_OK | windows.MB_ICONINFORMATION
|
||||
case dialog.ErrorDialog:
|
||||
case runtime.ErrorDialog:
|
||||
flags = windows.MB_ICONERROR | windows.MB_OK
|
||||
case dialog.QuestionDialog:
|
||||
case runtime.QuestionDialog:
|
||||
flags = windows.MB_YESNO
|
||||
case dialog.WarningDialog:
|
||||
case runtime.WarningDialog:
|
||||
flags = windows.MB_OK | windows.MB_ICONWARNING
|
||||
}
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ struct Application {
|
||||
int fullSizeContent;
|
||||
int useToolBar;
|
||||
int hideToolbarSeparator;
|
||||
int windowBackgroundIsTranslucent;
|
||||
int WindowIsTranslucent;
|
||||
int hasURLHandlers;
|
||||
const char *startupURL;
|
||||
|
||||
@@ -293,8 +293,8 @@ void Show(struct Application *app) {
|
||||
);
|
||||
}
|
||||
|
||||
void WindowBackgroundIsTranslucent(struct Application *app) {
|
||||
app->windowBackgroundIsTranslucent = 1;
|
||||
void WindowIsTranslucent(struct Application *app) {
|
||||
app->WindowIsTranslucent = 1;
|
||||
}
|
||||
|
||||
// Sends messages to the backend
|
||||
@@ -1534,7 +1534,7 @@ void Run(struct Application *app, int argc, char **argv) {
|
||||
applyWindowColour(app);
|
||||
|
||||
// Process translucency
|
||||
if (app->windowBackgroundIsTranslucent) {
|
||||
if (app->WindowIsTranslucent) {
|
||||
makeWindowBackgroundTranslucent(app);
|
||||
}
|
||||
|
||||
@@ -1775,7 +1775,7 @@ void* NewApplication(const char *title, int width, int height, int resizable, in
|
||||
result->useToolBar = 0;
|
||||
result->hideToolbarSeparator = 0;
|
||||
result->appearance = NULL;
|
||||
result->windowBackgroundIsTranslucent = 0;
|
||||
result->WindowIsTranslucent = 0;
|
||||
|
||||
// Window data
|
||||
result->delegate = NULL;
|
||||
|
||||
@@ -57,8 +57,8 @@ func (a *Application) processPlatformSettings() error {
|
||||
}
|
||||
|
||||
// Check if window should be translucent
|
||||
if mac.WindowBackgroundIsTranslucent {
|
||||
C.WindowBackgroundIsTranslucent(a.app)
|
||||
if mac.WindowIsTranslucent {
|
||||
C.WindowIsTranslucent(a.app)
|
||||
}
|
||||
|
||||
// Process menu
|
||||
|
||||
@@ -138,7 +138,7 @@ void HideToolbarSeparator(struct Application* app);
|
||||
void DisableFrame(struct Application* app);
|
||||
void SetAppearance(struct Application* app, const char *);
|
||||
void WebviewIsTransparent(struct Application* app);
|
||||
void WindowBackgroundIsTranslucent(struct Application* app);
|
||||
void WindowIsTranslucent(struct Application* app);
|
||||
void SetTray(struct Application* app, const char *, const char *, const char *);
|
||||
//void SetContextMenus(struct Application* app, const char *);
|
||||
void AddTrayMenu(struct Application* app, const char *);
|
||||
|
||||
@@ -862,7 +862,7 @@ 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 WindowIsTranslucent(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) {}
|
||||
|
||||
@@ -28,6 +28,25 @@ void dispatch(dispatchFunction func) {
|
||||
PostThreadMessage(mainThread, WM_APP, 0, (LPARAM) new dispatchFunction(func));
|
||||
}
|
||||
|
||||
void processKeyPress(UINT key) {
|
||||
// Get state of Control
|
||||
bool controlPressed = GetKeyState(VK_CONTROL) >> 15 != 0;
|
||||
bool altPressed = GetKeyState(VK_MENU) >> 15 != 0;
|
||||
bool shiftPressed = GetKeyState(VK_SHIFT) >> 15 != 0;
|
||||
|
||||
// Save the modifier keys
|
||||
BYTE modState = 0;
|
||||
if ( GetKeyState(VK_CONTROL) >> 15 != 0 ) { modState |= 1; }
|
||||
if ( GetKeyState(VK_MENU) >> 15 != 0 ) { modState |= 2; }
|
||||
if ( GetKeyState(VK_SHIFT) >> 15 != 0 ) { modState |= 4; }
|
||||
if ( GetKeyState(VK_LWIN) >> 15 != 0 ) { modState |= 8; }
|
||||
if ( GetKeyState(VK_RWIN) >> 15 != 0 ) { modState |= 8; }
|
||||
|
||||
// Notify app of keypress
|
||||
handleKeypressInGo(key, modState);
|
||||
}
|
||||
|
||||
|
||||
LPWSTR cstrToLPWSTR(const char *cstr) {
|
||||
int wchars_num = MultiByteToWideChar( CP_UTF8 , 0 , cstr , -1, NULL , 0 );
|
||||
wchar_t* wstr = new wchar_t[wchars_num+1];
|
||||
@@ -86,7 +105,7 @@ struct Application *NewApplication(const char *title, int width, int height, int
|
||||
result->logLevel = logLevel;
|
||||
result->hideWindowOnClose = hideWindowOnClose;
|
||||
result->webviewIsTranparent = false;
|
||||
result->windowBackgroundIsTranslucent = false;
|
||||
result->WindowIsTranslucent = false;
|
||||
result->disableWindowIcon = false;
|
||||
|
||||
// Min/Max Width/Height
|
||||
@@ -201,6 +220,11 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_KEYDOWN:
|
||||
// This is needed because webview2 is sometimes not in focus
|
||||
// https://github.com/MicrosoftEdge/WebView2Feedback/issues/1541
|
||||
processKeyPress(wParam);
|
||||
break;
|
||||
case WM_GETMINMAXINFO: {
|
||||
// Exit early if this is called before the window is created.
|
||||
if ( app == NULL ) {
|
||||
@@ -364,6 +388,7 @@ bool initWebView2(struct Application *app, int debugEnabled, messageCallback cb)
|
||||
}
|
||||
// Fix for invisible webview
|
||||
if( app->startHidden ) {}
|
||||
controller->MoveFocus(COREWEBVIEW2_MOVE_FOCUS_REASON_PROGRAMMATIC);
|
||||
flag.clear();
|
||||
}));
|
||||
if (!SUCCEEDED(res))
|
||||
@@ -440,7 +465,7 @@ bool initWebView2(struct Application *app, int debugEnabled, messageCallback cb)
|
||||
wvColor.G = app->backgroundColour.G;
|
||||
wvColor.B = app->backgroundColour.B;
|
||||
wvColor.A = app->backgroundColour.A == 0 ? 0 : 255;
|
||||
if( app->windowBackgroundIsTranslucent ) {
|
||||
if( app->WindowIsTranslucent ) {
|
||||
wvColor.A = 0;
|
||||
}
|
||||
HRESULT result = wc2->put_DefaultBackgroundColor(wvColor);
|
||||
@@ -513,7 +538,7 @@ void Run(struct Application* app, int argc, char **argv) {
|
||||
|
||||
// Configure translucency
|
||||
DWORD dwExStyle = 0;
|
||||
if ( app->windowBackgroundIsTranslucent) {
|
||||
if ( app->WindowIsTranslucent) {
|
||||
dwExStyle = WS_EX_NOREDIRECTIONBITMAP;
|
||||
wc.hbrBackground = CreateSolidBrush(RGB(255,255,255));
|
||||
}
|
||||
@@ -565,7 +590,7 @@ void Run(struct Application* app, int argc, char **argv) {
|
||||
SetWindowPos(nullptr, nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
|
||||
}
|
||||
|
||||
if ( app->windowBackgroundIsTranslucent ) {
|
||||
if ( app->WindowIsTranslucent ) {
|
||||
|
||||
// Enable the translucent background effect
|
||||
enableTranslucentBackground(app);
|
||||
@@ -852,8 +877,8 @@ void WebviewIsTransparent(struct Application *app) {
|
||||
app->webviewIsTranparent = true;
|
||||
}
|
||||
|
||||
void WindowBackgroundIsTranslucent(struct Application *app) {
|
||||
app->windowBackgroundIsTranslucent = true;
|
||||
void WindowIsTranslucent(struct Application *app) {
|
||||
app->WindowIsTranslucent = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -47,8 +47,8 @@ func (a *Application) processPlatformSettings() error {
|
||||
C.WebviewIsTransparent(a.app)
|
||||
}
|
||||
|
||||
if config.WindowBackgroundIsTranslucent {
|
||||
C.WindowBackgroundIsTranslucent(a.app)
|
||||
if config.WindowIsTranslucent {
|
||||
C.WindowIsTranslucent(a.app)
|
||||
}
|
||||
|
||||
if config.DisableWindowIcon {
|
||||
@@ -134,6 +134,19 @@ func createApplicationMenu(hwnd uintptr) {
|
||||
checkFatal(err)
|
||||
}
|
||||
|
||||
//export handleKeypressInGo
|
||||
func handleKeypressInGo(keycode uint16, modifiers uint8) {
|
||||
//fmt.Printf("Key code: %#x\n", keycode)
|
||||
menuID, menuType := getCallbackForKeyPress(keycode, modifiers)
|
||||
if menuID == "" {
|
||||
return
|
||||
}
|
||||
err := menuManager.ProcessClick(menuID, "", string(menuType), "")
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
This method is called by C when a menu item is pressed
|
||||
*/
|
||||
|
||||
@@ -43,7 +43,7 @@ struct Application{
|
||||
int frame;
|
||||
char *startupURL;
|
||||
bool webviewIsTranparent;
|
||||
bool windowBackgroundIsTranslucent;
|
||||
bool WindowIsTranslucent;
|
||||
COREWEBVIEW2_COLOR backgroundColour;
|
||||
bool disableWindowIcon;
|
||||
|
||||
@@ -79,6 +79,9 @@ void loadAssets(struct Application* app);
|
||||
// called when the application assets have been loaded into the DOM
|
||||
void completed(struct Application* app);
|
||||
|
||||
// Processes the given keycode
|
||||
void processKeyPress(UINT key);
|
||||
|
||||
// Callback
|
||||
extern "C" {
|
||||
void DisableWindowIcon(struct Application* app);
|
||||
@@ -86,6 +89,7 @@ extern "C" {
|
||||
void* GetWindowHandle(struct Application*);
|
||||
void createApplicationMenu(HWND hwnd);
|
||||
void menuClicked(UINT id);
|
||||
void handleKeypressInGo(UINT, BYTE);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,7 @@
|
||||
package wv2runtime
|
||||
|
||||
import (
|
||||
"github.com/leaanthony/go-webview2/webviewloader"
|
||||
"github.com/leaanthony/webview2runtime"
|
||||
)
|
||||
|
||||
@@ -19,11 +20,11 @@ func Process() (*webview2runtime.Info, error) {
|
||||
installedVersion := webview2runtime.GetInstalledVersion()
|
||||
if installedVersion != nil {
|
||||
installStatus = installed
|
||||
updateRequired, err := installedVersion.IsOlderThan(MinimumRuntimeVersion)
|
||||
compareResult, err := webviewloader.CompareBrowserVersions(installedVersion.Version, MinimumRuntimeVersion)
|
||||
if err != nil {
|
||||
_ = webview2runtime.Error(err.Error(), "Error")
|
||||
return installedVersion, err
|
||||
return nil, err
|
||||
}
|
||||
updateRequired := compareResult == -1
|
||||
// Installed and does not require updating
|
||||
if !updateRequired {
|
||||
return installedVersion, nil
|
||||
|
||||
@@ -3,8 +3,12 @@
|
||||
package ffenestri
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/wailsapp/wails/v2/internal/menumanager"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu/keys"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//-------------------- Types ------------------------
|
||||
@@ -83,8 +87,11 @@ func (m *Menu) processMenuItem(parent win32Menu, menuItem *menumanager.Processed
|
||||
}
|
||||
case menu.TextType, menu.CheckboxType, menu.RadioType:
|
||||
win32ID := addMenuCacheEntry(parent, m.menuType, menuItem, m.wailsMenu.Menu)
|
||||
//label := fmt.Sprintf("%s (%d)", menuItem.Label, win32ID)
|
||||
if menuItem.Accelerator != nil {
|
||||
m.processAccelerator(menuItem)
|
||||
}
|
||||
label := menuItem.Label
|
||||
//label := fmt.Sprintf("%s (%d)", menuItem.Label, win32ID)
|
||||
err := appendWin32MenuItem(parent, flags, uintptr(win32ID), label)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -164,10 +171,44 @@ func (m *Menu) Destroy() error {
|
||||
|
||||
globalRadioGroupMap.removeMenuFromRadioGroupMapping(m.wailsMenu.Menu)
|
||||
|
||||
// Free up callbacks
|
||||
resetCallbacks()
|
||||
|
||||
// Delete menu
|
||||
return destroyWin32Menu(m.menu)
|
||||
}
|
||||
|
||||
func (m *Menu) processAccelerator(menuitem *menumanager.ProcessedMenuItem) {
|
||||
|
||||
// Add in shortcut to label if there is no "\t" override
|
||||
if !strings.Contains(menuitem.Label, "\t") {
|
||||
menuitem.Label += "\t" + keys.Stringify(menuitem.Accelerator, runtime.GOOS)
|
||||
}
|
||||
|
||||
// Calculate the modifier
|
||||
var modifiers uint8
|
||||
for _, mod := range menuitem.Accelerator.Modifiers {
|
||||
switch mod {
|
||||
case keys.ControlKey, keys.CmdOrCtrlKey:
|
||||
modifiers |= 1
|
||||
case keys.OptionOrAltKey:
|
||||
modifiers |= 2
|
||||
case keys.ShiftKey:
|
||||
modifiers |= 4
|
||||
//case keys.SuperKey:
|
||||
// modifiers |= 8
|
||||
}
|
||||
}
|
||||
|
||||
var keycode = calculateKeycode(strings.ToLower(menuitem.Accelerator.Key))
|
||||
if keycode == 0 {
|
||||
fmt.Printf("WARNING: Key '%s' is unsupported in windows. Cannot bind callback.", menuitem.Accelerator.Key)
|
||||
return
|
||||
}
|
||||
addMenuCallback(keycode, modifiers, menuitem.ID, m.menuType)
|
||||
|
||||
}
|
||||
|
||||
var flagMap = map[menu.Type]uint32{
|
||||
menu.TextType: MF_STRING,
|
||||
menu.SeparatorType: MF_SEPARATOR,
|
||||
|
||||
126
v2/internal/ffenestri/windows_menu_callbacks.go
Normal file
126
v2/internal/ffenestri/windows_menu_callbacks.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package ffenestri
|
||||
|
||||
type callbackData struct {
|
||||
menuID string
|
||||
menuType menuType
|
||||
}
|
||||
|
||||
var callbacks = map[uint16]map[uint8]callbackData{}
|
||||
|
||||
func addMenuCallback(key uint16, modifiers uint8, menuID string, menutype menuType) {
|
||||
|
||||
if callbacks[key] == nil {
|
||||
callbacks[key] = make(map[uint8]callbackData)
|
||||
}
|
||||
callbacks[key][modifiers] = callbackData{
|
||||
menuID: menuID,
|
||||
menuType: menutype,
|
||||
}
|
||||
}
|
||||
|
||||
func resetCallbacks() {
|
||||
callbacks = map[uint16]map[uint8]callbackData{}
|
||||
}
|
||||
|
||||
func getCallbackForKeyPress(key uint16, modifiers uint8) (string, menuType) {
|
||||
if callbacks[key] == nil {
|
||||
return "", ""
|
||||
}
|
||||
result := callbacks[key][modifiers]
|
||||
return result.menuID, result.menuType
|
||||
}
|
||||
|
||||
func calculateKeycode(key string) uint16 {
|
||||
return keymap[key]
|
||||
}
|
||||
|
||||
// TODO: Complete this list
|
||||
var keymap = map[string]uint16{
|
||||
"0": 0x30,
|
||||
"1": 0x31,
|
||||
"2": 0x32,
|
||||
"3": 0x33,
|
||||
"4": 0x34,
|
||||
"5": 0x35,
|
||||
"6": 0x36,
|
||||
"7": 0x37,
|
||||
"8": 0x38,
|
||||
"9": 0x39,
|
||||
"a": 0x41,
|
||||
"b": 0x42,
|
||||
"c": 0x43,
|
||||
"d": 0x44,
|
||||
"e": 0x45,
|
||||
"f": 0x46,
|
||||
"g": 0x47,
|
||||
"h": 0x48,
|
||||
"i": 0x49,
|
||||
"j": 0x4A,
|
||||
"k": 0x4B,
|
||||
"l": 0x4C,
|
||||
"m": 0x4D,
|
||||
"n": 0x4E,
|
||||
"o": 0x4F,
|
||||
"p": 0x50,
|
||||
"q": 0x51,
|
||||
"r": 0x52,
|
||||
"s": 0x53,
|
||||
"t": 0x54,
|
||||
"u": 0x55,
|
||||
"v": 0x56,
|
||||
"w": 0x57,
|
||||
"x": 0x58,
|
||||
"y": 0x59,
|
||||
"z": 0x5A,
|
||||
"backspace": 0x08,
|
||||
"tab": 0x09,
|
||||
"return": 0x0D,
|
||||
"enter": 0x0D,
|
||||
"escape": 0x1B,
|
||||
"left": 0x25,
|
||||
"right": 0x27,
|
||||
"up": 0x26,
|
||||
"down": 0x28,
|
||||
"space": 0x20,
|
||||
"delete": 0x2E,
|
||||
"home": 0x24,
|
||||
"end": 0x23,
|
||||
"page up": 0x21,
|
||||
"page down": 0x22,
|
||||
"f1": 0x70,
|
||||
"f2": 0x71,
|
||||
"f3": 0x72,
|
||||
"f4": 0x73,
|
||||
"f5": 0x74,
|
||||
"f6": 0x75,
|
||||
"f7": 0x76,
|
||||
"f8": 0x77,
|
||||
"f9": 0x78,
|
||||
"f10": 0x79,
|
||||
"f11": 0x7A,
|
||||
"f12": 0x7B,
|
||||
"f13": 0x7C,
|
||||
"f14": 0x7D,
|
||||
"f15": 0x7E,
|
||||
"f16": 0x7F,
|
||||
"f17": 0x80,
|
||||
"f18": 0x81,
|
||||
"f19": 0x82,
|
||||
"f20": 0x83,
|
||||
"f21": 0x84,
|
||||
"f22": 0x85,
|
||||
"f23": 0x86,
|
||||
"f24": 0x87,
|
||||
// Windows doesn't have these apparently so use 0 for unsupported
|
||||
"f25": 0,
|
||||
"f26": 0,
|
||||
"f27": 0,
|
||||
"f28": 0,
|
||||
"f29": 0,
|
||||
"f30": 0,
|
||||
"f31": 0,
|
||||
"f32": 0,
|
||||
"f33": 0,
|
||||
"f34": 0,
|
||||
"f35": 0,
|
||||
}
|
||||
@@ -20,8 +20,9 @@ var (
|
||||
win32CheckMenuItem = user32.NewProc("CheckMenuItem")
|
||||
win32GetMenuState = user32.NewProc("GetMenuState")
|
||||
win32CheckMenuRadioItem = user32.NewProc("CheckMenuRadioItem")
|
||||
applicationMenu *menumanager.WailsMenu
|
||||
menuManager *menumanager.Manager
|
||||
|
||||
applicationMenu *menumanager.WailsMenu
|
||||
menuManager *menumanager.Manager
|
||||
)
|
||||
|
||||
const MF_BITMAP uint32 = 0x00000004
|
||||
|
||||
@@ -55,33 +55,22 @@ class wv2ComHandler
|
||||
|
||||
// This is our keyboard callback method
|
||||
HRESULT STDMETHODCALLTYPE Invoke(ICoreWebView2Controller *controller, ICoreWebView2AcceleratorKeyPressedEventArgs * args) {
|
||||
// Prevent WebView2 from processing the key
|
||||
args->put_Handled(TRUE);
|
||||
|
||||
COREWEBVIEW2_KEY_EVENT_KIND kind;
|
||||
args->get_KeyEventKind(&kind);
|
||||
if (kind == COREWEBVIEW2_KEY_EVENT_KIND_KEY_DOWN ||
|
||||
kind == COREWEBVIEW2_KEY_EVENT_KIND_SYSTEM_KEY_DOWN)
|
||||
{
|
||||
// UINT key;
|
||||
// args->get_VirtualKey(&key);
|
||||
// printf("Got key: %d\n", key);
|
||||
args->put_Handled(TRUE);
|
||||
// Check if the key is one we want to handle.
|
||||
// if (std::function<void()> action =
|
||||
// m_appWindow->GetAcceleratorKeyFunction(key))
|
||||
// {
|
||||
// // Keep the browser from handling this key, whether it's autorepeated or
|
||||
// // not.
|
||||
// CHECK_FAILURE(args->put_Handled(TRUE));
|
||||
//
|
||||
// // Filter out autorepeated keys.
|
||||
// COREWEBVIEW2_PHYSICAL_KEY_STATUS status;
|
||||
// CHECK_FAILURE(args->get_PhysicalKeyStatus(&status));
|
||||
// if (!status.WasKeyDown)
|
||||
// {
|
||||
// // Perform the action asynchronously to avoid blocking the
|
||||
// // browser process's event queue.
|
||||
// m_appWindow->RunAsync(action);
|
||||
// }
|
||||
// }
|
||||
UINT key;
|
||||
args->get_VirtualKey(&key);
|
||||
COREWEBVIEW2_PHYSICAL_KEY_STATUS status;
|
||||
args->get_PhysicalKeyStatus(&status);
|
||||
if (!status.WasKeyDown)
|
||||
{
|
||||
processKeyPress(key);
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
142
v2/internal/frontend/assetserver/assetserver_desktop.go
Normal file
142
v2/internal/frontend/assetserver/assetserver_desktop.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"embed"
|
||||
"fmt"
|
||||
"github.com/leaanthony/debme"
|
||||
"github.com/leaanthony/slicer"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/runtime"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type DesktopAssetServer struct {
|
||||
assets debme.Debme
|
||||
indexFile []byte
|
||||
runtimeJS []byte
|
||||
assetdir string
|
||||
logger *logger.Logger
|
||||
}
|
||||
|
||||
func NewDesktopAssetServer(ctx context.Context, assets embed.FS, bindingsJSON string) (*DesktopAssetServer, error) {
|
||||
result := &DesktopAssetServer{}
|
||||
|
||||
_logger := ctx.Value("logger")
|
||||
if _logger != nil {
|
||||
result.logger = _logger.(*logger.Logger)
|
||||
}
|
||||
|
||||
_assetdir := ctx.Value("assetdir")
|
||||
if _assetdir != nil {
|
||||
result.assetdir = _assetdir.(string)
|
||||
absdir, err := filepath.Abs(result.assetdir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.LogInfo("Loading assets from: %s", absdir)
|
||||
}
|
||||
|
||||
var buffer bytes.Buffer
|
||||
buffer.WriteString(`window.wailsbindings='` + bindingsJSON + `';` + "\n")
|
||||
buffer.Write(runtime.RuntimeDesktopJS)
|
||||
result.runtimeJS = buffer.Bytes()
|
||||
err := result.init(assets)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (d *DesktopAssetServer) LogInfo(message string, args ...interface{}) {
|
||||
if d.logger != nil {
|
||||
d.logger.Info("[DesktopAssetServer] "+message, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DesktopAssetServer) SetAssetDir(assetdir string) {
|
||||
d.assetdir = assetdir
|
||||
}
|
||||
|
||||
func PathToIndexHTML(assets embed.FS) (string, error) {
|
||||
stat, err := fs.Stat(assets, "index.html")
|
||||
if stat != nil {
|
||||
return ".", nil
|
||||
}
|
||||
var indexFiles slicer.StringSlicer
|
||||
err = fs.WalkDir(assets, ".", func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.HasSuffix(path, "index.html") {
|
||||
indexFiles.Add(path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if indexFiles.Length() > 1 {
|
||||
return "", fmt.Errorf("multiple 'index.html' files found in assets")
|
||||
}
|
||||
|
||||
path, _ := filepath.Split(indexFiles.AsSlice()[0])
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func processAssets(assets embed.FS) (debme.Debme, error) {
|
||||
|
||||
result, err := debme.FS(assets, ".")
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
// Find index.html
|
||||
path, err := PathToIndexHTML(assets)
|
||||
if err != nil {
|
||||
return debme.Debme{}, err
|
||||
}
|
||||
return debme.FS(assets, path)
|
||||
}
|
||||
|
||||
func (a *DesktopAssetServer) init(assets embed.FS) error {
|
||||
|
||||
var err error
|
||||
a.assets, err = processAssets(assets)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
indexHTML, err := a.assets.ReadFile("index.html")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.indexFile, err = injectHTML(string(indexHTML), `<script src="/wails/runtime.js"></script>`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.indexFile, err = injectHTML(string(a.indexFile), `<script src="/wails/ipc.js"></script>`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *DesktopAssetServer) Load(filename string) ([]byte, string, error) {
|
||||
var content []byte
|
||||
var err error
|
||||
switch filename {
|
||||
case "/":
|
||||
content = a.indexFile
|
||||
case "/wails/runtime.js":
|
||||
content = a.runtimeJS
|
||||
case "/wails/ipc.js":
|
||||
content = runtime.DesktopIPC
|
||||
default:
|
||||
content, err = a.ReadFile(filename)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
mimeType := GetMimetype(filename, content)
|
||||
return content, mimeType, nil
|
||||
}
|
||||
13
v2/internal/frontend/assetserver/assetserver_desktop_dev.go
Normal file
13
v2/internal/frontend/assetserver/assetserver_desktop_dev.go
Normal file
@@ -0,0 +1,13 @@
|
||||
//go:build dev
|
||||
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func (a *DesktopAssetServer) ReadFile(filename string) ([]byte, error) {
|
||||
a.LogInfo("Loading file from disk: %s", filename)
|
||||
return os.ReadFile(filepath.Join(a.assetdir, filename))
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
//go:build production
|
||||
|
||||
package assetserver
|
||||
|
||||
func (a *DesktopAssetServer) ReadFile(filename string) ([]byte, error) {
|
||||
return a.assets.ReadFile(filename)
|
||||
}
|
||||
93
v2/internal/frontend/assetserver/assetserver_dev.go
Normal file
93
v2/internal/frontend/assetserver/assetserver_dev.go
Normal file
@@ -0,0 +1,93 @@
|
||||
//go:build dev
|
||||
// +build dev
|
||||
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/runtime"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
The assetserver for dev serves assets from disk.
|
||||
It injects a websocket based IPC script into `index.html`.
|
||||
|
||||
*/
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
type AssetServer struct {
|
||||
indexFile []byte
|
||||
runtimeJS []byte
|
||||
assetdir string
|
||||
appOptions *options.App
|
||||
}
|
||||
|
||||
func NewAssetServer(assetdir string, bindingsJSON string, appOptions *options.App) (*AssetServer, error) {
|
||||
result := &AssetServer{
|
||||
assetdir: assetdir,
|
||||
appOptions: appOptions,
|
||||
}
|
||||
|
||||
err := result.init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var buffer bytes.Buffer
|
||||
buffer.WriteString(`window.wailsbindings='` + bindingsJSON + `';` + "\n")
|
||||
buffer.Write(runtime.RuntimeDesktopJS)
|
||||
result.runtimeJS = buffer.Bytes()
|
||||
err = result.init()
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (a *AssetServer) loadFileFromDisk(filename string) ([]byte, error) {
|
||||
return os.ReadFile(filepath.Join(a.assetdir, filename))
|
||||
}
|
||||
|
||||
func (a *AssetServer) init() error {
|
||||
var err error
|
||||
a.indexFile, err = a.loadFileFromDisk("index.html")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.indexFile, err = injectHTML(string(a.indexFile), `<div id="wails-spinner"></div>`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.indexFile, err = injectHTML(string(a.indexFile), `<script src="/wails/ipc.js"></script>`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.indexFile, err = injectHTML(string(a.indexFile), `<script src="/wails/runtime.js"></script>`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AssetServer) Load(filename string) ([]byte, string, error) {
|
||||
var content []byte
|
||||
var err error
|
||||
switch filename {
|
||||
case "/":
|
||||
content = a.indexFile
|
||||
case "/wails/runtime.js":
|
||||
content = a.runtimeJS
|
||||
case "/wails/ipc.js":
|
||||
content = runtime.WebsocketIPC
|
||||
default:
|
||||
content, err = a.loadFileFromDisk(filename)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
mimeType := GetMimetype(filename, content)
|
||||
return content, mimeType, nil
|
||||
}
|
||||
21
v2/internal/frontend/assetserver/common.go
Normal file
21
v2/internal/frontend/assetserver/common.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func injectHTML(input string, html string) ([]byte, error) {
|
||||
splits := strings.Split(input, "</body>")
|
||||
if len(splits) != 2 {
|
||||
return nil, fmt.Errorf("unable to locate a </body> tag in your html")
|
||||
}
|
||||
|
||||
var result bytes.Buffer
|
||||
result.WriteString(splits[0])
|
||||
result.WriteString(html)
|
||||
result.WriteString("</body>")
|
||||
result.WriteString(splits[1])
|
||||
return result.Bytes(), nil
|
||||
}
|
||||
42
v2/internal/frontend/assetserver/mimecache.go
Normal file
42
v2/internal/frontend/assetserver/mimecache.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
import "github.com/gabriel-vasile/mimetype"
|
||||
|
||||
var (
|
||||
cache = map[string]string{}
|
||||
mutex sync.Mutex
|
||||
)
|
||||
|
||||
func GetMimetype(filename string, data []byte) string {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
result := cache[filename]
|
||||
if result != "" {
|
||||
return result
|
||||
}
|
||||
|
||||
detect := mimetype.Detect(data)
|
||||
if detect == nil {
|
||||
result = http.DetectContentType(data)
|
||||
} else {
|
||||
result = detect.String()
|
||||
}
|
||||
|
||||
if filepath.Ext(filename) == ".css" && strings.HasPrefix(result, "text/plain") {
|
||||
result = strings.Replace(result, "text/plain", "text/css", 1)
|
||||
}
|
||||
|
||||
if result == "" {
|
||||
result = "application/octet-stream"
|
||||
}
|
||||
|
||||
cache[filename] = result
|
||||
return result
|
||||
}
|
||||
25
v2/internal/frontend/assetserver/mimecache_test.go
Normal file
25
v2/internal/frontend/assetserver/mimecache_test.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package assetserver
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestGetMimetype(t *testing.T) {
|
||||
type args struct {
|
||||
filename string
|
||||
data []byte
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
{"css", args{"test.css", []byte("body{margin:0;padding:0;background-color:#d579b2}#app{font-family:Avenir,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-align:center;color:#2c3e50;background-color:#ededed}#nav{padding:30px}#nav a{font-weight:700;color:#2c\n3e50}#nav a.router-link-exact-active{color:#42b983}.hello[data-v-4e26ad49]{margin:10px 0}")}, "text/css; charset=utf-8"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := GetMimetype(tt.args.filename, tt.args.data); got != tt.want {
|
||||
t.Errorf("GetMimetype() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
8
v2/internal/frontend/assetserver/testdata/index.html
vendored
Normal file
8
v2/internal/frontend/assetserver/testdata/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="/main.css" rel="stylesheet">
|
||||
</head>
|
||||
<body data-wails-drag>
|
||||
<div id="logo"></div>
|
||||
</body>
|
||||
</html>
|
||||
39
v2/internal/frontend/assetserver/testdata/main.css
vendored
Normal file
39
v2/internal/frontend/assetserver/testdata/main.css
vendored
Normal file
File diff suppressed because one or more lines are too long
20
v2/internal/frontend/assetserver/testdata/main.js
vendored
Normal file
20
v2/internal/frontend/assetserver/testdata/main.js
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
import {ready} from '@wails/runtime';
|
||||
|
||||
ready(() => {
|
||||
// Get input + focus
|
||||
let nameElement = document.getElementById("name");
|
||||
nameElement.focus();
|
||||
|
||||
// Setup the greet function
|
||||
window.greet = function () {
|
||||
|
||||
// Get name
|
||||
let name = nameElement.value;
|
||||
|
||||
// Call App.Greet(name)
|
||||
window.backend.main.App.Greet(name).then((result) => {
|
||||
// Update result with data back from App.Greet()
|
||||
document.getElementById("result").innerText = result;
|
||||
});
|
||||
};
|
||||
});
|
||||
8
v2/internal/frontend/assetserver/testdata/subdir/index.html
vendored
Normal file
8
v2/internal/frontend/assetserver/testdata/subdir/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="/main.css" rel="stylesheet">
|
||||
</head>
|
||||
<body data-wails-drag>
|
||||
<div id="logo"></div>
|
||||
</body>
|
||||
</html>
|
||||
39
v2/internal/frontend/assetserver/testdata/subdir/main.css
vendored
Normal file
39
v2/internal/frontend/assetserver/testdata/subdir/main.css
vendored
Normal file
File diff suppressed because one or more lines are too long
20
v2/internal/frontend/assetserver/testdata/subdir/main.js
vendored
Normal file
20
v2/internal/frontend/assetserver/testdata/subdir/main.js
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
import {ready} from '@wails/runtime';
|
||||
|
||||
ready(() => {
|
||||
// Get input + focus
|
||||
let nameElement = document.getElementById("name");
|
||||
nameElement.focus();
|
||||
|
||||
// Setup the greet function
|
||||
window.greet = function () {
|
||||
|
||||
// Get name
|
||||
let name = nameElement.value;
|
||||
|
||||
// Call App.Greet(name)
|
||||
window.backend.main.App.Greet(name).then((result) => {
|
||||
// Update result with data back from App.Greet()
|
||||
document.getElementById("result").innerText = result;
|
||||
});
|
||||
};
|
||||
});
|
||||
6
v2/internal/frontend/assetserver/testdata/testdata.go
vendored
Normal file
6
v2/internal/frontend/assetserver/testdata/testdata.go
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
package testdata
|
||||
|
||||
import "embed"
|
||||
|
||||
//go:embed index.html main.css main.js
|
||||
var TopLevelFS embed.FS
|
||||
5
v2/internal/frontend/calls.go
Normal file
5
v2/internal/frontend/calls.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package frontend
|
||||
|
||||
type Calls interface {
|
||||
Callback(string)
|
||||
}
|
||||
16
v2/internal/frontend/desktop/desktop_windows.go
Normal file
16
v2/internal/frontend/desktop/desktop_windows.go
Normal file
@@ -0,0 +1,16 @@
|
||||
//go:build windows
|
||||
|
||||
package desktop
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/desktop/windows"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
func NewFrontend(ctx context.Context, appoptions *options.App, logger *logger.Logger, appBindings *binding.Bindings, dispatcher frontend.Dispatcher) frontend.Frontend {
|
||||
return windows.NewFrontend(ctx, appoptions, logger, appBindings, dispatcher)
|
||||
}
|
||||
11
v2/internal/frontend/desktop/windows/browser.go
Normal file
11
v2/internal/frontend/desktop/windows/browser.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package windows
|
||||
|
||||
import (
|
||||
"github.com/pkg/browser"
|
||||
)
|
||||
|
||||
// BrowserOpenURL Use the default browser to open the url
|
||||
func (f *Frontend) BrowserOpenURL(url string) {
|
||||
// Specific method implementation
|
||||
_ = browser.OpenURL(url)
|
||||
}
|
||||
154
v2/internal/frontend/desktop/windows/dialog.go
Normal file
154
v2/internal/frontend/desktop/windows/dialog.go
Normal file
@@ -0,0 +1,154 @@
|
||||
//go:build windows
|
||||
|
||||
package windows
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"github.com/leaanthony/go-common-file-dialog/cfd"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
"golang.org/x/sys/windows"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// OpenDirectoryDialog prompts the user to select a directory
|
||||
func (f *Frontend) OpenDirectoryDialog(options frontend.OpenDialogOptions) (string, error) {
|
||||
config := cfd.DialogConfig{
|
||||
Title: options.Title,
|
||||
Role: "PickFolder",
|
||||
Folder: options.DefaultDirectory,
|
||||
}
|
||||
thisDialog, err := cfd.NewSelectFolderDialog(config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
thisDialog.SetParentWindowHandle(f.mainWindow.Handle())
|
||||
defer func(thisDialog cfd.SelectFolderDialog) {
|
||||
err := thisDialog.Release()
|
||||
if err != nil {
|
||||
println("ERROR: Unable to release dialog:", err.Error())
|
||||
}
|
||||
}(thisDialog)
|
||||
result, err := thisDialog.ShowAndGetResult()
|
||||
if err != nil && err != cfd.ErrorCancelled {
|
||||
return "", err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// OpenFileDialog prompts the user to select a file
|
||||
func (f *Frontend) OpenFileDialog(options frontend.OpenDialogOptions) (string, error) {
|
||||
config := cfd.DialogConfig{
|
||||
Folder: options.DefaultDirectory,
|
||||
FileFilters: convertFilters(options.Filters),
|
||||
FileName: options.DefaultFilename,
|
||||
Title: options.Title,
|
||||
}
|
||||
thisdialog, err := cfd.NewOpenFileDialog(config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
thisdialog.SetParentWindowHandle(f.mainWindow.Handle())
|
||||
defer func(thisdialog cfd.OpenFileDialog) {
|
||||
err := thisdialog.Release()
|
||||
if err != nil {
|
||||
println("ERROR: Unable to release dialog:", err.Error())
|
||||
}
|
||||
}(thisdialog)
|
||||
result, err := thisdialog.ShowAndGetResult()
|
||||
if err != nil && err != cfd.ErrorCancelled {
|
||||
return "", err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// OpenMultipleFilesDialog prompts the user to select a file
|
||||
func (f *Frontend) OpenMultipleFilesDialog(dialogOptions frontend.OpenDialogOptions) ([]string, error) {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
thisdialog.SetParentWindowHandle(f.mainWindow.Handle())
|
||||
defer func(thisdialog cfd.OpenMultipleFilesDialog) {
|
||||
err := thisdialog.Release()
|
||||
if err != nil {
|
||||
println("ERROR: Unable to release dialog:", err.Error())
|
||||
}
|
||||
}(thisdialog)
|
||||
result, err := thisdialog.ShowAndGetResults()
|
||||
if err != nil && err != cfd.ErrorCancelled {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// SaveFileDialog prompts the user to select a file
|
||||
func (f *Frontend) SaveFileDialog(dialogOptions frontend.SaveDialogOptions) (string, error) {
|
||||
saveDialog, err := cfd.NewSaveFileDialog(cfd.DialogConfig{
|
||||
Title: dialogOptions.Title,
|
||||
Role: "SaveFile",
|
||||
FileFilters: convertFilters(dialogOptions.Filters),
|
||||
FileName: dialogOptions.DefaultFilename,
|
||||
Folder: dialogOptions.DefaultDirectory,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
saveDialog.SetParentWindowHandle(f.mainWindow.Handle())
|
||||
err = saveDialog.Show()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
result, err := saveDialog.GetResult()
|
||||
if err != nil && err != cfd.ErrorCancelled {
|
||||
return "", err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// MessageDialog show a message dialog to the user
|
||||
func (f *Frontend) MessageDialog(options frontend.MessageDialogOptions) (string, error) {
|
||||
|
||||
title, err := syscall.UTF16PtrFromString(options.Title)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
message, err := syscall.UTF16PtrFromString(options.Message)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var flags uint32
|
||||
switch options.Type {
|
||||
case frontend.InfoDialog:
|
||||
flags = windows.MB_OK | windows.MB_ICONINFORMATION
|
||||
case frontend.ErrorDialog:
|
||||
flags = windows.MB_ICONERROR | windows.MB_OK
|
||||
case frontend.QuestionDialog:
|
||||
flags = windows.MB_YESNO
|
||||
case frontend.WarningDialog:
|
||||
flags = windows.MB_OK | windows.MB_ICONWARNING
|
||||
}
|
||||
|
||||
button, _ := windows.MessageBox(windows.HWND(f.mainWindow.Handle()), 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]
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func convertFilters(filters []frontend.FileFilter) []cfd.FileFilter {
|
||||
var result []cfd.FileFilter
|
||||
for _, filter := range filters {
|
||||
result = append(result, cfd.FileFilter(filter))
|
||||
}
|
||||
return result
|
||||
}
|
||||
427
v2/internal/frontend/desktop/windows/frontend.go
Normal file
427
v2/internal/frontend/desktop/windows/frontend.go
Normal file
@@ -0,0 +1,427 @@
|
||||
//go:build windows
|
||||
|
||||
package windows
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
|
||||
"github.com/leaanthony/go-webview2/pkg/edge"
|
||||
"github.com/leaanthony/winc"
|
||||
"github.com/leaanthony/winc/w32"
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/assetserver"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
type Frontend struct {
|
||||
|
||||
// Context
|
||||
ctx context.Context
|
||||
|
||||
frontendOptions *options.App
|
||||
logger *logger.Logger
|
||||
chromium *edge.Chromium
|
||||
debug bool
|
||||
|
||||
// Assets
|
||||
assets *assetserver.DesktopAssetServer
|
||||
|
||||
// main window handle
|
||||
mainWindow *Window
|
||||
minWidth, minHeight, maxWidth, maxHeight int
|
||||
bindings *binding.Bindings
|
||||
dispatcher frontend.Dispatcher
|
||||
servingFromDisk bool
|
||||
}
|
||||
|
||||
func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.Logger, appBindings *binding.Bindings, dispatcher frontend.Dispatcher) *Frontend {
|
||||
|
||||
result := &Frontend{
|
||||
frontendOptions: appoptions,
|
||||
logger: myLogger,
|
||||
bindings: appBindings,
|
||||
dispatcher: dispatcher,
|
||||
ctx: ctx,
|
||||
minHeight: appoptions.MinHeight,
|
||||
minWidth: appoptions.MinWidth,
|
||||
maxHeight: appoptions.MaxHeight,
|
||||
maxWidth: appoptions.MaxWidth,
|
||||
}
|
||||
|
||||
// Check if we have been given a directory to serve assets from.
|
||||
// If so, this means we are in dev mode and are serving assets off disk.
|
||||
// We indicate this through the `servingFromDisk` flag to ensure requests
|
||||
// aren't cached by WebView2 in dev mode
|
||||
_assetdir := ctx.Value("assetdir")
|
||||
if _assetdir != nil {
|
||||
result.servingFromDisk = true
|
||||
}
|
||||
|
||||
bindingsJSON, err := appBindings.ToJSON()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
assets, err := assetserver.NewDesktopAssetServer(ctx, appoptions.Assets, bindingsJSON)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
result.assets = assets
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowReload() {
|
||||
f.ExecJS("runtime.WindowReload();")
|
||||
}
|
||||
|
||||
func (f *Frontend) Run(ctx context.Context) error {
|
||||
|
||||
f.ctx = context.WithValue(ctx, "frontend", f)
|
||||
|
||||
mainWindow := NewWindow(nil, f.frontendOptions)
|
||||
f.mainWindow = mainWindow
|
||||
|
||||
var _debug = ctx.Value("debug")
|
||||
if _debug != nil {
|
||||
f.debug = _debug.(bool)
|
||||
}
|
||||
|
||||
f.WindowCenter()
|
||||
f.setupChromium()
|
||||
|
||||
mainWindow.OnSize().Bind(func(arg *winc.Event) {
|
||||
f.chromium.Resize()
|
||||
})
|
||||
|
||||
mainWindow.OnClose().Bind(func(arg *winc.Event) {
|
||||
if f.frontendOptions.HideWindowOnClose {
|
||||
f.WindowHide()
|
||||
} else {
|
||||
f.Quit()
|
||||
}
|
||||
})
|
||||
|
||||
// TODO: Move this into a callback from frontend
|
||||
go func() {
|
||||
if f.frontendOptions.OnStartup != nil {
|
||||
f.frontendOptions.OnStartup(f.ctx)
|
||||
}
|
||||
}()
|
||||
|
||||
mainWindow.Run()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowCenter() {
|
||||
runtime.LockOSThread()
|
||||
f.mainWindow.Center()
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowSetPos(x, y int) {
|
||||
runtime.LockOSThread()
|
||||
f.mainWindow.SetPos(x, y)
|
||||
}
|
||||
func (f *Frontend) WindowGetPos() (int, int) {
|
||||
runtime.LockOSThread()
|
||||
return f.mainWindow.Pos()
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowSetSize(width, height int) {
|
||||
runtime.LockOSThread()
|
||||
f.mainWindow.SetSize(width, height)
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowGetSize() (int, int) {
|
||||
runtime.LockOSThread()
|
||||
return f.mainWindow.Size()
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowSetTitle(title string) {
|
||||
runtime.LockOSThread()
|
||||
f.mainWindow.SetText(title)
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowFullscreen() {
|
||||
runtime.LockOSThread()
|
||||
f.mainWindow.SetMaxSize(0, 0)
|
||||
f.mainWindow.SetMinSize(0, 0)
|
||||
f.mainWindow.Fullscreen()
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowUnFullscreen() {
|
||||
runtime.LockOSThread()
|
||||
f.mainWindow.UnFullscreen()
|
||||
f.mainWindow.SetMaxSize(f.maxWidth, f.maxHeight)
|
||||
f.mainWindow.SetMinSize(f.minWidth, f.minHeight)
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowShow() {
|
||||
runtime.LockOSThread()
|
||||
f.mainWindow.Show()
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowHide() {
|
||||
runtime.LockOSThread()
|
||||
f.mainWindow.Hide()
|
||||
}
|
||||
func (f *Frontend) WindowMaximise() {
|
||||
runtime.LockOSThread()
|
||||
f.mainWindow.Maximise()
|
||||
}
|
||||
func (f *Frontend) WindowUnmaximise() {
|
||||
runtime.LockOSThread()
|
||||
f.mainWindow.Restore()
|
||||
}
|
||||
func (f *Frontend) WindowMinimise() {
|
||||
runtime.LockOSThread()
|
||||
f.mainWindow.Minimise()
|
||||
}
|
||||
func (f *Frontend) WindowUnminimise() {
|
||||
runtime.LockOSThread()
|
||||
f.mainWindow.Restore()
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowSetMinSize(width int, height int) {
|
||||
runtime.LockOSThread()
|
||||
f.minWidth = width
|
||||
f.minHeight = height
|
||||
f.mainWindow.SetMinSize(width, height)
|
||||
}
|
||||
func (f *Frontend) WindowSetMaxSize(width int, height int) {
|
||||
runtime.LockOSThread()
|
||||
f.maxWidth = width
|
||||
f.maxHeight = height
|
||||
f.mainWindow.SetMaxSize(width, height)
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowSetRGBA(col *options.RGBA) {
|
||||
runtime.LockOSThread()
|
||||
if col == nil {
|
||||
return
|
||||
}
|
||||
|
||||
f.mainWindow.Dispatch(func() {
|
||||
controller := f.chromium.GetController()
|
||||
controller2 := controller.GetICoreWebView2Controller2()
|
||||
|
||||
backgroundCol := edge.COREWEBVIEW2_COLOR{
|
||||
A: col.A,
|
||||
R: col.R,
|
||||
G: col.G,
|
||||
B: col.B,
|
||||
}
|
||||
|
||||
// Webview2 only has 0 and 255 as valid values.
|
||||
if backgroundCol.A > 0 && backgroundCol.A < 255 {
|
||||
backgroundCol.A = 255
|
||||
}
|
||||
|
||||
if f.frontendOptions.Windows != nil && f.frontendOptions.Windows.WebviewIsTransparent {
|
||||
backgroundCol.A = 0
|
||||
}
|
||||
|
||||
err := controller2.PutDefaultBackgroundColor(backgroundCol)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (f *Frontend) Quit() {
|
||||
winc.Exit()
|
||||
}
|
||||
|
||||
const (
|
||||
ctrlZ int = 90
|
||||
ctrlX = 88
|
||||
ctrlC = 67
|
||||
ctrlV = 86
|
||||
ctrlA = 65
|
||||
arrowUp = 38
|
||||
arrowDown = 40
|
||||
arrowRight = 39
|
||||
arrowLeft = 37
|
||||
keyDel = 46
|
||||
)
|
||||
|
||||
func (f *Frontend) setupChromium() {
|
||||
chromium := edge.NewChromium()
|
||||
f.chromium = chromium
|
||||
chromium.MessageCallback = f.processMessage
|
||||
chromium.WebResourceRequestedCallback = f.processRequest
|
||||
chromium.NavigationCompletedCallback = f.navigationCompleted
|
||||
acceleratorsWebviewShouldProcess := slicer.Int([]int{ctrlV, ctrlC, ctrlX, ctrlZ, ctrlA, arrowLeft, arrowRight, arrowUp, arrowDown, keyDel})
|
||||
|
||||
chromium.AcceleratorKeyCallback = func(vkey uint) bool {
|
||||
// We want webview to handle ctrl-C, ctrl-Z, ctrl-v, ctrl-x
|
||||
if acceleratorsWebviewShouldProcess.Contains(int(vkey)) {
|
||||
return false
|
||||
}
|
||||
// Post keypress
|
||||
w32.PostMessage(f.mainWindow.Handle(), w32.WM_KEYDOWN, uintptr(vkey), 0)
|
||||
return true
|
||||
}
|
||||
chromium.Embed(f.mainWindow.Handle())
|
||||
chromium.Resize()
|
||||
settings, err := chromium.GetSettings()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = settings.PutAreDefaultContextMenusEnabled(f.debug)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = settings.PutAreDevToolsEnabled(f.debug)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = settings.PutIsZoomControlEnabled(false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = settings.PutIsStatusBarEnabled(false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = settings.PutIsStatusBarEnabled(false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Set background colour
|
||||
f.WindowSetRGBA(f.frontendOptions.RGBA)
|
||||
|
||||
chromium.AddWebResourceRequestedFilter("*", edge.COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL)
|
||||
chromium.Navigate("file://wails/")
|
||||
}
|
||||
|
||||
type EventNotify struct {
|
||||
Name string `json:"name"`
|
||||
Data []interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func (f *Frontend) Notify(name string, data ...interface{}) {
|
||||
notification := EventNotify{
|
||||
Name: name,
|
||||
Data: data,
|
||||
}
|
||||
payload, err := json.Marshal(notification)
|
||||
if err != nil {
|
||||
f.logger.Error(err.Error())
|
||||
return
|
||||
}
|
||||
f.ExecJS(`window.wails.EventsNotify('` + string(payload) + `');`)
|
||||
}
|
||||
|
||||
func (f *Frontend) processRequest(req *edge.ICoreWebView2WebResourceRequest, args *edge.ICoreWebView2WebResourceRequestedEventArgs) {
|
||||
//Get the request
|
||||
uri, _ := req.GetUri()
|
||||
|
||||
// Translate URI
|
||||
uri = strings.TrimPrefix(uri, "file://wails")
|
||||
if !strings.HasPrefix(uri, "/") {
|
||||
return
|
||||
}
|
||||
|
||||
// Load file from asset store
|
||||
content, mimeType, err := f.assets.Load(uri)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
env := f.chromium.Environment()
|
||||
headers := "Content-Type: " + mimeType
|
||||
if f.servingFromDisk {
|
||||
headers += "\nPragma: no-cache"
|
||||
}
|
||||
response, err := env.CreateWebResourceResponse(content, 200, "OK", headers)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Send response back
|
||||
err = args.PutResponse(response)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (f *Frontend) processMessage(message string) {
|
||||
if message == "drag" {
|
||||
err := f.startDrag()
|
||||
if err != nil {
|
||||
f.logger.Error(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
result, err := f.dispatcher.ProcessMessage(message, f)
|
||||
if err != nil {
|
||||
f.logger.Error(err.Error())
|
||||
f.Callback(result)
|
||||
return
|
||||
}
|
||||
if result == "" {
|
||||
return
|
||||
}
|
||||
|
||||
switch result[0] {
|
||||
case 'c':
|
||||
// Callback from a method call
|
||||
f.Callback(result[1:])
|
||||
default:
|
||||
f.logger.Info("Unknown message returned from dispatcher: %+v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Frontend) Callback(message string) {
|
||||
f.mainWindow.Dispatch(func() {
|
||||
f.chromium.Eval(`window.wails.Callback(` + strconv.Quote(message) + `);`)
|
||||
})
|
||||
}
|
||||
|
||||
func (f *Frontend) startDrag() error {
|
||||
if !w32.ReleaseCapture() {
|
||||
return fmt.Errorf("unable to release mouse capture")
|
||||
}
|
||||
w32.SendMessage(f.mainWindow.Handle(), w32.WM_NCLBUTTONDOWN, w32.HTCAPTION, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Frontend) ExecJS(js string) {
|
||||
f.mainWindow.Dispatch(func() {
|
||||
f.chromium.Eval(js)
|
||||
})
|
||||
}
|
||||
|
||||
func (f *Frontend) navigationCompleted(sender *edge.ICoreWebView2, args *edge.ICoreWebView2NavigationCompletedEventArgs) {
|
||||
if f.frontendOptions.OnDomReady != nil {
|
||||
go f.frontendOptions.OnDomReady(f.ctx)
|
||||
}
|
||||
|
||||
// If you want to start hidden, return
|
||||
if f.frontendOptions.StartHidden {
|
||||
return
|
||||
}
|
||||
|
||||
// Hack to make it visible: https://github.com/MicrosoftEdge/WebView2Feedback/issues/1077#issuecomment-825375026
|
||||
err := f.chromium.Hide()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = f.chromium.Show()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
f.mainWindow.Show()
|
||||
|
||||
}
|
||||
202
v2/internal/frontend/desktop/windows/keys.go
Normal file
202
v2/internal/frontend/desktop/windows/keys.go
Normal file
@@ -0,0 +1,202 @@
|
||||
//go:build windows
|
||||
|
||||
package windows
|
||||
|
||||
import (
|
||||
"github.com/leaanthony/winc"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu/keys"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var ModifierMap = map[keys.Modifier]winc.Modifiers{
|
||||
keys.ShiftKey: winc.ModShift,
|
||||
keys.ControlKey: winc.ModControl,
|
||||
keys.OptionOrAltKey: winc.ModAlt,
|
||||
keys.CmdOrCtrlKey: winc.ModControl,
|
||||
}
|
||||
|
||||
func acceleratorToWincShortcut(accelerator *keys.Accelerator) winc.Shortcut {
|
||||
|
||||
if accelerator == nil {
|
||||
return winc.NoShortcut
|
||||
}
|
||||
inKey := strings.ToUpper(accelerator.Key)
|
||||
key, exists := keyMap[inKey]
|
||||
if !exists {
|
||||
return winc.NoShortcut
|
||||
}
|
||||
var modifiers winc.Modifiers
|
||||
if _, exists := shiftMap[inKey]; exists {
|
||||
modifiers = winc.ModShift
|
||||
}
|
||||
for _, mod := range accelerator.Modifiers {
|
||||
modifiers |= ModifierMap[mod]
|
||||
}
|
||||
return winc.Shortcut{
|
||||
Modifiers: modifiers,
|
||||
Key: key,
|
||||
}
|
||||
}
|
||||
|
||||
var shiftMap = map[string]struct{}{
|
||||
"~": {},
|
||||
")": {},
|
||||
"!": {},
|
||||
"@": {},
|
||||
"#": {},
|
||||
"$": {},
|
||||
"%": {},
|
||||
"^": {},
|
||||
"&": {},
|
||||
"*": {},
|
||||
"(": {},
|
||||
"_": {},
|
||||
"PLUS": {},
|
||||
"<": {},
|
||||
">": {},
|
||||
"?": {},
|
||||
":": {},
|
||||
`"`: {},
|
||||
"{": {},
|
||||
"}": {},
|
||||
"|": {},
|
||||
}
|
||||
|
||||
var keyMap = map[string]winc.Key{
|
||||
"0": winc.Key0,
|
||||
"1": winc.Key1,
|
||||
"2": winc.Key2,
|
||||
"3": winc.Key3,
|
||||
"4": winc.Key4,
|
||||
"5": winc.Key5,
|
||||
"6": winc.Key6,
|
||||
"7": winc.Key7,
|
||||
"8": winc.Key8,
|
||||
"9": winc.Key9,
|
||||
"A": winc.KeyA,
|
||||
"B": winc.KeyB,
|
||||
"C": winc.KeyC,
|
||||
"D": winc.KeyD,
|
||||
"E": winc.KeyE,
|
||||
"F": winc.KeyF,
|
||||
"G": winc.KeyG,
|
||||
"H": winc.KeyH,
|
||||
"I": winc.KeyI,
|
||||
"J": winc.KeyJ,
|
||||
"K": winc.KeyK,
|
||||
"L": winc.KeyL,
|
||||
"M": winc.KeyM,
|
||||
"N": winc.KeyN,
|
||||
"O": winc.KeyO,
|
||||
"P": winc.KeyP,
|
||||
"Q": winc.KeyQ,
|
||||
"R": winc.KeyR,
|
||||
"S": winc.KeyS,
|
||||
"T": winc.KeyT,
|
||||
"U": winc.KeyU,
|
||||
"V": winc.KeyV,
|
||||
"W": winc.KeyW,
|
||||
"X": winc.KeyX,
|
||||
"Y": winc.KeyY,
|
||||
"Z": winc.KeyZ,
|
||||
"F1": winc.KeyF1,
|
||||
"F2": winc.KeyF2,
|
||||
"F3": winc.KeyF3,
|
||||
"F4": winc.KeyF4,
|
||||
"F5": winc.KeyF5,
|
||||
"F6": winc.KeyF6,
|
||||
"F7": winc.KeyF7,
|
||||
"F8": winc.KeyF8,
|
||||
"F9": winc.KeyF9,
|
||||
"F10": winc.KeyF10,
|
||||
"F11": winc.KeyF11,
|
||||
"F12": winc.KeyF12,
|
||||
"F13": winc.KeyF13,
|
||||
"F14": winc.KeyF14,
|
||||
"F15": winc.KeyF15,
|
||||
"F16": winc.KeyF16,
|
||||
"F17": winc.KeyF17,
|
||||
"F18": winc.KeyF18,
|
||||
"F19": winc.KeyF19,
|
||||
"F20": winc.KeyF20,
|
||||
"F21": winc.KeyF21,
|
||||
"F22": winc.KeyF22,
|
||||
"F23": winc.KeyF23,
|
||||
"F24": winc.KeyF24,
|
||||
|
||||
"`": winc.KeyOEM3,
|
||||
",": winc.KeyOEMComma,
|
||||
".": winc.KeyOEMPeriod,
|
||||
"/": winc.KeyOEM2,
|
||||
";": winc.KeyOEM1,
|
||||
"'": winc.KeyOEM7,
|
||||
"[": winc.KeyOEM4,
|
||||
"]": winc.KeyOEM6,
|
||||
`\`: winc.KeyOEM5,
|
||||
|
||||
"~": winc.KeyOEM3, //
|
||||
")": winc.Key0,
|
||||
"!": winc.Key1,
|
||||
"@": winc.Key2,
|
||||
"#": winc.Key3,
|
||||
"$": winc.Key4,
|
||||
"%": winc.Key5,
|
||||
"^": winc.Key6,
|
||||
"&": winc.Key7,
|
||||
"*": winc.Key8,
|
||||
"(": winc.Key9,
|
||||
"_": winc.KeyOEMMinus,
|
||||
"PLUS": winc.KeyOEMPlus,
|
||||
"<": winc.KeyOEMComma,
|
||||
">": winc.KeyOEMPeriod,
|
||||
"?": winc.KeyOEM2,
|
||||
":": winc.KeyOEM1,
|
||||
`"`: winc.KeyOEM7,
|
||||
"{": winc.KeyOEM4,
|
||||
"}": winc.KeyOEM6,
|
||||
"|": winc.KeyOEM5,
|
||||
|
||||
"SPACE": winc.KeySpace,
|
||||
"TAB": winc.KeyTab,
|
||||
"CAPSLOCK": winc.KeyCapital,
|
||||
"NUMLOCK": winc.KeyNumlock,
|
||||
"SCROLLLOCK": winc.KeyScroll,
|
||||
"BACKSPACE": winc.KeyBack,
|
||||
"DELETE": winc.KeyDelete,
|
||||
"INSERT": winc.KeyInsert,
|
||||
"RETURN": winc.KeyReturn,
|
||||
"ENTER": winc.KeyReturn,
|
||||
"UP": winc.KeyUp,
|
||||
"DOWN": winc.KeyDown,
|
||||
"LEFT": winc.KeyLeft,
|
||||
"RIGHT": winc.KeyRight,
|
||||
"HOME": winc.KeyHome,
|
||||
"END": winc.KeyEnd,
|
||||
"PAGEUP": winc.KeyPrior,
|
||||
"PAGEDOWN": winc.KeyNext,
|
||||
"ESCAPE": winc.KeyEscape,
|
||||
"ESC": winc.KeyEscape,
|
||||
"VOLUMEUP": winc.KeyVolumeUp,
|
||||
"VOLUMEDOWN": winc.KeyVolumeDown,
|
||||
"VOLUMEMUTE": winc.KeyVolumeMute,
|
||||
"MEDIANEXTTRACK": winc.KeyMediaNextTrack,
|
||||
"MEDIAPREVIOUSTRACK": winc.KeyMediaPrevTrack,
|
||||
"MEDIASTOP": winc.KeyMediaStop,
|
||||
"MEDIAPLAYPAUSE": winc.KeyMediaPlayPause,
|
||||
"PRINTSCREEN": winc.KeyPrint,
|
||||
"NUM0": winc.KeyNumpad0,
|
||||
"NUM1": winc.KeyNumpad1,
|
||||
"NUM2": winc.KeyNumpad2,
|
||||
"NUM3": winc.KeyNumpad3,
|
||||
"NUM4": winc.KeyNumpad4,
|
||||
"NUM5": winc.KeyNumpad5,
|
||||
"NUM6": winc.KeyNumpad6,
|
||||
"NUM7": winc.KeyNumpad7,
|
||||
"NUM8": winc.KeyNumpad8,
|
||||
"NUM9": winc.KeyNumpad9,
|
||||
"nummult": winc.KeyMultiply,
|
||||
"numadd": winc.KeyAdd,
|
||||
"numsub": winc.KeySubtract,
|
||||
"numdec": winc.KeyDecimal,
|
||||
"numdiv": winc.KeyDivide,
|
||||
}
|
||||
129
v2/internal/frontend/desktop/windows/menu.go
Normal file
129
v2/internal/frontend/desktop/windows/menu.go
Normal file
@@ -0,0 +1,129 @@
|
||||
//go:build windows
|
||||
|
||||
package windows
|
||||
|
||||
import (
|
||||
"github.com/leaanthony/winc"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
)
|
||||
|
||||
var checkboxMap = map[*menu.MenuItem][]*winc.MenuItem{}
|
||||
var radioGroupMap = map[*menu.MenuItem][]*winc.MenuItem{}
|
||||
|
||||
func toggleCheckBox(menuItem *menu.MenuItem) {
|
||||
menuItem.Checked = !menuItem.Checked
|
||||
for _, wincMenu := range checkboxMap[menuItem] {
|
||||
wincMenu.SetChecked(menuItem.Checked)
|
||||
}
|
||||
}
|
||||
|
||||
func addCheckBoxToMap(menuItem *menu.MenuItem, wincMenuItem *winc.MenuItem) {
|
||||
if checkboxMap[menuItem] == nil {
|
||||
checkboxMap[menuItem] = []*winc.MenuItem{}
|
||||
}
|
||||
checkboxMap[menuItem] = append(checkboxMap[menuItem], wincMenuItem)
|
||||
}
|
||||
|
||||
func toggleRadioItem(menuItem *menu.MenuItem) {
|
||||
menuItem.Checked = !menuItem.Checked
|
||||
for _, wincMenu := range radioGroupMap[menuItem] {
|
||||
wincMenu.SetChecked(menuItem.Checked)
|
||||
}
|
||||
}
|
||||
|
||||
func addRadioItemToMap(menuItem *menu.MenuItem, wincMenuItem *winc.MenuItem) {
|
||||
if radioGroupMap[menuItem] == nil {
|
||||
radioGroupMap[menuItem] = []*winc.MenuItem{}
|
||||
}
|
||||
radioGroupMap[menuItem] = append(radioGroupMap[menuItem], wincMenuItem)
|
||||
}
|
||||
|
||||
func (w *Window) SetApplicationMenu(menu *menu.Menu) {
|
||||
w.applicationMenu = menu
|
||||
processMenu(w, menu)
|
||||
}
|
||||
|
||||
func processMenu(window *Window, menu *menu.Menu) {
|
||||
mainMenu := window.NewMenu()
|
||||
for _, menuItem := range menu.Items {
|
||||
submenu := mainMenu.AddSubMenu(menuItem.Label)
|
||||
for _, menuItem := range menuItem.SubMenu.Items {
|
||||
processMenuItem(submenu, menuItem)
|
||||
}
|
||||
}
|
||||
mainMenu.Show()
|
||||
}
|
||||
|
||||
func processMenuItem(parent *winc.MenuItem, menuItem *menu.MenuItem) {
|
||||
if menuItem.Hidden {
|
||||
return
|
||||
}
|
||||
switch menuItem.Type {
|
||||
case menu.SeparatorType:
|
||||
parent.AddSeparator()
|
||||
case menu.TextType:
|
||||
shortcut := acceleratorToWincShortcut(menuItem.Accelerator)
|
||||
newItem := parent.AddItem(menuItem.Label, shortcut)
|
||||
if menuItem.Tooltip != "" {
|
||||
newItem.SetToolTip(menuItem.Tooltip)
|
||||
}
|
||||
if menuItem.Click != nil {
|
||||
newItem.OnClick().Bind(func(e *winc.Event) {
|
||||
menuItem.Click(&menu.CallbackData{
|
||||
MenuItem: menuItem,
|
||||
})
|
||||
})
|
||||
}
|
||||
newItem.SetEnabled(!menuItem.Disabled)
|
||||
|
||||
case menu.CheckboxType:
|
||||
shortcut := acceleratorToWincShortcut(menuItem.Accelerator)
|
||||
newItem := parent.AddItem(menuItem.Label, shortcut)
|
||||
newItem.SetCheckable(true)
|
||||
newItem.SetChecked(menuItem.Checked)
|
||||
if menuItem.Tooltip != "" {
|
||||
newItem.SetToolTip(menuItem.Tooltip)
|
||||
}
|
||||
if menuItem.Click != nil {
|
||||
newItem.OnClick().Bind(func(e *winc.Event) {
|
||||
toggleCheckBox(menuItem)
|
||||
menuItem.Click(&menu.CallbackData{
|
||||
MenuItem: menuItem,
|
||||
})
|
||||
})
|
||||
}
|
||||
newItem.SetEnabled(!menuItem.Disabled)
|
||||
addCheckBoxToMap(menuItem, newItem)
|
||||
case menu.RadioType:
|
||||
shortcut := acceleratorToWincShortcut(menuItem.Accelerator)
|
||||
newItem := parent.AddItemRadio(menuItem.Label, shortcut)
|
||||
newItem.SetCheckable(true)
|
||||
newItem.SetChecked(menuItem.Checked)
|
||||
if menuItem.Tooltip != "" {
|
||||
newItem.SetToolTip(menuItem.Tooltip)
|
||||
}
|
||||
if menuItem.Click != nil {
|
||||
newItem.OnClick().Bind(func(e *winc.Event) {
|
||||
toggleRadioItem(menuItem)
|
||||
menuItem.Click(&menu.CallbackData{
|
||||
MenuItem: menuItem,
|
||||
})
|
||||
})
|
||||
}
|
||||
newItem.SetEnabled(!menuItem.Disabled)
|
||||
addRadioItemToMap(menuItem, newItem)
|
||||
case menu.SubmenuType:
|
||||
submenu := parent.AddSubMenu(menuItem.Label)
|
||||
for _, menuItem := range menuItem.SubMenu.Items {
|
||||
processMenuItem(submenu, menuItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Frontend) MenuSetApplicationMenu(menu *menu.Menu) {
|
||||
f.mainWindow.SetApplicationMenu(menu)
|
||||
}
|
||||
|
||||
func (f *Frontend) MenuUpdateApplicationMenu() {
|
||||
processMenu(f.mainWindow, f.mainWindow.applicationMenu)
|
||||
}
|
||||
116
v2/internal/frontend/desktop/windows/window.go
Normal file
116
v2/internal/frontend/desktop/windows/window.go
Normal file
@@ -0,0 +1,116 @@
|
||||
//go:build windows
|
||||
|
||||
package windows
|
||||
|
||||
import (
|
||||
"github.com/leaanthony/winc"
|
||||
"github.com/leaanthony/winc/w32"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Window struct {
|
||||
winc.Form
|
||||
frontendOptions *options.App
|
||||
applicationMenu *menu.Menu
|
||||
m sync.Mutex
|
||||
dispatchq []func()
|
||||
}
|
||||
|
||||
func NewWindow(parent winc.Controller, options *options.App) *Window {
|
||||
result := new(Window)
|
||||
result.frontendOptions = options
|
||||
result.SetIsForm(true)
|
||||
|
||||
var exStyle int
|
||||
if options.Windows != nil {
|
||||
exStyle = w32.WS_EX_CONTROLPARENT | w32.WS_EX_APPWINDOW
|
||||
if options.Windows.WindowIsTranslucent {
|
||||
exStyle |= w32.WS_EX_NOREDIRECTIONBITMAP
|
||||
}
|
||||
}
|
||||
|
||||
var dwStyle = w32.WS_OVERLAPPEDWINDOW
|
||||
if options.Frameless {
|
||||
dwStyle = w32.WS_POPUP
|
||||
}
|
||||
|
||||
winc.RegClassOnlyOnce("wailsWindow")
|
||||
result.SetHandle(winc.CreateWindow("wailsWindow", parent, uint(exStyle), uint(dwStyle)))
|
||||
result.SetParent(parent)
|
||||
|
||||
loadIcon := true
|
||||
if options.Windows != nil && options.Windows.DisableWindowIcon == true {
|
||||
loadIcon = false
|
||||
}
|
||||
if loadIcon {
|
||||
if ico, err := winc.NewIconFromResource(winc.GetAppInstance(), uint16(winc.AppIconID)); err == nil {
|
||||
result.SetIcon(0, ico)
|
||||
}
|
||||
}
|
||||
|
||||
result.SetSize(options.Width, options.Height)
|
||||
result.SetText(options.Title)
|
||||
result.EnableSizable(!options.DisableResize)
|
||||
result.EnableMaxButton(!options.DisableResize)
|
||||
result.SetMinSize(options.MinWidth, options.MinHeight)
|
||||
result.SetMaxSize(options.MaxWidth, options.MaxHeight)
|
||||
|
||||
if options.Windows != nil {
|
||||
if options.Windows.WindowIsTranslucent {
|
||||
result.SetTranslucentBackground()
|
||||
}
|
||||
|
||||
if options.Windows.DisableWindowIcon {
|
||||
result.DisableIcon()
|
||||
}
|
||||
}
|
||||
|
||||
// Dlg forces display of focus rectangles, as soon as the user starts to type.
|
||||
w32.SendMessage(result.Handle(), w32.WM_CHANGEUISTATE, w32.UIS_INITIALIZE, 0)
|
||||
winc.RegMsgHandler(result)
|
||||
|
||||
result.SetFont(winc.DefaultFont)
|
||||
|
||||
if options.Fullscreen {
|
||||
result.Fullscreen()
|
||||
}
|
||||
|
||||
if options.Menu != nil {
|
||||
result.SetApplicationMenu(options.Menu)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (w *Window) Run() int {
|
||||
var m w32.MSG
|
||||
|
||||
for w32.GetMessage(&m, 0, 0, 0) != 0 {
|
||||
if m.Message == w32.WM_APP {
|
||||
// Credit: https://github.com/jchv/go-webview2
|
||||
w.m.Lock()
|
||||
q := append([]func(){}, w.dispatchq...)
|
||||
w.dispatchq = []func(){}
|
||||
w.m.Unlock()
|
||||
for _, v := range q {
|
||||
v()
|
||||
}
|
||||
}
|
||||
if !w.PreTranslateMessage(&m) {
|
||||
w32.TranslateMessage(&m)
|
||||
w32.DispatchMessage(&m)
|
||||
}
|
||||
}
|
||||
|
||||
w32.GdiplusShutdown()
|
||||
return int(m.WParam)
|
||||
}
|
||||
|
||||
func (w *Window) Dispatch(f func()) {
|
||||
w.m.Lock()
|
||||
w.dispatchq = append(w.dispatchq, f)
|
||||
w.m.Unlock()
|
||||
w32.PostMainThreadMessage(w32.WM_APP, 0, 0)
|
||||
}
|
||||
369
v2/internal/frontend/devserver/devserver.go
Normal file
369
v2/internal/frontend/devserver/devserver.go
Normal file
@@ -0,0 +1,369 @@
|
||||
//go:build dev
|
||||
|
||||
// Package devserver provides a web-based frontend so that
|
||||
// it is possible to run a Wails app in a browsers.
|
||||
package devserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/websocket/v2"
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/assetserver"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/menumanager"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
type DevWebServer struct {
|
||||
server *fiber.App
|
||||
ctx context.Context
|
||||
appoptions *options.App
|
||||
logger *logger.Logger
|
||||
appBindings *binding.Bindings
|
||||
dispatcher frontend.Dispatcher
|
||||
assetServer *assetserver.AssetServer
|
||||
socketMutex sync.Mutex
|
||||
websocketClients map[*websocket.Conn]struct{}
|
||||
menuManager *menumanager.Manager
|
||||
starttime string
|
||||
|
||||
// Desktop frontend
|
||||
desktopFrontend frontend.Frontend
|
||||
}
|
||||
|
||||
func (d *DevWebServer) WindowReload() {
|
||||
d.broadcast("reload")
|
||||
}
|
||||
|
||||
func (d *DevWebServer) Run(ctx context.Context) error {
|
||||
d.ctx = ctx
|
||||
|
||||
d.server.Get("/wails/reload", func(fctx *fiber.Ctx) error {
|
||||
d.WindowReload()
|
||||
d.desktopFrontend.WindowReload()
|
||||
return nil
|
||||
})
|
||||
|
||||
d.server.Get("/wails/ipc", websocket.New(func(c *websocket.Conn) {
|
||||
d.newWebsocketSession(c)
|
||||
// websocket.Conn bindings https://pkg.go.dev/github.com/fasthttp/websocket?tab=doc#pkg-index
|
||||
var (
|
||||
mt int
|
||||
msg []byte
|
||||
err error
|
||||
)
|
||||
|
||||
for {
|
||||
if mt, msg, err = c.ReadMessage(); err != nil {
|
||||
break
|
||||
}
|
||||
// d.logger.Info("[%p] %s", c, msg)
|
||||
if string(msg) == "drag" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Notify the other browsers
|
||||
if len(msg) > 2 && strings.HasPrefix(string(msg), "EE") {
|
||||
d.notifyExcludingSender(msg, c)
|
||||
}
|
||||
|
||||
// Send the message to dispatch to the frontend
|
||||
result, err := d.dispatcher.ProcessMessage(string(msg), d)
|
||||
if err != nil {
|
||||
d.logger.Error(err.Error())
|
||||
}
|
||||
if result != "" {
|
||||
if err = c.WriteMessage(mt, []byte(result)); err != nil {
|
||||
log.Println("write:", err)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}))
|
||||
|
||||
_assetdir := ctx.Value("assetdir")
|
||||
if _assetdir == nil {
|
||||
return fmt.Errorf("no assetdir provided")
|
||||
}
|
||||
if _assetdir != nil {
|
||||
assetdir := _assetdir.(string)
|
||||
bindingsJSON, err := d.appBindings.ToJSON()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
d.assetServer, err = assetserver.NewAssetServer(assetdir, bindingsJSON, d.appoptions)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
absdir, err := filepath.Abs(assetdir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.LogInfo("Serving assets from: %s", absdir)
|
||||
}
|
||||
|
||||
d.server.Get("*", d.loadAsset)
|
||||
|
||||
// Start server
|
||||
go func(server *fiber.App, log *logger.Logger) {
|
||||
err := server.Listen(":34115")
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
}
|
||||
d.LogInfo("Shutdown completed")
|
||||
}(d.server, d.logger)
|
||||
|
||||
d.LogInfo("Serving application at http://localhost:34115")
|
||||
|
||||
// Launch desktop app
|
||||
err := d.desktopFrontend.Run(ctx)
|
||||
d.LogInfo("Starting shutdown")
|
||||
err2 := d.server.Shutdown()
|
||||
if err2 != nil {
|
||||
d.logger.Error(err.Error())
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *DevWebServer) Quit() {
|
||||
d.desktopFrontend.Quit()
|
||||
}
|
||||
|
||||
func (d *DevWebServer) OpenFileDialog(dialogOptions frontend.OpenDialogOptions) (string, error) {
|
||||
return d.desktopFrontend.OpenFileDialog(dialogOptions)
|
||||
}
|
||||
|
||||
func (d *DevWebServer) OpenMultipleFilesDialog(dialogOptions frontend.OpenDialogOptions) ([]string, error) {
|
||||
return d.OpenMultipleFilesDialog(dialogOptions)
|
||||
}
|
||||
|
||||
func (d *DevWebServer) OpenDirectoryDialog(dialogOptions frontend.OpenDialogOptions) (string, error) {
|
||||
return d.OpenDirectoryDialog(dialogOptions)
|
||||
}
|
||||
|
||||
func (d *DevWebServer) SaveFileDialog(dialogOptions frontend.SaveDialogOptions) (string, error) {
|
||||
return d.desktopFrontend.SaveFileDialog(dialogOptions)
|
||||
}
|
||||
|
||||
func (d *DevWebServer) MessageDialog(dialogOptions frontend.MessageDialogOptions) (string, error) {
|
||||
return d.desktopFrontend.MessageDialog(dialogOptions)
|
||||
}
|
||||
|
||||
func (d *DevWebServer) WindowSetTitle(title string) {
|
||||
d.desktopFrontend.WindowSetTitle(title)
|
||||
}
|
||||
|
||||
func (d *DevWebServer) WindowShow() {
|
||||
d.desktopFrontend.WindowShow()
|
||||
}
|
||||
|
||||
func (d *DevWebServer) WindowHide() {
|
||||
d.desktopFrontend.WindowHide()
|
||||
}
|
||||
|
||||
func (d *DevWebServer) WindowCenter() {
|
||||
d.desktopFrontend.WindowCenter()
|
||||
}
|
||||
|
||||
func (d *DevWebServer) WindowMaximise() {
|
||||
d.desktopFrontend.WindowMaximise()
|
||||
}
|
||||
|
||||
func (d *DevWebServer) WindowUnmaximise() {
|
||||
d.desktopFrontend.WindowUnmaximise()
|
||||
}
|
||||
|
||||
func (d *DevWebServer) WindowMinimise() {
|
||||
d.desktopFrontend.WindowMinimise()
|
||||
}
|
||||
|
||||
func (d *DevWebServer) WindowUnminimise() {
|
||||
d.desktopFrontend.WindowUnminimise()
|
||||
}
|
||||
|
||||
func (d *DevWebServer) WindowSetPos(x int, y int) {
|
||||
d.desktopFrontend.WindowSetPos(x, y)
|
||||
}
|
||||
|
||||
func (d *DevWebServer) WindowGetPos() (int, int) {
|
||||
return d.desktopFrontend.WindowGetPos()
|
||||
}
|
||||
|
||||
func (d *DevWebServer) WindowSetSize(width int, height int) {
|
||||
d.desktopFrontend.WindowSetSize(width, height)
|
||||
}
|
||||
|
||||
func (d *DevWebServer) WindowGetSize() (int, int) {
|
||||
return d.desktopFrontend.WindowGetSize()
|
||||
}
|
||||
|
||||
func (d *DevWebServer) WindowSetMinSize(width int, height int) {
|
||||
d.desktopFrontend.WindowSetMinSize(width, height)
|
||||
}
|
||||
|
||||
func (d *DevWebServer) WindowSetMaxSize(width int, height int) {
|
||||
d.desktopFrontend.WindowSetMaxSize(width, height)
|
||||
}
|
||||
|
||||
func (d *DevWebServer) WindowFullscreen() {
|
||||
d.desktopFrontend.WindowFullscreen()
|
||||
}
|
||||
|
||||
func (d *DevWebServer) WindowUnFullscreen() {
|
||||
d.desktopFrontend.WindowUnFullscreen()
|
||||
}
|
||||
|
||||
func (d *DevWebServer) WindowSetRGBA(col *options.RGBA) {
|
||||
d.desktopFrontend.WindowSetRGBA(col)
|
||||
}
|
||||
|
||||
func (d *DevWebServer) MenuSetApplicationMenu(menu *menu.Menu) {
|
||||
d.desktopFrontend.MenuSetApplicationMenu(menu)
|
||||
}
|
||||
|
||||
func (d *DevWebServer) MenuUpdateApplicationMenu() {
|
||||
d.desktopFrontend.MenuUpdateApplicationMenu()
|
||||
}
|
||||
|
||||
// BrowserOpenURL uses the system default browser to open the url
|
||||
func (d *DevWebServer) BrowserOpenURL(url string) {
|
||||
d.desktopFrontend.BrowserOpenURL(url)
|
||||
}
|
||||
|
||||
func (d *DevWebServer) Notify(name string, data ...interface{}) {
|
||||
d.notify(name, data...)
|
||||
}
|
||||
|
||||
func (d *DevWebServer) loadAsset(ctx *fiber.Ctx) error {
|
||||
data, mimetype, err := d.assetServer.Load(ctx.Path())
|
||||
if err != nil {
|
||||
_, ok := err.(*fs.PathError)
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
err := ctx.SendStatus(404)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
err = ctx.SendStatus(200)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx.Set("Content-Type", mimetype)
|
||||
err = ctx.Send(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DevWebServer) LogInfo(message string, args ...interface{}) {
|
||||
d.logger.Info("[DevWebServer] "+message, args...)
|
||||
}
|
||||
|
||||
func (d *DevWebServer) newWebsocketSession(c *websocket.Conn) {
|
||||
d.socketMutex.Lock()
|
||||
defer d.socketMutex.Unlock()
|
||||
c.SetCloseHandler(func(code int, text string) error {
|
||||
d.socketMutex.Lock()
|
||||
defer d.socketMutex.Unlock()
|
||||
delete(d.websocketClients, c)
|
||||
d.LogInfo(fmt.Sprintf("Websocket client %p disconnected", c))
|
||||
return nil
|
||||
})
|
||||
d.websocketClients[c] = struct{}{}
|
||||
d.LogInfo(fmt.Sprintf("Websocket client %p connected", c))
|
||||
}
|
||||
|
||||
type EventNotify struct {
|
||||
Name string `json:"name"`
|
||||
Data []interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func (d *DevWebServer) broadcast(message string) {
|
||||
d.socketMutex.Lock()
|
||||
defer d.socketMutex.Unlock()
|
||||
for client := range d.websocketClients {
|
||||
err := client.WriteMessage(websocket.TextMessage, []byte(message))
|
||||
if err != nil {
|
||||
d.logger.Error(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DevWebServer) notify(name string, data ...interface{}) {
|
||||
// Notify
|
||||
notification := EventNotify{
|
||||
Name: name,
|
||||
Data: data,
|
||||
}
|
||||
payload, err := json.Marshal(notification)
|
||||
if err != nil {
|
||||
d.logger.Error(err.Error())
|
||||
return
|
||||
}
|
||||
d.broadcast("n" + string(payload))
|
||||
}
|
||||
|
||||
func (d *DevWebServer) broadcastExcludingSender(message string, sender *websocket.Conn) {
|
||||
d.socketMutex.Lock()
|
||||
defer d.socketMutex.Unlock()
|
||||
for client := range d.websocketClients {
|
||||
if client == sender {
|
||||
continue
|
||||
}
|
||||
err := client.WriteMessage(websocket.TextMessage, []byte(message))
|
||||
if err != nil {
|
||||
d.logger.Error(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DevWebServer) notifyExcludingSender(eventMessage []byte, sender *websocket.Conn) {
|
||||
message := "n" + string(eventMessage[2:])
|
||||
d.broadcastExcludingSender(message, sender)
|
||||
|
||||
var notifyMessage EventNotify
|
||||
err := json.Unmarshal(eventMessage[2:], ¬ifyMessage)
|
||||
if err != nil {
|
||||
d.logger.Error(err.Error())
|
||||
return
|
||||
}
|
||||
d.desktopFrontend.Notify(notifyMessage.Name, notifyMessage.Data...)
|
||||
}
|
||||
|
||||
func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.Logger, appBindings *binding.Bindings, dispatcher frontend.Dispatcher, menuManager *menumanager.Manager, desktopFrontend frontend.Frontend) *DevWebServer {
|
||||
result := &DevWebServer{
|
||||
ctx: ctx,
|
||||
desktopFrontend: desktopFrontend,
|
||||
appoptions: appoptions,
|
||||
logger: myLogger,
|
||||
appBindings: appBindings,
|
||||
dispatcher: dispatcher,
|
||||
server: fiber.New(fiber.Config{
|
||||
ReadTimeout: time.Second * 5,
|
||||
DisableStartupMessage: true,
|
||||
}),
|
||||
menuManager: menuManager,
|
||||
websocketClients: make(map[*websocket.Conn]struct{}),
|
||||
}
|
||||
return result
|
||||
}
|
||||
5
v2/internal/frontend/dispatcher.go
Normal file
5
v2/internal/frontend/dispatcher.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package frontend
|
||||
|
||||
type Dispatcher interface {
|
||||
ProcessMessage(message string, sender Frontend) (string, error)
|
||||
}
|
||||
23
v2/internal/frontend/dispatcher/browser.go
Normal file
23
v2/internal/frontend/dispatcher/browser.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package dispatcher
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
)
|
||||
|
||||
// processBrowserMessage processing browser messages
|
||||
func (d *Dispatcher) processBrowserMessage(message string, sender frontend.Frontend) (string, error) {
|
||||
if len(message) < 2 {
|
||||
return "", errors.New("Invalid Browser Message: " + message)
|
||||
}
|
||||
switch message[1] {
|
||||
case 'O':
|
||||
url := message[3:]
|
||||
go sender.BrowserOpenURL(url)
|
||||
default:
|
||||
d.log.Error("unknown Browser message: %s", message)
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
81
v2/internal/frontend/dispatcher/calls.go
Normal file
81
v2/internal/frontend/dispatcher/calls.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package dispatcher
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type callMessage struct {
|
||||
Name string `json:"name"`
|
||||
Args []json.RawMessage `json:"args"`
|
||||
CallbackID string `json:"callbackID"`
|
||||
}
|
||||
|
||||
func (d *Dispatcher) processCallMessage(message string, sender frontend.Frontend) (string, error) {
|
||||
|
||||
var payload callMessage
|
||||
err := json.Unmarshal([]byte(message[1:]), &payload)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var result interface{}
|
||||
|
||||
// Handle different calls
|
||||
switch true {
|
||||
case strings.HasPrefix(payload.Name, systemCallPrefix):
|
||||
result, err = d.processSystemCall(payload, sender)
|
||||
default:
|
||||
// Lookup method
|
||||
registeredMethod := d.bindingsDB.GetMethod(payload.Name)
|
||||
|
||||
// Check we have it
|
||||
if registeredMethod == nil {
|
||||
return "", fmt.Errorf("method '%s' not registered", payload.Name)
|
||||
}
|
||||
|
||||
args, err2 := registeredMethod.ParseArgs(payload.Args)
|
||||
if err2 != nil {
|
||||
errmsg := fmt.Errorf("error parsing arguments: %s", err2.Error())
|
||||
result, _ := d.NewErrorCallback(errmsg.Error(), payload.CallbackID)
|
||||
return result, errmsg
|
||||
}
|
||||
result, err = registeredMethod.Call(args)
|
||||
}
|
||||
|
||||
callbackMessage := &CallbackMessage{
|
||||
CallbackID: payload.CallbackID,
|
||||
}
|
||||
if err != nil {
|
||||
callbackMessage.Err = err.Error()
|
||||
} else {
|
||||
callbackMessage.Result = result
|
||||
}
|
||||
messageData, err := json.Marshal(callbackMessage)
|
||||
d.log.Trace("json call result data: %+v\n", string(messageData))
|
||||
if err != nil {
|
||||
// what now?
|
||||
d.log.Fatal(err.Error())
|
||||
}
|
||||
|
||||
return "c" + string(messageData), nil
|
||||
}
|
||||
|
||||
// CallbackMessage defines a message that contains the result of a call
|
||||
type CallbackMessage struct {
|
||||
Result interface{} `json:"result"`
|
||||
Err string `json:"error"`
|
||||
CallbackID string `json:"callbackid"`
|
||||
}
|
||||
|
||||
func (d *Dispatcher) NewErrorCallback(message string, callbackID string) (string, error) {
|
||||
result := &CallbackMessage{
|
||||
CallbackID: callbackID,
|
||||
Err: message,
|
||||
}
|
||||
messageData, err := json.Marshal(result)
|
||||
d.log.Trace("json call result data: %+v\n", string(messageData))
|
||||
return string(messageData), err
|
||||
}
|
||||
47
v2/internal/frontend/dispatcher/dispatcher.go
Normal file
47
v2/internal/frontend/dispatcher/dispatcher.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package dispatcher
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
)
|
||||
|
||||
type Dispatcher struct {
|
||||
log *logger.Logger
|
||||
bindings *binding.Bindings
|
||||
events frontend.Events
|
||||
bindingsDB *binding.DB
|
||||
}
|
||||
|
||||
func NewDispatcher(log *logger.Logger, bindings *binding.Bindings, events frontend.Events) *Dispatcher {
|
||||
return &Dispatcher{
|
||||
log: log,
|
||||
bindings: bindings,
|
||||
events: events,
|
||||
bindingsDB: bindings.DB(),
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Dispatcher) ProcessMessage(message string, sender frontend.Frontend) (string, error) {
|
||||
if message == "" {
|
||||
return "", errors.New("No message to process")
|
||||
}
|
||||
switch message[0] {
|
||||
case 'L':
|
||||
return d.processLogMessage(message)
|
||||
case 'E':
|
||||
return d.processEventMessage(message, sender)
|
||||
case 'C':
|
||||
return d.processCallMessage(message, sender)
|
||||
case 'W':
|
||||
return d.processWindowMessage(message, sender)
|
||||
case 'B':
|
||||
return d.processBrowserMessage(message, sender)
|
||||
case 'Q':
|
||||
sender.Quit()
|
||||
return "", nil
|
||||
default:
|
||||
return "", errors.New("Unknown message from front end: " + message)
|
||||
}
|
||||
}
|
||||
33
v2/internal/frontend/dispatcher/events.go
Normal file
33
v2/internal/frontend/dispatcher/events.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package dispatcher
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
)
|
||||
|
||||
type EventMessage struct {
|
||||
Name string `json:"name"`
|
||||
Data []interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func (d *Dispatcher) processEventMessage(message string, sender frontend.Frontend) (string, error) {
|
||||
if len(message) < 3 {
|
||||
return "", errors.New("Invalid Event Message: " + message)
|
||||
}
|
||||
|
||||
switch message[1] {
|
||||
case 'E':
|
||||
var eventMessage EventMessage
|
||||
err := json.Unmarshal([]byte(message[2:]), &eventMessage)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
go d.events.Notify(sender, eventMessage.Name, eventMessage.Data)
|
||||
case 'X':
|
||||
eventName := message[2:]
|
||||
go d.events.Off(eventName)
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
49
v2/internal/frontend/dispatcher/log.go
Normal file
49
v2/internal/frontend/dispatcher/log.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package dispatcher
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
pkgLogger "github.com/wailsapp/wails/v2/pkg/logger"
|
||||
)
|
||||
|
||||
var logLevelMap = map[byte]logger.LogLevel{
|
||||
'1': pkgLogger.TRACE,
|
||||
'2': pkgLogger.DEBUG,
|
||||
'3': pkgLogger.INFO,
|
||||
'4': pkgLogger.WARNING,
|
||||
'5': pkgLogger.ERROR,
|
||||
}
|
||||
|
||||
func (d *Dispatcher) processLogMessage(message string) (string, error) {
|
||||
if len(message) < 3 {
|
||||
return "", errors.New("Invalid Log Message: " + message)
|
||||
}
|
||||
|
||||
messageText := message[2:]
|
||||
|
||||
switch message[1] {
|
||||
case 'T':
|
||||
d.log.Trace(messageText)
|
||||
case 'P':
|
||||
d.log.Print(messageText)
|
||||
case 'D':
|
||||
d.log.Debug(messageText)
|
||||
case 'I':
|
||||
d.log.Info(messageText)
|
||||
case 'W':
|
||||
d.log.Warning(messageText)
|
||||
case 'E':
|
||||
d.log.Error(messageText)
|
||||
case 'F':
|
||||
d.log.Fatal(messageText)
|
||||
case 'S':
|
||||
loglevel, exists := logLevelMap[message[2]]
|
||||
if !exists {
|
||||
return "", errors.New("Invalid Set Log Level Message: " + message)
|
||||
}
|
||||
d.log.SetLogLevel(loglevel)
|
||||
default:
|
||||
return "", errors.New("Invalid Log Message: " + message)
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
37
v2/internal/frontend/dispatcher/systemcalls.go
Normal file
37
v2/internal/frontend/dispatcher/systemcalls.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package dispatcher
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const systemCallPrefix = ":wails:"
|
||||
|
||||
type position struct {
|
||||
X int `json:"x"`
|
||||
Y int `json:"y"`
|
||||
}
|
||||
|
||||
type size struct {
|
||||
W int `json:"w"`
|
||||
H int `json:"h"`
|
||||
}
|
||||
|
||||
func (d *Dispatcher) processSystemCall(payload callMessage, sender frontend.Frontend) (interface{}, error) {
|
||||
|
||||
// Strip prefix
|
||||
name := strings.TrimPrefix(payload.Name, systemCallPrefix)
|
||||
|
||||
switch name {
|
||||
case "WindowGetPos":
|
||||
x, y := sender.WindowGetPos()
|
||||
return &position{x, y}, nil
|
||||
case "WindowGetSize":
|
||||
w, h := sender.WindowGetSize()
|
||||
return &position{w, h}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown systemcall message: %s", payload.Name)
|
||||
}
|
||||
|
||||
}
|
||||
79
v2/internal/frontend/dispatcher/window.go
Normal file
79
v2/internal/frontend/dispatcher/window.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package dispatcher
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (d *Dispatcher) mustAtoI(input string) int {
|
||||
result, err := strconv.Atoi(input)
|
||||
if err != nil {
|
||||
d.log.Error("cannot convert %s to integer!", input)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (d *Dispatcher) processWindowMessage(message string, sender frontend.Frontend) (string, error) {
|
||||
if len(message) < 2 {
|
||||
return "", errors.New("Invalid Event Message: " + message)
|
||||
}
|
||||
|
||||
switch message[1] {
|
||||
case 'c':
|
||||
go sender.WindowCenter()
|
||||
case 'T':
|
||||
title := message[2:]
|
||||
go sender.WindowSetTitle(title)
|
||||
case 'F':
|
||||
go sender.WindowFullscreen()
|
||||
case 'f':
|
||||
go sender.WindowUnFullscreen()
|
||||
case 's':
|
||||
parts := strings.Split(message[3:], ":")
|
||||
w := d.mustAtoI(parts[0])
|
||||
h := d.mustAtoI(parts[1])
|
||||
go sender.WindowSetSize(w, h)
|
||||
case 'p':
|
||||
parts := strings.Split(message[3:], ":")
|
||||
x := d.mustAtoI(parts[0])
|
||||
y := d.mustAtoI(parts[1])
|
||||
go sender.WindowSetPos(x, y)
|
||||
case 'H':
|
||||
go sender.WindowHide()
|
||||
case 'S':
|
||||
go sender.WindowShow()
|
||||
case 'r':
|
||||
var rgba options.RGBA
|
||||
err := json.Unmarshal([]byte(message[3:]), &rgba)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
go sender.WindowSetRGBA(&rgba)
|
||||
case 'M':
|
||||
go sender.WindowMaximise()
|
||||
case 'U':
|
||||
go sender.WindowUnmaximise()
|
||||
case 'm':
|
||||
go sender.WindowMinimise()
|
||||
case 'u':
|
||||
go sender.WindowUnminimise()
|
||||
case 'Z':
|
||||
parts := strings.Split(message[3:], ":")
|
||||
w := d.mustAtoI(parts[0])
|
||||
h := d.mustAtoI(parts[1])
|
||||
go sender.WindowSetMaxSize(w, h)
|
||||
case 'z':
|
||||
parts := strings.Split(message[3:], ":")
|
||||
w := d.mustAtoI(parts[0])
|
||||
h := d.mustAtoI(parts[1])
|
||||
go sender.WindowSetMinSize(w, h)
|
||||
default:
|
||||
d.log.Error("unknown Window message: %s", message)
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user