mirror of
https://github.com/taigrr/wails.git
synced 2026-04-14 10:50:53 -07:00
Compare commits
47 Commits
feature/v2
...
v2.0.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c6d3f57712 | ||
|
|
b4c669ff86 | ||
|
|
2d1b2c0947 | ||
|
|
4a0c5aa785 | ||
|
|
f48d7f8f60 | ||
|
|
651f24f641 | ||
|
|
8fd77148ca | ||
|
|
0dc0762fdf | ||
|
|
1a92550709 | ||
|
|
bffc15bc14 | ||
|
|
198d206c46 | ||
|
|
bb8e848ef6 | ||
|
|
bac3e9e5c1 | ||
|
|
bc5eddeb66 | ||
|
|
8e7258d812 | ||
|
|
7118762cec | ||
|
|
6af92cf0a4 | ||
|
|
1bb91634f7 | ||
|
|
f71ce7913f | ||
|
|
53db687a26 | ||
|
|
13939d3d6b | ||
|
|
552c6b8711 | ||
|
|
feee2b3db2 | ||
|
|
9889c2bdbb | ||
|
|
2432fccf71 | ||
|
|
70510fd180 | ||
|
|
17c6201469 | ||
|
|
0f209c8900 | ||
|
|
cbf043585c | ||
|
|
5ae621ceaa | ||
|
|
1231b59443 | ||
|
|
b18d4fbf41 | ||
|
|
9ec5605e63 | ||
|
|
98a4de8878 | ||
|
|
5fe709f558 | ||
|
|
5231a6893b | ||
|
|
74f3ce990f | ||
|
|
998a913853 | ||
|
|
964844835c | ||
|
|
4e152bb849 | ||
|
|
51133d098c | ||
|
|
d4191e7d1b | ||
|
|
9c273bc745 | ||
|
|
c6f6ad6beb | ||
|
|
4362a14459 | ||
|
|
0080e9e311 | ||
|
|
83d9297cac |
@@ -57,6 +57,11 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
|||||||
keepAssets := false
|
keepAssets := false
|
||||||
command.BoolFlag("k", "Keep generated assets", &keepAssets)
|
command.BoolFlag("k", "Keep generated assets", &keepAssets)
|
||||||
|
|
||||||
|
appleIdentity := ""
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
command.StringFlag("sign", "Signs your app with the given identity.", &appleIdentity)
|
||||||
|
}
|
||||||
|
|
||||||
command.Action(func() error {
|
command.Action(func() error {
|
||||||
|
|
||||||
// Create logger
|
// Create logger
|
||||||
@@ -72,6 +77,11 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
|||||||
app.PrintBanner()
|
app.PrintBanner()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure package is used with apple identity
|
||||||
|
if appleIdentity != "" && pack == false {
|
||||||
|
return fmt.Errorf("must use `-package` flag when using `-sign`")
|
||||||
|
}
|
||||||
|
|
||||||
task := fmt.Sprintf("Building %s Application", strings.Title(outputType))
|
task := fmt.Sprintf("Building %s Application", strings.Title(outputType))
|
||||||
logger.Println(task)
|
logger.Println(task)
|
||||||
logger.Println(strings.Repeat("-", len(task)))
|
logger.Println(strings.Repeat("-", len(task)))
|
||||||
@@ -84,14 +94,15 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
|||||||
|
|
||||||
// Create BuildOptions
|
// Create BuildOptions
|
||||||
buildOptions := &build.Options{
|
buildOptions := &build.Options{
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
OutputType: outputType,
|
OutputType: outputType,
|
||||||
Mode: mode,
|
Mode: mode,
|
||||||
Pack: pack,
|
Pack: pack,
|
||||||
Platform: platform,
|
Platform: platform,
|
||||||
LDFlags: ldflags,
|
LDFlags: ldflags,
|
||||||
Compiler: compilerCommand,
|
Compiler: compilerCommand,
|
||||||
KeepAssets: keepAssets,
|
KeepAssets: keepAssets,
|
||||||
|
AppleIdentity: appleIdentity,
|
||||||
}
|
}
|
||||||
|
|
||||||
return doBuild(buildOptions)
|
return doBuild(buildOptions)
|
||||||
|
|||||||
@@ -5,12 +5,13 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/wailsapp/wails/v2/internal/colour"
|
||||||
|
|
||||||
"github.com/fsnotify/fsnotify"
|
"github.com/fsnotify/fsnotify"
|
||||||
"github.com/leaanthony/clir"
|
"github.com/leaanthony/clir"
|
||||||
@@ -20,6 +21,21 @@ import (
|
|||||||
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func LogGreen(message string, args ...interface{}) {
|
||||||
|
text := fmt.Sprintf(message, args...)
|
||||||
|
println(colour.Green(text))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogRed(message string, args ...interface{}) {
|
||||||
|
text := fmt.Sprintf(message, args...)
|
||||||
|
println(colour.Red(text))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogDarkYellow(message string, args ...interface{}) {
|
||||||
|
text := fmt.Sprintf(message, args...)
|
||||||
|
println(colour.DarkYellow(text))
|
||||||
|
}
|
||||||
|
|
||||||
// AddSubcommand adds the `dev` command for the Wails application
|
// AddSubcommand adds the `dev` command for the Wails application
|
||||||
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||||
|
|
||||||
@@ -37,6 +53,13 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
|||||||
extensions := "go"
|
extensions := "go"
|
||||||
command.StringFlag("e", "Extensions to trigger rebuilds (comma separated) eg go,js,css,html", &extensions)
|
command.StringFlag("e", "Extensions to trigger rebuilds (comma separated) eg go,js,css,html", &extensions)
|
||||||
|
|
||||||
|
// extensions to trigger rebuilds
|
||||||
|
showWarnings := false
|
||||||
|
command.BoolFlag("w", "Show warnings", &showWarnings)
|
||||||
|
|
||||||
|
loglevel := ""
|
||||||
|
command.StringFlag("loglevel", "Loglevel to use - Trace, Debug, Info, Warning, Error", &loglevel)
|
||||||
|
|
||||||
command.Action(func() error {
|
command.Action(func() error {
|
||||||
|
|
||||||
// Create logger
|
// Create logger
|
||||||
@@ -52,7 +75,6 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
|||||||
defer watcher.Close()
|
defer watcher.Close()
|
||||||
|
|
||||||
var debugBinaryProcess *process.Process = nil
|
var debugBinaryProcess *process.Process = nil
|
||||||
var buildFrontend bool = false
|
|
||||||
var extensionsThatTriggerARebuild = strings.Split(extensions, ",")
|
var extensionsThatTriggerARebuild = strings.Split(extensions, ",")
|
||||||
|
|
||||||
// Setup signal handler
|
// Setup signal handler
|
||||||
@@ -63,7 +85,10 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
|||||||
|
|
||||||
// Do initial build
|
// Do initial build
|
||||||
logger.Println("Building application for development...")
|
logger.Println("Building application for development...")
|
||||||
debugBinaryProcess, err = restartApp(logger, "dev", ldflags, compilerCommand, debugBinaryProcess)
|
newProcess, err := restartApp(logger, "dev", ldflags, compilerCommand, debugBinaryProcess, loglevel)
|
||||||
|
if newProcess != nil {
|
||||||
|
debugBinaryProcess = newProcess
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -79,7 +104,7 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal("%s", err.Error())
|
logger.Fatal("%s", err.Error())
|
||||||
}
|
}
|
||||||
logger.Println("Watching directory: %s", event.Name)
|
LogGreen("[New Directory] Watching new directory: %s", event.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -88,33 +113,29 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
|||||||
// Check for file writes
|
// Check for file writes
|
||||||
if event.Op&fsnotify.Write == fsnotify.Write {
|
if event.Op&fsnotify.Write == fsnotify.Write {
|
||||||
|
|
||||||
logger.Println("modified file: %s", event.Name)
|
|
||||||
var rebuild bool = false
|
var rebuild bool = false
|
||||||
|
|
||||||
// Iterate all file patterns
|
// Iterate all file patterns
|
||||||
for _, pattern := range extensionsThatTriggerARebuild {
|
for _, pattern := range extensionsThatTriggerARebuild {
|
||||||
rebuild = strings.HasSuffix(event.Name, pattern)
|
if strings.HasSuffix(event.Name, pattern) {
|
||||||
if err != nil {
|
rebuild = true
|
||||||
logger.Fatal(err.Error())
|
|
||||||
}
|
|
||||||
if rebuild {
|
|
||||||
// Only build frontend when the file isn't a Go file
|
|
||||||
buildFrontend = !strings.HasSuffix(event.Name, "go")
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !rebuild {
|
if !rebuild {
|
||||||
logger.Println("Filename change: %s did not match extension list (%s)", event.Name, extensions)
|
if showWarnings {
|
||||||
|
LogDarkYellow("[File change] %s did not match extension list (%s)", event.Name, extensions)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Println("Partial build triggered: %s updated", event.Name)
|
LogGreen("[Attempting rebuild] %s updated", event.Name)
|
||||||
|
|
||||||
// Do a rebuild
|
// Do a rebuild
|
||||||
|
|
||||||
// Try and build the app
|
// Try and build the app
|
||||||
newBinaryProcess, err := restartApp(logger, "dev", ldflags, compilerCommand, debugBinaryProcess)
|
newBinaryProcess, err := restartApp(logger, "dev", ldflags, compilerCommand, debugBinaryProcess, loglevel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error during build: %s", err.Error())
|
fmt.Printf("Error during build: %s", err.Error())
|
||||||
return
|
return
|
||||||
@@ -128,23 +149,28 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Get project dir
|
// Get project dir
|
||||||
dir, err := os.Getwd()
|
projectDir, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all subdirectories
|
// Get all subdirectories
|
||||||
dirs, err := fs.GetSubdirectories(dir)
|
dirs, err := fs.GetSubdirectories(projectDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogGreen("Watching (sub)/directory: %s", projectDir)
|
||||||
|
|
||||||
// Setup a watcher for non-node_modules directories
|
// Setup a watcher for non-node_modules directories
|
||||||
dirs.Each(func(dir string) {
|
dirs.Each(func(dir string) {
|
||||||
if strings.Contains(dir, "node_modules") {
|
if strings.Contains(dir, "node_modules") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Println("Watching directory: %s", dir)
|
// Ignore build directory
|
||||||
|
if strings.HasPrefix(dir, filepath.Join(projectDir, "build")) {
|
||||||
|
return
|
||||||
|
}
|
||||||
err = watcher.Add(dir)
|
err = watcher.Add(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal(err.Error())
|
logger.Fatal(err.Error())
|
||||||
@@ -156,7 +182,7 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
|||||||
for quit == false {
|
for quit == false {
|
||||||
select {
|
select {
|
||||||
case <-quitChannel:
|
case <-quitChannel:
|
||||||
println("Caught quit")
|
LogGreen("\nCaught quit")
|
||||||
// Notify debouncer to quit
|
// Notify debouncer to quit
|
||||||
debounceQuit <- true
|
debounceQuit <- true
|
||||||
quit = true
|
quit = true
|
||||||
@@ -171,7 +197,7 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Println("Development mode exited")
|
LogGreen("Development mode exited")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@@ -198,15 +224,15 @@ exit:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func restartApp(logger *clilogger.CLILogger, outputType string, ldflags string, compilerCommand string, debugBinaryProcess *process.Process) (*process.Process, error) {
|
func restartApp(logger *clilogger.CLILogger, outputType string, ldflags string, compilerCommand string, debugBinaryProcess *process.Process, loglevel string) (*process.Process, error) {
|
||||||
|
|
||||||
appBinary, err := buildApp(logger, outputType, ldflags, compilerCommand)
|
appBinary, err := buildApp(logger, outputType, ldflags, compilerCommand)
|
||||||
println()
|
println()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal(err.Error())
|
LogRed("Build error - continuing to run current version")
|
||||||
return nil, errors.Wrap(err, "Build Failed:")
|
LogDarkYellow(err.Error())
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
logger.Println("Build new binary: %s", appBinary)
|
|
||||||
|
|
||||||
// Kill existing binary if need be
|
// Kill existing binary if need be
|
||||||
if debugBinaryProcess != nil {
|
if debugBinaryProcess != nil {
|
||||||
@@ -222,7 +248,7 @@ func restartApp(logger *clilogger.CLILogger, outputType string, ldflags string,
|
|||||||
// TODO: Generate `backend.js`
|
// TODO: Generate `backend.js`
|
||||||
|
|
||||||
// Start up new binary
|
// Start up new binary
|
||||||
newProcess := process.NewProcess(logger, appBinary)
|
newProcess := process.NewProcess(logger, appBinary, "-loglevel", loglevel)
|
||||||
err = newProcess.Start()
|
err = newProcess.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Remove binary
|
// Remove binary
|
||||||
@@ -239,7 +265,7 @@ func restartApp(logger *clilogger.CLILogger, outputType string, ldflags string,
|
|||||||
func buildApp(logger *clilogger.CLILogger, outputType string, ldflags string, compilerCommand string) (string, error) {
|
func buildApp(logger *clilogger.CLILogger, outputType string, ldflags string, compilerCommand string) (string, error) {
|
||||||
|
|
||||||
// Create random output file
|
// Create random output file
|
||||||
outputFile := fmt.Sprintf("debug-%d", time.Now().Unix())
|
outputFile := fmt.Sprintf("dev-%d", time.Now().Unix())
|
||||||
|
|
||||||
// Create BuildOptions
|
// Create BuildOptions
|
||||||
buildOptions := &build.Options{
|
buildOptions := &build.Options{
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ import (
|
|||||||
func AddSubcommand(app *clir.Cli, w io.Writer, currentVersion string) error {
|
func AddSubcommand(app *clir.Cli, w io.Writer, currentVersion string) error {
|
||||||
|
|
||||||
command := app.NewSubCommand("update", "Update the Wails CLI")
|
command := app.NewSubCommand("update", "Update the Wails CLI")
|
||||||
command.LongDescription(`This command allows you to update your version of Wails.`)
|
command.LongDescription(`This command allows you to update your version of the Wails CLI.`)
|
||||||
|
|
||||||
// Setup flags
|
// Setup flags
|
||||||
var prereleaseRequired bool
|
var prereleaseRequired bool
|
||||||
command.BoolFlag("pre", "Update to latest Prerelease", &prereleaseRequired)
|
command.BoolFlag("pre", "Update CLI to latest Prerelease", &prereleaseRequired)
|
||||||
|
|
||||||
var specificVersion string
|
var specificVersion string
|
||||||
command.StringFlag("version", "Install a specific version (Overrides other flags)", &specificVersion)
|
command.StringFlag("version", "Install a specific version (Overrides other flags) of the CLI", &specificVersion)
|
||||||
|
|
||||||
command.Action(func() error {
|
command.Action(func() error {
|
||||||
|
|
||||||
@@ -143,7 +143,7 @@ func updateToVersion(logger *clilogger.CLILogger, targetVersion *github.Semantic
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
logger.Print("Installing Wails " + desiredVersion + "...")
|
logger.Print("Installing Wails CLI " + desiredVersion + "...")
|
||||||
|
|
||||||
// Run command in non module directory
|
// Run command in non module directory
|
||||||
homeDir, err := os.UserHomeDir()
|
homeDir, err := os.UserHomeDir()
|
||||||
@@ -158,7 +158,7 @@ func updateToVersion(logger *clilogger.CLILogger, targetVersion *github.Semantic
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
logger.Println("Wails updated to " + desiredVersion)
|
logger.Println("Wails CLI updated to " + desiredVersion)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/internal/colour"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/update"
|
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/update"
|
||||||
|
|
||||||
"github.com/leaanthony/clir"
|
"github.com/leaanthony/clir"
|
||||||
@@ -19,12 +22,18 @@ func fatal(message string) {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func banner(_ *clir.Cli) string {
|
||||||
|
return fmt.Sprintf("%s %s - Go/HTML Application Framework", colour.Yellow("Wails"), colour.DarkRed(version))
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
app := clir.NewCli("Wails", "Go/HTML Application Framework", version)
|
app := clir.NewCli("Wails", "Go/HTML Application Framework", version)
|
||||||
|
|
||||||
|
app.SetBannerFunction(banner)
|
||||||
|
|
||||||
build.AddBuildSubcommand(app, os.Stdout)
|
build.AddBuildSubcommand(app, os.Stdout)
|
||||||
err = initialise.AddSubcommand(app, os.Stdout)
|
err = initialise.AddSubcommand(app, os.Stdout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
var version = "v2.0.0-alpha.26"
|
var version = "v2.0.0-alpha.42"
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ require (
|
|||||||
github.com/tdewolff/minify v2.3.6+incompatible
|
github.com/tdewolff/minify v2.3.6+incompatible
|
||||||
github.com/tdewolff/parse v2.3.4+incompatible // indirect
|
github.com/tdewolff/parse v2.3.4+incompatible // indirect
|
||||||
github.com/tdewolff/test v1.0.6 // indirect
|
github.com/tdewolff/test v1.0.6 // indirect
|
||||||
|
github.com/wzshiming/ctc v1.2.3
|
||||||
github.com/xyproto/xpm v1.2.1
|
github.com/xyproto/xpm v1.2.1
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202
|
golang.org/x/net v0.0.0-20200822124328-c89045814202
|
||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
|
|
||||||
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c
|
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c
|
||||||
golang.org/x/tools v0.0.0-20200902012652-d1954cc86c82
|
golang.org/x/tools v0.0.0-20200902012652-d1954cc86c82
|
||||||
nhooyr.io/websocket v1.8.6
|
nhooyr.io/websocket v1.8.6
|
||||||
|
|||||||
@@ -78,6 +78,10 @@ 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 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 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
|
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=
|
||||||
|
github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae/go.mod h1:VTAq37rkGeV+WOybvZwjXiJOicICdpLCN8ifpISjK20=
|
||||||
github.com/xyproto/xpm v1.2.1 h1:trdvGjjWBsOOKzBBUPT6JvaIQM3acJEEYfbxN7M96wg=
|
github.com/xyproto/xpm v1.2.1 h1:trdvGjjWBsOOKzBBUPT6JvaIQM3acJEEYfbxN7M96wg=
|
||||||
github.com/xyproto/xpm v1.2.1/go.mod h1:cMnesLsD0PBXLgjDfTDEaKr8XyTFsnP1QycSqRw7BiY=
|
github.com/xyproto/xpm v1.2.1/go.mod h1:cMnesLsD0PBXLgjDfTDEaKr8XyTFsnP1QycSqRw7BiY=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
@@ -92,11 +96,10 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up
|
|||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs=
|
|
||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
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-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-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 h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
|
||||||
|
|||||||
@@ -4,8 +4,9 @@ package app
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Init initialises the application for a debug environment
|
// Init initialises the application for a debug environment
|
||||||
@@ -19,10 +20,10 @@ func (a *App) Init() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set log levels
|
// Set log levels
|
||||||
greeting := flag.String("loglevel", "debug", "Loglevel to use - Trace, Debug, Info, Warning, Error")
|
loglevel := flag.String("loglevel", "debug", "Loglevel to use - Trace, Debug, Info, Warning, Error")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if len(*greeting) > 0 {
|
if len(*loglevel) > 0 {
|
||||||
switch strings.ToLower(*greeting) {
|
switch strings.ToLower(*loglevel) {
|
||||||
case "trace":
|
case "trace":
|
||||||
a.logger.SetLogLevel(logger.TRACE)
|
a.logger.SetLogLevel(logger.TRACE)
|
||||||
case "info":
|
case "info":
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ type App struct {
|
|||||||
//binding *subsystem.Binding
|
//binding *subsystem.Binding
|
||||||
call *subsystem.Call
|
call *subsystem.Call
|
||||||
menu *subsystem.Menu
|
menu *subsystem.Menu
|
||||||
|
url *subsystem.URL
|
||||||
dispatcher *messagedispatcher.Dispatcher
|
dispatcher *messagedispatcher.Dispatcher
|
||||||
|
|
||||||
menuManager *menumanager.Manager
|
menuManager *menumanager.Manager
|
||||||
@@ -117,14 +118,6 @@ func (a *App) Run() error {
|
|||||||
parentContext := context.WithValue(context.Background(), "waitgroup", &subsystemWaitGroup)
|
parentContext := context.WithValue(context.Background(), "waitgroup", &subsystemWaitGroup)
|
||||||
ctx, cancel := context.WithCancel(parentContext)
|
ctx, cancel := context.WithCancel(parentContext)
|
||||||
|
|
||||||
// Setup signal handler
|
|
||||||
signalsubsystem, err := signal.NewManager(ctx, cancel, a.servicebus, a.logger, a.shutdownCallback)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
a.signal = signalsubsystem
|
|
||||||
a.signal.Start()
|
|
||||||
|
|
||||||
// Start the service bus
|
// Start the service bus
|
||||||
a.servicebus.Debug()
|
a.servicebus.Debug()
|
||||||
err = a.servicebus.Start()
|
err = a.servicebus.Start()
|
||||||
@@ -132,7 +125,7 @@ func (a *App) Run() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
runtimesubsystem, err := subsystem.NewRuntime(ctx, a.servicebus, a.logger, a.startupCallback, a.shutdownCallback)
|
runtimesubsystem, err := subsystem.NewRuntime(ctx, a.servicebus, a.logger, a.startupCallback)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -168,6 +161,19 @@ func (a *App) Run() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if a.options.Mac.URLHandlers != nil {
|
||||||
|
// Start the url handler subsystem
|
||||||
|
url, err := subsystem.NewURL(a.servicebus, a.logger, a.options.Mac.URLHandlers)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.url = url
|
||||||
|
err = a.url.Start()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Start the eventing subsystem
|
// Start the eventing subsystem
|
||||||
eventsubsystem, err := subsystem.NewEvent(ctx, a.servicebus, a.logger)
|
eventsubsystem, err := subsystem.NewEvent(ctx, a.servicebus, a.logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -207,6 +213,14 @@ func (a *App) Run() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setup signal handler
|
||||||
|
signalsubsystem, err := signal.NewManager(ctx, cancel, a.servicebus, a.logger)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.signal = signalsubsystem
|
||||||
|
a.signal.Start()
|
||||||
|
|
||||||
err = a.window.Run(dispatcher, bindingDump, a.debug)
|
err = a.window.Run(dispatcher, bindingDump, a.debug)
|
||||||
a.logger.Trace("Ffenestri.Run() exited")
|
a.logger.Trace("Ffenestri.Run() exited")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -231,5 +245,10 @@ func (a *App) Run() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shutdown callback
|
||||||
|
if a.shutdownCallback != nil {
|
||||||
|
a.shutdownCallback()
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ func CreateApp(appoptions *options.App) (*App, error) {
|
|||||||
|
|
||||||
// Set up logger
|
// Set up logger
|
||||||
myLogger := logger.New(appoptions.Logger)
|
myLogger := logger.New(appoptions.Logger)
|
||||||
myLogger.SetLogLevel(appoptions.LogLevel)
|
|
||||||
|
|
||||||
// Create the menu manager
|
// Create the menu manager
|
||||||
menuManager := menumanager.NewManager()
|
menuManager := menumanager.NewManager()
|
||||||
@@ -119,14 +118,6 @@ func (a *App) Run() error {
|
|||||||
parentContext := context.WithValue(context.Background(), "waitgroup", &subsystemWaitGroup)
|
parentContext := context.WithValue(context.Background(), "waitgroup", &subsystemWaitGroup)
|
||||||
ctx, cancel := context.WithCancel(parentContext)
|
ctx, cancel := context.WithCancel(parentContext)
|
||||||
|
|
||||||
// Setup signal handler
|
|
||||||
signalsubsystem, err := signal.NewManager(ctx, cancel, a.servicebus, a.logger, a.shutdownCallback)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
a.signal = signalsubsystem
|
|
||||||
a.signal.Start()
|
|
||||||
|
|
||||||
// Start the service bus
|
// Start the service bus
|
||||||
a.servicebus.Debug()
|
a.servicebus.Debug()
|
||||||
err = a.servicebus.Start()
|
err = a.servicebus.Start()
|
||||||
@@ -134,7 +125,7 @@ func (a *App) Run() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
runtimesubsystem, err := subsystem.NewRuntime(ctx, a.servicebus, a.logger, a.startupCallback, a.shutdownCallback)
|
runtimesubsystem, err := subsystem.NewRuntime(ctx, a.servicebus, a.logger, a.startupCallback)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -212,6 +203,14 @@ func (a *App) Run() error {
|
|||||||
// Generate backend.js
|
// Generate backend.js
|
||||||
a.bindings.GenerateBackendJS()
|
a.bindings.GenerateBackendJS()
|
||||||
|
|
||||||
|
// Setup signal handler
|
||||||
|
signalsubsystem, err := signal.NewManager(ctx, cancel, a.servicebus, a.logger)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.signal = signalsubsystem
|
||||||
|
a.signal.Start()
|
||||||
|
|
||||||
err = a.bridge.Run(dispatcher, a.menuManager, bindingDump, a.debug)
|
err = a.bridge.Run(dispatcher, a.menuManager, bindingDump, a.debug)
|
||||||
a.logger.Trace("Bridge.Run() exited")
|
a.logger.Trace("Bridge.Run() exited")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -236,6 +235,10 @@ func (a *App) Run() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shutdown callback
|
||||||
|
if a.shutdownCallback != nil {
|
||||||
|
a.shutdownCallback()
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ const backend = {`)
|
|||||||
sortedPackageNames.Add(packageName)
|
sortedPackageNames.Add(packageName)
|
||||||
}
|
}
|
||||||
sortedPackageNames.Sort()
|
sortedPackageNames.Sort()
|
||||||
for _, packageName := range sortedPackageNames.AsSlice() {
|
sortedPackageNames.Each(func(packageName string) {
|
||||||
packages := store[packageName]
|
packages := store[packageName]
|
||||||
output.WriteString(fmt.Sprintf(" \"%s\": {", packageName))
|
output.WriteString(fmt.Sprintf(" \"%s\": {", packageName))
|
||||||
output.WriteString("\n")
|
output.WriteString("\n")
|
||||||
@@ -67,7 +67,8 @@ const backend = {`)
|
|||||||
sortedStructNames.Add(structName)
|
sortedStructNames.Add(structName)
|
||||||
}
|
}
|
||||||
sortedStructNames.Sort()
|
sortedStructNames.Sort()
|
||||||
for _, structName := range sortedStructNames.AsSlice() {
|
|
||||||
|
sortedStructNames.Each(func(structName string) {
|
||||||
structs := packages[structName]
|
structs := packages[structName]
|
||||||
output.WriteString(fmt.Sprintf(" \"%s\": {", structName))
|
output.WriteString(fmt.Sprintf(" \"%s\": {", structName))
|
||||||
output.WriteString("\n")
|
output.WriteString("\n")
|
||||||
@@ -78,7 +79,7 @@ const backend = {`)
|
|||||||
}
|
}
|
||||||
sortedMethodNames.Sort()
|
sortedMethodNames.Sort()
|
||||||
|
|
||||||
for _, methodName := range sortedMethodNames.AsSlice() {
|
sortedMethodNames.Each(func(methodName string) {
|
||||||
methodDetails := structs[methodName]
|
methodDetails := structs[methodName]
|
||||||
output.WriteString(" /**\n")
|
output.WriteString(" /**\n")
|
||||||
output.WriteString(" * " + methodName + "\n")
|
output.WriteString(" * " + methodName + "\n")
|
||||||
@@ -109,13 +110,16 @@ const backend = {`)
|
|||||||
output.WriteString("\n")
|
output.WriteString("\n")
|
||||||
output.WriteString(fmt.Sprintf(" },"))
|
output.WriteString(fmt.Sprintf(" },"))
|
||||||
output.WriteString("\n")
|
output.WriteString("\n")
|
||||||
}
|
|
||||||
|
})
|
||||||
|
|
||||||
output.WriteString(fmt.Sprintf(" }"))
|
output.WriteString(fmt.Sprintf(" }"))
|
||||||
output.WriteString("\n")
|
output.WriteString("\n")
|
||||||
}
|
})
|
||||||
|
|
||||||
output.WriteString(fmt.Sprintf(" }\n"))
|
output.WriteString(fmt.Sprintf(" }\n"))
|
||||||
output.WriteString("\n")
|
output.WriteString("\n")
|
||||||
}
|
})
|
||||||
|
|
||||||
output.WriteString(`};
|
output.WriteString(`};
|
||||||
export default backend;`)
|
export default backend;`)
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ type BridgeClient struct {
|
|||||||
messageCache chan string
|
messageCache chan string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b BridgeClient) DeleteTrayMenuByID(id string) {
|
||||||
|
b.session.sendMessage("TD" + id)
|
||||||
|
}
|
||||||
|
|
||||||
func NewBridgeClient() *BridgeClient {
|
func NewBridgeClient() *BridgeClient {
|
||||||
return &BridgeClient{
|
return &BridgeClient{
|
||||||
messageCache: make(chan string, 100),
|
messageCache: make(chan string, 100),
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ type DialogClient struct {
|
|||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DialogClient) DeleteTrayMenuByID(id string) {
|
||||||
|
}
|
||||||
|
|
||||||
func NewDialogClient(log *logger.Logger) *DialogClient {
|
func NewDialogClient(log *logger.Logger) *DialogClient {
|
||||||
return &DialogClient{
|
return &DialogClient{
|
||||||
log: log,
|
log: log,
|
||||||
|
|||||||
89
v2/internal/colour/colour.go
Normal file
89
v2/internal/colour/colour.go
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
package colour
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/wzshiming/ctc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Col(col ctc.Color, text string) string {
|
||||||
|
return fmt.Sprintf("%s%s%s", col, text, ctc.Reset)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Yellow(text string) string {
|
||||||
|
return Col(ctc.ForegroundBrightYellow, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Red(text string) string {
|
||||||
|
return Col(ctc.ForegroundBrightRed, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Blue(text string) string {
|
||||||
|
return Col(ctc.ForegroundBrightBlue, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Green(text string) string {
|
||||||
|
return Col(ctc.ForegroundBrightGreen, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Cyan(text string) string {
|
||||||
|
return Col(ctc.ForegroundBrightCyan, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Magenta(text string) string {
|
||||||
|
return Col(ctc.ForegroundBrightMagenta, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func White(text string) string {
|
||||||
|
return Col(ctc.ForegroundBrightWhite, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Black(text string) string {
|
||||||
|
return Col(ctc.ForegroundBrightBlack, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DarkYellow(text string) string {
|
||||||
|
return Col(ctc.ForegroundYellow, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DarkRed(text string) string {
|
||||||
|
return Col(ctc.ForegroundRed, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DarkBlue(text string) string {
|
||||||
|
return Col(ctc.ForegroundBlue, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DarkGreen(text string) string {
|
||||||
|
return Col(ctc.ForegroundGreen, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DarkCyan(text string) string {
|
||||||
|
return Col(ctc.ForegroundCyan, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DarkMagenta(text string) string {
|
||||||
|
return Col(ctc.ForegroundMagenta, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DarkWhite(text string) string {
|
||||||
|
return Col(ctc.ForegroundWhite, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DarkBlack(text string) string {
|
||||||
|
return Col(ctc.ForegroundBlack, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
var rainbowCols = []func(string) string{Red, Yellow, Green, Cyan, Blue, Magenta}
|
||||||
|
|
||||||
|
func Rainbow(text string) string {
|
||||||
|
var builder strings.Builder
|
||||||
|
|
||||||
|
for i := 0; i < len(text); i++ {
|
||||||
|
fn := rainbowCols[i%len(rainbowCols)]
|
||||||
|
builder.WriteString(fn(text[i : i+1]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
@@ -37,6 +37,7 @@ extern void DarkModeEnabled(struct Application*, char *callbackID);
|
|||||||
extern void SetApplicationMenu(struct Application*, const char *);
|
extern void SetApplicationMenu(struct Application*, const char *);
|
||||||
extern void AddTrayMenu(struct Application*, const char *menuTrayJSON);
|
extern void AddTrayMenu(struct Application*, const char *menuTrayJSON);
|
||||||
extern void SetTrayMenu(struct Application*, const char *menuTrayJSON);
|
extern void SetTrayMenu(struct Application*, const char *menuTrayJSON);
|
||||||
|
extern void DeleteTrayMenuByID(struct Application*, const char *id);
|
||||||
extern void UpdateTrayMenuLabel(struct Application*, const char* JSON);
|
extern void UpdateTrayMenuLabel(struct Application*, const char* JSON);
|
||||||
extern void AddContextMenu(struct Application*, char *contextMenuJSON);
|
extern void AddContextMenu(struct Application*, char *contextMenuJSON);
|
||||||
extern void UpdateContextMenu(struct Application*, char *contextMenuJSON);
|
extern void UpdateContextMenu(struct Application*, char *contextMenuJSON);
|
||||||
|
|||||||
@@ -208,3 +208,7 @@ func (c *Client) UpdateTrayMenuLabel(JSON string) {
|
|||||||
func (c *Client) UpdateContextMenu(contextMenuJSON string) {
|
func (c *Client) UpdateContextMenu(contextMenuJSON string) {
|
||||||
C.UpdateContextMenu(c.app.app, c.app.string2CString(contextMenuJSON))
|
C.UpdateContextMenu(c.app.app, c.app.string2CString(contextMenuJSON))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteTrayMenuByID(id string) {
|
||||||
|
C.DeleteTrayMenuByID(c.app.app, c.app.string2CString(id))
|
||||||
|
}
|
||||||
|
|||||||
@@ -46,6 +46,15 @@ int hashmap_log(void *const context, struct hashmap_element_s *const e) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void filelog(const char *message) {
|
||||||
|
FILE *fp = fopen("/tmp/wailslog.txt", "ab");
|
||||||
|
if (fp != NULL)
|
||||||
|
{
|
||||||
|
fputs(message, fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Utility function to visualise a hashmap
|
// Utility function to visualise a hashmap
|
||||||
void dumpHashmap(const char *name, struct hashmap_s *hashmap) {
|
void dumpHashmap(const char *name, struct hashmap_s *hashmap) {
|
||||||
printf("%s = { ", name);
|
printf("%s = { ", name);
|
||||||
@@ -79,6 +88,7 @@ struct Application {
|
|||||||
id mouseEvent;
|
id mouseEvent;
|
||||||
id mouseDownMonitor;
|
id mouseDownMonitor;
|
||||||
id mouseUpMonitor;
|
id mouseUpMonitor;
|
||||||
|
int activationPolicy;
|
||||||
|
|
||||||
// Window Data
|
// Window Data
|
||||||
const char *title;
|
const char *title;
|
||||||
@@ -112,6 +122,7 @@ struct Application {
|
|||||||
int useToolBar;
|
int useToolBar;
|
||||||
int hideToolbarSeparator;
|
int hideToolbarSeparator;
|
||||||
int windowBackgroundIsTranslucent;
|
int windowBackgroundIsTranslucent;
|
||||||
|
int hasURLHandlers;
|
||||||
|
|
||||||
// Menu
|
// Menu
|
||||||
Menu *applicationMenu;
|
Menu *applicationMenu;
|
||||||
@@ -253,7 +264,7 @@ void Hide(struct Application *app) {
|
|||||||
if( app->shuttingDown ) return;
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
msg(app->application, s("hide:"))
|
msg(app->application, s("hide:"));
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,31 +509,6 @@ void DestroyApplication(struct Application *app) {
|
|||||||
Debug(app, "Finished Destroying Application");
|
Debug(app, "Finished Destroying Application");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quit will stop the cocoa application and free up all the memory
|
|
||||||
// used by the application
|
|
||||||
void Quit(struct Application *app) {
|
|
||||||
Debug(app, "Quit Called");
|
|
||||||
ON_MAIN_THREAD (
|
|
||||||
// Terminate app
|
|
||||||
msg(app->application, s("stop:"), NULL);
|
|
||||||
id fakeevent = msg(c("NSEvent"),
|
|
||||||
s("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"),
|
|
||||||
15, // Type
|
|
||||||
msg(c("CGPoint"), s("init:x:y:"), 0, 0), // location
|
|
||||||
0, // flags
|
|
||||||
0, // timestamp
|
|
||||||
0, // window
|
|
||||||
NULL, // context
|
|
||||||
0, // subtype
|
|
||||||
0, // data1
|
|
||||||
0 // data2
|
|
||||||
);
|
|
||||||
msg(c("NSApp"), s("postEvent:atStart:"), fakeevent, true);
|
|
||||||
// msg(c(app->mainWindow), s("performClose:"))
|
|
||||||
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetTitle sets the main window title to the given string
|
// SetTitle sets the main window title to the given string
|
||||||
void SetTitle(struct Application *app, const char *title) {
|
void SetTitle(struct Application *app, const char *title) {
|
||||||
// Guard against calling during shutdown
|
// Guard against calling during shutdown
|
||||||
@@ -1071,6 +1057,12 @@ void SetTrayMenu(struct Application *app, const char* trayMenuJSON) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeleteTrayMenuByID(struct Application *app, const char *id) {
|
||||||
|
ON_MAIN_THREAD(
|
||||||
|
DeleteTrayMenuInStore(app->trayMenuStore, id);
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void UpdateTrayMenuLabel(struct Application* app, const char* JSON) {
|
void UpdateTrayMenuLabel(struct Application* app, const char* JSON) {
|
||||||
// Guard against calling during shutdown
|
// Guard against calling during shutdown
|
||||||
if( app->shuttingDown ) return;
|
if( app->shuttingDown ) return;
|
||||||
@@ -1137,7 +1129,7 @@ void processDecorations(struct Application *app) {
|
|||||||
void createApplication(struct Application *app) {
|
void createApplication(struct Application *app) {
|
||||||
id application = msg(c("NSApplication"), s("sharedApplication"));
|
id application = msg(c("NSApplication"), s("sharedApplication"));
|
||||||
app->application = application;
|
app->application = application;
|
||||||
msg(application, s("setActivationPolicy:"), 0);
|
msg(application, s("setActivationPolicy:"), app->activationPolicy);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DarkModeEnabled(struct Application *app, const char *callbackID) {
|
void DarkModeEnabled(struct Application *app, const char *callbackID) {
|
||||||
@@ -1161,17 +1153,31 @@ void DarkModeEnabled(struct Application *app, const char *callbackID) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void getURL(id self, SEL selector, id event, id replyEvent) {
|
||||||
|
id desc = msg(event, s("paramDescriptorForKeyword:"), keyDirectObject);
|
||||||
|
id url = msg(desc, s("stringValue"));
|
||||||
|
const char* curl = cstr(url);
|
||||||
|
const char* message = concat("UC", curl);
|
||||||
|
messageFromWindowCallback(message);
|
||||||
|
MEMFREE(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void createDelegate(struct Application *app) {
|
void createDelegate(struct Application *app) {
|
||||||
// Define delegate
|
// Define delegate
|
||||||
Class delegateClass = objc_allocateClassPair((Class) c("NSObject"), "AppDelegate", 0);
|
Class delegateClass = objc_allocateClassPair((Class) c("NSObject"), "AppDelegate", 0);
|
||||||
bool resultAddProtoc = class_addProtocol(delegateClass, objc_getProtocol("NSApplicationDelegate"));
|
bool resultAddProtoc = class_addProtocol(delegateClass, objc_getProtocol("NSApplicationDelegate"));
|
||||||
class_addMethod(delegateClass, s("applicationShouldTerminateAfterLastWindowClosed:"), (IMP) no, "c@:@");
|
class_addMethod(delegateClass, s("applicationShouldTerminateAfterLastWindowClosed:"), (IMP) no, "c@:@");
|
||||||
// class_addMethod(delegateClass, s("applicationWillTerminate:"), (IMP) closeWindow, "v@:@");
|
|
||||||
class_addMethod(delegateClass, s("applicationWillFinishLaunching:"), (IMP) willFinishLaunching, "v@:@");
|
class_addMethod(delegateClass, s("applicationWillFinishLaunching:"), (IMP) willFinishLaunching, "v@:@");
|
||||||
|
|
||||||
// All Menu Items use a common callback
|
// All Menu Items use a common callback
|
||||||
class_addMethod(delegateClass, s("menuItemCallback:"), (IMP)menuItemCallback, "v@:@");
|
class_addMethod(delegateClass, s("menuItemCallback:"), (IMP)menuItemCallback, "v@:@");
|
||||||
|
|
||||||
|
// If there are URL Handlers, register the callback method
|
||||||
|
if( app->hasURLHandlers ) {
|
||||||
|
class_addMethod(delegateClass, s("getUrl:withReplyEvent:"), (IMP) getURL, "i@:@@");
|
||||||
|
}
|
||||||
|
|
||||||
// Script handler
|
// Script handler
|
||||||
class_addMethod(delegateClass, s("userContentController:didReceiveScriptMessage:"), (IMP) messageHandler, "v@:@@");
|
class_addMethod(delegateClass, s("userContentController:didReceiveScriptMessage:"), (IMP) messageHandler, "v@:@@");
|
||||||
objc_registerClassPair(delegateClass);
|
objc_registerClassPair(delegateClass);
|
||||||
@@ -1180,6 +1186,12 @@ void createDelegate(struct Application *app) {
|
|||||||
id delegate = msg((id)delegateClass, s("new"));
|
id delegate = msg((id)delegateClass, s("new"));
|
||||||
objc_setAssociatedObject(delegate, "application", (id)app, OBJC_ASSOCIATION_ASSIGN);
|
objc_setAssociatedObject(delegate, "application", (id)app, OBJC_ASSOCIATION_ASSIGN);
|
||||||
|
|
||||||
|
// If there are URL Handlers, register a listener for them
|
||||||
|
if( app->hasURLHandlers ) {
|
||||||
|
id eventManager = msg(c("NSAppleEventManager"), s("sharedAppleEventManager"));
|
||||||
|
msg(eventManager, s("setEventHandler:andSelector:forEventClass:andEventID:"), delegate, s("getUrl:withReplyEvent:"), kInternetEventClass, kAEGetURL);
|
||||||
|
}
|
||||||
|
|
||||||
// Theme change listener
|
// Theme change listener
|
||||||
class_addMethod(delegateClass, s("themeChanged:"), (IMP) themeChanged, "v@:@@");
|
class_addMethod(delegateClass, s("themeChanged:"), (IMP) themeChanged, "v@:@@");
|
||||||
|
|
||||||
@@ -1195,13 +1207,19 @@ void createDelegate(struct Application *app) {
|
|||||||
bool windowShouldClose(id self, SEL cmd, id sender) {
|
bool windowShouldClose(id self, SEL cmd, id sender) {
|
||||||
msg(sender, s("orderBack:"));
|
msg(sender, s("orderBack:"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool windowShouldExit(id self, SEL cmd, id sender) {
|
||||||
|
msg(sender, s("orderBack:"));
|
||||||
|
messageFromWindowCallback("WC");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void createMainWindow(struct Application *app) {
|
void createMainWindow(struct Application *app) {
|
||||||
// Create main window
|
// Create main window
|
||||||
id mainWindow = ALLOC("NSWindow");
|
id mainWindow = ALLOC("NSWindow");
|
||||||
mainWindow = msg(mainWindow, s("initWithContentRect:styleMask:backing:defer:"),
|
mainWindow = msg(mainWindow, s("initWithContentRect:styleMask:backing:defer:"),
|
||||||
CGRectMake(0, 0, app->width, app->height), app->decorations, NSBackingStoreBuffered, NO);
|
CGRectMake(0, 0, app->width, app->height), app->decorations, NSBackingStoreBuffered, NO);
|
||||||
msg(mainWindow, s("autorelease"));
|
msg(mainWindow, s("autorelease"));
|
||||||
|
|
||||||
// Set Appearance
|
// Set Appearance
|
||||||
@@ -1215,14 +1233,16 @@ void createMainWindow(struct Application *app) {
|
|||||||
msg(mainWindow, s("setTitlebarAppearsTransparent:"), app->titlebarAppearsTransparent ? YES : NO);
|
msg(mainWindow, s("setTitlebarAppearsTransparent:"), app->titlebarAppearsTransparent ? YES : NO);
|
||||||
msg(mainWindow, s("setTitleVisibility:"), app->hideTitle);
|
msg(mainWindow, s("setTitleVisibility:"), app->hideTitle);
|
||||||
|
|
||||||
if( app->hideWindowOnClose ) {
|
// Create window delegate to override windowShouldClose
|
||||||
// Create window delegate to override windowShouldClose
|
Class delegateClass = objc_allocateClassPair((Class) c("NSObject"), "WindowDelegate", 0);
|
||||||
Class delegateClass = objc_allocateClassPair((Class) c("NSObject"), "WindowDelegate", 0);
|
bool resultAddProtoc = class_addProtocol(delegateClass, objc_getProtocol("NSWindowDelegate"));
|
||||||
bool resultAddProtoc = class_addProtocol(delegateClass, objc_getProtocol("NSWindowDelegate"));
|
if( app->hideWindowOnClose ) {
|
||||||
class_replaceMethod(delegateClass, s("windowShouldClose:"), (IMP) windowShouldClose, "v@:@");
|
class_replaceMethod(delegateClass, s("windowShouldClose:"), (IMP) windowShouldClose, "v@:@");
|
||||||
app->windowDelegate = msg((id)delegateClass, s("new"));
|
} else {
|
||||||
msg(mainWindow, s("setDelegate:"), app->windowDelegate);
|
class_replaceMethod(delegateClass, s("windowShouldClose:"), (IMP) windowShouldExit, "v@:@");
|
||||||
}
|
}
|
||||||
|
app->windowDelegate = msg((id)delegateClass, s("new"));
|
||||||
|
msg(mainWindow, s("setDelegate:"), app->windowDelegate);
|
||||||
|
|
||||||
app->mainWindow = mainWindow;
|
app->mainWindow = mainWindow;
|
||||||
}
|
}
|
||||||
@@ -1837,6 +1857,23 @@ void Run(struct Application *app, int argc, char **argv) {
|
|||||||
MEMFREE(internalCode);
|
MEMFREE(internalCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetActivationPolicy(struct Application* app, int policy) {
|
||||||
|
app->activationPolicy = policy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HasURLHandlers(struct Application* app) {
|
||||||
|
app->hasURLHandlers = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quit will stop the cocoa application and free up all the memory
|
||||||
|
// used by the application
|
||||||
|
void Quit(struct Application *app) {
|
||||||
|
Debug(app, "Quit Called");
|
||||||
|
msg(app->application, s("stop:"), NULL);
|
||||||
|
SetSize(app, 0, 0);
|
||||||
|
Show(app);
|
||||||
|
Hide(app);
|
||||||
|
}
|
||||||
|
|
||||||
void* NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden, int logLevel, int hideWindowOnClose) {
|
void* NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden, int logLevel, int hideWindowOnClose) {
|
||||||
|
|
||||||
@@ -1899,6 +1936,10 @@ void* NewApplication(const char *title, int width, int height, int resizable, in
|
|||||||
|
|
||||||
result->shuttingDown = false;
|
result->shuttingDown = false;
|
||||||
|
|
||||||
|
result->activationPolicy = NSApplicationActivationPolicyRegular;
|
||||||
|
|
||||||
|
result->hasURLHandlers = 0;
|
||||||
|
|
||||||
return (void*) result;
|
return (void*) result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ func (a *Application) processPlatformSettings() error {
|
|||||||
C.SetAppearance(a.app, a.string2CString(string(mac.Appearance)))
|
C.SetAppearance(a.app, a.string2CString(string(mac.Appearance)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set activation policy
|
||||||
|
C.SetActivationPolicy(a.app, C.int(mac.ActivationPolicy))
|
||||||
|
|
||||||
// Check if the webview should be transparent
|
// Check if the webview should be transparent
|
||||||
if mac.WebviewIsTransparent {
|
if mac.WebviewIsTransparent {
|
||||||
C.WebviewIsTransparent(a.app)
|
C.WebviewIsTransparent(a.app)
|
||||||
@@ -87,5 +90,10 @@ func (a *Application) processPlatformSettings() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process URL Handlers
|
||||||
|
if a.config.Mac.URLHandlers != nil {
|
||||||
|
C.HasURLHandlers(a.app)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,10 @@
|
|||||||
// Macros to make it slightly more sane
|
// Macros to make it slightly more sane
|
||||||
#define msg objc_msgSend
|
#define msg objc_msgSend
|
||||||
|
|
||||||
|
#define kInternetEventClass 'GURL'
|
||||||
|
#define kAEGetURL 'GURL'
|
||||||
|
#define keyDirectObject '----'
|
||||||
|
|
||||||
#define c(str) (id)objc_getClass(str)
|
#define c(str) (id)objc_getClass(str)
|
||||||
#define s(str) sel_registerName(str)
|
#define s(str) sel_registerName(str)
|
||||||
#define u(str) sel_getUid(str)
|
#define u(str) sel_getUid(str)
|
||||||
@@ -66,6 +70,10 @@
|
|||||||
#define NSControlStateValueOff 0
|
#define NSControlStateValueOff 0
|
||||||
#define NSControlStateValueOn 1
|
#define NSControlStateValueOn 1
|
||||||
|
|
||||||
|
#define NSApplicationActivationPolicyRegular 0
|
||||||
|
#define NSApplicationActivationPolicyAccessory 1
|
||||||
|
#define NSApplicationActivationPolicyProhibited 2
|
||||||
|
|
||||||
// Unbelievably, if the user swaps their button preference
|
// Unbelievably, if the user swaps their button preference
|
||||||
// then right buttons are reported as left buttons
|
// then right buttons are reported as left buttons
|
||||||
#define NSEventMaskLeftMouseDown 1 << 1
|
#define NSEventMaskLeftMouseDown 1 << 1
|
||||||
@@ -110,6 +118,10 @@ void SetTray(struct Application* app, const char *, const char *, const char *);
|
|||||||
//void SetContextMenus(struct Application* app, const char *);
|
//void SetContextMenus(struct Application* app, const char *);
|
||||||
void AddTrayMenu(struct Application* app, const char *);
|
void AddTrayMenu(struct Application* app, const char *);
|
||||||
|
|
||||||
|
void SetActivationPolicy(struct Application* app, int policy);
|
||||||
|
|
||||||
void* lookupStringConstant(id constantName);
|
void* lookupStringConstant(id constantName);
|
||||||
|
|
||||||
|
void HasURLHandlers(struct Application* app);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -180,151 +180,151 @@ id processAcceleratorKey(const char *key) {
|
|||||||
return str("");
|
return str("");
|
||||||
}
|
}
|
||||||
|
|
||||||
if( STREQ(key, "Backspace") ) {
|
if( STREQ(key, "backspace") ) {
|
||||||
return strunicode(0x0008);
|
return strunicode(0x0008);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "Tab") ) {
|
if( STREQ(key, "tab") ) {
|
||||||
return strunicode(0x0009);
|
return strunicode(0x0009);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "Return") ) {
|
if( STREQ(key, "return") ) {
|
||||||
return strunicode(0x000d);
|
return strunicode(0x000d);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "Escape") ) {
|
if( STREQ(key, "escape") ) {
|
||||||
return strunicode(0x001b);
|
return strunicode(0x001b);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "Left") ) {
|
if( STREQ(key, "left") ) {
|
||||||
return strunicode(0x001c);
|
return strunicode(0x001c);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "Right") ) {
|
if( STREQ(key, "right") ) {
|
||||||
return strunicode(0x001d);
|
return strunicode(0x001d);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "Up") ) {
|
if( STREQ(key, "up") ) {
|
||||||
return strunicode(0x001e);
|
return strunicode(0x001e);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "Down") ) {
|
if( STREQ(key, "down") ) {
|
||||||
return strunicode(0x001f);
|
return strunicode(0x001f);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "Space") ) {
|
if( STREQ(key, "space") ) {
|
||||||
return strunicode(0x0020);
|
return strunicode(0x0020);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "Delete") ) {
|
if( STREQ(key, "delete") ) {
|
||||||
return strunicode(0x007f);
|
return strunicode(0x007f);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "Home") ) {
|
if( STREQ(key, "home") ) {
|
||||||
return strunicode(0x2196);
|
return strunicode(0x2196);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "End") ) {
|
if( STREQ(key, "end") ) {
|
||||||
return strunicode(0x2198);
|
return strunicode(0x2198);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "Page Up") ) {
|
if( STREQ(key, "page up") ) {
|
||||||
return strunicode(0x21de);
|
return strunicode(0x21de);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "Page Down") ) {
|
if( STREQ(key, "page down") ) {
|
||||||
return strunicode(0x21df);
|
return strunicode(0x21df);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F1") ) {
|
if( STREQ(key, "f1") ) {
|
||||||
return strunicode(0xf704);
|
return strunicode(0xf704);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F2") ) {
|
if( STREQ(key, "f2") ) {
|
||||||
return strunicode(0xf705);
|
return strunicode(0xf705);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F3") ) {
|
if( STREQ(key, "f3") ) {
|
||||||
return strunicode(0xf706);
|
return strunicode(0xf706);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F4") ) {
|
if( STREQ(key, "f4") ) {
|
||||||
return strunicode(0xf707);
|
return strunicode(0xf707);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F5") ) {
|
if( STREQ(key, "f5") ) {
|
||||||
return strunicode(0xf708);
|
return strunicode(0xf708);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F6") ) {
|
if( STREQ(key, "f6") ) {
|
||||||
return strunicode(0xf709);
|
return strunicode(0xf709);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F7") ) {
|
if( STREQ(key, "f7") ) {
|
||||||
return strunicode(0xf70a);
|
return strunicode(0xf70a);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F8") ) {
|
if( STREQ(key, "f8") ) {
|
||||||
return strunicode(0xf70b);
|
return strunicode(0xf70b);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F9") ) {
|
if( STREQ(key, "f9") ) {
|
||||||
return strunicode(0xf70c);
|
return strunicode(0xf70c);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F10") ) {
|
if( STREQ(key, "f10") ) {
|
||||||
return strunicode(0xf70d);
|
return strunicode(0xf70d);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F11") ) {
|
if( STREQ(key, "f11") ) {
|
||||||
return strunicode(0xf70e);
|
return strunicode(0xf70e);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F12") ) {
|
if( STREQ(key, "f12") ) {
|
||||||
return strunicode(0xf70f);
|
return strunicode(0xf70f);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F13") ) {
|
if( STREQ(key, "f13") ) {
|
||||||
return strunicode(0xf710);
|
return strunicode(0xf710);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F14") ) {
|
if( STREQ(key, "f14") ) {
|
||||||
return strunicode(0xf711);
|
return strunicode(0xf711);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F15") ) {
|
if( STREQ(key, "f15") ) {
|
||||||
return strunicode(0xf712);
|
return strunicode(0xf712);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F16") ) {
|
if( STREQ(key, "f16") ) {
|
||||||
return strunicode(0xf713);
|
return strunicode(0xf713);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F17") ) {
|
if( STREQ(key, "f17") ) {
|
||||||
return strunicode(0xf714);
|
return strunicode(0xf714);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F18") ) {
|
if( STREQ(key, "f18") ) {
|
||||||
return strunicode(0xf715);
|
return strunicode(0xf715);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F19") ) {
|
if( STREQ(key, "f19") ) {
|
||||||
return strunicode(0xf716);
|
return strunicode(0xf716);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F20") ) {
|
if( STREQ(key, "f20") ) {
|
||||||
return strunicode(0xf717);
|
return strunicode(0xf717);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F21") ) {
|
if( STREQ(key, "f21") ) {
|
||||||
return strunicode(0xf718);
|
return strunicode(0xf718);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F22") ) {
|
if( STREQ(key, "f22") ) {
|
||||||
return strunicode(0xf719);
|
return strunicode(0xf719);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F23") ) {
|
if( STREQ(key, "f23") ) {
|
||||||
return strunicode(0xf71a);
|
return strunicode(0xf71a);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F24") ) {
|
if( STREQ(key, "f24") ) {
|
||||||
return strunicode(0xf71b);
|
return strunicode(0xf71b);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F25") ) {
|
if( STREQ(key, "f25") ) {
|
||||||
return strunicode(0xf71c);
|
return strunicode(0xf71c);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F26") ) {
|
if( STREQ(key, "f26") ) {
|
||||||
return strunicode(0xf71d);
|
return strunicode(0xf71d);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F27") ) {
|
if( STREQ(key, "f27") ) {
|
||||||
return strunicode(0xf71e);
|
return strunicode(0xf71e);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F28") ) {
|
if( STREQ(key, "f28") ) {
|
||||||
return strunicode(0xf71f);
|
return strunicode(0xf71f);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F29") ) {
|
if( STREQ(key, "f29") ) {
|
||||||
return strunicode(0xf720);
|
return strunicode(0xf720);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F30") ) {
|
if( STREQ(key, "f30") ) {
|
||||||
return strunicode(0xf721);
|
return strunicode(0xf721);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F31") ) {
|
if( STREQ(key, "f31") ) {
|
||||||
return strunicode(0xf722);
|
return strunicode(0xf722);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F32") ) {
|
if( STREQ(key, "f32") ) {
|
||||||
return strunicode(0xf723);
|
return strunicode(0xf723);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F33") ) {
|
if( STREQ(key, "f33") ) {
|
||||||
return strunicode(0xf724);
|
return strunicode(0xf724);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F34") ) {
|
if( STREQ(key, "f34") ) {
|
||||||
return strunicode(0xf725);
|
return strunicode(0xf725);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "F35") ) {
|
if( STREQ(key, "f35") ) {
|
||||||
return strunicode(0xf726);
|
return strunicode(0xf726);
|
||||||
}
|
}
|
||||||
// if( STREQ(key, "Insert") ) {
|
// if( STREQ(key, "Insert") ) {
|
||||||
@@ -336,7 +336,7 @@ id processAcceleratorKey(const char *key) {
|
|||||||
// if( STREQ(key, "ScrollLock") ) {
|
// if( STREQ(key, "ScrollLock") ) {
|
||||||
// return strunicode(0xf72f);
|
// return strunicode(0xf72f);
|
||||||
// }
|
// }
|
||||||
if( STREQ(key, "NumLock") ) {
|
if( STREQ(key, "numLock") ) {
|
||||||
return strunicode(0xf739);
|
return strunicode(0xf739);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -508,20 +508,21 @@ unsigned long parseModifiers(const char **modifiers) {
|
|||||||
const char *thisModifier = modifiers[0];
|
const char *thisModifier = modifiers[0];
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while( thisModifier != NULL ) {
|
while( thisModifier != NULL ) {
|
||||||
|
|
||||||
// Determine flags
|
// Determine flags
|
||||||
if( STREQ(thisModifier, "CmdOrCtrl") ) {
|
if( STREQ(thisModifier, "cmdorctrl") ) {
|
||||||
result |= NSEventModifierFlagCommand;
|
result |= NSEventModifierFlagCommand;
|
||||||
}
|
}
|
||||||
if( STREQ(thisModifier, "OptionOrAlt") ) {
|
if( STREQ(thisModifier, "optionoralt") ) {
|
||||||
result |= NSEventModifierFlagOption;
|
result |= NSEventModifierFlagOption;
|
||||||
}
|
}
|
||||||
if( STREQ(thisModifier, "Shift") ) {
|
if( STREQ(thisModifier, "shift") ) {
|
||||||
result |= NSEventModifierFlagShift;
|
result |= NSEventModifierFlagShift;
|
||||||
}
|
}
|
||||||
if( STREQ(thisModifier, "Super") ) {
|
if( STREQ(thisModifier, "super") ) {
|
||||||
result |= NSEventModifierFlagCommand;
|
result |= NSEventModifierFlagCommand;
|
||||||
}
|
}
|
||||||
if( STREQ(thisModifier, "Control") ) {
|
if( STREQ(thisModifier, "ctrl") ) {
|
||||||
result |= NSEventModifierFlagControl;
|
result |= NSEventModifierFlagControl;
|
||||||
}
|
}
|
||||||
count++;
|
count++;
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ TrayMenuStore* NewTrayMenuStore() {
|
|||||||
ABORT("[NewTrayMenuStore] Not enough memory to allocate trayMenuMap!");
|
ABORT("[NewTrayMenuStore] Not enough memory to allocate trayMenuMap!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pthread_mutex_init(&result->lock, NULL) != 0) {
|
||||||
|
printf("\n mutex init has failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,15 +30,19 @@ int dumpTrayMenu(void *const context, struct hashmap_element_s *const e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DumpTrayMenuStore(TrayMenuStore* store) {
|
void DumpTrayMenuStore(TrayMenuStore* store) {
|
||||||
|
pthread_mutex_lock(&store->lock);
|
||||||
hashmap_iterate_pairs(&store->trayMenuMap, dumpTrayMenu, NULL);
|
hashmap_iterate_pairs(&store->trayMenuMap, dumpTrayMenu, NULL);
|
||||||
|
pthread_mutex_unlock(&store->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddTrayMenuToStore(TrayMenuStore* store, const char* menuJSON) {
|
void AddTrayMenuToStore(TrayMenuStore* store, const char* menuJSON) {
|
||||||
|
|
||||||
TrayMenu* newMenu = NewTrayMenu(menuJSON);
|
TrayMenu* newMenu = NewTrayMenu(menuJSON);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&store->lock);
|
||||||
//TODO: check if there is already an entry for this menu
|
//TODO: check if there is already an entry for this menu
|
||||||
hashmap_put(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu);
|
hashmap_put(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu);
|
||||||
|
pthread_mutex_unlock(&store->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
int showTrayMenu(void *const context, struct hashmap_element_s *const e) {
|
int showTrayMenu(void *const context, struct hashmap_element_s *const e) {
|
||||||
@@ -43,12 +52,13 @@ int showTrayMenu(void *const context, struct hashmap_element_s *const e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ShowTrayMenusInStore(TrayMenuStore* store) {
|
void ShowTrayMenusInStore(TrayMenuStore* store) {
|
||||||
|
pthread_mutex_lock(&store->lock);
|
||||||
if( hashmap_num_entries(&store->trayMenuMap) > 0 ) {
|
if( hashmap_num_entries(&store->trayMenuMap) > 0 ) {
|
||||||
hashmap_iterate_pairs(&store->trayMenuMap, showTrayMenu, NULL);
|
hashmap_iterate_pairs(&store->trayMenuMap, showTrayMenu, NULL);
|
||||||
}
|
}
|
||||||
|
pthread_mutex_unlock(&store->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int freeTrayMenu(void *const context, struct hashmap_element_s *const e) {
|
int freeTrayMenu(void *const context, struct hashmap_element_s *const e) {
|
||||||
DeleteTrayMenu(e->data);
|
DeleteTrayMenu(e->data);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -65,22 +75,39 @@ void DeleteTrayMenuStore(TrayMenuStore *store) {
|
|||||||
|
|
||||||
// Destroy tray menu map
|
// Destroy tray menu map
|
||||||
hashmap_destroy(&store->trayMenuMap);
|
hashmap_destroy(&store->trayMenuMap);
|
||||||
|
|
||||||
|
pthread_mutex_destroy(&store->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
TrayMenu* GetTrayMenuFromStore(TrayMenuStore* store, const char* menuID) {
|
TrayMenu* GetTrayMenuFromStore(TrayMenuStore* store, const char* menuID) {
|
||||||
// Get the current menu
|
// Get the current menu
|
||||||
return hashmap_get(&store->trayMenuMap, menuID, strlen(menuID));
|
pthread_mutex_lock(&store->lock);
|
||||||
|
TrayMenu* result = hashmap_get(&store->trayMenuMap, menuID, strlen(menuID));
|
||||||
|
pthread_mutex_unlock(&store->lock);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TrayMenu* MustGetTrayMenuFromStore(TrayMenuStore* store, const char* menuID) {
|
TrayMenu* MustGetTrayMenuFromStore(TrayMenuStore* store, const char* menuID) {
|
||||||
// Get the current menu
|
// Get the current menu
|
||||||
|
pthread_mutex_lock(&store->lock);
|
||||||
TrayMenu* result = hashmap_get(&store->trayMenuMap, menuID, strlen(menuID));
|
TrayMenu* result = hashmap_get(&store->trayMenuMap, menuID, strlen(menuID));
|
||||||
|
pthread_mutex_unlock(&store->lock);
|
||||||
|
|
||||||
if (result == NULL ) {
|
if (result == NULL ) {
|
||||||
ABORT("Unable to find TrayMenu with ID '%s' in the TrayMenuStore!", menuID);
|
ABORT("Unable to find TrayMenu with ID '%s' in the TrayMenuStore!", menuID);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeleteTrayMenuInStore(TrayMenuStore* store, const char* ID) {
|
||||||
|
|
||||||
|
TrayMenu *menu = MustGetTrayMenuFromStore(store, ID);
|
||||||
|
pthread_mutex_lock(&store->lock);
|
||||||
|
hashmap_remove(&store->trayMenuMap, ID, strlen(ID));
|
||||||
|
pthread_mutex_unlock(&store->lock);
|
||||||
|
DeleteTrayMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
void UpdateTrayMenuLabelInStore(TrayMenuStore* store, const char* JSON) {
|
void UpdateTrayMenuLabelInStore(TrayMenuStore* store, const char* JSON) {
|
||||||
// Parse the JSON
|
// Parse the JSON
|
||||||
JsonNode *parsedUpdate = mustParseJSON(JSON);
|
JsonNode *parsedUpdate = mustParseJSON(JSON);
|
||||||
@@ -105,7 +132,9 @@ void UpdateTrayMenuInStore(TrayMenuStore* store, const char* menuJSON) {
|
|||||||
// If we don't have a menu, we create one
|
// If we don't have a menu, we create one
|
||||||
if ( currentMenu == NULL ) {
|
if ( currentMenu == NULL ) {
|
||||||
// Store the new menu
|
// Store the new menu
|
||||||
|
pthread_mutex_lock(&store->lock);
|
||||||
hashmap_put(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu);
|
hashmap_put(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu);
|
||||||
|
pthread_mutex_unlock(&store->lock);
|
||||||
|
|
||||||
// Show it
|
// Show it
|
||||||
ShowTrayMenu(newMenu);
|
ShowTrayMenu(newMenu);
|
||||||
@@ -116,7 +145,9 @@ void UpdateTrayMenuInStore(TrayMenuStore* store, const char* menuJSON) {
|
|||||||
// Save the status bar reference
|
// Save the status bar reference
|
||||||
newMenu->statusbaritem = currentMenu->statusbaritem;
|
newMenu->statusbaritem = currentMenu->statusbaritem;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&store->lock);
|
||||||
hashmap_remove(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID));
|
hashmap_remove(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID));
|
||||||
|
pthread_mutex_unlock(&store->lock);
|
||||||
|
|
||||||
// Delete the current menu
|
// Delete the current menu
|
||||||
DeleteMenu(currentMenu->menu);
|
DeleteMenu(currentMenu->menu);
|
||||||
@@ -125,9 +156,10 @@ void UpdateTrayMenuInStore(TrayMenuStore* store, const char* menuJSON) {
|
|||||||
// Free the tray menu memory
|
// Free the tray menu memory
|
||||||
MEMFREE(currentMenu);
|
MEMFREE(currentMenu);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&store->lock);
|
||||||
hashmap_put(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu);
|
hashmap_put(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu);
|
||||||
|
pthread_mutex_unlock(&store->lock);
|
||||||
|
|
||||||
// Show the updated menu
|
// Show the updated menu
|
||||||
ShowTrayMenu(newMenu);
|
ShowTrayMenu(newMenu);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
#ifndef TRAYMENUSTORE_DARWIN_H
|
#ifndef TRAYMENUSTORE_DARWIN_H
|
||||||
#define TRAYMENUSTORE_DARWIN_H
|
#define TRAYMENUSTORE_DARWIN_H
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
||||||
int dummy;
|
int dummy;
|
||||||
@@ -13,6 +15,8 @@ typedef struct {
|
|||||||
// It maps tray IDs to TrayMenu*
|
// It maps tray IDs to TrayMenu*
|
||||||
struct hashmap_s trayMenuMap;
|
struct hashmap_s trayMenuMap;
|
||||||
|
|
||||||
|
pthread_mutex_t lock;
|
||||||
|
|
||||||
} TrayMenuStore;
|
} TrayMenuStore;
|
||||||
|
|
||||||
TrayMenuStore* NewTrayMenuStore();
|
TrayMenuStore* NewTrayMenuStore();
|
||||||
@@ -23,5 +27,6 @@ void ShowTrayMenusInStore(TrayMenuStore* store);
|
|||||||
void DeleteTrayMenuStore(TrayMenuStore* store);
|
void DeleteTrayMenuStore(TrayMenuStore* store);
|
||||||
|
|
||||||
void UpdateTrayMenuLabelInStore(TrayMenuStore* store, const char* JSON);
|
void UpdateTrayMenuLabelInStore(TrayMenuStore* store, const char* JSON);
|
||||||
|
void DeleteTrayMenuInStore(TrayMenuStore* store, const char* id);
|
||||||
|
|
||||||
#endif //TRAYMENUSTORE_DARWIN_H
|
#endif //TRAYMENUSTORE_DARWIN_H
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ func Mkdir(dirname string) error {
|
|||||||
// Returns error on failure
|
// Returns error on failure
|
||||||
func MkDirs(fullPath string, mode ...os.FileMode) error {
|
func MkDirs(fullPath string, mode ...os.FileMode) error {
|
||||||
var perms os.FileMode
|
var perms os.FileMode
|
||||||
perms = 0700
|
perms = 0755
|
||||||
if len(mode) == 1 {
|
if len(mode) == 1 {
|
||||||
perms = mode[0]
|
perms = mode[0]
|
||||||
}
|
}
|
||||||
@@ -243,7 +243,7 @@ func CopyDir(src string, dst string) (err error) {
|
|||||||
return fmt.Errorf("destination already exists")
|
return fmt.Errorf("destination already exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = os.MkdirAll(dst, si.Mode())
|
err = MkDirs(dst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,20 +3,23 @@ package menumanager
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
"sync"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var trayMenuID int
|
var trayMenuID int
|
||||||
var trayMenuIDMutex sync.Mutex
|
var trayMenuIDMutex sync.Mutex
|
||||||
|
|
||||||
func generateTrayID() string {
|
func generateTrayID() string {
|
||||||
|
var idStr string
|
||||||
trayMenuIDMutex.Lock()
|
trayMenuIDMutex.Lock()
|
||||||
result := fmt.Sprintf("%d", trayMenuID)
|
idStr = strconv.Itoa(trayMenuID)
|
||||||
trayMenuID++
|
trayMenuID++
|
||||||
trayMenuIDMutex.Unlock()
|
trayMenuIDMutex.Unlock()
|
||||||
return result
|
return idStr
|
||||||
}
|
}
|
||||||
|
|
||||||
type TrayMenu struct {
|
type TrayMenu struct {
|
||||||
@@ -65,6 +68,14 @@ func (m *Manager) AddTrayMenu(trayMenu *menu.TrayMenu) (string, error) {
|
|||||||
return newTrayMenu.AsJSON()
|
return newTrayMenu.AsJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Manager) GetTrayID(trayMenu *menu.TrayMenu) (string, error) {
|
||||||
|
trayID, exists := m.trayMenuPointers[trayMenu]
|
||||||
|
if !exists {
|
||||||
|
return "", fmt.Errorf("Unable to find menu ID for tray menu!")
|
||||||
|
}
|
||||||
|
return trayID, nil
|
||||||
|
}
|
||||||
|
|
||||||
// SetTrayMenu updates or creates a menu
|
// SetTrayMenu updates or creates a menu
|
||||||
func (m *Manager) SetTrayMenu(trayMenu *menu.TrayMenu) (string, error) {
|
func (m *Manager) SetTrayMenu(trayMenu *menu.TrayMenu) (string, error) {
|
||||||
trayID, trayMenuKnown := m.trayMenuPointers[trayMenu]
|
trayID, trayMenuKnown := m.trayMenuPointers[trayMenu]
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ type Client interface {
|
|||||||
SetTrayMenu(trayMenuJSON string)
|
SetTrayMenu(trayMenuJSON string)
|
||||||
UpdateTrayMenuLabel(JSON string)
|
UpdateTrayMenuLabel(JSON string)
|
||||||
UpdateContextMenu(contextMenuJSON string)
|
UpdateContextMenu(contextMenuJSON string)
|
||||||
|
DeleteTrayMenuByID(id string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DispatchClient is what the frontends use to interface with the
|
// DispatchClient is what the frontends use to interface with the
|
||||||
|
|||||||
@@ -21,13 +21,14 @@ var messageParsers = map[byte]func(string) (*parsedMessage, error){
|
|||||||
'M': menuMessageParser,
|
'M': menuMessageParser,
|
||||||
'T': trayMessageParser,
|
'T': trayMessageParser,
|
||||||
'X': contextMenusMessageParser,
|
'X': contextMenusMessageParser,
|
||||||
|
'U': urlMessageParser,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse will attempt to parse the given message
|
// Parse will attempt to parse the given message
|
||||||
func Parse(message string) (*parsedMessage, error) {
|
func Parse(message string) (*parsedMessage, error) {
|
||||||
|
|
||||||
if len(message) == 0 {
|
if len(message) == 0 {
|
||||||
return nil, fmt.Errorf("MessageParser received blank message");
|
return nil, fmt.Errorf("MessageParser received blank message")
|
||||||
}
|
}
|
||||||
|
|
||||||
parseMethod := messageParsers[message[0]]
|
parseMethod := messageParsers[message[0]]
|
||||||
|
|||||||
20
v2/internal/messagedispatcher/message/url.go
Normal file
20
v2/internal/messagedispatcher/message/url.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package message
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// urlMessageParser does what it says on the tin!
|
||||||
|
func urlMessageParser(message string) (*parsedMessage, error) {
|
||||||
|
|
||||||
|
// Sanity check: URL messages must be at least 2 bytes
|
||||||
|
if len(message) < 2 {
|
||||||
|
return nil, fmt.Errorf("log message was an invalid length")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch on the log type
|
||||||
|
switch message[1] {
|
||||||
|
case 'C':
|
||||||
|
return &parsedMessage{Topic: "url:handler", Data: message[2:]}, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("url message type '%c' invalid", message[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -527,6 +527,17 @@ func (d *Dispatcher) processMenuMessage(result *servicebus.Message) {
|
|||||||
for _, client := range d.clients {
|
for _, client := range d.clients {
|
||||||
client.frontend.UpdateTrayMenuLabel(updatedTrayMenuLabel)
|
client.frontend.UpdateTrayMenuLabel(updatedTrayMenuLabel)
|
||||||
}
|
}
|
||||||
|
case "deletetraymenu":
|
||||||
|
traymenuid, ok := result.Data().(string)
|
||||||
|
if !ok {
|
||||||
|
d.logger.Error("Invalid data for 'menufrontend:updatetraymenulabel' : %#v",
|
||||||
|
result.Data())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, client := range d.clients {
|
||||||
|
client.frontend.DeleteTrayMenuByID(traymenuid)
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
d.logger.Error("Unknown menufrontend command: %s", command)
|
d.logger.Error("Unknown menufrontend command: %s", command)
|
||||||
|
|||||||
@@ -39,7 +39,12 @@ func (p *Process) Start() error {
|
|||||||
|
|
||||||
go func(cmd *exec.Cmd, running *bool, logger *clilogger.CLILogger, exitChannel chan bool) {
|
go func(cmd *exec.Cmd, running *bool, logger *clilogger.CLILogger, exitChannel chan bool) {
|
||||||
logger.Println("Starting process (PID: %d)", cmd.Process.Pid)
|
logger.Println("Starting process (PID: %d)", cmd.Process.Pid)
|
||||||
cmd.Wait()
|
err := cmd.Wait()
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() != "signal: killed" {
|
||||||
|
logger.Fatal("Fatal error from app: " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
logger.Println("Exiting process (PID: %d)", cmd.Process.Pid)
|
logger.Println("Exiting process (PID: %d)", cmd.Process.Pid)
|
||||||
*running = false
|
*running = false
|
||||||
exitChannel <- true
|
exitChannel <- true
|
||||||
|
|||||||
@@ -620,7 +620,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Menubar **/
|
/** Menubar **/
|
||||||
const menuVisible = writable(true);
|
const menuVisible = writable(false);
|
||||||
|
|
||||||
/** Trays **/
|
/** Trays **/
|
||||||
|
|
||||||
@@ -649,6 +649,18 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function deleteTrayMenu(id) {
|
||||||
|
trays.update((current) => {
|
||||||
|
// Remove existing if it exists, else add
|
||||||
|
const index = current.findIndex(item => item.ID === id);
|
||||||
|
if ( index === -1 ) {
|
||||||
|
return log("ERROR: Attempted to delete tray index ")
|
||||||
|
}
|
||||||
|
current.splice(index, 1);
|
||||||
|
return current;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let selectedMenu = writable(null);
|
let selectedMenu = writable(null);
|
||||||
|
|
||||||
function fade(node, { delay = 0, duration = 400, easing = identity } = {}) {
|
function fade(node, { delay = 0, duration = 400, easing = identity } = {}) {
|
||||||
@@ -1220,11 +1232,11 @@
|
|||||||
|
|
||||||
function get_each_context$1(ctx, list, i) {
|
function get_each_context$1(ctx, list, i) {
|
||||||
const child_ctx = ctx.slice();
|
const child_ctx = ctx.slice();
|
||||||
child_ctx[8] = list[i];
|
child_ctx[9] = list[i];
|
||||||
return child_ctx;
|
return child_ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
// (29:0) {#if $menuVisible }
|
// (38:0) {#if $menuVisible }
|
||||||
function create_if_block$3(ctx) {
|
function create_if_block$3(ctx) {
|
||||||
let div;
|
let div;
|
||||||
let span1;
|
let span1;
|
||||||
@@ -1336,11 +1348,11 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// (32:4) {#each $trays as tray}
|
// (41:4) {#each $trays as tray}
|
||||||
function create_each_block$1(ctx) {
|
function create_each_block$1(ctx) {
|
||||||
let traymenu;
|
let traymenu;
|
||||||
let current;
|
let current;
|
||||||
traymenu = new TrayMenu({ props: { tray: /*tray*/ ctx[8] } });
|
traymenu = new TrayMenu({ props: { tray: /*tray*/ ctx[9] } });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
c() {
|
c() {
|
||||||
@@ -1352,7 +1364,7 @@
|
|||||||
},
|
},
|
||||||
p(ctx, dirty) {
|
p(ctx, dirty) {
|
||||||
const traymenu_changes = {};
|
const traymenu_changes = {};
|
||||||
if (dirty & /*$trays*/ 4) traymenu_changes.tray = /*tray*/ ctx[8];
|
if (dirty & /*$trays*/ 4) traymenu_changes.tray = /*tray*/ ctx[9];
|
||||||
traymenu.$set(traymenu_changes);
|
traymenu.$set(traymenu_changes);
|
||||||
},
|
},
|
||||||
i(local) {
|
i(local) {
|
||||||
@@ -1373,6 +1385,8 @@
|
|||||||
function create_fragment$3(ctx) {
|
function create_fragment$3(ctx) {
|
||||||
let if_block_anchor;
|
let if_block_anchor;
|
||||||
let current;
|
let current;
|
||||||
|
let mounted;
|
||||||
|
let dispose;
|
||||||
let if_block = /*$menuVisible*/ ctx[1] && create_if_block$3(ctx);
|
let if_block = /*$menuVisible*/ ctx[1] && create_if_block$3(ctx);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -1384,6 +1398,11 @@
|
|||||||
if (if_block) if_block.m(target, anchor);
|
if (if_block) if_block.m(target, anchor);
|
||||||
insert(target, if_block_anchor, anchor);
|
insert(target, if_block_anchor, anchor);
|
||||||
current = true;
|
current = true;
|
||||||
|
|
||||||
|
if (!mounted) {
|
||||||
|
dispose = listen(window, "keydown", /*handleKeydown*/ ctx[3]);
|
||||||
|
mounted = true;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
p(ctx, [dirty]) {
|
p(ctx, [dirty]) {
|
||||||
if (/*$menuVisible*/ ctx[1]) {
|
if (/*$menuVisible*/ ctx[1]) {
|
||||||
@@ -1421,6 +1440,8 @@
|
|||||||
d(detaching) {
|
d(detaching) {
|
||||||
if (if_block) if_block.d(detaching);
|
if (if_block) if_block.d(detaching);
|
||||||
if (detaching) detach(if_block_anchor);
|
if (detaching) detach(if_block_anchor);
|
||||||
|
mounted = false;
|
||||||
|
dispose();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1440,7 +1461,7 @@
|
|||||||
onMount(() => {
|
onMount(() => {
|
||||||
const interval = setInterval(
|
const interval = setInterval(
|
||||||
() => {
|
() => {
|
||||||
$$invalidate(3, time = new Date());
|
$$invalidate(4, time = new Date());
|
||||||
},
|
},
|
||||||
1000
|
1000
|
||||||
);
|
);
|
||||||
@@ -1450,33 +1471,52 @@
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function handleKeydown(e) {
|
||||||
|
// Backtick toggle
|
||||||
|
if (e.keyCode == 192) {
|
||||||
|
menuVisible.update(current => {
|
||||||
|
return !current;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$$self.$$.update = () => {
|
$$self.$$.update = () => {
|
||||||
if ($$self.$$.dirty & /*time*/ 8) {
|
if ($$self.$$.dirty & /*time*/ 16) {
|
||||||
$$invalidate(4, day = time.toLocaleString("default", { weekday: "short" }));
|
$$invalidate(5, day = time.toLocaleString("default", { weekday: "short" }));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($$self.$$.dirty & /*time*/ 8) {
|
if ($$self.$$.dirty & /*time*/ 16) {
|
||||||
$$invalidate(5, dom = time.getDate());
|
$$invalidate(6, dom = time.getDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($$self.$$.dirty & /*time*/ 8) {
|
if ($$self.$$.dirty & /*time*/ 16) {
|
||||||
$$invalidate(6, mon = time.toLocaleString("default", { month: "short" }));
|
$$invalidate(7, mon = time.toLocaleString("default", { month: "short" }));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($$self.$$.dirty & /*time*/ 8) {
|
if ($$self.$$.dirty & /*time*/ 16) {
|
||||||
$$invalidate(7, currentTime = time.toLocaleString("en-US", {
|
$$invalidate(8, currentTime = time.toLocaleString("en-US", {
|
||||||
hour: "numeric",
|
hour: "numeric",
|
||||||
minute: "numeric",
|
minute: "numeric",
|
||||||
hour12: true
|
hour12: true
|
||||||
}).toLowerCase());
|
}).toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($$self.$$.dirty & /*day, dom, mon, currentTime*/ 240) {
|
if ($$self.$$.dirty & /*day, dom, mon, currentTime*/ 480) {
|
||||||
$$invalidate(0, dateTimeString = `${day} ${dom} ${mon} ${currentTime}`);
|
$$invalidate(0, dateTimeString = `${day} ${dom} ${mon} ${currentTime}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return [dateTimeString, $menuVisible, $trays, time, day, dom, mon, currentTime];
|
return [
|
||||||
|
dateTimeString,
|
||||||
|
$menuVisible,
|
||||||
|
$trays,
|
||||||
|
handleKeydown,
|
||||||
|
time,
|
||||||
|
day,
|
||||||
|
dom,
|
||||||
|
mon,
|
||||||
|
currentTime
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
class Menubar extends SvelteComponent {
|
class Menubar extends SvelteComponent {
|
||||||
@@ -1638,6 +1678,11 @@
|
|||||||
let trayLabelData = JSON.parse(updateTrayLabelJSON);
|
let trayLabelData = JSON.parse(updateTrayLabelJSON);
|
||||||
updateTrayLabel(trayLabelData);
|
updateTrayLabel(trayLabelData);
|
||||||
break
|
break
|
||||||
|
case 'D':
|
||||||
|
// Delete Tray Menu
|
||||||
|
const id = trayMessage.slice(1);
|
||||||
|
deleteTrayMenu(id);
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
log('Unknown tray message: ' + message.data);
|
log('Unknown tray message: ' + message.data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wails/runtime",
|
"name": "@wails/runtime",
|
||||||
"version": "1.3.9",
|
"version": "1.3.12",
|
||||||
"description": "Wails V2 Javascript runtime library",
|
"description": "Wails V2 Javascript runtime library",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"types": "runtime.d.ts",
|
"types": "runtime.d.ts",
|
||||||
|
|||||||
@@ -24,6 +24,15 @@
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function handleKeydown(e) {
|
||||||
|
// Backtick toggle
|
||||||
|
if( e.keyCode == 192 ) {
|
||||||
|
menuVisible.update( (current) => {
|
||||||
|
return !current;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $menuVisible }
|
{#if $menuVisible }
|
||||||
@@ -37,6 +46,8 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<svelte:window on:keydown={handleKeydown}/>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
.tray-menus {
|
.tray-menus {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export function hideOverlay() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Menubar **/
|
/** Menubar **/
|
||||||
export const menuVisible = writable(true);
|
export const menuVisible = writable(false);
|
||||||
|
|
||||||
export function showMenuBar() {
|
export function showMenuBar() {
|
||||||
menuVisible.set(true);
|
menuVisible.set(true);
|
||||||
@@ -49,4 +49,16 @@ export function updateTrayLabel(tray) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function deleteTrayMenu(id) {
|
||||||
|
trays.update((current) => {
|
||||||
|
// Remove existing if it exists, else add
|
||||||
|
const index = current.findIndex(item => item.ID === id);
|
||||||
|
if ( index === -1 ) {
|
||||||
|
return log("ERROR: Attempted to delete tray index ", id, "but it doesn't exist")
|
||||||
|
}
|
||||||
|
current.splice(index, 1);
|
||||||
|
return current;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export let selectedMenu = writable(null);
|
export let selectedMenu = writable(null);
|
||||||
@@ -10,7 +10,7 @@ The lightweight framework for web-like apps
|
|||||||
/* jshint esversion: 6 */
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
|
||||||
import {setTray, hideOverlay, showOverlay, updateTrayLabel} from "./store";
|
import {setTray, hideOverlay, showOverlay, updateTrayLabel, deleteTrayMenu} from "./store";
|
||||||
import {log} from "./log";
|
import {log} from "./log";
|
||||||
|
|
||||||
let websocket = null;
|
let websocket = null;
|
||||||
@@ -154,6 +154,11 @@ function handleMessage(message) {
|
|||||||
let trayLabelData = JSON.parse(updateTrayLabelJSON)
|
let trayLabelData = JSON.parse(updateTrayLabelJSON)
|
||||||
updateTrayLabel(trayLabelData)
|
updateTrayLabel(trayLabelData)
|
||||||
break
|
break
|
||||||
|
case 'D':
|
||||||
|
// Delete Tray Menu
|
||||||
|
const id = trayMessage.slice(1);
|
||||||
|
deleteTrayMenu(id)
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
log('Unknown tray message: ' + message.data);
|
log('Unknown tray message: ' + message.data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ type Menu interface {
|
|||||||
UpdateApplicationMenu()
|
UpdateApplicationMenu()
|
||||||
UpdateContextMenu(contextMenu *menu.ContextMenu)
|
UpdateContextMenu(contextMenu *menu.ContextMenu)
|
||||||
SetTrayMenu(trayMenu *menu.TrayMenu)
|
SetTrayMenu(trayMenu *menu.TrayMenu)
|
||||||
|
DeleteTrayMenu(trayMenu *menu.TrayMenu)
|
||||||
UpdateTrayMenuLabel(trayMenu *menu.TrayMenu)
|
UpdateTrayMenuLabel(trayMenu *menu.TrayMenu)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,3 +40,7 @@ func (m *menuRuntime) SetTrayMenu(trayMenu *menu.TrayMenu) {
|
|||||||
func (m *menuRuntime) UpdateTrayMenuLabel(trayMenu *menu.TrayMenu) {
|
func (m *menuRuntime) UpdateTrayMenuLabel(trayMenu *menu.TrayMenu) {
|
||||||
m.bus.Publish("menu:updatetraymenulabel", trayMenu)
|
m.bus.Publish("menu:updatetraymenulabel", trayMenu)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *menuRuntime) DeleteTrayMenu(trayMenu *menu.TrayMenu) {
|
||||||
|
m.bus.Publish("menu:deletetraymenu", trayMenu)
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,20 +6,19 @@ import (
|
|||||||
|
|
||||||
// Runtime is a means for the user to interact with the application at runtime
|
// Runtime is a means for the user to interact with the application at runtime
|
||||||
type Runtime struct {
|
type Runtime struct {
|
||||||
Browser Browser
|
Browser Browser
|
||||||
Events Events
|
Events Events
|
||||||
Window Window
|
Window Window
|
||||||
Dialog Dialog
|
Dialog Dialog
|
||||||
System System
|
System System
|
||||||
Menu Menu
|
Menu Menu
|
||||||
Store *StoreProvider
|
Store *StoreProvider
|
||||||
Log Log
|
Log Log
|
||||||
bus *servicebus.ServiceBus
|
bus *servicebus.ServiceBus
|
||||||
shutdownCallback func()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new runtime
|
// New creates a new runtime
|
||||||
func New(serviceBus *servicebus.ServiceBus, shutdownCallback func()) *Runtime {
|
func New(serviceBus *servicebus.ServiceBus) *Runtime {
|
||||||
result := &Runtime{
|
result := &Runtime{
|
||||||
Browser: newBrowser(),
|
Browser: newBrowser(),
|
||||||
Events: newEvents(serviceBus),
|
Events: newEvents(serviceBus),
|
||||||
@@ -36,11 +35,6 @@ func New(serviceBus *servicebus.ServiceBus, shutdownCallback func()) *Runtime {
|
|||||||
|
|
||||||
// Quit the application
|
// Quit the application
|
||||||
func (r *Runtime) Quit() {
|
func (r *Runtime) Quit() {
|
||||||
// Call back to user's shutdown method if defined
|
|
||||||
if r.shutdownCallback != nil {
|
|
||||||
r.shutdownCallback()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start shutdown of Wails
|
// Start shutdown of Wails
|
||||||
r.bus.Publish("quit", "runtime.Quit()")
|
r.bus.Publish("quit", "runtime.Quit()")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,25 +26,20 @@ type Manager struct {
|
|||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
|
|
||||||
// The shutdown callback to notify the user's app that a shutdown
|
|
||||||
// has started
|
|
||||||
shutdownCallback func()
|
|
||||||
|
|
||||||
// Parent waitgroup
|
// Parent waitgroup
|
||||||
wg *sync.WaitGroup
|
wg *sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewManager creates a new signal manager
|
// NewManager creates a new signal manager
|
||||||
func NewManager(ctx context.Context, cancel context.CancelFunc, bus *servicebus.ServiceBus, logger *logger.Logger, shutdownCallback func()) (*Manager, error) {
|
func NewManager(ctx context.Context, cancel context.CancelFunc, bus *servicebus.ServiceBus, logger *logger.Logger) (*Manager, error) {
|
||||||
|
|
||||||
result := &Manager{
|
result := &Manager{
|
||||||
bus: bus,
|
bus: bus,
|
||||||
logger: logger.CustomLogger("Event Manager"),
|
logger: logger.CustomLogger("Event Manager"),
|
||||||
signalchannel: make(chan os.Signal, 2),
|
signalchannel: make(chan os.Signal, 2),
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
shutdownCallback: shutdownCallback,
|
wg: ctx.Value("waitgroup").(*sync.WaitGroup),
|
||||||
wg: ctx.Value("waitgroup").(*sync.WaitGroup),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -67,11 +62,6 @@ func (m *Manager) Start() {
|
|||||||
m.logger.Trace("Ctrl+C detected. Shutting down...")
|
m.logger.Trace("Ctrl+C detected. Shutting down...")
|
||||||
m.bus.Publish("quit", "ctrl-c pressed")
|
m.bus.Publish("quit", "ctrl-c pressed")
|
||||||
|
|
||||||
// Shutdown app first
|
|
||||||
if m.shutdownCallback != nil {
|
|
||||||
m.shutdownCallback()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start shutdown of Wails
|
// Start shutdown of Wails
|
||||||
m.cancel()
|
m.cancel()
|
||||||
|
|
||||||
|
|||||||
@@ -137,6 +137,17 @@ func (m *Menu) Start() error {
|
|||||||
// Notify frontend of menu change
|
// Notify frontend of menu change
|
||||||
m.bus.Publish("menufrontend:settraymenu", updatedMenu)
|
m.bus.Publish("menufrontend:settraymenu", updatedMenu)
|
||||||
|
|
||||||
|
case "deletetraymenu":
|
||||||
|
trayMenu := menuMessage.Data().(*menu.TrayMenu)
|
||||||
|
trayID, err := m.menuManager.GetTrayID(trayMenu)
|
||||||
|
if err != nil {
|
||||||
|
m.logger.Trace("%s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify frontend of menu change
|
||||||
|
m.bus.Publish("menufrontend:deletetraymenu", trayID)
|
||||||
|
|
||||||
case "updatetraymenulabel":
|
case "updatetraymenulabel":
|
||||||
trayMenu := menuMessage.Data().(*menu.TrayMenu)
|
trayMenu := menuMessage.Data().(*menu.TrayMenu)
|
||||||
updatedLabel, err := m.menuManager.UpdateTrayMenuLabel(trayMenu)
|
updatedLabel, err := m.menuManager.UpdateTrayMenuLabel(trayMenu)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ type Runtime struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewRuntime creates a new runtime subsystem
|
// NewRuntime creates a new runtime subsystem
|
||||||
func NewRuntime(ctx context.Context, bus *servicebus.ServiceBus, logger *logger.Logger, startupCallback func(*runtime.Runtime), shutdownCallback func()) (*Runtime, error) {
|
func NewRuntime(ctx context.Context, bus *servicebus.ServiceBus, logger *logger.Logger, startupCallback func(*runtime.Runtime)) (*Runtime, error) {
|
||||||
|
|
||||||
// Subscribe to log messages
|
// Subscribe to log messages
|
||||||
runtimeChannel, err := bus.Subscribe("runtime:")
|
runtimeChannel, err := bus.Subscribe("runtime:")
|
||||||
@@ -52,13 +52,12 @@ func NewRuntime(ctx context.Context, bus *servicebus.ServiceBus, logger *logger.
|
|||||||
}
|
}
|
||||||
|
|
||||||
result := &Runtime{
|
result := &Runtime{
|
||||||
runtimeChannel: runtimeChannel,
|
runtimeChannel: runtimeChannel,
|
||||||
hooksChannel: hooksChannel,
|
hooksChannel: hooksChannel,
|
||||||
logger: logger.CustomLogger("Runtime Subsystem"),
|
logger: logger.CustomLogger("Runtime Subsystem"),
|
||||||
runtime: runtime.New(bus, shutdownCallback),
|
runtime: runtime.New(bus),
|
||||||
startupCallback: startupCallback,
|
startupCallback: startupCallback,
|
||||||
shutdownCallback: shutdownCallback,
|
ctx: ctx,
|
||||||
ctx: ctx,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
|
|||||||
94
v2/internal/subsystem/url.go
Normal file
94
v2/internal/subsystem/url.go
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
package subsystem
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// URL is the URL Handler subsystem. It handles messages with topics starting
|
||||||
|
// with "url:"
|
||||||
|
type URL struct {
|
||||||
|
urlChannel <-chan *servicebus.Message
|
||||||
|
|
||||||
|
// quit flag
|
||||||
|
shouldQuit bool
|
||||||
|
|
||||||
|
// Logger!
|
||||||
|
logger *logger.Logger
|
||||||
|
|
||||||
|
// Context for shutdown
|
||||||
|
ctx context.Context
|
||||||
|
cancel context.CancelFunc
|
||||||
|
|
||||||
|
// internal waitgroup
|
||||||
|
wg sync.WaitGroup
|
||||||
|
|
||||||
|
// Handlers
|
||||||
|
handlers map[string]func(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewURL creates a new log subsystem
|
||||||
|
func NewURL(bus *servicebus.ServiceBus, logger *logger.Logger, handlers map[string]func(string)) (*URL, error) {
|
||||||
|
|
||||||
|
// Subscribe to log messages
|
||||||
|
urlChannel, err := bus.Subscribe("url")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
result := &URL{
|
||||||
|
urlChannel: urlChannel,
|
||||||
|
logger: logger,
|
||||||
|
ctx: ctx,
|
||||||
|
cancel: cancel,
|
||||||
|
handlers: handlers,
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the subsystem
|
||||||
|
func (u *URL) Start() error {
|
||||||
|
|
||||||
|
u.wg.Add(1)
|
||||||
|
|
||||||
|
// Spin off a go routine
|
||||||
|
go func() {
|
||||||
|
defer u.logger.Trace("URL Shutdown")
|
||||||
|
|
||||||
|
for u.shouldQuit == false {
|
||||||
|
select {
|
||||||
|
case <-u.ctx.Done():
|
||||||
|
u.wg.Done()
|
||||||
|
return
|
||||||
|
case urlMessage := <-u.urlChannel:
|
||||||
|
messageType := strings.TrimPrefix(urlMessage.Topic(), "url:")
|
||||||
|
switch messageType {
|
||||||
|
case "handler":
|
||||||
|
url := urlMessage.Data().(string)
|
||||||
|
splitURL := strings.Split(url, ":")
|
||||||
|
protocol := splitURL[0]
|
||||||
|
callback, ok := u.handlers[protocol]
|
||||||
|
if ok {
|
||||||
|
go callback(url)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
u.logger.Error("unknown url message: %+v", urlMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *URL) Close() {
|
||||||
|
u.cancel()
|
||||||
|
u.wg.Wait()
|
||||||
|
}
|
||||||
@@ -12,20 +12,19 @@ type Basic struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// newBasic creates a new Basic application struct
|
// newBasic creates a new Basic application struct
|
||||||
func newBasic() *Basic {
|
func NewBasic() *Basic {
|
||||||
return &Basic{}
|
return &Basic{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WailsInit is called at application startup
|
// startup is called at application startup
|
||||||
func (b *Basic) WailsInit(runtime *wails.Runtime) error {
|
func (b *Basic) startup(runtime *wails.Runtime) {
|
||||||
// Perform your setup here
|
// Perform your setup here
|
||||||
b.runtime = runtime
|
b.runtime = runtime
|
||||||
runtime.Window.SetTitle("{{.ProjectName}}")
|
runtime.Window.SetTitle("{{.ProjectName}}")
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WailsShutdown is called at application termination
|
// shutdown is called at application termination
|
||||||
func (b *Basic) WailsShutdown() {
|
func (b *Basic) shutdown() {
|
||||||
// Perform your teardown here
|
// Perform your teardown here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<link rel="stylesheet" href="/main.css">
|
<link rel="stylesheet" href="/main.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body data-wails-drag>
|
||||||
<div id="logo"></div>
|
<div id="logo"></div>
|
||||||
<div id="input">
|
<div id="input">
|
||||||
<input id="name" type="text"></input>
|
<input id="name" type="text"></input>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,21 +1,38 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/wailsapp/wails/v2"
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
"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() {
|
func main() {
|
||||||
|
|
||||||
// Create application with options
|
// Create application with options
|
||||||
app, err := wails.CreateApp("{{.ProjectName}}", 1024, 768)
|
app := NewBasic()
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
app.Bind(newBasic())
|
err := wails.Run(&options.App{
|
||||||
|
Title: "{{.ProjectName}}",
|
||||||
err = app.Run()
|
Width: 800,
|
||||||
|
Height: 600,
|
||||||
|
DisableResize: 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 {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/internal/colour"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CLILogger is used by the cli
|
// CLILogger is used by the cli
|
||||||
@@ -51,9 +53,9 @@ func (c *CLILogger) Println(message string, args ...interface{}) {
|
|||||||
// Fatal prints the given message then aborts
|
// Fatal prints the given message then aborts
|
||||||
func (c *CLILogger) Fatal(message string, args ...interface{}) {
|
func (c *CLILogger) Fatal(message string, args ...interface{}) {
|
||||||
temp := fmt.Sprintf(message, args...)
|
temp := fmt.Sprintf(message, args...)
|
||||||
_, err := fmt.Fprintln(c.Writer, "FATAL: "+temp)
|
_, err := fmt.Fprintln(c.Writer, colour.Red("FATAL: "+temp))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println("FATAL: ", err)
|
println(colour.Red("FATAL: " + err.Error()))
|
||||||
}
|
}
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,6 +145,13 @@ func (b *BaseBuilder) CleanUp() {
|
|||||||
// CompileProject compiles the project
|
// CompileProject compiles the project
|
||||||
func (b *BaseBuilder) CompileProject(options *Options) error {
|
func (b *BaseBuilder) CompileProject(options *Options) error {
|
||||||
|
|
||||||
|
// Run go mod tidy first
|
||||||
|
cmd := exec.Command(options.Compiler, "mod", "tidy")
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Default go build command
|
// Default go build command
|
||||||
commands := slicer.String([]string{"build"})
|
commands := slicer.String([]string{"build"})
|
||||||
|
|
||||||
@@ -188,7 +195,7 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
|
|||||||
|
|
||||||
// Get application build directory
|
// Get application build directory
|
||||||
appDir := options.BuildDirectory
|
appDir := options.BuildDirectory
|
||||||
err := cleanBuildDirectory(options)
|
err = cleanBuildDirectory(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -211,7 +218,7 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
|
|||||||
options.CompiledBinary = compiledBinary
|
options.CompiledBinary = compiledBinary
|
||||||
|
|
||||||
// Create the command
|
// Create the command
|
||||||
cmd := exec.Command(options.Compiler, commands.AsSlice()...)
|
cmd = exec.Command(options.Compiler, commands.AsSlice()...)
|
||||||
|
|
||||||
// Set the directory
|
// Set the directory
|
||||||
cmd.Dir = b.projectData.Path
|
cmd.Dir = b.projectData.Path
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ type Options struct {
|
|||||||
BuildDirectory string // Directory to use for building the application
|
BuildDirectory string // Directory to use for building the application
|
||||||
CompiledBinary string // Fully qualified path to the compiled binary
|
CompiledBinary string // Fully qualified path to the compiled binary
|
||||||
KeepAssets bool // /Keep the generated assets/files
|
KeepAssets bool // /Keep the generated assets/files
|
||||||
|
AppleIdentity string
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetModeAsString returns the current mode as a string
|
// GetModeAsString returns the current mode as a string
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ package build
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -52,6 +54,14 @@ func packageApplication(options *Options) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sign app if needed
|
||||||
|
if options.AppleIdentity != "" {
|
||||||
|
err = signApplication(options)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,3 +186,21 @@ func processApplicationIcon(resourceDir string, iconsDir string) (err error) {
|
|||||||
}()
|
}()
|
||||||
return icns.Encode(dest, srcImg)
|
return icns.Encode(dest, srcImg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func signApplication(options *Options) error {
|
||||||
|
bundlename := filepath.Join(options.BuildDirectory, options.ProjectData.Name+".app")
|
||||||
|
identity := fmt.Sprintf(`"%s"`, options.AppleIdentity)
|
||||||
|
cmd := exec.Command("codesign", "--sign", identity, "--deep", "--force", "--verbose", "--timestamp", "--options", "runtime", bundlename)
|
||||||
|
var stdo, stde bytes.Buffer
|
||||||
|
cmd.Stdout = &stdo
|
||||||
|
cmd.Stderr = &stde
|
||||||
|
|
||||||
|
// Run command
|
||||||
|
err := cmd.Run()
|
||||||
|
|
||||||
|
// Format error if we have one
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%s\n%s", err, string(stde.Bytes()))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,21 +1,43 @@
|
|||||||
package keys
|
package keys
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
// Modifier is actually a string
|
// Modifier is actually a string
|
||||||
type Modifier string
|
type Modifier string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// CmdOrCtrlKey represents Command on Mac and Control on other platforms
|
// CmdOrCtrlKey represents Command on Mac and Control on other platforms
|
||||||
CmdOrCtrlKey Modifier = "CmdOrCtrl"
|
CmdOrCtrlKey Modifier = "cmdorctrl"
|
||||||
// OptionOrAltKey represents Option on Mac and Alt on other platforms
|
// OptionOrAltKey represents Option on Mac and Alt on other platforms
|
||||||
OptionOrAltKey Modifier = "OptionOrAlt"
|
OptionOrAltKey Modifier = "optionoralt"
|
||||||
// ShiftKey represents the shift key on all systems
|
// ShiftKey represents the shift key on all systems
|
||||||
ShiftKey Modifier = "Shift"
|
ShiftKey Modifier = "shift"
|
||||||
// SuperKey represents Command on Mac and the Windows key on the other platforms
|
// SuperKey represents Command on Mac and the Windows key on the other platforms
|
||||||
SuperKey Modifier = "Super"
|
SuperKey Modifier = "super"
|
||||||
// ControlKey represents the control key on all systems
|
// ControlKey represents the control key on all systems
|
||||||
ControlKey Modifier = "Control"
|
ControlKey Modifier = "ctrl"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var modifierMap = map[string]Modifier{
|
||||||
|
"cmdorctrl": CmdOrCtrlKey,
|
||||||
|
"optionoralt": OptionOrAltKey,
|
||||||
|
"shift": ShiftKey,
|
||||||
|
"super": SuperKey,
|
||||||
|
"ctrl": ControlKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseModifier(text string) (*Modifier, error) {
|
||||||
|
result, valid := modifierMap[text]
|
||||||
|
if !valid {
|
||||||
|
return nil, fmt.Errorf("'%s' is not a valid modifier", text)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Accelerator holds the keyboard shortcut for a menu item
|
// Accelerator holds the keyboard shortcut for a menu item
|
||||||
type Accelerator struct {
|
type Accelerator struct {
|
||||||
Key string
|
Key string
|
||||||
@@ -25,14 +47,14 @@ type Accelerator struct {
|
|||||||
// Key creates a standard key Accelerator
|
// Key creates a standard key Accelerator
|
||||||
func Key(key string) *Accelerator {
|
func Key(key string) *Accelerator {
|
||||||
return &Accelerator{
|
return &Accelerator{
|
||||||
Key: key,
|
Key: strings.ToLower(key),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CmdOrCtrl creates a 'CmdOrCtrl' Accelerator
|
// CmdOrCtrl creates a 'CmdOrCtrl' Accelerator
|
||||||
func CmdOrCtrl(key string) *Accelerator {
|
func CmdOrCtrl(key string) *Accelerator {
|
||||||
return &Accelerator{
|
return &Accelerator{
|
||||||
Key: key,
|
Key: strings.ToLower(key),
|
||||||
Modifiers: []Modifier{CmdOrCtrlKey},
|
Modifiers: []Modifier{CmdOrCtrlKey},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -40,7 +62,7 @@ func CmdOrCtrl(key string) *Accelerator {
|
|||||||
// OptionOrAlt creates a 'OptionOrAlt' Accelerator
|
// OptionOrAlt creates a 'OptionOrAlt' Accelerator
|
||||||
func OptionOrAlt(key string) *Accelerator {
|
func OptionOrAlt(key string) *Accelerator {
|
||||||
return &Accelerator{
|
return &Accelerator{
|
||||||
Key: key,
|
Key: strings.ToLower(key),
|
||||||
Modifiers: []Modifier{OptionOrAltKey},
|
Modifiers: []Modifier{OptionOrAltKey},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,7 +70,7 @@ func OptionOrAlt(key string) *Accelerator {
|
|||||||
// Shift creates a 'Shift' Accelerator
|
// Shift creates a 'Shift' Accelerator
|
||||||
func Shift(key string) *Accelerator {
|
func Shift(key string) *Accelerator {
|
||||||
return &Accelerator{
|
return &Accelerator{
|
||||||
Key: key,
|
Key: strings.ToLower(key),
|
||||||
Modifiers: []Modifier{ShiftKey},
|
Modifiers: []Modifier{ShiftKey},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,7 +78,7 @@ func Shift(key string) *Accelerator {
|
|||||||
// Control creates a 'Control' Accelerator
|
// Control creates a 'Control' Accelerator
|
||||||
func Control(key string) *Accelerator {
|
func Control(key string) *Accelerator {
|
||||||
return &Accelerator{
|
return &Accelerator{
|
||||||
Key: key,
|
Key: strings.ToLower(key),
|
||||||
Modifiers: []Modifier{ControlKey},
|
Modifiers: []Modifier{ControlKey},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,7 +86,7 @@ func Control(key string) *Accelerator {
|
|||||||
// Super creates a 'Super' Accelerator
|
// Super creates a 'Super' Accelerator
|
||||||
func Super(key string) *Accelerator {
|
func Super(key string) *Accelerator {
|
||||||
return &Accelerator{
|
return &Accelerator{
|
||||||
Key: key,
|
Key: strings.ToLower(key),
|
||||||
Modifiers: []Modifier{SuperKey},
|
Modifiers: []Modifier{SuperKey},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
90
v2/pkg/menu/keys/parser.go
Normal file
90
v2/pkg/menu/keys/parser.go
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
package keys
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/leaanthony/slicer"
|
||||||
|
)
|
||||||
|
|
||||||
|
var namedKeys = slicer.String([]string{"backspace", "tab", "return", "escape", "left", "right", "up", "down", "space", "delete", "home", "end", "page up", "page down", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", "f32", "f33", "f34", "f35", "numlock"})
|
||||||
|
|
||||||
|
func parseKey(key string) (string, bool) {
|
||||||
|
|
||||||
|
// Lowercase!
|
||||||
|
key = strings.ToLower(key)
|
||||||
|
|
||||||
|
// Check special case
|
||||||
|
if key == "plus" {
|
||||||
|
return "+", true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle named keys
|
||||||
|
if namedKeys.Contains(key) {
|
||||||
|
return key, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check we only have a single character
|
||||||
|
if len(key) != 1 {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
runeKey := rune(key[0])
|
||||||
|
|
||||||
|
// This may be too inclusive
|
||||||
|
if strconv.IsPrint(runeKey) {
|
||||||
|
return key, true
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", false
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func Parse(shortcut string) (*Accelerator, error) {
|
||||||
|
|
||||||
|
var result Accelerator
|
||||||
|
|
||||||
|
// Split the shortcut by +
|
||||||
|
components := strings.Split(shortcut, "+")
|
||||||
|
|
||||||
|
// If we only have one it should be a key
|
||||||
|
// We require components
|
||||||
|
if len(components) == 0 {
|
||||||
|
return nil, fmt.Errorf("no components given to validateComponents")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep track of modifiers we have processed
|
||||||
|
var modifiersProcessed slicer.StringSlicer
|
||||||
|
|
||||||
|
// Check components
|
||||||
|
for index, component := range components {
|
||||||
|
|
||||||
|
// If last component
|
||||||
|
if index == len(components)-1 {
|
||||||
|
processedkey, validKey := parseKey(component)
|
||||||
|
if !validKey {
|
||||||
|
return nil, fmt.Errorf("'%s' is not a valid key", component)
|
||||||
|
}
|
||||||
|
result.Key = processedkey
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not last component - needs to be modifier
|
||||||
|
lowercaseComponent := strings.ToLower(component)
|
||||||
|
thisModifier, valid := modifierMap[lowercaseComponent]
|
||||||
|
if !valid {
|
||||||
|
return nil, fmt.Errorf("'%s' is not a valid modifier", component)
|
||||||
|
}
|
||||||
|
// Needs to be unique
|
||||||
|
if modifiersProcessed.Contains(lowercaseComponent) {
|
||||||
|
return nil, fmt.Errorf("Modifier '%s' is defined twice for shortcut: %s", component, shortcut)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save this data
|
||||||
|
result.Modifiers = append(result.Modifiers, thisModifier)
|
||||||
|
modifiersProcessed.Add(lowercaseComponent)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
38
v2/pkg/menu/keys/parser_test.go
Normal file
38
v2/pkg/menu/keys/parser_test.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package keys
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/matryer/is"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParse(t *testing.T) {
|
||||||
|
|
||||||
|
i := is.New(t)
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
Input string
|
||||||
|
Expected *Accelerator
|
||||||
|
}
|
||||||
|
|
||||||
|
gooddata := []args{
|
||||||
|
{"CmdOrCtrl+A", CmdOrCtrl("A")},
|
||||||
|
{"SHIFT+.", Shift(".")},
|
||||||
|
{"CTRL+plus", Control("+")},
|
||||||
|
{"CTRL+SHIFT+escApe", Combo("escape", ControlKey, ShiftKey)},
|
||||||
|
{";", Key(";")},
|
||||||
|
{"Super+Tab", Super("tab")},
|
||||||
|
{"OptionOrAlt+Page Down", OptionOrAlt("Page Down")},
|
||||||
|
}
|
||||||
|
for _, tt := range gooddata {
|
||||||
|
result, err := Parse(tt.Input)
|
||||||
|
i.NoErr(err)
|
||||||
|
i.Equal(result, tt.Expected)
|
||||||
|
}
|
||||||
|
baddata := []string{"CmdOrCrl+A", "SHIT+.", "CTL+plus", "CTRL+SHIF+esApe", "escap", "Sper+Tab", "OptionOrAlt"}
|
||||||
|
for _, d := range baddata {
|
||||||
|
result, err := Parse(d)
|
||||||
|
i.True(err != nil)
|
||||||
|
i.Equal(result, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,14 @@ package mac
|
|||||||
|
|
||||||
import "github.com/wailsapp/wails/v2/pkg/menu"
|
import "github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
|
|
||||||
|
type ActivationPolicy int
|
||||||
|
|
||||||
|
const (
|
||||||
|
NSApplicationActivationPolicyRegular ActivationPolicy = 0
|
||||||
|
NSApplicationActivationPolicyAccessory ActivationPolicy = 1
|
||||||
|
NSApplicationActivationPolicyProhibited ActivationPolicy = 2
|
||||||
|
)
|
||||||
|
|
||||||
// Options are options specific to Mac
|
// Options are options specific to Mac
|
||||||
type Options struct {
|
type Options struct {
|
||||||
TitleBar *TitleBar
|
TitleBar *TitleBar
|
||||||
@@ -11,4 +19,6 @@ type Options struct {
|
|||||||
Menu *menu.Menu
|
Menu *menu.Menu
|
||||||
TrayMenus []*menu.TrayMenu
|
TrayMenus []*menu.TrayMenu
|
||||||
ContextMenus []*menu.ContextMenu
|
ContextMenus []*menu.ContextMenu
|
||||||
|
ActivationPolicy ActivationPolicy
|
||||||
|
URLHandlers map[string]func(string)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user