mirror of
https://github.com/taigrr/wails.git
synced 2026-04-14 10:50:53 -07:00
Compare commits
3 Commits
v1.8.1-pre
...
v2-linux
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71bfd29376 | ||
|
|
c158fd369a | ||
|
|
a213e8bcd1 |
11
.gitignore
vendored
11
.gitignore
vendored
@@ -16,4 +16,13 @@ examples/**/example*
|
|||||||
cmd/wails/wails
|
cmd/wails/wails
|
||||||
.DS_Store
|
.DS_Store
|
||||||
tmp
|
tmp
|
||||||
node_modules/
|
node_modules/
|
||||||
|
package.json.md5
|
||||||
|
v2/test/**/frontend/dist
|
||||||
|
v2/test/**/build/
|
||||||
|
v2/test/frameless/icon.png
|
||||||
|
v2/test/hidden/icon.png
|
||||||
|
v2/internal/ffenestri/runtime.c
|
||||||
|
v2/internal/runtime/assets/desktop.js
|
||||||
|
v2/test/kitchensink/frontend/public/bundle.*
|
||||||
|
v2/pkg/parser/testproject/frontend/wails
|
||||||
|
|||||||
@@ -32,8 +32,3 @@ Wails is what it is because of the time and effort given by these great people.
|
|||||||
* [Zámbó, Levente](https://github.com/Lyimmi)
|
* [Zámbó, Levente](https://github.com/Lyimmi)
|
||||||
* [artem](https://github.com/Unix4ever)
|
* [artem](https://github.com/Unix4ever)
|
||||||
* [Tim Kipp](https://github.com/timkippdev)
|
* [Tim Kipp](https://github.com/timkippdev)
|
||||||
* [Dmitry Gomzyakov](https://github.com/kyoto44)
|
|
||||||
* [Arthur Wiebe](https://github.com/artooro)
|
|
||||||
* [Ilgıt Yıldırım](https://github.com/ilgityildirim)
|
|
||||||
* [Altynbek](https://github.com/gelleson)
|
|
||||||
* [Kyle](https://github.com/kmuchmore)
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
<a href="https://houndci.com"><img src="https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg"/></a>
|
<a href="https://houndci.com"><img src="https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg"/></a>
|
||||||
<a href="https://github.com/avelino/awesome-go" rel="nofollow"><img src="https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg" alt="Awesome"></a>
|
<a href="https://github.com/avelino/awesome-go" rel="nofollow"><img src="https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg" alt="Awesome"></a>
|
||||||
<a href="https://github.com/wailsapp/wails/workflows/release/badge.svg?branch=master" rel="nofollow"><img src="https://github.com/wailsapp/wails/workflows/release/badge.svg?branch=master" alt="Release Pipelines"></a>
|
<a href="https://github.com/wailsapp/wails/workflows/release/badge.svg?branch=master" rel="nofollow"><img src="https://github.com/wailsapp/wails/workflows/release/badge.svg?branch=master" alt="Release Pipelines"></a>
|
||||||
|
<a href="https://github.com/wailsapp/wails/workflows/latest-pre/badge.svg?branch=masterr" rel="nofollow"><img src="https://github.com/wailsapp/wails/workflows/latest-pre/badge.svg?branch=master" alt="Pre-Release Pipelines"></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
The traditional method of providing web interfaces to Go programs is via a built-in web server. Wails offers a different approach: it provides the ability to wrap both Go code and a web frontend into a single binary. Tools are provided to make this easy for you by handling project creation, compilation and bundling. All you have to do is get creative!
|
The traditional method of providing web interfaces to Go programs is via a built-in web server. Wails offers a different approach: it provides the ability to wrap both Go code and a web frontend into a single binary. Tools are provided to make this easy for you by handling project creation, compilation and bundling. All you have to do is get creative!
|
||||||
@@ -56,7 +57,7 @@ _Ubuntu: 16.04, 18.04, 19.04_
|
|||||||
|
|
||||||
_Also succesfully tested on: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, Kali, Neon_, Pop!_OS
|
_Also succesfully tested on: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, Kali, Neon_, Pop!_OS
|
||||||
|
|
||||||
#### Arch Linux / ArchLabs / Ctlos Linux
|
#### Arch Linux / ArchLabs
|
||||||
|
|
||||||
`sudo pacman -S webkit2gtk gtk3`
|
`sudo pacman -S webkit2gtk gtk3`
|
||||||
|
|
||||||
|
|||||||
13
app.go
13
app.go
@@ -13,7 +13,6 @@ import (
|
|||||||
"github.com/wailsapp/wails/lib/ipc"
|
"github.com/wailsapp/wails/lib/ipc"
|
||||||
"github.com/wailsapp/wails/lib/logger"
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
"github.com/wailsapp/wails/lib/renderer"
|
"github.com/wailsapp/wails/lib/renderer"
|
||||||
wailsruntime "github.com/wailsapp/wails/runtime"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// -------------------------------- Compile time Flags ------------------------------
|
// -------------------------------- Compile time Flags ------------------------------
|
||||||
@@ -21,16 +20,6 @@ import (
|
|||||||
// BuildMode indicates what mode we are in
|
// BuildMode indicates what mode we are in
|
||||||
var BuildMode = cmd.BuildModeProd
|
var BuildMode = cmd.BuildModeProd
|
||||||
|
|
||||||
// Runtime is the Go Runtime struct
|
|
||||||
type Runtime = wailsruntime.Runtime
|
|
||||||
|
|
||||||
// Store is a state store used for syncing with
|
|
||||||
// the front end
|
|
||||||
type Store = wailsruntime.Store
|
|
||||||
|
|
||||||
// CustomLogger is a specialised logger
|
|
||||||
type CustomLogger = logger.CustomLogger
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
|
|
||||||
// App defines the main application struct
|
// App defines the main application struct
|
||||||
@@ -136,7 +125,7 @@ func (a *App) start() error {
|
|||||||
a.ipc.Start(a.eventManager, a.bindingManager)
|
a.ipc.Start(a.eventManager, a.bindingManager)
|
||||||
|
|
||||||
// Create the runtime
|
// Create the runtime
|
||||||
a.runtime = wailsruntime.NewRuntime(a.eventManager, a.renderer)
|
a.runtime = NewRuntime(a.eventManager, a.renderer)
|
||||||
|
|
||||||
// Start binding manager and give it our renderer
|
// Start binding manager and give it our renderer
|
||||||
err = a.bindingManager.Start(a.renderer, a.runtime)
|
err = a.bindingManager.Start(a.renderer, a.runtime)
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ import (
|
|||||||
"github.com/leaanthony/spinner"
|
"github.com/leaanthony/spinner"
|
||||||
)
|
)
|
||||||
|
|
||||||
const xgoVersion = "1.0.1"
|
|
||||||
|
|
||||||
var fs = NewFSHelper()
|
var fs = NewFSHelper()
|
||||||
|
|
||||||
// ValidateFrontendConfig checks if the frontend config is valid
|
// ValidateFrontendConfig checks if the frontend config is valid
|
||||||
@@ -92,17 +90,16 @@ func InitializeCrossCompilation(verbose bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var packSpinner *spinner.Spinner
|
var packSpinner *spinner.Spinner
|
||||||
msg := fmt.Sprintf("Pulling wailsapp/xgo:%s docker image... (may take a while)", xgoVersion)
|
|
||||||
if !verbose {
|
if !verbose {
|
||||||
packSpinner = spinner.New(msg)
|
packSpinner = spinner.New("Pulling wailsapp/xgo:latest docker image... (may take a while)")
|
||||||
packSpinner.SetSpinSpeed(50)
|
packSpinner.SetSpinSpeed(50)
|
||||||
packSpinner.Start()
|
packSpinner.Start()
|
||||||
} else {
|
} else {
|
||||||
println(msg)
|
println("Pulling wailsapp/xgo:latest docker image... (may take a while)")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := NewProgramHelper(verbose).RunCommandArray([]string{"docker",
|
err := NewProgramHelper(verbose).RunCommandArray([]string{"docker",
|
||||||
"pull", fmt.Sprintf("wailsapp/xgo:%s", xgoVersion)})
|
"pull", "wailsapp/xgo:latest"})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if packSpinner != nil {
|
if packSpinner != nil {
|
||||||
@@ -117,7 +114,7 @@ func InitializeCrossCompilation(verbose bool) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildDocker builds the project using the cross compiling wailsapp/xgo:<xgoVersion> container
|
// BuildDocker builds the project using the cross compiling wailsapp/xgo:latest container
|
||||||
func BuildDocker(binaryName string, buildMode string, projectOptions *ProjectOptions) error {
|
func BuildDocker(binaryName string, buildMode string, projectOptions *ProjectOptions) error {
|
||||||
var packSpinner *spinner.Spinner
|
var packSpinner *spinner.Spinner
|
||||||
if buildMode == BuildModeBridge {
|
if buildMode == BuildModeBridge {
|
||||||
@@ -143,31 +140,24 @@ func BuildDocker(binaryName string, buildMode string, projectOptions *ProjectOpt
|
|||||||
"-v", fmt.Sprintf("%s:/build", filepath.Join(fs.Cwd(), "build")),
|
"-v", fmt.Sprintf("%s:/build", filepath.Join(fs.Cwd(), "build")),
|
||||||
"-v", fmt.Sprintf("%s:/source", fs.Cwd()),
|
"-v", fmt.Sprintf("%s:/source", fs.Cwd()),
|
||||||
"-e", fmt.Sprintf("LOCAL_USER_ID=%v", userid),
|
"-e", fmt.Sprintf("LOCAL_USER_ID=%v", userid),
|
||||||
"-e", fmt.Sprintf("FLAG_TAGS=%s", projectOptions.Tags),
|
|
||||||
"-e", fmt.Sprintf("FLAG_LDFLAGS=%s", ldFlags(projectOptions, buildMode)),
|
"-e", fmt.Sprintf("FLAG_LDFLAGS=%s", ldFlags(projectOptions, buildMode)),
|
||||||
"-e", "FLAG_V=false",
|
"-e", "FLAG_V=false",
|
||||||
"-e", "FLAG_X=false",
|
"-e", "FLAG_X=false",
|
||||||
"-e", "FLAG_RACE=false",
|
"-e", "FLAG_RACE=false",
|
||||||
"-e", "FLAG_BUILDMODE=default",
|
"-e", "FLAG_BUILDMODE=default",
|
||||||
"-e", "FLAG_TRIMPATH=false",
|
"-e", "FLAG_TRIMPATH=false",
|
||||||
"-e", fmt.Sprintf("TARGETS=%s/%s", projectOptions.Platform, projectOptions.Architecture),
|
"-e", fmt.Sprintf("TARGETS=%s", projectOptions.Platform+"/"+projectOptions.Architecture),
|
||||||
"-e", "GOPROXY=",
|
"-e", "GOPROXY=",
|
||||||
"-e", "GO111MODULE=on",
|
"-e", "GO111MODULE=on",
|
||||||
|
"wailsapp/xgo:latest",
|
||||||
|
".",
|
||||||
} {
|
} {
|
||||||
buildCommand.Add(arg)
|
buildCommand.Add(arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if projectOptions.GoPath != "" {
|
|
||||||
buildCommand.Add("-v")
|
|
||||||
buildCommand.Add(fmt.Sprintf("%s:/go", projectOptions.GoPath))
|
|
||||||
}
|
|
||||||
|
|
||||||
buildCommand.Add(fmt.Sprintf("wailsapp/xgo:%s", xgoVersion))
|
|
||||||
buildCommand.Add(".")
|
|
||||||
|
|
||||||
compileMessage := fmt.Sprintf(
|
compileMessage := fmt.Sprintf(
|
||||||
"Packing + Compiling project for %s/%s using docker image wailsapp/xgo:%s",
|
"Packing + Compiling project for %s/%s using docker image wailsapp/xgo:latest",
|
||||||
projectOptions.Platform, projectOptions.Architecture, xgoVersion)
|
projectOptions.Platform, projectOptions.Architecture)
|
||||||
|
|
||||||
if buildMode == BuildModeDebug {
|
if buildMode == BuildModeDebug {
|
||||||
compileMessage += " (Debug Mode)"
|
compileMessage += " (Debug Mode)"
|
||||||
@@ -226,6 +216,10 @@ func BuildNative(binaryName string, forceRebuild bool, buildMode string, project
|
|||||||
buildCommand.Add("go")
|
buildCommand.Add("go")
|
||||||
|
|
||||||
buildCommand.Add("build")
|
buildCommand.Add("build")
|
||||||
|
if buildMode == BuildModeBridge {
|
||||||
|
// Ignore errors
|
||||||
|
buildCommand.Add("-i")
|
||||||
|
}
|
||||||
|
|
||||||
if binaryName != "" {
|
if binaryName != "" {
|
||||||
// Alter binary name based on OS
|
// Alter binary name based on OS
|
||||||
@@ -249,10 +243,6 @@ func BuildNative(binaryName string, forceRebuild bool, buildMode string, project
|
|||||||
|
|
||||||
buildCommand.AddSlice([]string{"-ldflags", ldFlags(projectOptions, buildMode)})
|
buildCommand.AddSlice([]string{"-ldflags", ldFlags(projectOptions, buildMode)})
|
||||||
|
|
||||||
if projectOptions.Tags != "" {
|
|
||||||
buildCommand.AddSlice([]string{"--tags", projectOptions.Tags})
|
|
||||||
}
|
|
||||||
|
|
||||||
if projectOptions.Verbose {
|
if projectOptions.Verbose {
|
||||||
fmt.Printf("Command: %v\n", buildCommand.AsSlice())
|
fmt.Printf("Command: %v\n", buildCommand.AsSlice())
|
||||||
}
|
}
|
||||||
@@ -540,9 +530,6 @@ func InstallProdRuntime(projectDir string, projectOptions *ProjectOptions) error
|
|||||||
func ServeProject(projectOptions *ProjectOptions, logger *Logger) error {
|
func ServeProject(projectOptions *ProjectOptions, logger *Logger) error {
|
||||||
go func() {
|
go func() {
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
if projectOptions.Platform == "windows" {
|
|
||||||
logger.Yellow("*** Please note: Windows builds use mshtml which is only compatible with IE11. We strongly recommend only using IE11 when running 'wails serve'! For more information, please read https://wails.app/guides/windows/ ***")
|
|
||||||
}
|
|
||||||
logger.Green(">>>>> To connect, you will need to run '" + projectOptions.FrontEnd.Serve + "' in the '" + projectOptions.FrontEnd.Dir + "' directory <<<<<")
|
logger.Green(">>>>> To connect, you will need to run '" + projectOptions.FrontEnd.Serve + "' in the '" + projectOptions.FrontEnd.Dir + "' directory <<<<<")
|
||||||
}()
|
}()
|
||||||
location, err := filepath.Abs(filepath.Join("build", projectOptions.BinaryName))
|
location, err := filepath.Abs(filepath.Join("build", projectOptions.BinaryName))
|
||||||
|
|||||||
@@ -63,8 +63,6 @@ const (
|
|||||||
PopOS
|
PopOS
|
||||||
// Solus distribution
|
// Solus distribution
|
||||||
Solus
|
Solus
|
||||||
// Ctlos Linux distribution
|
|
||||||
Ctlos
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DistroInfo contains all the information relating to a linux distribution
|
// DistroInfo contains all the information relating to a linux distribution
|
||||||
@@ -131,8 +129,6 @@ func parseOsRelease(osRelease string) *DistroInfo {
|
|||||||
result.Distribution = Arch
|
result.Distribution = Arch
|
||||||
case "archlabs":
|
case "archlabs":
|
||||||
result.Distribution = ArchLabs
|
result.Distribution = ArchLabs
|
||||||
case "ctlos":
|
|
||||||
result.Distribution = Ctlos
|
|
||||||
case "debian":
|
case "debian":
|
||||||
result.Distribution = Debian
|
result.Distribution = Debian
|
||||||
case "ubuntu":
|
case "ubuntu":
|
||||||
|
|||||||
@@ -193,16 +193,7 @@ distributions:
|
|||||||
name: ArchLabs
|
name: ArchLabs
|
||||||
gccversioncommand: *gccdumpversion
|
gccversioncommand: *gccdumpversion
|
||||||
programs: *archdefaultprograms
|
programs: *archdefaultprograms
|
||||||
libraries: *archdefaultlibraries
|
libraries: *archdefaultlibraries
|
||||||
ctlos:
|
|
||||||
id: ctlos
|
|
||||||
releases:
|
|
||||||
default:
|
|
||||||
version: default
|
|
||||||
name: Ctlos Linux
|
|
||||||
gccversioncommand: *gccdumpversion
|
|
||||||
programs: *archdefaultprograms
|
|
||||||
libraries: *archdefaultlibraries
|
|
||||||
manjaro:
|
manjaro:
|
||||||
id: manjaro
|
id: manjaro
|
||||||
releases:
|
releases:
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -151,7 +150,6 @@ type ProjectOptions struct {
|
|||||||
Template string `json:"-"`
|
Template string `json:"-"`
|
||||||
BinaryName string `json:"binaryname"`
|
BinaryName string `json:"binaryname"`
|
||||||
FrontEnd *frontend `json:"frontend,omitempty"`
|
FrontEnd *frontend `json:"frontend,omitempty"`
|
||||||
Tags string `json:"tags"`
|
|
||||||
NPMProjectName string `json:"-"`
|
NPMProjectName string `json:"-"`
|
||||||
system *SystemHelper
|
system *SystemHelper
|
||||||
log *Logger
|
log *Logger
|
||||||
@@ -164,24 +162,6 @@ type ProjectOptions struct {
|
|||||||
Platform string
|
Platform string
|
||||||
Architecture string
|
Architecture string
|
||||||
LdFlags string
|
LdFlags string
|
||||||
GoPath string
|
|
||||||
|
|
||||||
// Supported platforms
|
|
||||||
Platforms []string `json:"platforms,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// PlatformSupported returns true if the template is supported
|
|
||||||
// on the current platform
|
|
||||||
func (po *ProjectOptions) PlatformSupported() bool {
|
|
||||||
|
|
||||||
// Default is all platforms supported
|
|
||||||
if len(po.Platforms) == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that the platform is in the list
|
|
||||||
platformsSupported := slicer.String(po.Platforms)
|
|
||||||
return platformsSupported.Contains(runtime.GOOS)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defaults sets the default project template
|
// Defaults sets the default project template
|
||||||
@@ -252,16 +232,13 @@ func (po *ProjectOptions) PromptForInputs() error {
|
|||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
templateDetail := templateDetails[k]
|
templateDetail := templateDetails[k]
|
||||||
templateList.Add(templateDetail)
|
templateList.Add(templateDetail)
|
||||||
if !templateDetail.Metadata.PlatformSupported() {
|
|
||||||
templateDetail.Metadata.Name = "* " + templateDetail.Metadata.Name
|
|
||||||
}
|
|
||||||
options.Add(fmt.Sprintf("%s - %s", templateDetail.Metadata.Name, templateDetail.Metadata.ShortDescription))
|
options.Add(fmt.Sprintf("%s - %s", templateDetail.Metadata.Name, templateDetail.Metadata.ShortDescription))
|
||||||
}
|
}
|
||||||
|
|
||||||
templateIndex := 0
|
templateIndex := 0
|
||||||
|
|
||||||
if len(options.AsSlice()) > 1 {
|
if len(options.AsSlice()) > 1 {
|
||||||
templateIndex = PromptSelection("Please select a template (* means unsupported on current platform)", options.AsSlice(), 0)
|
templateIndex = PromptSelection("Please select a template", options.AsSlice(), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(templateList.AsSlice()) == 0 {
|
if len(templateList.AsSlice()) == 0 {
|
||||||
@@ -272,10 +249,6 @@ func (po *ProjectOptions) PromptForInputs() error {
|
|||||||
po.selectedTemplate = templateList.AsSlice()[templateIndex].(*TemplateDetails)
|
po.selectedTemplate = templateList.AsSlice()[templateIndex].(*TemplateDetails)
|
||||||
}
|
}
|
||||||
|
|
||||||
po.selectedTemplate.Metadata.Name = strings.TrimPrefix(po.selectedTemplate.Metadata.Name, "* ")
|
|
||||||
if !po.selectedTemplate.Metadata.PlatformSupported() {
|
|
||||||
println("WARNING: This template is unsupported on this platform!")
|
|
||||||
}
|
|
||||||
fmt.Println("Template: " + po.selectedTemplate.Metadata.Name)
|
fmt.Println("Template: " + po.selectedTemplate.Metadata.Name)
|
||||||
|
|
||||||
// Setup NPM Project name
|
// Setup NPM Project name
|
||||||
@@ -398,9 +371,5 @@ func processTemplateMetadata(templateMetadata *TemplateMetadata, po *ProjectOpti
|
|||||||
}
|
}
|
||||||
po.FrontEnd.Serve = templateMetadata.Serve
|
po.FrontEnd.Serve = templateMetadata.Serve
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save platforms
|
|
||||||
po.Platforms = templateMetadata.Platforms
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -276,7 +276,7 @@ func CheckDependencies(logger *Logger) (bool, error) {
|
|||||||
switch distroInfo.Distribution {
|
switch distroInfo.Distribution {
|
||||||
case Ubuntu, Debian, Zorin, Parrot, Linuxmint, Elementary, Kali, Neon, Deepin, Raspbian, PopOS:
|
case Ubuntu, Debian, Zorin, Parrot, Linuxmint, Elementary, Kali, Neon, Deepin, Raspbian, PopOS:
|
||||||
libraryChecker = DpkgInstalled
|
libraryChecker = DpkgInstalled
|
||||||
case Arch, ArcoLinux, ArchLabs, Ctlos, Manjaro, ManjaroARM:
|
case Arch, ArcoLinux, ArchLabs, Manjaro, ManjaroARM:
|
||||||
libraryChecker = PacmanInstalled
|
libraryChecker = PacmanInstalled
|
||||||
case CentOS, Fedora, Tumbleweed, Leap:
|
case CentOS, Fedora, Tumbleweed, Leap:
|
||||||
libraryChecker = RpmInstalled
|
libraryChecker = RpmInstalled
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
@@ -30,26 +29,6 @@ type TemplateMetadata struct {
|
|||||||
Bridge string `json:"bridge"`
|
Bridge string `json:"bridge"`
|
||||||
WailsDir string `json:"wailsdir"`
|
WailsDir string `json:"wailsdir"`
|
||||||
TemplateDependencies []*TemplateDependency `json:"dependencies,omitempty"`
|
TemplateDependencies []*TemplateDependency `json:"dependencies,omitempty"`
|
||||||
|
|
||||||
// List of platforms that this template is supported on.
|
|
||||||
// No value means all platforms. A platform name is the same string
|
|
||||||
// as `runtime.GOOS` will return, eg: "darwin". NOTE: This is
|
|
||||||
// case sensitive.
|
|
||||||
Platforms []string `json:"platforms,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// PlatformSupported returns true if this template supports the
|
|
||||||
// currently running platform
|
|
||||||
func (m *TemplateMetadata) PlatformSupported() bool {
|
|
||||||
|
|
||||||
// Default is all platforms supported
|
|
||||||
if len(m.Platforms) == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that the platform is in the list
|
|
||||||
platformsSupported := slicer.String(m.Platforms)
|
|
||||||
return platformsSupported.Contains(runtime.GOOS)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TemplateDependency defines a binary dependency for the template
|
// TemplateDependency defines a binary dependency for the template
|
||||||
@@ -149,11 +128,11 @@ func (t *TemplateHelper) GetTemplateDetails() (map[string]*TemplateDetails, erro
|
|||||||
result[name] = &TemplateDetails{
|
result[name] = &TemplateDetails{
|
||||||
Path: dir,
|
Path: dir,
|
||||||
}
|
}
|
||||||
|
_ = &TemplateMetadata{}
|
||||||
metadata, err := t.LoadMetadata(dir)
|
metadata, err := t.LoadMetadata(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
result[name].Metadata = metadata
|
result[name].Metadata = metadata
|
||||||
if metadata.Name != "" {
|
if metadata.Name != "" {
|
||||||
result[name].Name = metadata.Name
|
result[name].Name = metadata.Name
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ const routes: Routes = [];
|
|||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
RouterModule.forRoot(routes,{useHash:true})
|
RouterModule.forRoot(routes)
|
||||||
],
|
],
|
||||||
exports: [RouterModule]
|
exports: [RouterModule]
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "{{.NPMProjectName}}",
|
|
||||||
"author": "{{.Author.Name}}<{{.Author.Email}}>",
|
|
||||||
"scripts": {
|
|
||||||
"build": "rollup -c",
|
|
||||||
"dev": "rollup -c -w",
|
|
||||||
"start": "sirv public"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@babel/core": "^7.11.6",
|
|
||||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
|
||||||
"@babel/plugin-transform-runtime": "^7.11.5",
|
|
||||||
"@babel/preset-env": "^7.11.5",
|
|
||||||
"@rollup/plugin-commonjs": "^14.0.0",
|
|
||||||
"@rollup/plugin-image": "^2.0.5",
|
|
||||||
"@rollup/plugin-node-resolve": "^8.0.0",
|
|
||||||
"core-js": "^3.6.5",
|
|
||||||
"rollup": "^2.3.4",
|
|
||||||
"rollup-plugin-babel": "^4.4.0",
|
|
||||||
"rollup-plugin-livereload": "^2.0.0",
|
|
||||||
"rollup-plugin-polyfill": "^3.0.0",
|
|
||||||
"rollup-plugin-svelte": "^6.0.0",
|
|
||||||
"rollup-plugin-terser": "^7.0.0",
|
|
||||||
"svelte": "^3.0.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"sirv-cli": "^1.0.0",
|
|
||||||
"@wailsapp/runtime": "^1.0.10",
|
|
||||||
"svelte-simple-modal": "^0.6.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.1 KiB |
@@ -1,17 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset='utf-8'>
|
|
||||||
<meta name='viewport' content='width=device-width,initial-scale=1'>
|
|
||||||
|
|
||||||
<title>Svelte app</title>
|
|
||||||
|
|
||||||
<link rel='icon' type='image/png' href='/favicon.png'>
|
|
||||||
<link rel='stylesheet' href='/build/bundle.css'>
|
|
||||||
|
|
||||||
<script defer src='/build/bundle.js'></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import Modal from 'svelte-simple-modal';
|
|
||||||
import HelloWorld from './components/HelloWorld.svelte'
|
|
||||||
import logo from './logo.png';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<div class="App">
|
|
||||||
<header class="App-header">
|
|
||||||
<Modal>
|
|
||||||
<img src={logo} class="App-logo" alt="logo" />
|
|
||||||
<p>Welcome to your new <code>wails/svelte</code> project.</p>
|
|
||||||
<HelloWorld/>
|
|
||||||
</Modal>
|
|
||||||
</header>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
:global(body) {
|
|
||||||
margin: 0;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
|
||||||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
|
||||||
sans-serif;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
.App {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.App-logo {
|
|
||||||
height: 40vmin;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
|
||||||
.App-logo {
|
|
||||||
animation: App-logo-spin infinite 20s linear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.App-header {
|
|
||||||
background-color: #282c34;
|
|
||||||
min-height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: calc(10px + 2vmin);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes App-logo-spin {
|
|
||||||
from {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { getContext } from 'svelte';
|
|
||||||
import ModalContent from './ModalContent.svelte'
|
|
||||||
|
|
||||||
const { open } = getContext('simple-modal');
|
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
|
||||||
window.backend.basic().then((result) => {
|
|
||||||
open(ModalContent, { message: result });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<p><button on:click={handleOpenModal}>Hello</button></p>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<style></style>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<script>
|
|
||||||
export let message;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
{message}
|
|
||||||
</p>
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import App from './App.svelte';
|
|
||||||
|
|
||||||
import * as Wails from '@wailsapp/runtime';
|
|
||||||
|
|
||||||
let app;
|
|
||||||
|
|
||||||
Wails.Init(() => {
|
|
||||||
app = new App({
|
|
||||||
target: document.body,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
export default app;
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
module {{.BinaryName}}
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/wailsapp/wails {{.WailsVersion}}
|
|
||||||
)
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/leaanthony/mewn"
|
|
||||||
"github.com/wailsapp/wails"
|
|
||||||
)
|
|
||||||
|
|
||||||
func basic() string {
|
|
||||||
return "World!"
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
js := mewn.String("./frontend/public/build/bundle.js")
|
|
||||||
css := mewn.String("./frontend/public/build/bundle.css")
|
|
||||||
|
|
||||||
app := wails.CreateApp(&wails.AppConfig{
|
|
||||||
Width: 1024,
|
|
||||||
Height: 768,
|
|
||||||
Title: "{{.Name}}",
|
|
||||||
JS: js,
|
|
||||||
CSS: css,
|
|
||||||
Colour: "#131313",
|
|
||||||
})
|
|
||||||
|
|
||||||
app.Bind(basic)
|
|
||||||
app.Run()
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Svelte",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"shortdescription": "A basic Svelte template",
|
|
||||||
"description": "A basic Svelte template",
|
|
||||||
"install": "npm install",
|
|
||||||
"build": "npm run build",
|
|
||||||
"author": "Tim Kipp <timkipp.22.developer@gmail.com>",
|
|
||||||
"created": "2020-09-06 13:06:10.469848 -0700 PDT m=+213.578828559",
|
|
||||||
"frontenddir": "frontend",
|
|
||||||
"serve": "npm run dev",
|
|
||||||
"bridge": "src",
|
|
||||||
"wailsdir": ""
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Counter is what we use for counting
|
|
||||||
type Counter struct {
|
|
||||||
r *wails.Runtime
|
|
||||||
store *wails.Store
|
|
||||||
}
|
|
||||||
|
|
||||||
// WailsInit is called when the component is being initialised
|
|
||||||
func (c *Counter) WailsInit(runtime *wails.Runtime) error {
|
|
||||||
c.r = runtime
|
|
||||||
c.store = runtime.Store.New("Counter", 0)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RandomValue sets the counter to a random value
|
|
||||||
func (c *Counter) RandomValue() {
|
|
||||||
c.store.Set(rand.Intn(1000))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increment will increment the counter
|
|
||||||
func (c *Counter) Increment() {
|
|
||||||
|
|
||||||
increment := func(data int) int {
|
|
||||||
return data + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the store using the increment function
|
|
||||||
c.store.Update(increment)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decrement will decrement the counter
|
|
||||||
func (c *Counter) Decrement() {
|
|
||||||
|
|
||||||
decrement := func(data int) int {
|
|
||||||
return data - 1
|
|
||||||
}
|
|
||||||
// Update the store using the decrement function
|
|
||||||
c.store.Update(decrement)
|
|
||||||
}
|
|
||||||
@@ -2,35 +2,20 @@
|
|||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
color: black;
|
width: 1024px;
|
||||||
width: 100%;
|
height: 768px;
|
||||||
height: 100%;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
background-color: rgb(254,254,254);
|
|
||||||
color: black;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
display: block;
|
display: block;
|
||||||
width:100%;
|
width:100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 1rem;
|
margin-top: 3rem;
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
background-color: white;
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.result {
|
|
||||||
margin-top: 1rem;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 2rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ const runtime = require('@wailsapp/runtime');
|
|||||||
// Main entry point
|
// Main entry point
|
||||||
function start() {
|
function start() {
|
||||||
|
|
||||||
var mystore = runtime.Store.New('Counter');
|
|
||||||
|
|
||||||
// Ensure the default app div is 100% wide/high
|
// Ensure the default app div is 100% wide/high
|
||||||
var app = document.getElementById('app');
|
var app = document.getElementById('app');
|
||||||
app.style.width = '100%';
|
app.style.width = '100%';
|
||||||
@@ -15,32 +13,17 @@ function start() {
|
|||||||
app.innerHTML = `
|
app.innerHTML = `
|
||||||
<div class='logo'></div>
|
<div class='logo'></div>
|
||||||
<div class='container'>
|
<div class='container'>
|
||||||
<button onClick='window.backend.Counter.Increment()'>
|
<button id='button'>Click Me!</button>
|
||||||
Increment Counter
|
<div id='result'/>
|
||||||
</button>
|
|
||||||
<button onClick='window.backend.Counter.Decrement()'>
|
|
||||||
Decrement Counter
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class='result'>Counter: <span id='counter'></span></div>
|
|
||||||
<div class='container'>
|
|
||||||
<input id='newCounter' type="number" value="0"/>
|
|
||||||
<button id='setvalue'>Set Counter Value</button>
|
|
||||||
<button onclick='window.backend.Counter.RandomValue()'>Set to Random Value</button>
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// Connect counter value button to Go method
|
// Connect button to Go method
|
||||||
document.getElementById('setvalue').onclick = function() {
|
document.getElementById('button').onclick = function() {
|
||||||
let newValue = parseInt(document.getElementById('newCounter').value,10);
|
window.backend.basic().then( function(result) {
|
||||||
mystore.set(newValue);
|
document.getElementById('result').innerText = result;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
mystore.subscribe( function(state) {
|
|
||||||
document.getElementById('counter').innerText = state;
|
|
||||||
});
|
|
||||||
|
|
||||||
mystore.set(0);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// We provide our entrypoint as a callback for runtime.Init
|
// We provide our entrypoint as a callback for runtime.Init
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ import (
|
|||||||
"github.com/wailsapp/wails"
|
"github.com/wailsapp/wails"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func basic() string {
|
||||||
|
return "Hello World!"
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
js := mewn.String("./frontend/build/main.js")
|
js := mewn.String("./frontend/build/main.js")
|
||||||
@@ -18,6 +22,6 @@ func main() {
|
|||||||
CSS: css,
|
CSS: css,
|
||||||
Colour: "#131313",
|
Colour: "#131313",
|
||||||
})
|
})
|
||||||
app.Bind(&Counter{})
|
app.Bind(basic)
|
||||||
app.Run()
|
app.Run()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
> 1%
|
|
||||||
last 2 versions
|
|
||||||
not dead
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
root: true,
|
|
||||||
env: {
|
|
||||||
node: true
|
|
||||||
},
|
|
||||||
'extends': [
|
|
||||||
'plugin:vue/vue3-essential',
|
|
||||||
'eslint:recommended',
|
|
||||||
'@vue/typescript/recommended'
|
|
||||||
],
|
|
||||||
parserOptions: {
|
|
||||||
ecmaVersion: 2020
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
|
||||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
|
|
||||||
},
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: [
|
|
||||||
'**/__tests__/*.{j,t}s?(x)',
|
|
||||||
'**/tests/unit/**/*.spec.{j,t}s?(x)'
|
|
||||||
],
|
|
||||||
env: {
|
|
||||||
mocha: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
21
cmd/templates/vue3-full/frontend/.gitignore
vendored
21
cmd/templates/vue3-full/frontend/.gitignore
vendored
@@ -1,21 +0,0 @@
|
|||||||
.DS_Store
|
|
||||||
node_modules
|
|
||||||
/dist
|
|
||||||
|
|
||||||
# local env files
|
|
||||||
.env.local
|
|
||||||
.env.*.local
|
|
||||||
|
|
||||||
# Log files
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
|
|
||||||
# Editor directories and files
|
|
||||||
.idea
|
|
||||||
.vscode
|
|
||||||
*.suo
|
|
||||||
*.ntvs*
|
|
||||||
*.njsproj
|
|
||||||
*.sln
|
|
||||||
*.sw*
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# vue basic
|
|
||||||
|
|
||||||
## Project setup
|
|
||||||
|
|
||||||
```
|
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
### Compiles and hot-reloads for development
|
|
||||||
|
|
||||||
```
|
|
||||||
npm run serve
|
|
||||||
```
|
|
||||||
|
|
||||||
### Compiles and minifies for production
|
|
||||||
|
|
||||||
```
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
|
|
||||||
### Run your tests
|
|
||||||
|
|
||||||
```
|
|
||||||
npm run test
|
|
||||||
```
|
|
||||||
|
|
||||||
### Lints and fixes files
|
|
||||||
|
|
||||||
```
|
|
||||||
npm run lint
|
|
||||||
```
|
|
||||||
|
|
||||||
### Customize configuration
|
|
||||||
|
|
||||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "{{.NPMProjectName}}",
|
|
||||||
"author": "{{.Author.Name}}<{{.Author.Email}}>",
|
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
|
||||||
"serve": "vue-cli-service serve",
|
|
||||||
"build": "vue-cli-service build",
|
|
||||||
"test:unit": "vue-cli-service test:unit",
|
|
||||||
"lint": "vue-cli-service lint"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"vue": "^3.0.0-0",
|
|
||||||
"vue-router": "^4.0.0-0",
|
|
||||||
"regenerator-runtime": "^0.13.7",
|
|
||||||
"@wailsapp/runtime": "^1.1.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/chai": "^4.2.12",
|
|
||||||
"@types/mocha": "^8.0.3",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^4.3.0",
|
|
||||||
"@typescript-eslint/parser": "^4.3.0",
|
|
||||||
"@vue/cli-plugin-eslint": "~4.5.6",
|
|
||||||
"@vue/cli-plugin-router": "~4.5.6",
|
|
||||||
"@vue/cli-plugin-typescript": "~4.5.6",
|
|
||||||
"@vue/cli-plugin-unit-mocha": "~4.5.6",
|
|
||||||
"@vue/cli-service": "~4.5.6",
|
|
||||||
"@vue/compiler-sfc": "^3.0.0",
|
|
||||||
"@vue/eslint-config-typescript": "^5.1.0",
|
|
||||||
"@vue/test-utils": "^2.0.0-0",
|
|
||||||
"chai": "^4.2.0",
|
|
||||||
"eslint": "^7.10.0",
|
|
||||||
"eslint-plugin-vue": "^7.0.0",
|
|
||||||
"node-sass": "^4.14.1",
|
|
||||||
"sass-loader": "^10.0.2",
|
|
||||||
"typescript": "~4.0.3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div id=app>
|
|
||||||
<div id="nav">
|
|
||||||
<router-link to="/">Home</router-link> |
|
|
||||||
<router-link to="/about">About</router-link>
|
|
||||||
</div>
|
|
||||||
<router-view/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
#app {
|
|
||||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
text-align: center;
|
|
||||||
color: #2c3e50;
|
|
||||||
}
|
|
||||||
|
|
||||||
#nav {
|
|
||||||
padding: 30px;
|
|
||||||
|
|
||||||
a {
|
|
||||||
font-weight: bold;
|
|
||||||
color: #2c3e50;
|
|
||||||
|
|
||||||
&.router-link-exact-active {
|
|
||||||
color: #42b983;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 106 KiB |
@@ -1,34 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="hello">
|
|
||||||
<h1>{{ msg }}</h1>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'HelloWorld',
|
|
||||||
props: {
|
|
||||||
msg: String,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
|
||||||
<style scoped lang="scss">
|
|
||||||
h3 {
|
|
||||||
margin: 40px 0 0;
|
|
||||||
}
|
|
||||||
ul {
|
|
||||||
list-style-type: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
li {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 10px;
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
color: #42b983;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
import { createApp } from 'vue';
|
|
||||||
import App from './App.vue';
|
|
||||||
import router from './router';
|
|
||||||
import * as Wails from '@wailsapp/runtime';
|
|
||||||
|
|
||||||
Wails.Init(() => {
|
|
||||||
createApp(App).use(router).mount('#app');
|
|
||||||
});
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import { createRouter, createMemoryHistory, RouteRecordRaw } from 'vue-router'
|
|
||||||
import Home from '../views/Home.vue'
|
|
||||||
import About from '../views/About.vue'
|
|
||||||
|
|
||||||
const routes: Array<RouteRecordRaw> = [
|
|
||||||
{
|
|
||||||
path: '/',
|
|
||||||
name: 'Home',
|
|
||||||
component: Home
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/about',
|
|
||||||
name: 'About',
|
|
||||||
// route level code-splitting
|
|
||||||
// this generates a separate chunk (about.[hash].js) for this route
|
|
||||||
// which is lazy-loaded when the route is visited.
|
|
||||||
// component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
|
|
||||||
component: About
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const router = createRouter({
|
|
||||||
history: createMemoryHistory(),
|
|
||||||
routes
|
|
||||||
})
|
|
||||||
|
|
||||||
export default router
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
declare module '*.vue' {
|
|
||||||
import { defineComponent } from 'vue'
|
|
||||||
const component: ReturnType<typeof defineComponent>
|
|
||||||
export default component
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="about">
|
|
||||||
<h1>This is an about page</h1>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="home">
|
|
||||||
<img @click="getMessage" alt="Vue logo" src="../assets/appicon.png" :style="{ height: '400px' }"/>
|
|
||||||
<HelloWorld :msg="message" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { ref, defineComponent } from "vue";
|
|
||||||
import HelloWorld from "@/components/HelloWorld.vue"; // @ is an alias to /src
|
|
||||||
|
|
||||||
interface Backend {
|
|
||||||
basic(): Promise<string>;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface Window {
|
|
||||||
backend: Backend;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "Home",
|
|
||||||
components: {
|
|
||||||
HelloWorld,
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
|
|
||||||
const message = ref("Click the Icon");
|
|
||||||
|
|
||||||
const getMessage = () => {
|
|
||||||
window.backend.basic().then(result => {
|
|
||||||
message.value = result;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return { message: message, getMessage: getMessage };
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { expect } from 'chai';
|
|
||||||
import { describe, it } from 'mocha';
|
|
||||||
import { shallowMount } from '@vue/test-utils';
|
|
||||||
import HelloWorld from '@/components/HelloWorld.vue';
|
|
||||||
|
|
||||||
describe('HelloWorld.vue', () => {
|
|
||||||
it('renders props.msg when passed', () => {
|
|
||||||
const msg = 'new message';
|
|
||||||
const wrapper = shallowMount(HelloWorld, {
|
|
||||||
props: { msg }
|
|
||||||
});
|
|
||||||
expect(wrapper.text()).to.include(msg);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "es5",
|
|
||||||
"module": "esnext",
|
|
||||||
"strict": true,
|
|
||||||
"jsx": "preserve",
|
|
||||||
"importHelpers": true,
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"allowSyntheticDefaultImports": true,
|
|
||||||
"sourceMap": true,
|
|
||||||
"baseUrl": ".",
|
|
||||||
"types": [
|
|
||||||
"webpack-env",
|
|
||||||
"mocha",
|
|
||||||
"chai"
|
|
||||||
],
|
|
||||||
"paths": {
|
|
||||||
"@/*": [
|
|
||||||
"src/*"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"lib": [
|
|
||||||
"esnext",
|
|
||||||
"dom",
|
|
||||||
"dom.iterable",
|
|
||||||
"scripthost"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"src/**/*.ts",
|
|
||||||
"src/**/*.tsx",
|
|
||||||
"src/**/*.vue",
|
|
||||||
"tests/**/*.ts",
|
|
||||||
"tests/**/*.tsx"
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"node_modules"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
module {{.BinaryName}}
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/wailsapp/wails {{.WailsVersion}}
|
|
||||||
)
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/leaanthony/mewn"
|
|
||||||
"github.com/wailsapp/wails"
|
|
||||||
)
|
|
||||||
|
|
||||||
func basic() string {
|
|
||||||
return "Hello World!"
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
js := mewn.String("./frontend/dist/app.js")
|
|
||||||
css := mewn.String("./frontend/dist/app.css")
|
|
||||||
|
|
||||||
app := wails.CreateApp(&wails.AppConfig{
|
|
||||||
Width: 1024,
|
|
||||||
Height: 768,
|
|
||||||
Title: "{{.Name}}",
|
|
||||||
JS: js,
|
|
||||||
CSS: css,
|
|
||||||
Colour: "#131313",
|
|
||||||
})
|
|
||||||
app.Bind(basic)
|
|
||||||
app.Run()
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Vue3 Full",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"shortdescription": "Vue 3, Vuex, Vue-router, and Webpack4",
|
|
||||||
"description": "Vue3.0.0 Vuex, Vue-router, and Webpack 4",
|
|
||||||
"install": "npm install",
|
|
||||||
"build": "npm run build",
|
|
||||||
"author": "Kyle Muchmore <kmuchmor@gmail.com>",
|
|
||||||
"created": "2020-09-24 21:18:55.09417 +0000 UTC m=+90.125590001",
|
|
||||||
"frontenddir": "frontend",
|
|
||||||
"serve": "npm run serve",
|
|
||||||
"bridge": "src",
|
|
||||||
"wailsdir": "",
|
|
||||||
"platforms": ["linux", "darwin"]
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
// Version - Wails version
|
// Version - Wails version
|
||||||
const Version = "v1.8.1-pre1"
|
const Version = "v1.7.2-pre3"
|
||||||
|
|||||||
@@ -26,12 +26,10 @@ func init() {
|
|||||||
var packageApp = false
|
var packageApp = false
|
||||||
var forceRebuild = false
|
var forceRebuild = false
|
||||||
var debugMode = false
|
var debugMode = false
|
||||||
var gopath = ""
|
|
||||||
var typescriptFilename = ""
|
var typescriptFilename = ""
|
||||||
var verbose = false
|
var verbose = false
|
||||||
var platform = ""
|
var platform = ""
|
||||||
var ldflags = ""
|
var ldflags = ""
|
||||||
var tags = ""
|
|
||||||
|
|
||||||
buildSpinner := spinner.NewSpinner()
|
buildSpinner := spinner.NewSpinner()
|
||||||
buildSpinner.SetSpinSpeed(50)
|
buildSpinner.SetSpinSpeed(50)
|
||||||
@@ -44,9 +42,7 @@ func init() {
|
|||||||
BoolFlag("d", "Build in Debug mode", &debugMode).
|
BoolFlag("d", "Build in Debug mode", &debugMode).
|
||||||
BoolFlag("verbose", "Verbose output", &verbose).
|
BoolFlag("verbose", "Verbose output", &verbose).
|
||||||
StringFlag("t", "Generate Typescript definitions to given file (at runtime)", &typescriptFilename).
|
StringFlag("t", "Generate Typescript definitions to given file (at runtime)", &typescriptFilename).
|
||||||
StringFlag("ldflags", "Extra options for -ldflags", &ldflags).
|
StringFlag("ldflags", "Extra options for -ldflags", &ldflags)
|
||||||
StringFlag("gopath", "Specify your GOPATH location. Mounted to /go during cross-compilation.", &gopath).
|
|
||||||
StringFlag("tags", "Build tags to pass to the go compiler (quoted and space separated)", &tags)
|
|
||||||
|
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
for _, plat := range getSupportedPlatforms() {
|
for _, plat := range getSupportedPlatforms() {
|
||||||
@@ -80,11 +76,6 @@ func init() {
|
|||||||
return fmt.Errorf("Unable to find 'project.json'. Please check you are in a Wails project directory")
|
return fmt.Errorf("Unable to find 'project.json'. Please check you are in a Wails project directory")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that this platform is supported
|
|
||||||
if !projectOptions.PlatformSupported() {
|
|
||||||
logger.Yellow("WARNING: This project is unsupported on %s - it probably won't work!\n Valid platforms: %s\n", runtime.GOOS, strings.Join(projectOptions.Platforms, ", "))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set cross-compile
|
// Set cross-compile
|
||||||
projectOptions.Platform = runtime.GOOS
|
projectOptions.Platform = runtime.GOOS
|
||||||
if len(platform) > 0 {
|
if len(platform) > 0 {
|
||||||
@@ -106,10 +97,6 @@ func init() {
|
|||||||
|
|
||||||
// Add ldflags
|
// Add ldflags
|
||||||
projectOptions.LdFlags = ldflags
|
projectOptions.LdFlags = ldflags
|
||||||
projectOptions.GoPath = gopath
|
|
||||||
|
|
||||||
// Add tags
|
|
||||||
projectOptions.Tags = tags
|
|
||||||
|
|
||||||
// Validate config
|
// Validate config
|
||||||
// Check if we have a frontend
|
// Check if we have a frontend
|
||||||
@@ -194,10 +181,6 @@ func init() {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if projectOptions.Platform == "windows" {
|
|
||||||
logger.Yellow("*** Please note: Windows builds use mshtml which is only compatible with IE11. For more information, please read https://wails.app/guides/windows/ ***")
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Yellow("Awesome! Project '%s' built!", projectOptions.Name)
|
logger.Yellow("Awesome! Project '%s' built!", projectOptions.Name)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.Yellow("Awesome! Project '%s' built!", projectOptions.Name)
|
logger.Yellow("Awesome! Project '%s' built!", projectOptions.Name)
|
||||||
|
|
||||||
return cmd.ServeProject(projectOptions, logger)
|
return cmd.ServeProject(projectOptions, logger)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -22,7 +22,7 @@ require (
|
|||||||
github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba
|
github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba
|
||||||
golang.org/x/image v0.0.0-20200430140353-33d19683fad8
|
golang.org/x/image v0.0.0-20200430140353-33d19683fad8
|
||||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd
|
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c
|
||||||
golang.org/x/text v0.3.0
|
golang.org/x/text v0.3.0
|
||||||
gopkg.in/AlecAivazis/survey.v1 v1.8.4
|
gopkg.in/AlecAivazis/survey.v1 v1.8.4
|
||||||
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22
|
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -81,6 +81,8 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||||
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/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
gopkg.in/AlecAivazis/survey.v1 v1.8.4 h1:10xXXN3wgIhPheb5NI58zFgZv32Ana7P3Tl4shW+0Qc=
|
gopkg.in/AlecAivazis/survey.v1 v1.8.4 h1:10xXXN3wgIhPheb5NI58zFgZv32Ana7P3Tl4shW+0Qc=
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ func (b *boundMethod) processWailsInit() error {
|
|||||||
// It must be *wails.Runtime
|
// It must be *wails.Runtime
|
||||||
inputName := b.inputs[0].String()
|
inputName := b.inputs[0].String()
|
||||||
b.log.Debugf("WailsInit input type: %s", inputName)
|
b.log.Debugf("WailsInit input type: %s", inputName)
|
||||||
if inputName != "*runtime.Runtime" {
|
if inputName != "*wails.Runtime" {
|
||||||
return fmt.Errorf("Invalid WailsInit() definition. Expected input to be wails.Runtime, but got %s", inputName)
|
return fmt.Errorf("Invalid WailsInit() definition. Expected input to be wails.Runtime, but got %s", inputName)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,7 +219,7 @@ func (b *boundMethod) processWailsInit() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *boundMethod) processWailsShutdown() error {
|
func (b *boundMethod) processWailsShutdown() error {
|
||||||
// We must not have any inputs
|
// We must have only 1 input, it must be *wails.Runtime
|
||||||
if len(b.inputs) != 0 {
|
if len(b.inputs) != 0 {
|
||||||
return fmt.Errorf("Invalid WailsShutdown() definition. Expected 0 inputs, but got %d", len(b.inputs))
|
return fmt.Errorf("Invalid WailsShutdown() definition. Expected 0 inputs, but got %d", len(b.inputs))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,5 +5,5 @@ package renderer
|
|||||||
import "github.com/leaanthony/mewn"
|
import "github.com/leaanthony/mewn"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
mewn.AddAsset(".", "../../runtime/assets/wails.js", "1f8b08000000000000ff94587f6f1b37d2fe2a2be27d5532a6b752ae875e56dd06a9eba23e38761127d73f744241ed8e24262b52478eac0812bffb61f6b76cb9770704b1440ec9e13ccfcc3cd460b135196a6bb8118747e5224c0f61d20c46c09d38e805c7a99b0907b87526a2cf317cdd58877e424b6c4a43e941274e16c9602cebc9e410c2a45e646851a68a82db66adb4b2fb0c42dab84807a36e2c40bc4e8d84384b51429ca79dab12a51307882d7d14c7e3fdfc336418e7b0d0067e7376030ef7a5d901cc760d4ecd0b480623b9044c5c104142ecd2fed5d9d654ab73364871bf01bb881ef6ebb92d86c3ea6f8cf6019d36cb8f6a391cbe74e2735b797854c51612f6dee6db025810f2a5c5ec8f3fc0d766cdb2c1a872174fae5f82321ee270c84d0adc0821ff36c4062133d10bfe1dcd325b1ec5d2e64e6638a47f717752b788b07469ed5ce6402170b32d0a41db41ecb87bc97527590e0bb52d903d8d78750b13847c5d3ae4cbb874413662611d2f69146913190171ce9db4b2bd2e8a434b229c8578ae4d5efa25ad100dbf1cc5c8a4cfd9fce4b66f5b8b6ed7b8f63d2467265b06935f2899621285443ace3e81a436ac43b471162d5d325e297fbf334db0aa2ca005b4c726654c0287d8a72311f8f484e340bcf41051cc326413c20085ac3db9311a99e4cf7dfe1a84a8c13c84490d5c1556f633ccb7cbb3ab8a205aab1bb3b0678d7ccfe877e50c4179ce6ed1b3bb76cebab35679cfea1785aa386bb56bae639bebd86a9595ec7e03e6d387dbb3ebf6cdeeb5dd2f9ad2ea8ce1bc39403707e86aa196ec0e7667d75c356b543a9d75f5326b70abc34ff8274612e473957db9f93901b951fbc2aa3cc13039a9be7ac177dae47617ef942efcdce97c096f9f0fc53b987b9b7d018c3d502a88a43682af08cea822d6e6d17ea1b220555c8059e2eac7519b67988e26f8433331c18b0ba1a638e34604fef787fbbbb84a51bdd873274468efb6ad589e7156d8259387021ea1488c5c83f76a0909869e714137da7296577c33bd295f4fe99264fd99453db36b98d59fcceb49a8e8d49fdad5538b8a434604bae7463e9ef4b265834d93dadba218a4301cd61f8e470ee9484803bbe83767d7da03ef9077d256a8ea496e0f3a3517ec925d6cb808bb952e803f4ef5ac2a943f8e44450c0ff851afc16e91f719647999119c5da9a288d046ecc25cb008f51af2c86e318e3ec0bfb6e031baf93989d88516220809624247a407acb6fc5599bc80444907546e122b1d785b3c42e2c204dd9e7022da3179a082a9cdf24ead898bb942953cc1996a9116215398ad28969935de161097b12662843e115627e56ec959c5ce985d9455adb5dbd356b5d58ab39f9cdd7970719bb37d08e72fdb56796b44d8a435cf33b7dfa0ed97720ab84909b94fdae05f5ebf734eedf9b86d0f270be325e0076572bbfe073527e2e374343b57fddf8c46df8fdfbc79fdd7efbeff6ef4e6cdf8d57b85abd8956bb908650158b75d2032bce4d7e059a71e701369e351998c7a1e0a812b67771139fc71bf819610c6588c08b6484559a1bc8f948f54d46cc844e0b8d25e1a2181187b3996f43dbeaa0bcc49036cf45aac369b625fb54c23e4e5789012ed47699a72b84cc72204797d922af74daa5c4fcd2ca5ff8ec7e9acee29e4f4babce98466e2cdd6afb8eb61f9d075df273c9bce625fe80c6a8f945b6ed760d08b6a988fa962a707d3632a8649c6193c824126a1caecbb1367bfd071c4f826af6117fdd28481913dbb30420e461dbf2bcbc138744e5f5560913948975254299b07fdfa5ba356a3f53b0d45da478499361ab52ab4879c35dd6a3a6be85762e4b7739f393d8713906c153f234285a4879ed24371801465df87f89a42e1e3ebb546aa94baf089df9b2cf1681d24db4dae10f2f97ee1ac4130794259f9040610a4b617d65dab6cd5ab4d461c0c0741c95e3953ed764e5571101347ce96b5e39c83f7e6cfdc23b236de9d3a507166a39c2f1b18a4e63ff92a84c4e1b0891e2924fadc41fbb94d68feb991b7ca7bbd34c7637fbfae418ea94136e4ec37ca8a1f693b37c5d9a459e648bf82f8afe41f482748bbd3bb09e86d155abd29eae428f3bccb9050c7b80e5c7a388d7adaff723c76b39d7dc9ca9bf47007bb9faa8e903c07763a8b336b3285dcc47e5310c76226ca8f6d7e9eee4c59828dca18b72ac3a5a389fba199b81c4fdc453aae4ea9de8b65767de156885eded6a9c51a27ac644d86a9e851153a8f3eab474579b4c148e760502f34b898093181a99d51139fda597a0865859cda59a8941dc61bbbe1a23e55ffe9a9fa7f3b55cfd227ad882456ef0dddd0a62d7f25073a6c276d2b3512a885b64f8e4e429c2421a6861e0fcb33b35dd90f1202174136bde139da1393e690d91c3e7db8b9b2eb8d35600878079b4265c0bffda7bff876291913ddd07474f9465d2e6687d781a6feffff8614042abf789ab975b56d6a6aca6e4c154ab28a36ca7bc849fd34da3889daf8635c6b4ac9e2e87d2d2f23265a6a8a4955890b0e955eab10acdb834b316e76d5b9b4e96343b746c2a5ac094af44d7baa93ec9b1273074bed11f2c160c09a934e1591ee9f4ac2a900e51aad67e3138926640e052044e485c46a87b736ae741baf07444223a580e31853e71341de59d48b7df24c4e50dbedca15940dbaeea0425689570ed585ab9f79344e7e68ea4e94b982a0d37de8b0075dce4f6123c7220f06093953ba174765c18fa8694769d96b836d0509d7623884a67e383916a1d41410827c97e70f654a3db96175a9dc66657ad4bf445c1740df38abb2908909c4085f3135b2b59cdb7c4fd5134c7eb5d2454eecc0e1f0a1ec513786e27df5f070a6eabd7816ee0b200e5022be43747abe45e08cea3a938cceff36f39e09897169fbb002c0b7fd2f71e6fdc7d2cf044f7c7b7226d9dcd9bcfa2da79b5c81ca8fc7f6eb12b076ceffb4ffa84a4dcf191931d2b0e2e484ead61a93af14ea9bdfae6e89d606dc4904542b4082bc4d0fb776993859ebefc4caaa9b27877bf304a5fbfa378c7bf37e5ba0de1490dc4b5225c983fc1594c339a85364bb773149d1c91df1a057b7ca24ba3108ee5115e54f1654bd1c3da3dad1fe3b8a646610a50fefb22fc6ee0ac897903c79520fe8989edcce5b99adba45d1d6d06713ad1ac77b75c148f60dd538da8853941e4a29a3e51fc94d4f867ead2489089f4f9ef1f25634add89a32d54f7fc70459be2c4f14d4ad5dc6754f7af5ead5abe84a6d972b8c3e99555951f2aaf04434c7847c6969573849febe64f5e9c32d59e0cb16b7da407467c90a5eb6bab2c5766d6a3bf7b25d1902b2b122c88746221656e5a49cc34c4cfe1d0000ffff6a61b37f93160000")
|
mewn.AddAsset(".", "../../runtime/assets/wails.js", "1f8b08000000000000ff94586d8f1bb711fe2b2ba255481f8f91dc14a977c318cee582a838df053ebbfda00a01b53b92e85b915b2e758a20f1bf17b3efba97a2050c7bc519728633cf3c33f468b533a9d7d650c38e8fca45208f216917234f1d3bea1585b95b30077ee74c84df02fe28acf365825bacc42579d4b1e3793c9af246181f43489a4d0637a52acfa96df772cbfb6fcfb815b91c4dfab5e0c5561aee452a817b91c9de550edcb1a317163fd9e974b7fc0aa91719acb481df9c2dc0f943a57604b3db8253cb1ce2d184afc1c72eb0c0bd70727875b233f5ee8c8ca43f146057d1fd61bbb4f9785cff2bbcbdf74e9bf567b51e8f5fb3f85c971f1f55be83987cb4d92e0712187f6d33f9fd77281bb576db6852bbebcfae5f25653a86f1981ae9a9618cff6d0c6d864ca257f43b94125b9922b2bd93198ff18fe82df59b30974e36cea50e94076a7679cef0382f1c75afb9ee38c960a576b9274f235edfc204c6df560e95555cfa201bb6b28e56308ab4890cf322a38e5bde5d17d8b103112c82586a93557e71cb588b2f873132f2399a9fdcf67da7d19f2a1adf43fc82b04330fa059c28c281714073f6494a1ac5264485b3dee225c54695777bd306abae02dc8067149210eea917a59cb040e76718f788cb12228c59ea49823900c61b4f66467bc2e9739f6781b12699c7903489abc34a7e86e56efde2ae5d609dd6ccacec8b4af940e99fca194ce54b7aab81deb573d6bda8950db47e515ee52f6a95ed756c7b1d5befb29cdc1560be7cba7971dfa13dbdd1fb456359bda0b86c0d68395ff4dca7da1c34a1c45cc68663fa962a7d98fd1c7b5ea8436e55164348ce9854afe85e9bcceec55ee9bc5c3a9dade1fdf325b1876569d307f0a20484358b1b25f8c383332a17da3cda07a086712d72306bbff971d2d50cc849023fb482042e2e989ec3821a16e8dfefef6e455d6e7a75a08eb1d0dd2dad11ab28c9ed9af0630e8f90c7866fa12cd51a620803e51dde28a524abb16306a2bc11e90a3043c9aa91ec5b940c855923841a1a4351d98856351e0c0b78cf3d2fcefad2639b9bb64c77793e927e3c6e3e4e27eae5847103fbe83767b7ba04da67de715b675527993d6a692ec825b9d85316f61b9d032de67a5193de8f13867aa92cc17fd65bb03b4f8708b2b4423725572acf236f2372612e48e4f516b2c8eebc883ec1bf7750fa68f6731c910bcd5860dcb3044dc8a3af8ffc55992c8738e50e903a62cb1d94367f84d885c4bb03e6096147f811c94f9bf5adda221633e555fc24cfc82b9a8554f97453c5d29ad2e620aa582330c21008eb33ea7aa4a446a720171543757a073caad15a53f293b3fb129ce8ea6f98c2e5ebba750d1a16f6b2c179ea0e85b7435ac6801b8999fba28dffcbdb0fcea9039d76547fb651acc17f5226b3db7f60a341f4cc278b9798fcdd64f2fdf4ddbbb77ffdeefbef26efde4ddf7c547e235cb597b25011c0b663f4c8d00a5fa3675d77444da44de99549b17f01637ee3ec3e42873f1f0ae800618cf511a62d52519aabb28c5419a9a83d90b040fd4697dc30ee11b197538ebfc555433067cdac9dbd842a8afc50b73fc3f8e5742411f6132925f59772ca42e09bb352b96b4b6533370b897f9d4ef345d31fd0e96d75d30425a2d8951bea06b9bcee3be9139ccd17a2cc75da7aa4dc7ab705e34b562fd329b2af3c9a015221248a127804e309f77565df9f39fb80e610f16d5dc33efaa50d03417d7261181f4d7a7cd79aa369e89dbeeab24eafda794695a55e9bd36918d49e45a709fcd0dd60c8a6d5ddbdec64735824ed3687038b67ff53bff7dc311cd67050f6384c876ec0604d042b30f4610c0dce110a6032790c7cd83fe4f0c7e9d44b7bfd2ac75fe5f116f63fd5b4113f9f8fe60b915a932a4f8d288b5c7b4a0461d56797c4f3939118a16d45d3ae15393949dc0fade0729ab80b39adadd40f04dc377aa096b141729b6a21ad139693489711968e8a1e55aeb3e8ab7a5465ea74e1239d81f17aa5c109c258e2e776814c3fb70b790c5519cded22d4ad1c44610bca1aabfabf5ad5ff9f55bd904ff80afbf0e0d1d4c2a6ab910a037d6e938e6f0df7c8b3dd8cd9f799b3f20769705a5cbf20edb921701f280bbc2590e7d94e8ccc20b5197cf934bbb2dbc21a3098780745ae52a0dffeabbcf876cd0961fdd27c72f94e5dae16c7b701457ffed3b80a823b1c1b4a28942b713e694a12dacb9399a943895a51a1ca12326c91ed0015475dfc413483072722fad8cc2011611d34595293ec8efabaa9d7196c38c4c93ac278aaceb895450bb7b6cf4bd20625faa6b3ea38f9a6cab983b52e3d64a3d188b496cedba61e5ac5ee9a8372ed4060c5591f673c831c3c44e8056f4e786f45dddc69b3c0625ca9ba3c0581f4c802bfb55eaf0ef1b39e83dcdcd395af58bca159c6ebc2ab961ae21a561eaea31fd56c8b95cb30757a983a18a42ea3e76943c7a2128cc7cc99ca3d115d238347c8ec91ac0839d8ae6b51cdc663dff287e35316aac6e343e01fb2ecbe2aa92737ac2f95d9b42a8fe6e9799d03fea2a4ae424c8cf0f0879786779a4b9b1d903dc164571b9d67880e188fafab21686630de57f7f72fb0deabb6fc2107c212c042fce0bdd3cb9d074a90d7092768ffdbb42c09e3202addfb0d807f3ffc21d2b2fc5cf919c3996f4f6ca2ceadcda07abcf7c20da8ec74ea7eaec137ce953f1d3eab6af0a30495080e3aeccc427d6bede319867af6dbd50dc2da803b8b80aebb3c4e82fc561e6fec3a76bc19d262cbabe496f1f1ce3cc9d25df368bd331f77b9d7450ef11dbfde6a1f5ff35f4139bf04759ed9fef184f34a728f3818f056554433e3c13daabc7aa3227b399cb5bbd5e1b08db34860950f1fd20763f739646b889fbcbb466866309365dd2ca6fa4dd1cee0b78936ade3035e309c7c831c8707518cd2eff1d7c18c32434386b27075f6c6e3b7ac6dc1d654257efe1f569e57cf8ee1167163d7a2e9456fdebc79135da9dd7ae3a32f6653314956134e8432c2f86b5b7bc2c4d9e835ad2f9f6e50035ed7b8d106a25b8b5afe75ad2b9befb6a6d173afeb5521401dcb02bfc687a0cecb185fcb901116162cf94f000000ffff04075a367c140000")
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1431,13 +1431,6 @@ struct webview_priv
|
|||||||
style = WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
|
style = WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scale
|
|
||||||
// Credit: https://github.com/webview/webview/issues/54#issuecomment-379528243
|
|
||||||
HDC hDC = GetDC(NULL);
|
|
||||||
w->width = GetDeviceCaps(hDC, 88)*w->width/96.0;
|
|
||||||
w->height = GetDeviceCaps(hDC, 90)*w->height/96.0;
|
|
||||||
ReleaseDC(NULL, hDC);
|
|
||||||
|
|
||||||
rect.left = 0;
|
rect.left = 0;
|
||||||
rect.top = 0;
|
rect.top = 0;
|
||||||
rect.right = w->width;
|
rect.right = w->width;
|
||||||
|
|||||||
32
runtime.go
Normal file
32
runtime.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package wails
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
|
"github.com/wailsapp/wails/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CustomLogger type alias
|
||||||
|
type CustomLogger = logger.CustomLogger
|
||||||
|
|
||||||
|
// Runtime is the Wails Runtime Interface, given to a user who has defined the WailsInit method
|
||||||
|
type Runtime struct {
|
||||||
|
Events *runtime.Events
|
||||||
|
Log *runtime.Log
|
||||||
|
Dialog *runtime.Dialog
|
||||||
|
Window *runtime.Window
|
||||||
|
Browser *runtime.Browser
|
||||||
|
FileSystem *runtime.FileSystem
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRuntime creates a new Runtime struct
|
||||||
|
func NewRuntime(eventManager interfaces.EventManager, renderer interfaces.Renderer) *Runtime {
|
||||||
|
return &Runtime{
|
||||||
|
Events: runtime.NewEvents(eventManager),
|
||||||
|
Log: runtime.NewLog(),
|
||||||
|
Dialog: runtime.NewDialog(renderer),
|
||||||
|
Window: runtime.NewWindow(renderer),
|
||||||
|
Browser: runtime.NewBrowser(),
|
||||||
|
FileSystem: runtime.NewFileSystem(),
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -15,7 +15,6 @@ import { NewBinding } from './bindings';
|
|||||||
import { Callback } from './calls';
|
import { Callback } from './calls';
|
||||||
import { AddScript, InjectCSS } from './utils';
|
import { AddScript, InjectCSS } from './utils';
|
||||||
import { AddIPCListener } from './ipc';
|
import { AddIPCListener } from './ipc';
|
||||||
import * as Store from './store';
|
|
||||||
|
|
||||||
// Initialise global if not already
|
// Initialise global if not already
|
||||||
window.wails = window.wails || {};
|
window.wails = window.wails || {};
|
||||||
@@ -43,7 +42,6 @@ var runtime = {
|
|||||||
Heartbeat,
|
Heartbeat,
|
||||||
Acknowledge,
|
Acknowledge,
|
||||||
},
|
},
|
||||||
Store,
|
|
||||||
_: internal,
|
_: internal,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
1103
runtime/js/package-lock.json
generated
1103
runtime/js/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -13,12 +13,10 @@ const Log = require('./log');
|
|||||||
const Browser = require('./browser');
|
const Browser = require('./browser');
|
||||||
const Events = require('./events');
|
const Events = require('./events');
|
||||||
const Init = require('./init');
|
const Init = require('./init');
|
||||||
const Store = require('./store');
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
Log: Log,
|
Log: Log,
|
||||||
Browser: Browser,
|
Browser: Browser,
|
||||||
Events: Events,
|
Events: Events,
|
||||||
Init: Init,
|
Init: Init
|
||||||
Store: Store,
|
|
||||||
};
|
};
|
||||||
492
runtime/js/runtime/package-lock.json
generated
492
runtime/js/runtime/package-lock.json
generated
@@ -1,492 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@wailsapp/runtime",
|
|
||||||
"version": "1.1.0",
|
|
||||||
"lockfileVersion": 1,
|
|
||||||
"requires": true,
|
|
||||||
"dependencies": {
|
|
||||||
"ansi-regex": {
|
|
||||||
"version": "2.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
|
||||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"camelcase": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
|
|
||||||
"integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"cliui": {
|
|
||||||
"version": "3.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
|
|
||||||
"integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"string-width": "^1.0.1",
|
|
||||||
"strip-ansi": "^3.0.1",
|
|
||||||
"wrap-ansi": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"code-point-at": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
|
|
||||||
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"decamelize": {
|
|
||||||
"version": "1.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
|
||||||
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"dts-dom": {
|
|
||||||
"version": "3.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/dts-dom/-/dts-dom-3.6.0.tgz",
|
|
||||||
"integrity": "sha512-on5jxTgt+A6r0Zyyz6ZRHXaAO7J1VPnOd6+AmvI1vH440AlAZZNc5rUHzgPuTjGlrVr1rOWQYNl7ZJK6rDohbw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"dts-gen": {
|
|
||||||
"version": "0.5.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/dts-gen/-/dts-gen-0.5.8.tgz",
|
|
||||||
"integrity": "sha512-kIAV6dlHaF7r5J+tIuOC1BJls2P72YM0cyWQUR88zcJEpX2ccRZe+HmXLfkkvfPwjvSO3FEqUiyC8On/grx5qw==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"dts-dom": "^3.6.0",
|
|
||||||
"parse-git-config": "^1.1.1",
|
|
||||||
"typescript": "^3.5.1",
|
|
||||||
"yargs": "^4.8.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"error-ex": {
|
|
||||||
"version": "1.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
|
||||||
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"is-arrayish": "^0.2.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"extend-shallow": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
|
||||||
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"is-extendable": "^0.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"find-up": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
|
|
||||||
"integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"path-exists": "^2.0.0",
|
|
||||||
"pinkie-promise": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"fs-exists-sync": {
|
|
||||||
"version": "0.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz",
|
|
||||||
"integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"get-caller-file": {
|
|
||||||
"version": "1.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
|
|
||||||
"integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"git-config-path": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/git-config-path/-/git-config-path-1.0.1.tgz",
|
|
||||||
"integrity": "sha1-bTP37WPbDQ4RgTFQO6s6ykfVRmQ=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"extend-shallow": "^2.0.1",
|
|
||||||
"fs-exists-sync": "^0.1.0",
|
|
||||||
"homedir-polyfill": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"graceful-fs": {
|
|
||||||
"version": "4.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
|
|
||||||
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"homedir-polyfill": {
|
|
||||||
"version": "1.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
|
|
||||||
"integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"parse-passwd": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"hosted-git-info": {
|
|
||||||
"version": "2.8.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
|
|
||||||
"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"ini": {
|
|
||||||
"version": "1.3.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
|
|
||||||
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"invert-kv": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
|
|
||||||
"integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"is-arrayish": {
|
|
||||||
"version": "0.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
|
||||||
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"is-extendable": {
|
|
||||||
"version": "0.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
|
|
||||||
"integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"is-fullwidth-code-point": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
|
|
||||||
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"number-is-nan": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"is-utf8": {
|
|
||||||
"version": "0.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
|
|
||||||
"integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"lcid": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
|
|
||||||
"integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"invert-kv": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"load-json-file": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
|
|
||||||
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"graceful-fs": "^4.1.2",
|
|
||||||
"parse-json": "^2.2.0",
|
|
||||||
"pify": "^2.0.0",
|
|
||||||
"pinkie-promise": "^2.0.0",
|
|
||||||
"strip-bom": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lodash.assign": {
|
|
||||||
"version": "4.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz",
|
|
||||||
"integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"normalize-package-data": {
|
|
||||||
"version": "2.5.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
|
|
||||||
"integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"hosted-git-info": "^2.1.4",
|
|
||||||
"resolve": "^1.10.0",
|
|
||||||
"semver": "2 || 3 || 4 || 5",
|
|
||||||
"validate-npm-package-license": "^3.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"number-is-nan": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
|
|
||||||
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"os-locale": {
|
|
||||||
"version": "1.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
|
|
||||||
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"lcid": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"parse-git-config": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/parse-git-config/-/parse-git-config-1.1.1.tgz",
|
|
||||||
"integrity": "sha1-06mYQxcTL1c5hxK7pDjhKVkN34w=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"extend-shallow": "^2.0.1",
|
|
||||||
"fs-exists-sync": "^0.1.0",
|
|
||||||
"git-config-path": "^1.0.1",
|
|
||||||
"ini": "^1.3.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"parse-json": {
|
|
||||||
"version": "2.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
|
|
||||||
"integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"error-ex": "^1.2.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"parse-passwd": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
|
|
||||||
"integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"path-exists": {
|
|
||||||
"version": "2.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
|
|
||||||
"integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"pinkie-promise": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"path-parse": {
|
|
||||||
"version": "1.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
|
|
||||||
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"path-type": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
|
|
||||||
"integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"graceful-fs": "^4.1.2",
|
|
||||||
"pify": "^2.0.0",
|
|
||||||
"pinkie-promise": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pify": {
|
|
||||||
"version": "2.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
|
||||||
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"pinkie": {
|
|
||||||
"version": "2.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
|
|
||||||
"integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"pinkie-promise": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
|
|
||||||
"integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"pinkie": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"read-pkg": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
|
|
||||||
"integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"load-json-file": "^1.0.0",
|
|
||||||
"normalize-package-data": "^2.3.2",
|
|
||||||
"path-type": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"read-pkg-up": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
|
|
||||||
"integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"find-up": "^1.0.0",
|
|
||||||
"read-pkg": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"require-directory": {
|
|
||||||
"version": "2.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
|
||||||
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"require-main-filename": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
|
|
||||||
"integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"resolve": {
|
|
||||||
"version": "1.17.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
|
|
||||||
"integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"path-parse": "^1.0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"semver": {
|
|
||||||
"version": "5.7.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
|
||||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"set-blocking": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
|
||||||
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"spdx-correct": {
|
|
||||||
"version": "3.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
|
|
||||||
"integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"spdx-expression-parse": "^3.0.0",
|
|
||||||
"spdx-license-ids": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"spdx-exceptions": {
|
|
||||||
"version": "2.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
|
|
||||||
"integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"spdx-expression-parse": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"spdx-exceptions": "^2.1.0",
|
|
||||||
"spdx-license-ids": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"spdx-license-ids": {
|
|
||||||
"version": "3.0.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
|
|
||||||
"integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"string-width": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
|
|
||||||
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"code-point-at": "^1.0.0",
|
|
||||||
"is-fullwidth-code-point": "^1.0.0",
|
|
||||||
"strip-ansi": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"strip-ansi": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
|
||||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"ansi-regex": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"strip-bom": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
|
|
||||||
"integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"is-utf8": "^0.2.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"typescript": {
|
|
||||||
"version": "3.9.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz",
|
|
||||||
"integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"validate-npm-package-license": {
|
|
||||||
"version": "3.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
|
|
||||||
"integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"spdx-correct": "^3.0.0",
|
|
||||||
"spdx-expression-parse": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"which-module": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
|
|
||||||
"integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"window-size": {
|
|
||||||
"version": "0.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz",
|
|
||||||
"integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"wrap-ansi": {
|
|
||||||
"version": "2.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
|
|
||||||
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"string-width": "^1.0.1",
|
|
||||||
"strip-ansi": "^3.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"y18n": {
|
|
||||||
"version": "3.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
|
|
||||||
"integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"yargs": {
|
|
||||||
"version": "4.8.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz",
|
|
||||||
"integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"cliui": "^3.2.0",
|
|
||||||
"decamelize": "^1.1.1",
|
|
||||||
"get-caller-file": "^1.0.1",
|
|
||||||
"lodash.assign": "^4.0.3",
|
|
||||||
"os-locale": "^1.4.0",
|
|
||||||
"read-pkg-up": "^1.0.1",
|
|
||||||
"require-directory": "^2.1.1",
|
|
||||||
"require-main-filename": "^1.0.1",
|
|
||||||
"set-blocking": "^2.0.0",
|
|
||||||
"string-width": "^1.0.1",
|
|
||||||
"which-module": "^1.0.0",
|
|
||||||
"window-size": "^0.2.0",
|
|
||||||
"y18n": "^3.2.1",
|
|
||||||
"yargs-parser": "^2.4.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"yargs-parser": {
|
|
||||||
"version": "2.4.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz",
|
|
||||||
"integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"camelcase": "^3.0.0",
|
|
||||||
"lodash.assign": "^4.0.6"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wailsapp/runtime",
|
"name": "@wailsapp/runtime",
|
||||||
"version": "1.1.1",
|
"version": "1.0.11",
|
||||||
"description": "Wails Javascript runtime library",
|
"description": "Wails Javascript runtime library",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"types": "runtime.d.ts",
|
"types": "runtime.d.ts",
|
||||||
@@ -25,4 +25,4 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"dts-gen": "^0.5.8"
|
"dts-gen": "^0.5.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
3
runtime/js/runtime/runtime.d.ts
vendored
3
runtime/js/runtime/runtime.d.ts
vendored
@@ -21,9 +21,6 @@ declare const wailsapp__runtime: {
|
|||||||
Info(message: string): void;
|
Info(message: string): void;
|
||||||
Warning(message: string): void;
|
Warning(message: string): void;
|
||||||
};
|
};
|
||||||
Store: {
|
|
||||||
New(name: string, optionalDefault?: any): any;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
package runtime
|
|
||||||
|
|
||||||
import "github.com/wailsapp/wails/lib/interfaces"
|
|
||||||
|
|
||||||
// Runtime is the Wails Runtime Interface, given to a user who has defined the WailsInit method
|
|
||||||
type Runtime struct {
|
|
||||||
Events *Events
|
|
||||||
Log *Log
|
|
||||||
Dialog *Dialog
|
|
||||||
Window *Window
|
|
||||||
Browser *Browser
|
|
||||||
FileSystem *FileSystem
|
|
||||||
Store *StoreProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRuntime creates a new Runtime struct
|
|
||||||
func NewRuntime(eventManager interfaces.EventManager, renderer interfaces.Renderer) *Runtime {
|
|
||||||
result := &Runtime{
|
|
||||||
Events: NewEvents(eventManager),
|
|
||||||
Log: NewLog(),
|
|
||||||
Dialog: NewDialog(renderer),
|
|
||||||
Window: NewWindow(renderer),
|
|
||||||
Browser: NewBrowser(),
|
|
||||||
FileSystem: NewFileSystem(),
|
|
||||||
}
|
|
||||||
// We need a reference to itself
|
|
||||||
result.Store = NewStoreProvider(result)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
13
v2/.vscode/settings.json
vendored
Normal file
13
v2/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"ios": "c",
|
||||||
|
"typeinfo": "c",
|
||||||
|
"sstream": "c",
|
||||||
|
"__functional_03": "c",
|
||||||
|
"functional": "c",
|
||||||
|
"__locale": "c",
|
||||||
|
"locale": "c",
|
||||||
|
"chrono": "c",
|
||||||
|
"system_error": "c"
|
||||||
|
}
|
||||||
|
}
|
||||||
40
v2/NOTES.md
Normal file
40
v2/NOTES.md
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
# Packing linux
|
||||||
|
|
||||||
|
* create app, app.desktop, app.png (512x512)
|
||||||
|
* chmod +x app!
|
||||||
|
* ./linuxdeploy-x86_64.AppImage --appdir AppDir -i react.png -d react.desktop -e react --output appimage
|
||||||
|
|
||||||
|
|
||||||
|
# Wails Doctor
|
||||||
|
|
||||||
|
Tested on:
|
||||||
|
|
||||||
|
* Debian 8
|
||||||
|
* Ubuntu 20.04
|
||||||
|
* Ubuntu 19.10
|
||||||
|
* Solus 4.1
|
||||||
|
* Centos 8
|
||||||
|
* Gentoo
|
||||||
|
* OpenSUSE/leap
|
||||||
|
* Fedora 31
|
||||||
|
|
||||||
|
### Development
|
||||||
|
|
||||||
|
Add a new package manager processor here: `v2/internal/system/packagemanager/`. IsAvailable should work even if the package is installed.
|
||||||
|
Add your new package manager to the list of package managers in `v2/internal/system/packagemanager/packagemanager.go`:
|
||||||
|
|
||||||
|
```
|
||||||
|
var db = map[string]PackageManager{
|
||||||
|
"eopkg": NewEopkg(),
|
||||||
|
"apt": NewApt(),
|
||||||
|
"yum": NewYum(),
|
||||||
|
"pacman": NewPacman(),
|
||||||
|
"emerge": NewEmerge(),
|
||||||
|
"zypper": NewZypper(),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Gentoo
|
||||||
|
|
||||||
|
* Setup docker image using: emerge-webrsync -x -v
|
||||||
5
v2/README.md
Normal file
5
v2/README.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Wails v2 ALPHA
|
||||||
|
|
||||||
|
This branch contains WORK IN PROGRESS! There are no guarantees. Use at your peril!
|
||||||
|
|
||||||
|
This document will be updated as progress is made.
|
||||||
113
v2/cmd/wails/internal/commands/build/build.go
Normal file
113
v2/cmd/wails/internal/commands/build/build.go
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
package build
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/leaanthony/clir"
|
||||||
|
"github.com/leaanthony/slicer"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddBuildSubcommand adds the `build` command for the Wails application
|
||||||
|
func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
||||||
|
|
||||||
|
outputType := "desktop"
|
||||||
|
|
||||||
|
validTargetTypes := slicer.String([]string{"desktop", "hybrid", "server"})
|
||||||
|
|
||||||
|
command := app.NewSubCommand("build", "Builds the application")
|
||||||
|
|
||||||
|
// Setup target type flag
|
||||||
|
description := "Type of application to build. Valid types: " + validTargetTypes.Join(",")
|
||||||
|
command.StringFlag("t", description, &outputType)
|
||||||
|
|
||||||
|
// Setup production flag
|
||||||
|
production := false
|
||||||
|
command.BoolFlag("production", "Build in production mode", &production)
|
||||||
|
|
||||||
|
// Setup pack flag
|
||||||
|
pack := false
|
||||||
|
command.BoolFlag("pack", "Create a platform specific package", &pack)
|
||||||
|
|
||||||
|
compilerCommand := "go"
|
||||||
|
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &compilerCommand)
|
||||||
|
|
||||||
|
// Setup Platform flag
|
||||||
|
platform := runtime.GOOS
|
||||||
|
command.StringFlag("platform", "Platform to target", &platform)
|
||||||
|
|
||||||
|
// Quiet Build
|
||||||
|
quiet := false
|
||||||
|
command.BoolFlag("q", "Supress output to console", &quiet)
|
||||||
|
|
||||||
|
// ldflags to pass to `go`
|
||||||
|
ldflags := ""
|
||||||
|
command.StringFlag("ldflags", "optional ldflags", &ldflags)
|
||||||
|
|
||||||
|
// Log to file
|
||||||
|
logFile := ""
|
||||||
|
command.StringFlag("l", "Log to file", &logFile)
|
||||||
|
|
||||||
|
command.Action(func() error {
|
||||||
|
|
||||||
|
// Create logger
|
||||||
|
logger := clilogger.New(w)
|
||||||
|
logger.Mute(quiet)
|
||||||
|
|
||||||
|
// Validate output type
|
||||||
|
if !validTargetTypes.Contains(outputType) {
|
||||||
|
return fmt.Errorf("output type '%s' is not valid", outputType)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !quiet {
|
||||||
|
app.PrintBanner()
|
||||||
|
}
|
||||||
|
|
||||||
|
task := fmt.Sprintf("Building %s Application", strings.Title(outputType))
|
||||||
|
logger.Println(task)
|
||||||
|
logger.Println(strings.Repeat("-", len(task)))
|
||||||
|
|
||||||
|
// Setup mode
|
||||||
|
mode := build.Debug
|
||||||
|
if production {
|
||||||
|
mode = build.Production
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create BuildOptions
|
||||||
|
buildOptions := &build.Options{
|
||||||
|
Logger: logger,
|
||||||
|
OutputType: outputType,
|
||||||
|
Mode: mode,
|
||||||
|
Pack: pack,
|
||||||
|
Platform: platform,
|
||||||
|
LDFlags: ldflags,
|
||||||
|
Compiler: compilerCommand,
|
||||||
|
}
|
||||||
|
|
||||||
|
return doBuild(buildOptions)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// doBuild is our main build command
|
||||||
|
func doBuild(buildOptions *build.Options) error {
|
||||||
|
|
||||||
|
// Start Time
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
outputFilename, err := build.Build(buildOptions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Output stats
|
||||||
|
elapsed := time.Since(start)
|
||||||
|
buildOptions.Logger.Println("")
|
||||||
|
buildOptions.Logger.Println(fmt.Sprintf("Built '%s' in %s.", outputFilename, elapsed.Round(time.Millisecond).String()))
|
||||||
|
buildOptions.Logger.Println("")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
261
v2/cmd/wails/internal/commands/dev/dev.go
Normal file
261
v2/cmd/wails/internal/commands/dev/dev.go
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
package dev
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/fsnotify/fsnotify"
|
||||||
|
"github.com/leaanthony/clir"
|
||||||
|
"github.com/leaanthony/slicer"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/fs"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/process"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddSubcommand adds the `dev` command for the Wails application
|
||||||
|
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||||
|
|
||||||
|
command := app.NewSubCommand("dev", "Development mode")
|
||||||
|
|
||||||
|
outputType := "desktop"
|
||||||
|
|
||||||
|
validTargetTypes := slicer.String([]string{"desktop", "hybrid", "server"})
|
||||||
|
|
||||||
|
// Setup target type flag
|
||||||
|
description := "Type of application to develop. Valid types: " + validTargetTypes.Join(",")
|
||||||
|
command.StringFlag("t", description, &outputType)
|
||||||
|
|
||||||
|
// Passthrough ldflags
|
||||||
|
ldflags := ""
|
||||||
|
command.StringFlag("ldflags", "optional ldflags", &ldflags)
|
||||||
|
|
||||||
|
// compiler command
|
||||||
|
compilerCommand := "go"
|
||||||
|
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &compilerCommand)
|
||||||
|
|
||||||
|
// extensions to trigger rebuilds
|
||||||
|
extensions := "go"
|
||||||
|
command.StringFlag("m", "Extensions to trigger rebuilds (comma separated) eg go,js,css,html", &extensions)
|
||||||
|
|
||||||
|
command.Action(func() error {
|
||||||
|
|
||||||
|
// Validate inputs
|
||||||
|
if !validTargetTypes.Contains(outputType) {
|
||||||
|
return fmt.Errorf("output type '%s' is not valid", outputType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create logger
|
||||||
|
logger := clilogger.New(w)
|
||||||
|
app.PrintBanner()
|
||||||
|
|
||||||
|
// TODO: Check you are in a project directory
|
||||||
|
|
||||||
|
watcher, err := fsnotify.NewWatcher()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer watcher.Close()
|
||||||
|
|
||||||
|
var debugBinaryProcess *process.Process = nil
|
||||||
|
var buildFrontend bool = true
|
||||||
|
var extensionsThatTriggerARebuild = strings.Split(extensions, ",")
|
||||||
|
|
||||||
|
// Setup signal handler
|
||||||
|
quitChannel := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(quitChannel, os.Interrupt, os.Kill, syscall.SIGTERM)
|
||||||
|
|
||||||
|
debounceQuit := make(chan bool, 1)
|
||||||
|
|
||||||
|
// Do initial build
|
||||||
|
logger.Println("Building application for development...")
|
||||||
|
debugBinaryProcess = restartApp(logger, outputType, ldflags, compilerCommand, buildFrontend, debugBinaryProcess)
|
||||||
|
|
||||||
|
go debounce(100*time.Millisecond, watcher.Events, debounceQuit, func(event fsnotify.Event) {
|
||||||
|
// logger.Println("event: %+v", event)
|
||||||
|
|
||||||
|
// Check for new directories
|
||||||
|
if event.Op&fsnotify.Create == fsnotify.Create {
|
||||||
|
// If this is a folder, add it to our watch list
|
||||||
|
if fs.DirExists(event.Name) {
|
||||||
|
if !strings.Contains(event.Name, "node_modules") {
|
||||||
|
watcher.Add(event.Name)
|
||||||
|
logger.Println("Watching directory: %s", event.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for file writes
|
||||||
|
if event.Op&fsnotify.Write == fsnotify.Write {
|
||||||
|
|
||||||
|
// logger.Println("modified file: %s", event.Name)
|
||||||
|
var rebuild bool = false
|
||||||
|
|
||||||
|
// Iterate all file patterns
|
||||||
|
for _, pattern := range extensionsThatTriggerARebuild {
|
||||||
|
rebuild = strings.HasSuffix(event.Name, pattern)
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
if rebuild {
|
||||||
|
// Only build frontend when the file isn't a Go file
|
||||||
|
buildFrontend = !strings.HasSuffix(event.Name, "go")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !rebuild {
|
||||||
|
logger.Println("Filename change: %s did not match extension list %s", event.Name, extensions)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if buildFrontend {
|
||||||
|
logger.Println("Full rebuild triggered: %s updated", event.Name)
|
||||||
|
} else {
|
||||||
|
logger.Println("Partial build triggered: %s updated", event.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do a rebuild
|
||||||
|
|
||||||
|
// Try and build the app
|
||||||
|
newBinaryProcess := restartApp(logger, outputType, ldflags, compilerCommand, buildFrontend, debugBinaryProcess)
|
||||||
|
|
||||||
|
// If we have a new process, save it
|
||||||
|
if newBinaryProcess != nil {
|
||||||
|
debugBinaryProcess = newBinaryProcess
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Get project dir
|
||||||
|
dir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all subdirectories
|
||||||
|
dirs, err := fs.GetSubdirectories(dir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup a watcher for non-node_modules directories
|
||||||
|
dirs.Each(func(dir string) {
|
||||||
|
if strings.Contains(dir, "node_modules") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logger.Println("Watching directory: %s", dir)
|
||||||
|
err = watcher.Add(dir)
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Wait until we get a quit signal
|
||||||
|
quit := false
|
||||||
|
for quit == false {
|
||||||
|
select {
|
||||||
|
case <-quitChannel:
|
||||||
|
println()
|
||||||
|
// Notify debouncer to quit
|
||||||
|
debounceQuit <- true
|
||||||
|
quit = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kill the current program if running
|
||||||
|
if debugBinaryProcess != nil {
|
||||||
|
debugBinaryProcess.Kill()
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Println("Development mode exited")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Credit: https://drailing.net/2018/01/debounce-function-for-golang/
|
||||||
|
func debounce(interval time.Duration, input chan fsnotify.Event, quitChannel chan bool, cb func(arg fsnotify.Event)) {
|
||||||
|
var item fsnotify.Event
|
||||||
|
timer := time.NewTimer(interval)
|
||||||
|
exit:
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case item = <-input:
|
||||||
|
timer.Reset(interval)
|
||||||
|
case <-timer.C:
|
||||||
|
if item.Name != "" {
|
||||||
|
cb(item)
|
||||||
|
}
|
||||||
|
case <-quitChannel:
|
||||||
|
break exit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func restartApp(logger *clilogger.CLILogger, outputType string, ldflags string, compilerCommand string, buildFrontend bool, debugBinaryProcess *process.Process) *process.Process {
|
||||||
|
|
||||||
|
appBinary, err := buildApp(logger, outputType, ldflags, compilerCommand, buildFrontend)
|
||||||
|
println()
|
||||||
|
if err != nil {
|
||||||
|
logger.Println("[ERROR] Build Failed: %s", err.Error())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
logger.Println("Build new binary: %s", appBinary)
|
||||||
|
|
||||||
|
// Kill existing binary if need be
|
||||||
|
if debugBinaryProcess != nil {
|
||||||
|
killError := debugBinaryProcess.Kill()
|
||||||
|
|
||||||
|
if killError != nil {
|
||||||
|
logger.Fatal("Unable to kill debug binary (PID: %d)!", debugBinaryProcess.PID())
|
||||||
|
}
|
||||||
|
|
||||||
|
debugBinaryProcess = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Generate `backend.js`
|
||||||
|
|
||||||
|
// Start up new binary
|
||||||
|
newProcess := process.NewProcess(logger, appBinary)
|
||||||
|
err = newProcess.Start()
|
||||||
|
if err != nil {
|
||||||
|
// Remove binary
|
||||||
|
fs.DeleteFile(appBinary)
|
||||||
|
logger.Fatal("Unable to start application: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return newProcess
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildApp(logger *clilogger.CLILogger, outputType string, ldflags string, compilerCommand string, buildFrontend bool) (string, error) {
|
||||||
|
|
||||||
|
// Create random output file
|
||||||
|
outputFile := fmt.Sprintf("debug-%d", time.Now().Unix())
|
||||||
|
|
||||||
|
// Create BuildOptions
|
||||||
|
buildOptions := &build.Options{
|
||||||
|
Logger: logger,
|
||||||
|
OutputType: outputType,
|
||||||
|
Mode: build.Debug,
|
||||||
|
Pack: false,
|
||||||
|
Platform: runtime.GOOS,
|
||||||
|
LDFlags: ldflags,
|
||||||
|
Compiler: compilerCommand,
|
||||||
|
OutputFile: outputFile,
|
||||||
|
IgnoreFrontend: !buildFrontend,
|
||||||
|
}
|
||||||
|
|
||||||
|
return build.Build(buildOptions)
|
||||||
|
|
||||||
|
}
|
||||||
154
v2/cmd/wails/internal/commands/doctor/doctor.go
Normal file
154
v2/cmd/wails/internal/commands/doctor/doctor.go
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
package doctor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"text/tabwriter"
|
||||||
|
|
||||||
|
"github.com/leaanthony/clir"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/system"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/system/packagemanager"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddSubcommand adds the `doctor` command for the Wails application
|
||||||
|
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||||
|
|
||||||
|
command := app.NewSubCommand("doctor", "Diagnose your environment")
|
||||||
|
|
||||||
|
command.Action(func() error {
|
||||||
|
|
||||||
|
logger := clilogger.New(w)
|
||||||
|
|
||||||
|
app.PrintBanner()
|
||||||
|
logger.Print("Scanning system - please wait...")
|
||||||
|
|
||||||
|
// Get system info
|
||||||
|
info, err := system.GetInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Println("Done.")
|
||||||
|
|
||||||
|
// Start a new tabwriter
|
||||||
|
w := new(tabwriter.Writer)
|
||||||
|
w.Init(os.Stdout, 8, 8, 0, '\t', 0)
|
||||||
|
|
||||||
|
// Write out the system information
|
||||||
|
fmt.Fprintf(w, "\n")
|
||||||
|
fmt.Fprintf(w, "System\n")
|
||||||
|
fmt.Fprintf(w, "------\n")
|
||||||
|
fmt.Fprintf(w, "%s\t%s\n", "OS:", info.OS.Name)
|
||||||
|
fmt.Fprintf(w, "%s\t%s\n", "Version: ", info.OS.Version)
|
||||||
|
fmt.Fprintf(w, "%s\t%s\n", "ID:", info.OS.ID)
|
||||||
|
|
||||||
|
// Exit early if PM not found
|
||||||
|
if info.PM == nil {
|
||||||
|
fmt.Fprintf(w, "\n%s\t%s", "Package Manager:", "Not Found")
|
||||||
|
w.Flush()
|
||||||
|
println()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "%s\t%s\n", "Package Manager: ", info.PM.Name())
|
||||||
|
|
||||||
|
// Output Go Information
|
||||||
|
fmt.Fprintf(w, "%s\t%s\n", "Go Version:", runtime.Version())
|
||||||
|
fmt.Fprintf(w, "%s\t%s\n", "Platform:", runtime.GOOS)
|
||||||
|
fmt.Fprintf(w, "%s\t%s\n", "Architecture:", runtime.GOARCH)
|
||||||
|
|
||||||
|
// Output Dependencies Status
|
||||||
|
var dependenciesMissing = []string{}
|
||||||
|
var externalPackages = []*packagemanager.Dependancy{}
|
||||||
|
var dependenciesAvailableRequired = 0
|
||||||
|
var dependenciesAvailableOptional = 0
|
||||||
|
fmt.Fprintf(w, "\n")
|
||||||
|
fmt.Fprintf(w, "Dependency\tPackage Name\tStatus\tVersion\n")
|
||||||
|
fmt.Fprintf(w, "----------\t------------\t------\t-------\n")
|
||||||
|
|
||||||
|
// Loop over dependencies
|
||||||
|
for _, dependency := range info.Dependencies {
|
||||||
|
|
||||||
|
name := dependency.Name
|
||||||
|
if dependency.Optional {
|
||||||
|
name += "*"
|
||||||
|
}
|
||||||
|
packageName := "Unknown"
|
||||||
|
status := "Not Found"
|
||||||
|
|
||||||
|
// If we found the package
|
||||||
|
if dependency.PackageName != "" {
|
||||||
|
|
||||||
|
packageName = dependency.PackageName
|
||||||
|
|
||||||
|
// If it's installed, update the status
|
||||||
|
if dependency.Installed {
|
||||||
|
status = "Installed"
|
||||||
|
} else {
|
||||||
|
// Generate meaningful status text
|
||||||
|
status = "Available"
|
||||||
|
|
||||||
|
if dependency.Optional {
|
||||||
|
dependenciesAvailableOptional++
|
||||||
|
} else {
|
||||||
|
dependenciesAvailableRequired++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !dependency.Optional {
|
||||||
|
dependenciesMissing = append(dependenciesMissing, dependency.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if dependency.External {
|
||||||
|
externalPackages = append(externalPackages, dependency)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", name, packageName, status, dependency.Version)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "\n")
|
||||||
|
fmt.Fprintf(w, "* - Optional Dependency\n")
|
||||||
|
w.Flush()
|
||||||
|
logger.Println("")
|
||||||
|
logger.Println("Diagnosis")
|
||||||
|
logger.Println("---------\n")
|
||||||
|
|
||||||
|
// Generate an appropriate diagnosis
|
||||||
|
|
||||||
|
if len(dependenciesMissing) == 0 && dependenciesAvailableRequired == 0 {
|
||||||
|
logger.Println("Your system is ready for Wails development!")
|
||||||
|
}
|
||||||
|
|
||||||
|
if dependenciesAvailableRequired != 0 {
|
||||||
|
log.Println("Install required packages using: " + info.Dependencies.InstallAllRequiredCommand())
|
||||||
|
}
|
||||||
|
|
||||||
|
if dependenciesAvailableOptional != 0 {
|
||||||
|
log.Println("Install optional packages using: " + info.Dependencies.InstallAllOptionalCommand())
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(externalPackages) > 0 {
|
||||||
|
for _, p := range externalPackages {
|
||||||
|
if p.Optional {
|
||||||
|
print("[Optional] ")
|
||||||
|
}
|
||||||
|
log.Println("Install " + p.Name + ": " + p.InstallCommand)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(dependenciesMissing) != 0 {
|
||||||
|
// TODO: Check if apps are available locally and if so, adjust the diagnosis
|
||||||
|
log.Println("Fatal:")
|
||||||
|
log.Println("Required dependencies missing: " + strings.Join(dependenciesMissing, " "))
|
||||||
|
log.Println("Please read this article on how to resolve this: https://wails.app/guides/resolving-missing-packages")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("")
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
91
v2/cmd/wails/internal/commands/generate/generate.go
Normal file
91
v2/cmd/wails/internal/commands/generate/generate.go
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
package generate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/leaanthony/clir"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/parser"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddSubcommand adds the `dev` command for the Wails application
|
||||||
|
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||||
|
|
||||||
|
command := app.NewSubCommand("generate", "Code Generation Tools")
|
||||||
|
|
||||||
|
// Backend API
|
||||||
|
backendAPI := command.NewSubCommand("module", "Generates a JS module for the frontend to interface with the backend")
|
||||||
|
|
||||||
|
// Quiet Init
|
||||||
|
quiet := false
|
||||||
|
backendAPI.BoolFlag("q", "Supress output to console", &quiet)
|
||||||
|
|
||||||
|
backendAPI.Action(func() error {
|
||||||
|
|
||||||
|
// Create logger
|
||||||
|
logger := clilogger.New(w)
|
||||||
|
logger.Mute(quiet)
|
||||||
|
|
||||||
|
app.PrintBanner()
|
||||||
|
|
||||||
|
logger.Print("Generating Javascript module for Go code...")
|
||||||
|
|
||||||
|
// Start Time
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
p, err := parser.GenerateWailsFrontendPackage()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Println("done.")
|
||||||
|
logger.Println("")
|
||||||
|
|
||||||
|
elapsed := time.Since(start)
|
||||||
|
packages := p.Packages
|
||||||
|
|
||||||
|
// Print report
|
||||||
|
for _, pkg := range p.Packages {
|
||||||
|
if pkg.ShouldGenerate() {
|
||||||
|
logPackage(pkg, logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Println("%d packages parsed in %s.", len(packages), elapsed)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func logPackage(pkg *parser.Package, logger *clilogger.CLILogger) {
|
||||||
|
|
||||||
|
logger.Println("Processed Go package '" + pkg.Gopackage.Name + "' as '" + pkg.Name + "'")
|
||||||
|
for _, strct := range pkg.Structs() {
|
||||||
|
logger.Println("")
|
||||||
|
logger.Println(" Processed struct '" + strct.Name + "'")
|
||||||
|
if strct.IsBound {
|
||||||
|
for _, method := range strct.Methods {
|
||||||
|
logger.Println(" Bound method '" + method.Name + "'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if strct.IsUsedAsData {
|
||||||
|
for _, field := range strct.Fields {
|
||||||
|
if !field.Ignored {
|
||||||
|
logger.Print(" Processed ")
|
||||||
|
if field.IsOptional {
|
||||||
|
logger.Print("optional ")
|
||||||
|
}
|
||||||
|
logger.Println("field '" + field.Name + "' as '" + field.JSName() + "'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.Println("")
|
||||||
|
|
||||||
|
// logger.Println(" Original Go Package Path:", pkg.Gopackage.PkgPath)
|
||||||
|
// logger.Println(" Original Go Package Path:", pkg.Gopackage.PkgPath)
|
||||||
|
}
|
||||||
130
v2/cmd/wails/internal/commands/initialise/initialise.go
Normal file
130
v2/cmd/wails/internal/commands/initialise/initialise.go
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
package initialise
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/leaanthony/clir"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/templates"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddSubcommand adds the `init` command for the Wails application
|
||||||
|
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||||
|
|
||||||
|
// Load the template shortnames
|
||||||
|
validShortNames, err := templates.TemplateShortNames()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
command := app.NewSubCommand("init", "Initialise a new Wails project")
|
||||||
|
|
||||||
|
// Setup template name flag
|
||||||
|
templateName := "vanilla"
|
||||||
|
description := "Name of template to use. Valid tempates: " + validShortNames.Join(" ")
|
||||||
|
command.StringFlag("t", description, &templateName)
|
||||||
|
|
||||||
|
// Setup project name
|
||||||
|
projectName := ""
|
||||||
|
command.StringFlag("n", "Name of project", &projectName)
|
||||||
|
|
||||||
|
// Setup project directory
|
||||||
|
projectDirectory := ""
|
||||||
|
command.StringFlag("d", "Project directory", &projectDirectory)
|
||||||
|
|
||||||
|
// Quiet Init
|
||||||
|
quiet := false
|
||||||
|
command.BoolFlag("q", "Supress output to console", &quiet)
|
||||||
|
|
||||||
|
// VSCode project files
|
||||||
|
vscode := false
|
||||||
|
command.BoolFlag("vscode", "Generate VSCode project files", &vscode)
|
||||||
|
|
||||||
|
// List templates
|
||||||
|
list := false
|
||||||
|
command.BoolFlag("l", "List templates", &list)
|
||||||
|
|
||||||
|
command.Action(func() error {
|
||||||
|
|
||||||
|
// Create logger
|
||||||
|
logger := clilogger.New(w)
|
||||||
|
logger.Mute(quiet)
|
||||||
|
|
||||||
|
// Are we listing templates?
|
||||||
|
if list {
|
||||||
|
app.PrintBanner()
|
||||||
|
err := templates.OutputList(logger)
|
||||||
|
logger.Println("")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate output type
|
||||||
|
if !validShortNames.Contains(templateName) {
|
||||||
|
logger.Print(fmt.Sprintf("[ERROR] Template '%s' is not valid", templateName))
|
||||||
|
logger.Println("")
|
||||||
|
command.PrintHelp()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate name
|
||||||
|
if len(projectName) == 0 {
|
||||||
|
logger.Println("ERROR: Project name required")
|
||||||
|
logger.Println("")
|
||||||
|
command.PrintHelp()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !quiet {
|
||||||
|
app.PrintBanner()
|
||||||
|
}
|
||||||
|
|
||||||
|
task := fmt.Sprintf("Initialising Project %s", strings.Title(projectName))
|
||||||
|
logger.Println(task)
|
||||||
|
logger.Println(strings.Repeat("-", len(task)))
|
||||||
|
|
||||||
|
// Create Template Options
|
||||||
|
options := &templates.Options{
|
||||||
|
ProjectName: projectName,
|
||||||
|
TargetDir: projectDirectory,
|
||||||
|
TemplateName: templateName,
|
||||||
|
Logger: logger,
|
||||||
|
GenerateVSCode: vscode,
|
||||||
|
}
|
||||||
|
|
||||||
|
return initProject(options)
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// initProject is our main init command
|
||||||
|
func initProject(options *templates.Options) error {
|
||||||
|
|
||||||
|
// Start Time
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
// Install the template
|
||||||
|
err := templates.Install(options)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output stats
|
||||||
|
elapsed := time.Since(start)
|
||||||
|
options.Logger.Println("")
|
||||||
|
options.Logger.Println("Project Name: " + options.ProjectName)
|
||||||
|
options.Logger.Println("Project Directory: " + options.TargetDir)
|
||||||
|
options.Logger.Println("Project Template: " + options.TemplateName)
|
||||||
|
options.Logger.Println("")
|
||||||
|
if options.GenerateVSCode {
|
||||||
|
options.Logger.Println("VSCode config files generated.")
|
||||||
|
}
|
||||||
|
options.Logger.Println("")
|
||||||
|
options.Logger.Println(fmt.Sprintf("Initialised project '%s' in %s.", options.ProjectName, elapsed.Round(time.Millisecond).String()))
|
||||||
|
options.Logger.Println("")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
50
v2/cmd/wails/main.go
Normal file
50
v2/cmd/wails/main.go
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/leaanthony/clir"
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/build"
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/dev"
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/doctor"
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/generate"
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/initialise"
|
||||||
|
)
|
||||||
|
|
||||||
|
func fatal(message string) {
|
||||||
|
println(message)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
var err error
|
||||||
|
version := "v2.0.0-alpha"
|
||||||
|
|
||||||
|
app := clir.NewCli("Wails", "Go/HTML Application Framework", version)
|
||||||
|
|
||||||
|
build.AddBuildSubcommand(app, os.Stdout)
|
||||||
|
err = initialise.AddSubcommand(app, os.Stdout)
|
||||||
|
if err != nil {
|
||||||
|
fatal(err.Error())
|
||||||
|
}
|
||||||
|
err = doctor.AddSubcommand(app, os.Stdout)
|
||||||
|
if err != nil {
|
||||||
|
fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = dev.AddSubcommand(app, os.Stdout)
|
||||||
|
if err != nil {
|
||||||
|
fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = generate.AddSubcommand(app, os.Stdout)
|
||||||
|
if err != nil {
|
||||||
|
fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = app.Run()
|
||||||
|
if err != nil {
|
||||||
|
println("\n\nERROR: " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
26
v2/go.mod
Normal file
26
v2/go.mod
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
module github.com/wailsapp/wails/v2
|
||||||
|
|
||||||
|
go 1.13
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1
|
||||||
|
github.com/fatih/structtag v1.2.0
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9
|
||||||
|
github.com/imdario/mergo v0.3.11
|
||||||
|
github.com/leaanthony/clir v1.0.4
|
||||||
|
github.com/leaanthony/gosod v0.0.4
|
||||||
|
github.com/leaanthony/slicer v1.5.0
|
||||||
|
github.com/matryer/is v1.4.0
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||||
|
github.com/olekukonko/tablewriter v0.0.4
|
||||||
|
github.com/pkg/errors v0.9.1
|
||||||
|
github.com/tdewolff/minify v2.3.6+incompatible
|
||||||
|
github.com/tdewolff/parse v2.3.4+incompatible // indirect
|
||||||
|
github.com/tdewolff/test v1.0.6 // indirect
|
||||||
|
github.com/xyproto/xpm v1.2.1
|
||||||
|
golang.org/x/net v0.0.0-20200822124328-c89045814202
|
||||||
|
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c
|
||||||
|
golang.org/x/tools v0.0.0-20200902012652-d1954cc86c82
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
|
||||||
|
nhooyr.io/websocket v1.8.6
|
||||||
|
)
|
||||||
130
v2/go.sum
Normal file
130
v2/go.sum
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
|
||||||
|
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
|
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
|
||||||
|
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||||
|
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||||
|
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
|
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||||
|
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||||
|
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||||
|
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||||
|
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
|
||||||
|
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||||
|
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
|
||||||
|
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||||
|
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
|
||||||
|
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||||
|
github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
|
||||||
|
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||||
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls=
|
||||||
|
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||||
|
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||||
|
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
|
||||||
|
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
|
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||||
|
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/klauspost/compress v1.10.3 h1:OP96hzwJVBIHYU52pVTI6CczrxPvrGfgqF9N5eTO0Q8=
|
||||||
|
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/leaanthony/clir v1.0.4 h1:Dov2y9zWJmZr7CjaCe86lKa4b5CSxskGAt2yBkoDyiU=
|
||||||
|
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
|
||||||
|
github.com/leaanthony/gosod v0.0.4 h1:v4hepo4IyL8E8c9qzDsvYcA0KGh7Npf8As74K5ibQpI=
|
||||||
|
github.com/leaanthony/gosod v0.0.4/go.mod h1:nGMCb1PJfXwBDbOAike78jEYlpqge+xUKFf0iBKjKxU=
|
||||||
|
github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
|
||||||
|
github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
|
||||||
|
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||||
|
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||||
|
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||||
|
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||||
|
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||||
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
|
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||||
|
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
||||||
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
|
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
|
||||||
|
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/tdewolff/minify v2.3.6+incompatible h1:2hw5/9ZvxhWLvBUnHE06gElGYz+Jv9R4Eys0XUzItYo=
|
||||||
|
github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs=
|
||||||
|
github.com/tdewolff/parse v2.3.4+incompatible h1:x05/cnGwIMf4ceLuDMBOdQ1qGniMoxpP46ghf0Qzh38=
|
||||||
|
github.com/tdewolff/parse v2.3.4+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ=
|
||||||
|
github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
|
||||||
|
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
||||||
|
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||||
|
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||||
|
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||||
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
|
github.com/xyproto/xpm v1.2.1 h1:trdvGjjWBsOOKzBBUPT6JvaIQM3acJEEYfbxN7M96wg=
|
||||||
|
github.com/xyproto/xpm v1.2.1/go.mod h1:cMnesLsD0PBXLgjDfTDEaKr8XyTFsnP1QycSqRw7BiY=
|
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
|
||||||
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9 h1:L2auWcuQIvxz9xSEqzESnV/QN/gNRXNApHi3fYwl2w0=
|
||||||
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
|
||||||
|
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20200902012652-d1954cc86c82 h1:shxDsb9Dz27xzk3A0DxP0JuJnZMpKrdg8+E14eiUAX4=
|
||||||
|
golang.org/x/tools v0.0.0-20200902012652-d1954cc86c82/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k=
|
||||||
|
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
||||||
9
v2/internal/app/debug.go
Normal file
9
v2/internal/app/debug.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// +build debug
|
||||||
|
|
||||||
|
package app
|
||||||
|
|
||||||
|
// Init initialises the application for a debug environment
|
||||||
|
func (a *App) Init() error {
|
||||||
|
a.debug = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
42
v2/internal/app/default.go
Normal file
42
v2/internal/app/default.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// +build !desktop,!hybrid,!server
|
||||||
|
|
||||||
|
package app
|
||||||
|
|
||||||
|
// This is the default application that will get run if the user compiles using `go build`.
|
||||||
|
// The reason we want to prevent that is that the `wails build` command does a lot of behind
|
||||||
|
// the scenes work such as asset compilation. If we allow `go build`, the state of these assets
|
||||||
|
// will be unknown and the application will not work as expected.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
|
)
|
||||||
|
|
||||||
|
// App defines a Wails application structure
|
||||||
|
type App struct {
|
||||||
|
Title string
|
||||||
|
Width int
|
||||||
|
Height int
|
||||||
|
Resizable bool
|
||||||
|
|
||||||
|
// Indicates if the app is running in debug mode
|
||||||
|
debug bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateApp returns a null application
|
||||||
|
func CreateApp(options *options.App) *App {
|
||||||
|
return &App{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the application
|
||||||
|
func (a *App) Run() error {
|
||||||
|
println(`FATAL: This application was built using "go build". This is unsupported. Please compile using "wails build".`)
|
||||||
|
os.Exit(1)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind the dummy interface
|
||||||
|
func (a *App) Bind(dummy interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
159
v2/internal/app/desktop.go
Normal file
159
v2/internal/app/desktop.go
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
// +build desktop,!server
|
||||||
|
|
||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/wailsapp/wails/v2/internal/binding"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/ffenestri"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/signal"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/subsystem"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// App defines a Wails application structure
|
||||||
|
type App struct {
|
||||||
|
window *ffenestri.Application
|
||||||
|
servicebus *servicebus.ServiceBus
|
||||||
|
logger *logger.Logger
|
||||||
|
signal *signal.Manager
|
||||||
|
options *options.App
|
||||||
|
|
||||||
|
// Subsystems
|
||||||
|
log *subsystem.Log
|
||||||
|
runtime *subsystem.Runtime
|
||||||
|
event *subsystem.Event
|
||||||
|
binding *subsystem.Binding
|
||||||
|
call *subsystem.Call
|
||||||
|
dispatcher *messagedispatcher.Dispatcher
|
||||||
|
|
||||||
|
// Indicates if the app is in debug mode
|
||||||
|
debug bool
|
||||||
|
|
||||||
|
// This is our binding DB
|
||||||
|
bindings *binding.Bindings
|
||||||
|
|
||||||
|
// LogLevel Store
|
||||||
|
loglevelStore *runtime.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create App
|
||||||
|
func CreateApp(options *options.App) *App {
|
||||||
|
|
||||||
|
// Merge default options
|
||||||
|
options.MergeDefaults()
|
||||||
|
|
||||||
|
// Set up logger
|
||||||
|
myLogger := logger.New(options.Logger)
|
||||||
|
myLogger.SetLogLevel(options.LogLevel)
|
||||||
|
|
||||||
|
window := ffenestri.NewApplicationWithConfig(options, myLogger)
|
||||||
|
|
||||||
|
result := &App{
|
||||||
|
window: window,
|
||||||
|
servicebus: servicebus.New(myLogger),
|
||||||
|
logger: myLogger,
|
||||||
|
bindings: binding.NewBindings(myLogger),
|
||||||
|
}
|
||||||
|
|
||||||
|
result.options = options
|
||||||
|
|
||||||
|
// Initialise the app
|
||||||
|
result.Init()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the application
|
||||||
|
func (a *App) Run() error {
|
||||||
|
|
||||||
|
// Setup signal handler
|
||||||
|
signal, err := signal.NewManager(a.servicebus, a.logger)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.signal = signal
|
||||||
|
a.signal.Start()
|
||||||
|
|
||||||
|
// Start the service bus
|
||||||
|
a.servicebus.Debug()
|
||||||
|
a.servicebus.Start()
|
||||||
|
|
||||||
|
// Start the runtime
|
||||||
|
runtime, err := subsystem.NewRuntime(a.servicebus, a.logger)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.runtime = runtime
|
||||||
|
a.runtime.Start()
|
||||||
|
|
||||||
|
// Application Stores
|
||||||
|
a.loglevelStore = a.runtime.GoRuntime().Store.New("loglevel", a.options.LogLevel)
|
||||||
|
|
||||||
|
// Start the binding subsystem
|
||||||
|
binding, err := subsystem.NewBinding(a.servicebus, a.logger, a.bindings, a.runtime.GoRuntime())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.binding = binding
|
||||||
|
a.binding.Start()
|
||||||
|
|
||||||
|
// Start the logging subsystem
|
||||||
|
log, err := subsystem.NewLog(a.servicebus, a.logger, a.loglevelStore)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.log = log
|
||||||
|
a.log.Start()
|
||||||
|
|
||||||
|
// create the dispatcher
|
||||||
|
dispatcher, err := messagedispatcher.New(a.servicebus, a.logger)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.dispatcher = dispatcher
|
||||||
|
dispatcher.Start()
|
||||||
|
|
||||||
|
// Start the eventing subsystem
|
||||||
|
event, err := subsystem.NewEvent(a.servicebus, a.logger)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.event = event
|
||||||
|
a.event.Start()
|
||||||
|
|
||||||
|
// Start the call subsystem
|
||||||
|
call, err := subsystem.NewCall(a.servicebus, a.logger, a.bindings.DB(), a.runtime.GoRuntime())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.call = call
|
||||||
|
a.call.Start()
|
||||||
|
|
||||||
|
// Dump bindings as a debug
|
||||||
|
bindingDump, err := a.bindings.ToJSON()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := a.window.Run(dispatcher, bindingDump)
|
||||||
|
a.logger.Trace("Ffenestri.Run() exited")
|
||||||
|
a.servicebus.Stop()
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind a struct to the application by passing in
|
||||||
|
// a pointer to it
|
||||||
|
func (a *App) Bind(structPtr interface{}) {
|
||||||
|
|
||||||
|
// Add the struct to the bindings
|
||||||
|
err := a.bindings.Add(structPtr)
|
||||||
|
if err != nil {
|
||||||
|
a.logger.Fatal("Error during binding: " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
207
v2/internal/app/hybrid.go
Normal file
207
v2/internal/app/hybrid.go
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
// +build !server,!desktop,hybrid
|
||||||
|
|
||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/leaanthony/clir"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/binding"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/ffenestri"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/subsystem"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/webserver"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config defines the Application's configuration
|
||||||
|
type Config struct {
|
||||||
|
Title string // Title is the value to be displayed in the title bar
|
||||||
|
Width int // Width is the desired window width
|
||||||
|
Height int // Height is the desired window height
|
||||||
|
DevTools bool // DevTools enables or disables the browser development tools
|
||||||
|
Resizable bool // Resizable when False prevents window resizing
|
||||||
|
ServerEnabled bool // ServerEnabled when True allows remote connections
|
||||||
|
}
|
||||||
|
|
||||||
|
// App defines a Wails application structure
|
||||||
|
type App struct {
|
||||||
|
config Config
|
||||||
|
window *ffenestri.Application
|
||||||
|
webserver *webserver.WebServer
|
||||||
|
binding *subsystem.Binding
|
||||||
|
call *subsystem.Call
|
||||||
|
event *subsystem.Event
|
||||||
|
log *subsystem.Log
|
||||||
|
runtime *subsystem.Runtime
|
||||||
|
|
||||||
|
bindings *binding.Bindings
|
||||||
|
logger *logger.Logger
|
||||||
|
dispatcher *messagedispatcher.Dispatcher
|
||||||
|
servicebus *servicebus.ServiceBus
|
||||||
|
|
||||||
|
debug bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create App
|
||||||
|
func CreateApp(options *Options) *App {
|
||||||
|
|
||||||
|
// Merge default options
|
||||||
|
options.mergeDefaults()
|
||||||
|
|
||||||
|
// Set up logger
|
||||||
|
myLogger := logger.New(os.Stdout)
|
||||||
|
myLogger.SetLogLevel(logger.INFO)
|
||||||
|
|
||||||
|
window := ffenestri.NewApplicationWithConfig(&ffenestri.Config{
|
||||||
|
Title: options.Title,
|
||||||
|
Width: options.Width,
|
||||||
|
Height: options.Height,
|
||||||
|
MinWidth: options.MinWidth,
|
||||||
|
MinHeight: options.MinHeight,
|
||||||
|
MaxWidth: options.MaxWidth,
|
||||||
|
MaxHeight: options.MaxHeight,
|
||||||
|
StartHidden: options.StartHidden,
|
||||||
|
|
||||||
|
// This should be controlled by the compile time flags...
|
||||||
|
DevTools: true,
|
||||||
|
|
||||||
|
Resizable: !options.DisableResize,
|
||||||
|
Fullscreen: options.Fullscreen,
|
||||||
|
}, myLogger)
|
||||||
|
|
||||||
|
app := &App{
|
||||||
|
window: window,
|
||||||
|
webserver: webserver.NewWebServer(myLogger),
|
||||||
|
servicebus: servicebus.New(myLogger),
|
||||||
|
logger: myLogger,
|
||||||
|
bindings: binding.NewBindings(myLogger),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise the app
|
||||||
|
app.Init()
|
||||||
|
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the application
|
||||||
|
func (a *App) Run() error {
|
||||||
|
|
||||||
|
// Default app options
|
||||||
|
var port = 8080
|
||||||
|
var ip = "localhost"
|
||||||
|
var suppressLogging = false
|
||||||
|
|
||||||
|
// Create CLI
|
||||||
|
cli := clir.NewCli(filepath.Base(os.Args[0]), "Desktop/Server Build", "")
|
||||||
|
|
||||||
|
// Setup flags
|
||||||
|
cli.IntFlag("p", "Port to serve on", &port)
|
||||||
|
cli.StringFlag("i", "IP to serve on", &ip)
|
||||||
|
cli.BoolFlag("q", "Suppress logging", &suppressLogging)
|
||||||
|
|
||||||
|
// Setup main action
|
||||||
|
cli.Action(func() error {
|
||||||
|
|
||||||
|
// Set IP + Port
|
||||||
|
a.webserver.SetPort(port)
|
||||||
|
a.webserver.SetIP(ip)
|
||||||
|
a.webserver.SetBindings(a.bindings)
|
||||||
|
// Log information (if we aren't suppressing it)
|
||||||
|
if !suppressLogging {
|
||||||
|
cli.PrintBanner()
|
||||||
|
a.logger.Info("Running server at %s", a.webserver.URL())
|
||||||
|
}
|
||||||
|
|
||||||
|
a.servicebus.Start()
|
||||||
|
log, err := subsystem.NewLog(a.servicebus, a.logger)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.log = log
|
||||||
|
a.log.Start()
|
||||||
|
dispatcher, err := messagedispatcher.New(a.servicebus, a.logger)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.dispatcher = dispatcher
|
||||||
|
a.dispatcher.Start()
|
||||||
|
|
||||||
|
// Start the runtime
|
||||||
|
runtime, err := subsystem.NewRuntime(a.servicebus, a.logger)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.runtime = runtime
|
||||||
|
a.runtime.Start()
|
||||||
|
|
||||||
|
// Start the binding subsystem
|
||||||
|
binding, err := subsystem.NewBinding(a.servicebus, a.logger, a.bindings, runtime.GoRuntime())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.binding = binding
|
||||||
|
a.binding.Start()
|
||||||
|
|
||||||
|
// Start the eventing subsystem
|
||||||
|
event, err := subsystem.NewEvent(a.servicebus, a.logger)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.event = event
|
||||||
|
a.event.Start()
|
||||||
|
|
||||||
|
// Start the call subsystem
|
||||||
|
call, err := subsystem.NewCall(a.servicebus, a.logger, a.bindings.DB())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.call = call
|
||||||
|
a.call.Start()
|
||||||
|
|
||||||
|
// Required so that the WailsInit functions are fired!
|
||||||
|
runtime.GoRuntime().Events.Emit("wails:loaded")
|
||||||
|
|
||||||
|
// Set IP + Port
|
||||||
|
a.webserver.SetPort(port)
|
||||||
|
a.webserver.SetIP(ip)
|
||||||
|
|
||||||
|
// Log information (if we aren't suppressing it)
|
||||||
|
if !suppressLogging {
|
||||||
|
cli.PrintBanner()
|
||||||
|
println("Running server at " + a.webserver.URL())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump bindings as a debug
|
||||||
|
bindingDump, err := a.bindings.ToJSON()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := a.webserver.Start(dispatcher, event); err != nil {
|
||||||
|
a.logger.Error("Webserver failed to start %s", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
result := a.window.Run(dispatcher, bindingDump)
|
||||||
|
a.servicebus.Stop()
|
||||||
|
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
|
||||||
|
return cli.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind a struct to the application by passing in
|
||||||
|
// a pointer to it
|
||||||
|
func (a *App) Bind(structPtr interface{}) {
|
||||||
|
|
||||||
|
// Add the struct to the bindings
|
||||||
|
err := a.bindings.Add(structPtr)
|
||||||
|
if err != nil {
|
||||||
|
a.logger.Fatal("Error during binding: " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
9
v2/internal/app/production.go
Normal file
9
v2/internal/app/production.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// +build !debug
|
||||||
|
|
||||||
|
package app
|
||||||
|
|
||||||
|
// Init initialises the application for a production environment
|
||||||
|
func (a *App) Init() error {
|
||||||
|
println("Processing production cli options")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
160
v2/internal/app/server.go
Normal file
160
v2/internal/app/server.go
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
// +build server,!desktop
|
||||||
|
|
||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/leaanthony/clir"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/binding"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/subsystem"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/webserver"
|
||||||
|
)
|
||||||
|
|
||||||
|
// App defines a Wails application structure
|
||||||
|
type App struct {
|
||||||
|
binding *subsystem.Binding
|
||||||
|
call *subsystem.Call
|
||||||
|
event *subsystem.Event
|
||||||
|
log *subsystem.Log
|
||||||
|
runtime *subsystem.Runtime
|
||||||
|
|
||||||
|
bindings *binding.Bindings
|
||||||
|
logger *logger.Logger
|
||||||
|
dispatcher *messagedispatcher.Dispatcher
|
||||||
|
servicebus *servicebus.ServiceBus
|
||||||
|
webserver *webserver.WebServer
|
||||||
|
|
||||||
|
debug bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create App
|
||||||
|
func CreateApp(options *Options) *App {
|
||||||
|
options.mergeDefaults()
|
||||||
|
// We ignore the inputs (for now)
|
||||||
|
|
||||||
|
// TODO: Allow logger output override on CLI
|
||||||
|
myLogger := logger.New(os.Stdout)
|
||||||
|
myLogger.SetLogLevel(logger.TRACE)
|
||||||
|
|
||||||
|
result := &App{
|
||||||
|
bindings: binding.NewBindings(myLogger),
|
||||||
|
logger: myLogger,
|
||||||
|
servicebus: servicebus.New(myLogger),
|
||||||
|
webserver: webserver.NewWebServer(myLogger),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise app
|
||||||
|
result.Init()
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the application
|
||||||
|
func (a *App) Run() error {
|
||||||
|
|
||||||
|
// Default app options
|
||||||
|
var port = 8080
|
||||||
|
var ip = "localhost"
|
||||||
|
var supressLogging = false
|
||||||
|
var debugMode = false
|
||||||
|
|
||||||
|
// Create CLI
|
||||||
|
cli := clir.NewCli(filepath.Base(os.Args[0]), "Server Build", "")
|
||||||
|
|
||||||
|
// Setup flags
|
||||||
|
cli.IntFlag("p", "Port to serve on", &port)
|
||||||
|
cli.StringFlag("i", "IP to serve on", &ip)
|
||||||
|
cli.BoolFlag("d", "Debug mode", &debugMode)
|
||||||
|
cli.BoolFlag("q", "Supress logging", &supressLogging)
|
||||||
|
|
||||||
|
// Setup main action
|
||||||
|
cli.Action(func() error {
|
||||||
|
|
||||||
|
// Set IP + Port
|
||||||
|
a.webserver.SetPort(port)
|
||||||
|
a.webserver.SetIP(ip)
|
||||||
|
a.webserver.SetBindings(a.bindings)
|
||||||
|
// Log information (if we aren't supressing it)
|
||||||
|
if !supressLogging {
|
||||||
|
cli.PrintBanner()
|
||||||
|
a.logger.Info("Running server at %s", a.webserver.URL())
|
||||||
|
}
|
||||||
|
|
||||||
|
if debugMode {
|
||||||
|
a.servicebus.Debug()
|
||||||
|
}
|
||||||
|
a.servicebus.Start()
|
||||||
|
log, err := subsystem.NewLog(a.servicebus, a.logger)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.log = log
|
||||||
|
a.log.Start()
|
||||||
|
dispatcher, err := messagedispatcher.New(a.servicebus, a.logger)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.dispatcher = dispatcher
|
||||||
|
a.dispatcher.Start()
|
||||||
|
|
||||||
|
// Start the runtime
|
||||||
|
runtime, err := subsystem.NewRuntime(a.servicebus, a.logger)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.runtime = runtime
|
||||||
|
a.runtime.Start()
|
||||||
|
|
||||||
|
// Start the binding subsystem
|
||||||
|
binding, err := subsystem.NewBinding(a.servicebus, a.logger, a.bindings, runtime.GoRuntime())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.binding = binding
|
||||||
|
a.binding.Start()
|
||||||
|
|
||||||
|
// Start the eventing subsystem
|
||||||
|
event, err := subsystem.NewEvent(a.servicebus, a.logger)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.event = event
|
||||||
|
a.event.Start()
|
||||||
|
|
||||||
|
// Start the call subsystem
|
||||||
|
call, err := subsystem.NewCall(a.servicebus, a.logger, a.bindings.DB())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.call = call
|
||||||
|
a.call.Start()
|
||||||
|
|
||||||
|
// Required so that the WailsInit functions are fired!
|
||||||
|
runtime.GoRuntime().Events.Emit("wails:loaded")
|
||||||
|
|
||||||
|
if err := a.webserver.Start(dispatcher, event); err != nil {
|
||||||
|
a.logger.Error("Webserver failed to start %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return cli.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind a struct to the application by passing in
|
||||||
|
// a pointer to it
|
||||||
|
func (a *App) Bind(structPtr interface{}) {
|
||||||
|
|
||||||
|
// Add the struct to the bindings
|
||||||
|
err := a.bindings.Add(structPtr)
|
||||||
|
if err != nil {
|
||||||
|
a.logger.Fatal("Error during binding: " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
112
v2/internal/assetdb/assetdb.go
Normal file
112
v2/internal/assetdb/assetdb.go
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
package assetdb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AssetDB is a database for assets encoded as byte slices
|
||||||
|
type AssetDB struct {
|
||||||
|
db map[string][]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAssetDB creates a new AssetDB and initialises a blank db
|
||||||
|
func NewAssetDB() *AssetDB {
|
||||||
|
return &AssetDB{
|
||||||
|
db: make(map[string][]byte),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddAsset saves the given byte slice under the given name
|
||||||
|
func (a *AssetDB) AddAsset(name string, data []byte) {
|
||||||
|
a.db[name] = data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove removes the named asset
|
||||||
|
func (a *AssetDB) Remove(name string) {
|
||||||
|
delete(a.db, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Asset retrieves the byte slice for the given name
|
||||||
|
func (a *AssetDB) Read(name string) ([]byte, error) {
|
||||||
|
result := a.db[name]
|
||||||
|
if result == nil {
|
||||||
|
return nil, fmt.Errorf("asset '%s' not found", name)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssetAsString returns the asset as a string.
|
||||||
|
// It also returns a boolean indicating whether the asset existed or not.
|
||||||
|
func (a *AssetDB) String(name string) (string, error) {
|
||||||
|
asset, err := a.Read(name)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return *(*string)(unsafe.Pointer(&asset)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AssetDB) Dump() {
|
||||||
|
fmt.Printf("Assets:\n")
|
||||||
|
for k, _ := range a.db {
|
||||||
|
fmt.Println(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize converts the entire database to a file that when compiled will
|
||||||
|
// reconstruct the AssetDB during init()
|
||||||
|
// name: name of the asset.AssetDB instance
|
||||||
|
// pkg: package name placed at the top of the file
|
||||||
|
func (a *AssetDB) Serialize(name, pkg string) string {
|
||||||
|
var cdata strings.Builder
|
||||||
|
// Set buffer size to 4k
|
||||||
|
cdata.Grow(4096)
|
||||||
|
|
||||||
|
// Write header
|
||||||
|
header := `// DO NOT EDIT - Generated automatically
|
||||||
|
package %s
|
||||||
|
|
||||||
|
import "github.com/wailsapp/wails/v2/internal/assetdb"
|
||||||
|
|
||||||
|
var (
|
||||||
|
%s *assetdb.AssetDB = assetdb.NewAssetDB()
|
||||||
|
)
|
||||||
|
|
||||||
|
// AssetsDB is a clean interface to the assetdb.AssetDB struct
|
||||||
|
type AssetsDB interface {
|
||||||
|
Read(string) ([]byte, error)
|
||||||
|
String(string) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assets returns the asset database
|
||||||
|
func Assets() AssetsDB {
|
||||||
|
return %s
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
`
|
||||||
|
cdata.WriteString(fmt.Sprintf(header, pkg, name, name))
|
||||||
|
|
||||||
|
for aname, bytes := range a.db {
|
||||||
|
cdata.WriteString(fmt.Sprintf("\t%s.AddAsset(\"%s\", []byte{",
|
||||||
|
name,
|
||||||
|
aname))
|
||||||
|
|
||||||
|
l := len(bytes)
|
||||||
|
if l == 0 {
|
||||||
|
cdata.WriteString("0x00})\n")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert each byte to hex
|
||||||
|
for _, b := range bytes[:l-1] {
|
||||||
|
cdata.WriteString(fmt.Sprintf("0x%x, ", b))
|
||||||
|
}
|
||||||
|
cdata.WriteString(fmt.Sprintf("0x%x})\n", bytes[l-1]))
|
||||||
|
}
|
||||||
|
|
||||||
|
cdata.WriteString(`}`)
|
||||||
|
|
||||||
|
return cdata.String()
|
||||||
|
}
|
||||||
70
v2/internal/assetdb/assetdb_test.go
Normal file
70
v2/internal/assetdb/assetdb_test.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package assetdb
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
import "github.com/matryer/is"
|
||||||
|
|
||||||
|
func TestExistsAsBytes(t *testing.T) {
|
||||||
|
|
||||||
|
is := is.New(t)
|
||||||
|
|
||||||
|
var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33}
|
||||||
|
|
||||||
|
db := NewAssetDB()
|
||||||
|
db.AddAsset("hello", helloworld)
|
||||||
|
|
||||||
|
result, err := db.Read("hello")
|
||||||
|
|
||||||
|
is.True(err == nil)
|
||||||
|
is.Equal(result, helloworld)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNotExistsAsBytes(t *testing.T) {
|
||||||
|
|
||||||
|
is := is.New(t)
|
||||||
|
|
||||||
|
var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33}
|
||||||
|
|
||||||
|
db := NewAssetDB()
|
||||||
|
db.AddAsset("hello4", helloworld)
|
||||||
|
|
||||||
|
result, err := db.Read("hello")
|
||||||
|
|
||||||
|
is.True(err != nil)
|
||||||
|
is.True(result == nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExistsAsString(t *testing.T) {
|
||||||
|
|
||||||
|
is := is.New(t)
|
||||||
|
|
||||||
|
var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33}
|
||||||
|
|
||||||
|
db := NewAssetDB()
|
||||||
|
db.AddAsset("hello", helloworld)
|
||||||
|
|
||||||
|
result, err := db.String("hello")
|
||||||
|
|
||||||
|
// Ensure it exists
|
||||||
|
is.True(err == nil)
|
||||||
|
|
||||||
|
// Ensure the string is the same as the byte slice
|
||||||
|
is.Equal(result, "Hello, World!")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNotExistsAsString(t *testing.T) {
|
||||||
|
|
||||||
|
is := is.New(t)
|
||||||
|
|
||||||
|
var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33}
|
||||||
|
|
||||||
|
db := NewAssetDB()
|
||||||
|
db.AddAsset("hello", helloworld)
|
||||||
|
|
||||||
|
result, err := db.String("help")
|
||||||
|
|
||||||
|
// Ensure it doesn't exist
|
||||||
|
is.True(err != nil)
|
||||||
|
|
||||||
|
// Ensure the string is blank
|
||||||
|
is.Equal(result, "")
|
||||||
|
}
|
||||||
176
v2/internal/assetdb/filesystem.go
Normal file
176
v2/internal/assetdb/filesystem.go
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
// +build !desktop
|
||||||
|
package assetdb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errWhence = errors.New("Seek: invalid whence")
|
||||||
|
var errOffset = errors.New("Seek: invalid offset")
|
||||||
|
|
||||||
|
// Open implements the http.FileSystem interface for the AssetDB
|
||||||
|
func (a *AssetDB) Open(name string) (http.File, error) {
|
||||||
|
if name == "/" || name == "" {
|
||||||
|
return &Entry{name: "/", dir: true, db: a}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if data, ok := a.db[name]; ok {
|
||||||
|
return &Entry{name: name, data: data, size: len(data)}, nil
|
||||||
|
} else {
|
||||||
|
for n, _ := range a.db {
|
||||||
|
if strings.HasPrefix(n, name+"/") {
|
||||||
|
return &Entry{name: name, db: a, dir: true}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &Entry{}, os.ErrNotExist
|
||||||
|
}
|
||||||
|
|
||||||
|
// readdir returns the directory entries for the requested directory
|
||||||
|
func (a *AssetDB) readdir(name string) ([]os.FileInfo, error) {
|
||||||
|
dir := name
|
||||||
|
var ents []string
|
||||||
|
|
||||||
|
fim := make(map[string]os.FileInfo)
|
||||||
|
for fn, data := range a.db {
|
||||||
|
if strings.HasPrefix(fn, dir) {
|
||||||
|
pieces := strings.Split(fn[len(dir)+1:], "/")
|
||||||
|
if len(pieces) == 1 {
|
||||||
|
fim[pieces[0]] = FI{name: pieces[0], dir: false, size: len(data)}
|
||||||
|
ents = append(ents, pieces[0])
|
||||||
|
} else {
|
||||||
|
fim[pieces[0]] = FI{name: pieces[0], dir: true, size: -1}
|
||||||
|
ents = append(ents, pieces[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ents) == 0 {
|
||||||
|
return nil, os.ErrNotExist
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(ents)
|
||||||
|
var list []os.FileInfo
|
||||||
|
for _, dir := range ents {
|
||||||
|
list = append(list, fim[dir])
|
||||||
|
}
|
||||||
|
return list, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry implements the http.File interface to allow for
|
||||||
|
// use in the http.FileSystem implementation of AssetDB
|
||||||
|
type Entry struct {
|
||||||
|
name string
|
||||||
|
data []byte
|
||||||
|
dir bool
|
||||||
|
size int
|
||||||
|
db *AssetDB
|
||||||
|
off int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close is a noop
|
||||||
|
func (e Entry) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read fills the slice provided returning how many bytes were written
|
||||||
|
// and any errors encountered
|
||||||
|
func (e *Entry) Read(p []byte) (n int, err error) {
|
||||||
|
if e.off >= e.size {
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
numout := len(p)
|
||||||
|
if numout > e.size {
|
||||||
|
numout = e.size
|
||||||
|
}
|
||||||
|
for i := 0; i < numout; i++ {
|
||||||
|
p[i] = e.data[e.off+i]
|
||||||
|
}
|
||||||
|
e.off += numout
|
||||||
|
n = int(numout)
|
||||||
|
err = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seek seeks to the specified offset from the location specified by whence
|
||||||
|
func (e *Entry) Seek(offset int64, whence int) (int64, error) {
|
||||||
|
switch whence {
|
||||||
|
default:
|
||||||
|
return 0, errWhence
|
||||||
|
case io.SeekStart:
|
||||||
|
offset += 0
|
||||||
|
case io.SeekCurrent:
|
||||||
|
offset += int64(e.off)
|
||||||
|
case io.SeekEnd:
|
||||||
|
offset += int64(e.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
if offset < 0 {
|
||||||
|
return 0, errOffset
|
||||||
|
}
|
||||||
|
e.off = int(offset)
|
||||||
|
return offset, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Readdir returns the directory entries inside this entry if it is a directory
|
||||||
|
func (e Entry) Readdir(count int) ([]os.FileInfo, error) {
|
||||||
|
ents := []os.FileInfo{}
|
||||||
|
if !e.dir {
|
||||||
|
return ents, errors.New("Not a directory")
|
||||||
|
}
|
||||||
|
return e.db.readdir(e.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stat returns information about this directory entry
|
||||||
|
func (e Entry) Stat() (os.FileInfo, error) {
|
||||||
|
return FI{e.name, e.size, e.dir}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FI is the AssetDB implementation of os.FileInfo.
|
||||||
|
type FI struct {
|
||||||
|
name string
|
||||||
|
size int
|
||||||
|
dir bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDir returns true if this is a directory
|
||||||
|
func (fi FI) IsDir() bool {
|
||||||
|
return fi.dir
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModTime always returns now
|
||||||
|
func (fi FI) ModTime() time.Time {
|
||||||
|
return time.Time{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mode returns the file as readonly and directories
|
||||||
|
// as world writeable and executable
|
||||||
|
func (fi FI) Mode() os.FileMode {
|
||||||
|
if fi.IsDir() {
|
||||||
|
return 0755 | os.ModeDir
|
||||||
|
}
|
||||||
|
return 0444
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns the name of this object without
|
||||||
|
// any leading slashes
|
||||||
|
func (fi FI) Name() string {
|
||||||
|
return path.Base(fi.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the size of this item
|
||||||
|
func (fi FI) Size() int64 {
|
||||||
|
return int64(fi.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sys returns nil
|
||||||
|
func (fi FI) Sys() interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
108
v2/internal/assetdb/filesystem_test.go
Normal file
108
v2/internal/assetdb/filesystem_test.go
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
package assetdb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/matryer/is"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestOpenLeadingSlash(t *testing.T) {
|
||||||
|
is := is.New(t)
|
||||||
|
|
||||||
|
var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33}
|
||||||
|
|
||||||
|
db := NewAssetDB()
|
||||||
|
db.AddAsset("/hello", helloworld)
|
||||||
|
|
||||||
|
file, err := db.Open("/hello")
|
||||||
|
// Ensure it does exist
|
||||||
|
is.True(err == nil)
|
||||||
|
|
||||||
|
buff := make([]byte, len(helloworld))
|
||||||
|
n, err := file.Read(buff)
|
||||||
|
fmt.Printf("Error %v\n", err)
|
||||||
|
is.True(err == nil)
|
||||||
|
is.Equal(n, len(helloworld))
|
||||||
|
result := string(buff)
|
||||||
|
|
||||||
|
// Ensure the string is blank
|
||||||
|
is.Equal(result, string(helloworld))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOpen(t *testing.T) {
|
||||||
|
is := is.New(t)
|
||||||
|
|
||||||
|
var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33}
|
||||||
|
|
||||||
|
db := NewAssetDB()
|
||||||
|
db.AddAsset("/hello", helloworld)
|
||||||
|
|
||||||
|
file, err := db.Open("/hello")
|
||||||
|
|
||||||
|
// Ensure it does exist
|
||||||
|
is.True(err == nil)
|
||||||
|
|
||||||
|
buff := make([]byte, len(helloworld))
|
||||||
|
n, err := file.Read(buff)
|
||||||
|
is.True(err == nil)
|
||||||
|
is.Equal(n, len(helloworld))
|
||||||
|
result := string(buff)
|
||||||
|
|
||||||
|
// Ensure the string is blank
|
||||||
|
is.Equal(result, string(helloworld))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReaddir(t *testing.T) {
|
||||||
|
is := is.New(t)
|
||||||
|
|
||||||
|
var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33}
|
||||||
|
|
||||||
|
db := NewAssetDB()
|
||||||
|
db.AddAsset("/hello", helloworld)
|
||||||
|
db.AddAsset("/directory/hello", helloworld)
|
||||||
|
db.AddAsset("/directory/subdirectory/hello", helloworld)
|
||||||
|
|
||||||
|
dir, err := db.Open("/doesntexist")
|
||||||
|
is.True(err == os.ErrNotExist)
|
||||||
|
ents, err := dir.Readdir(-1)
|
||||||
|
is.Equal([]os.FileInfo{}, ents)
|
||||||
|
|
||||||
|
dir, err = db.Open("/")
|
||||||
|
is.True(dir != nil)
|
||||||
|
is.True(err == nil)
|
||||||
|
ents, err = dir.Readdir(-1)
|
||||||
|
is.True(err == nil)
|
||||||
|
is.Equal(3, len(ents))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReaddirSubdirectory(t *testing.T) {
|
||||||
|
is := is.New(t)
|
||||||
|
|
||||||
|
var helloworld = []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33}
|
||||||
|
|
||||||
|
db := NewAssetDB()
|
||||||
|
db.AddAsset("/hello", helloworld)
|
||||||
|
db.AddAsset("/directory/hello", helloworld)
|
||||||
|
db.AddAsset("/directory/subdirectory/hello", helloworld)
|
||||||
|
|
||||||
|
expected := []os.FileInfo{
|
||||||
|
FI{name: "hello", dir: false, size: len(helloworld)},
|
||||||
|
FI{name: "subdirectory", dir: true, size: -1},
|
||||||
|
}
|
||||||
|
|
||||||
|
dir, err := db.Open("/directory")
|
||||||
|
is.True(dir != nil)
|
||||||
|
is.True(err == nil)
|
||||||
|
ents, err := dir.Readdir(-1)
|
||||||
|
is.Equal(expected, ents)
|
||||||
|
|
||||||
|
// Check sub-subdirectory
|
||||||
|
dir, err = db.Open("/directory/subdirectory")
|
||||||
|
is.True(dir != nil)
|
||||||
|
is.True(err == nil)
|
||||||
|
ents, err = dir.Readdir(-1)
|
||||||
|
is.True(err == nil)
|
||||||
|
is.Equal([]os.FileInfo{FI{name: "hello", size: len(helloworld)}}, ents)
|
||||||
|
}
|
||||||
9
v2/internal/bind/bind.go
Normal file
9
v2/internal/bind/bind.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package bind
|
||||||
|
|
||||||
|
func IsStructPointer(value interface{}) bool {
|
||||||
|
switch t := value.(type) {
|
||||||
|
default:
|
||||||
|
println(t)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
70
v2/internal/binding/binding.go
Executable file
70
v2/internal/binding/binding.go
Executable file
@@ -0,0 +1,70 @@
|
|||||||
|
package binding
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Bindings struct {
|
||||||
|
db *DB
|
||||||
|
logger logger.CustomLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBindings returns a new Bindings object
|
||||||
|
func NewBindings(logger *logger.Logger) *Bindings {
|
||||||
|
return &Bindings{
|
||||||
|
db: newDB(),
|
||||||
|
logger: logger.CustomLogger("Bindings"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the given struct methods to the Bindings
|
||||||
|
func (b *Bindings) Add(structPtr interface{}) error {
|
||||||
|
|
||||||
|
methods, err := getMethods(structPtr)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannout bind value to app: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, method := range methods {
|
||||||
|
splitName := strings.Split(method.Name, ".")
|
||||||
|
packageName := splitName[0]
|
||||||
|
structName := splitName[1]
|
||||||
|
methodName := splitName[2]
|
||||||
|
|
||||||
|
// Is this WailsInit?
|
||||||
|
if method.IsWailsInit() {
|
||||||
|
err := b.db.AddWailsInit(method)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
b.logger.Trace("Registered WailsInit method: %s", method.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is this WailsShutdown?
|
||||||
|
if method.IsWailsShutdown() {
|
||||||
|
err := b.db.AddWailsShutdown(method)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
b.logger.Trace("Registered WailsShutdown method: %s", method.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add it as a regular method
|
||||||
|
b.db.AddMethod(packageName, structName, methodName, method)
|
||||||
|
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bindings) DB() *DB {
|
||||||
|
return b.db
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bindings) ToJSON() (string, error) {
|
||||||
|
return b.db.ToJSON()
|
||||||
|
}
|
||||||
150
v2/internal/binding/boundMethod.go
Normal file
150
v2/internal/binding/boundMethod.go
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
package binding
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BoundMethod defines all the data related to a Go method that is
|
||||||
|
// bound to the Wails application
|
||||||
|
type BoundMethod struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Inputs []*Parameter `json:"inputs,omitempty"`
|
||||||
|
Outputs []*Parameter `json:"outputs,omitempty"`
|
||||||
|
Comments string `json:"comments,omitempty"`
|
||||||
|
Method reflect.Value `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsWailsInit returns true if the method name is "WailsInit"
|
||||||
|
func (b *BoundMethod) IsWailsInit() bool {
|
||||||
|
return strings.HasSuffix(b.Name, "WailsInit")
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsWailsShutdown returns true if the method name is "WailsShutdown"
|
||||||
|
func (b *BoundMethod) IsWailsShutdown() bool {
|
||||||
|
return strings.HasSuffix(b.Name, "WailsShutdown")
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyWailsInit checks if the WailsInit signature is correct
|
||||||
|
func (b *BoundMethod) VerifyWailsInit() error {
|
||||||
|
// Must only have 1 input
|
||||||
|
if b.InputCount() != 1 {
|
||||||
|
return fmt.Errorf("invalid method signature for %s: expected `WailsInit(*wails.Runtime) error`", b.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check input type
|
||||||
|
if !b.Inputs[0].IsType("*runtime.Runtime") {
|
||||||
|
return fmt.Errorf("invalid method signature for %s: expected `WailsInit(*wails.Runtime) error`", b.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must only have 1 output
|
||||||
|
if b.OutputCount() != 1 {
|
||||||
|
return fmt.Errorf("invalid method signature for %s: expected `WailsInit(*wails.Runtime) error`", b.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check output type
|
||||||
|
if !b.Outputs[0].IsError() {
|
||||||
|
return fmt.Errorf("invalid method signature for %s: expected `WailsInit(*wails.Runtime) error`", b.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input must be of type Runtime
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyWailsShutdown checks if the WailsShutdown signature is correct
|
||||||
|
func (b *BoundMethod) VerifyWailsShutdown() error {
|
||||||
|
// Must have no inputs
|
||||||
|
if b.InputCount() != 0 {
|
||||||
|
return fmt.Errorf("invalid method signature for WailsShutdown: expected `WailsShutdown()`")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must have no outputs
|
||||||
|
if b.OutputCount() != 0 {
|
||||||
|
return fmt.Errorf("invalid method signature for WailsShutdown: expected `WailsShutdown()`")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input must be of type Runtime
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InputCount returns the number of inputs this bound method has
|
||||||
|
func (b *BoundMethod) InputCount() int {
|
||||||
|
return len(b.Inputs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OutputCount returns the number of outputs this bound method has
|
||||||
|
func (b *BoundMethod) OutputCount() int {
|
||||||
|
return len(b.Outputs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseArgs method converts the input json into the types expected by the method
|
||||||
|
func (b *BoundMethod) ParseArgs(args []json.RawMessage) ([]interface{}, error) {
|
||||||
|
|
||||||
|
result := make([]interface{}, b.InputCount())
|
||||||
|
for index, arg := range args {
|
||||||
|
typ := b.Inputs[index].reflectType
|
||||||
|
inputValue := reflect.New(typ).Interface()
|
||||||
|
err := json.Unmarshal(arg, inputValue)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if inputValue == nil {
|
||||||
|
result[index] = reflect.Zero(typ).Interface()
|
||||||
|
} else {
|
||||||
|
result[index] = reflect.ValueOf(inputValue).Elem().Interface()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call will attempt to call this bound method with the given args
|
||||||
|
func (b *BoundMethod) Call(args []interface{}) (interface{}, error) {
|
||||||
|
// Check inputs
|
||||||
|
expectedInputLength := len(b.Inputs)
|
||||||
|
actualInputLength := len(args)
|
||||||
|
if expectedInputLength != actualInputLength {
|
||||||
|
return nil, fmt.Errorf("%s takes %d inputs. Received %d", b.Name, expectedInputLength, actualInputLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert inputs to reflect values **/
|
||||||
|
|
||||||
|
// Create slice for the input arguments to the method call
|
||||||
|
callArgs := make([]reflect.Value, expectedInputLength)
|
||||||
|
|
||||||
|
// Iterate over given arguments
|
||||||
|
for index, arg := range args {
|
||||||
|
// Save the converted argument
|
||||||
|
callArgs[index] = reflect.ValueOf(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do the call
|
||||||
|
callResults := b.Method.Call(callArgs)
|
||||||
|
|
||||||
|
//** Check results **//
|
||||||
|
var returnValue interface{}
|
||||||
|
var err error
|
||||||
|
|
||||||
|
switch b.OutputCount() {
|
||||||
|
case 1:
|
||||||
|
// Loop over results and determine if the result
|
||||||
|
// is an error or not
|
||||||
|
for _, result := range callResults {
|
||||||
|
interfac := result.Interface()
|
||||||
|
temp, ok := interfac.(error)
|
||||||
|
if ok {
|
||||||
|
err = temp
|
||||||
|
} else {
|
||||||
|
returnValue = interfac
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
returnValue = callResults[0].Interface()
|
||||||
|
if temp, ok := callResults[1].Interface().(error); ok {
|
||||||
|
err = temp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue, err
|
||||||
|
}
|
||||||
150
v2/internal/binding/db.go
Normal file
150
v2/internal/binding/db.go
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
package binding
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DB is our database of method bindings
|
||||||
|
type DB struct {
|
||||||
|
// map[packagename] -> map[structname] -> map[methodname]*method
|
||||||
|
store map[string]map[string]map[string]*BoundMethod
|
||||||
|
|
||||||
|
// This uses fully qualified method names as a shortcut for store traversal.
|
||||||
|
// It used for performance gains at runtime
|
||||||
|
methodMap map[string]*BoundMethod
|
||||||
|
|
||||||
|
// These are slices of methods registered using WailsInit and WailsShutdown
|
||||||
|
wailsInitMethods []*BoundMethod
|
||||||
|
wailsShutdownMethods []*BoundMethod
|
||||||
|
|
||||||
|
// Lock to ensure sync access to the data
|
||||||
|
lock sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDB() *DB {
|
||||||
|
return &DB{
|
||||||
|
store: make(map[string]map[string]map[string]*BoundMethod),
|
||||||
|
methodMap: make(map[string]*BoundMethod),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMethodFromStore returns the method for the given package/struct/method names
|
||||||
|
// nil is returned if any one of those does not exist
|
||||||
|
func (d *DB) GetMethodFromStore(packageName string, structName string, methodName string) *BoundMethod {
|
||||||
|
|
||||||
|
// Lock the db whilst processing and unlock on return
|
||||||
|
d.lock.RLock()
|
||||||
|
defer d.lock.RUnlock()
|
||||||
|
|
||||||
|
structMap, exists := d.store[packageName]
|
||||||
|
if !exists {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
methodMap, exists := structMap[structName]
|
||||||
|
if !exists {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return methodMap[methodName]
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMethod returns the method for the given qualified method name
|
||||||
|
// qualifiedMethodName is "packagename.structname.methodname"
|
||||||
|
func (d *DB) GetMethod(qualifiedMethodName string) *BoundMethod {
|
||||||
|
|
||||||
|
// Lock the db whilst processing and unlock on return
|
||||||
|
d.lock.RLock()
|
||||||
|
defer d.lock.RUnlock()
|
||||||
|
|
||||||
|
return d.methodMap[qualifiedMethodName]
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddMethod adds the given method definition to the db using the given qualified path: packageName.structName.methodName
|
||||||
|
func (d *DB) AddMethod(packageName string, structName string, methodName string, methodDefinition *BoundMethod) {
|
||||||
|
|
||||||
|
// TODO: Validate inputs?
|
||||||
|
|
||||||
|
// Lock the db whilst processing and unlock on return
|
||||||
|
d.lock.Lock()
|
||||||
|
defer d.lock.Unlock()
|
||||||
|
|
||||||
|
// Get the map associated with the package name
|
||||||
|
structMap, exists := d.store[packageName]
|
||||||
|
if !exists {
|
||||||
|
// Create a new map for this packagename
|
||||||
|
d.store[packageName] = make(map[string]map[string]*BoundMethod)
|
||||||
|
structMap = d.store[packageName]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the map associated with the struct name
|
||||||
|
methodMap, exists := structMap[structName]
|
||||||
|
if !exists {
|
||||||
|
// Create a new map for this packagename
|
||||||
|
structMap[structName] = make(map[string]*BoundMethod)
|
||||||
|
methodMap = structMap[structName]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the method definition
|
||||||
|
methodMap[methodName] = methodDefinition
|
||||||
|
|
||||||
|
// Store in the methodMap
|
||||||
|
key := packageName + "." + structName + "." + methodName
|
||||||
|
d.methodMap[key] = methodDefinition
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddWailsInit checks the given method is a WailsInit method and if it
|
||||||
|
// is, adds it to the list of WailsInit methods
|
||||||
|
func (d *DB) AddWailsInit(method *BoundMethod) error {
|
||||||
|
err := method.VerifyWailsInit()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock the db whilst processing and unlock on return
|
||||||
|
d.lock.Lock()
|
||||||
|
defer d.lock.Unlock()
|
||||||
|
|
||||||
|
d.wailsInitMethods = append(d.wailsInitMethods, method)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddWailsShutdown checks the given method is a WailsInit method and if it
|
||||||
|
// is, adds it to the list of WailsShutdown methods
|
||||||
|
func (d *DB) AddWailsShutdown(method *BoundMethod) error {
|
||||||
|
err := method.VerifyWailsShutdown()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock the db whilst processing and unlock on return
|
||||||
|
d.lock.Lock()
|
||||||
|
defer d.lock.Unlock()
|
||||||
|
|
||||||
|
d.wailsShutdownMethods = append(d.wailsShutdownMethods, method)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToJSON converts the method map to JSON
|
||||||
|
func (d *DB) ToJSON() (string, error) {
|
||||||
|
|
||||||
|
// Lock the db whilst processing and unlock on return
|
||||||
|
d.lock.RLock()
|
||||||
|
defer d.lock.RUnlock()
|
||||||
|
|
||||||
|
bytes, err := json.Marshal(&d.store)
|
||||||
|
|
||||||
|
// Return zero copy string as this string will be read only
|
||||||
|
return *(*string)(unsafe.Pointer(&bytes)), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// WailsInitMethods returns the list of registered WailsInit methods
|
||||||
|
func (d *DB) WailsInitMethods() []*BoundMethod {
|
||||||
|
return d.wailsInitMethods
|
||||||
|
}
|
||||||
|
|
||||||
|
// WailsShutdownMethods returns the list of registered WailsInit methods
|
||||||
|
func (d *DB) WailsShutdownMethods() []*BoundMethod {
|
||||||
|
return d.wailsShutdownMethods
|
||||||
|
}
|
||||||
28
v2/internal/binding/parameter.go
Normal file
28
v2/internal/binding/parameter.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package binding
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
// Parameter defines a Go method parameter
|
||||||
|
type Parameter struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
TypeName string `json:"type"`
|
||||||
|
reflectType reflect.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
func newParameter(Name string, Type reflect.Type) *Parameter {
|
||||||
|
return &Parameter{
|
||||||
|
Name: Name,
|
||||||
|
TypeName: Type.String(),
|
||||||
|
reflectType: Type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsType returns true if the given
|
||||||
|
func (p *Parameter) IsType(typename string) bool {
|
||||||
|
return p.TypeName == typename
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsError returns true if the parameter type is an error
|
||||||
|
func (p *Parameter) IsError() bool {
|
||||||
|
return p.IsType("error")
|
||||||
|
}
|
||||||
123
v2/internal/binding/reflect.go
Executable file
123
v2/internal/binding/reflect.go
Executable file
@@ -0,0 +1,123 @@
|
|||||||
|
package binding
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// isStructPtr returns true if the value given is a
|
||||||
|
// pointer to a struct
|
||||||
|
func isStructPtr(value interface{}) bool {
|
||||||
|
return reflect.ValueOf(value).Kind() == reflect.Ptr &&
|
||||||
|
reflect.ValueOf(value).Elem().Kind() == reflect.Struct
|
||||||
|
}
|
||||||
|
|
||||||
|
// isStructPtr returns true if the value given is a struct
|
||||||
|
func isStruct(value interface{}) bool {
|
||||||
|
return reflect.ValueOf(value).Kind() == reflect.Struct
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMethods(value interface{}) ([]*BoundMethod, error) {
|
||||||
|
|
||||||
|
// Create result placeholder
|
||||||
|
var result []*BoundMethod
|
||||||
|
|
||||||
|
// Check type
|
||||||
|
if !isStructPtr(value) {
|
||||||
|
|
||||||
|
if isStruct(value) {
|
||||||
|
name := reflect.ValueOf(value).Type().Name()
|
||||||
|
return nil, fmt.Errorf("%s is a struct, not a pointer to a struct", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("not a pointer to a struct")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process Struct
|
||||||
|
structType := reflect.TypeOf(value)
|
||||||
|
structValue := reflect.ValueOf(value)
|
||||||
|
baseName := structType.String()[1:]
|
||||||
|
|
||||||
|
// Process Methods
|
||||||
|
for i := 0; i < structType.NumMethod(); i++ {
|
||||||
|
methodDef := structType.Method(i)
|
||||||
|
methodName := methodDef.Name
|
||||||
|
fullMethodName := baseName + "." + methodName
|
||||||
|
method := structValue.MethodByName(methodName)
|
||||||
|
|
||||||
|
// Create new method
|
||||||
|
boundMethod := &BoundMethod{
|
||||||
|
Name: fullMethodName,
|
||||||
|
Inputs: nil,
|
||||||
|
Outputs: nil,
|
||||||
|
Comments: "",
|
||||||
|
Method: method,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate inputs
|
||||||
|
methodType := method.Type()
|
||||||
|
inputParamCount := methodType.NumIn()
|
||||||
|
var inputs []*Parameter
|
||||||
|
for inputIndex := 0; inputIndex < inputParamCount; inputIndex++ {
|
||||||
|
input := methodType.In(inputIndex)
|
||||||
|
thisParam := newParameter("", input)
|
||||||
|
inputs = append(inputs, thisParam)
|
||||||
|
}
|
||||||
|
|
||||||
|
boundMethod.Inputs = inputs
|
||||||
|
|
||||||
|
// Iterate outputs
|
||||||
|
// TODO: Determine what to do about limiting return types
|
||||||
|
// especially around errors.
|
||||||
|
outputParamCount := methodType.NumOut()
|
||||||
|
var outputs []*Parameter
|
||||||
|
for outputIndex := 0; outputIndex < outputParamCount; outputIndex++ {
|
||||||
|
output := methodType.Out(outputIndex)
|
||||||
|
thisParam := newParameter("", output)
|
||||||
|
outputs = append(outputs, thisParam)
|
||||||
|
}
|
||||||
|
boundMethod.Outputs = outputs
|
||||||
|
|
||||||
|
// Save method in result
|
||||||
|
result = append(result, boundMethod)
|
||||||
|
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertArgToValue
|
||||||
|
func convertArgToValue(input json.RawMessage, target *Parameter) (result reflect.Value, err error) {
|
||||||
|
|
||||||
|
// Catch type conversion panics thrown by convert
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
// Modify error
|
||||||
|
err = fmt.Errorf("%s", r.(string)[23:])
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Do the conversion
|
||||||
|
|
||||||
|
// Handle nil values
|
||||||
|
if input == nil {
|
||||||
|
switch target.reflectType.Kind() {
|
||||||
|
case reflect.Chan,
|
||||||
|
reflect.Func,
|
||||||
|
reflect.Interface,
|
||||||
|
reflect.Map,
|
||||||
|
reflect.Ptr,
|
||||||
|
reflect.Slice:
|
||||||
|
result = reflect.ValueOf(input).Convert(target.reflectType)
|
||||||
|
default:
|
||||||
|
return reflect.Zero(target.reflectType), fmt.Errorf("Unable to use null value")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = reflect.ValueOf(input).Convert(target.reflectType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't like doing this but it's the only way to
|
||||||
|
// handle recover() correctly
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
17
v2/internal/crypto/crypto.go
Normal file
17
v2/internal/crypto/crypto.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RandomID returns a random ID as a string
|
||||||
|
func RandomID() string {
|
||||||
|
b := make([]byte, 16)
|
||||||
|
_, err := rand.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%x", b)
|
||||||
|
}
|
||||||
62
v2/internal/ffenestri/README.md
Normal file
62
v2/internal/ffenestri/README.md
Normal file
File diff suppressed because one or more lines are too long
181
v2/internal/ffenestri/ffenestri.go
Normal file
181
v2/internal/ffenestri/ffenestri.go
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
package ffenestri
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
#cgo linux CFLAGS: -DFFENESTRI_LINUX=1
|
||||||
|
#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0
|
||||||
|
|
||||||
|
#cgo darwin CFLAGS: -DFFENESTRI_DARWIN=1
|
||||||
|
#cgo darwin LDFLAGS: -framework WebKit -lobjc
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "ffenestri.h"
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// DEBUG is the global Ffenestri debug flag.
|
||||||
|
// TODO: move to compile time.
|
||||||
|
var DEBUG bool = true
|
||||||
|
|
||||||
|
// Application is our main application object
|
||||||
|
type Application struct {
|
||||||
|
config *options.App
|
||||||
|
memory []unsafe.Pointer
|
||||||
|
|
||||||
|
// This is the main app pointer
|
||||||
|
app unsafe.Pointer
|
||||||
|
|
||||||
|
// Logger
|
||||||
|
logger logger.CustomLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Application) saveMemoryReference(mem unsafe.Pointer) {
|
||||||
|
a.memory = append(a.memory, mem)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Application) string2CString(str string) *C.char {
|
||||||
|
result := C.CString(str)
|
||||||
|
a.saveMemoryReference(unsafe.Pointer(result))
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewApplicationWithConfig creates a new application based on the given config
|
||||||
|
func NewApplicationWithConfig(config *options.App, logger *logger.Logger) *Application {
|
||||||
|
return &Application{
|
||||||
|
config: config,
|
||||||
|
logger: logger.CustomLogger("Ffenestri"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewApplication creates a new Application with the default config
|
||||||
|
func NewApplication(logger *logger.Logger) *Application {
|
||||||
|
return &Application{
|
||||||
|
config: options.Default,
|
||||||
|
logger: logger.CustomLogger("Ffenestri"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Application) freeMemory() {
|
||||||
|
for _, mem := range a.memory {
|
||||||
|
// fmt.Printf("Freeing memory: %+v\n", mem)
|
||||||
|
C.free(mem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// bool2Cint converts a Go boolean to a C integer
|
||||||
|
func (a *Application) bool2Cint(value bool) C.int {
|
||||||
|
if value {
|
||||||
|
return C.int(1)
|
||||||
|
}
|
||||||
|
return C.int(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dispatcher is the interface to send messages to
|
||||||
|
var dispatcher *messagedispatcher.DispatchClient
|
||||||
|
|
||||||
|
// Dispatcher is what we register out client with
|
||||||
|
type Dispatcher interface {
|
||||||
|
RegisterClient(client messagedispatcher.Client) *messagedispatcher.DispatchClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// DispatchClient is the means for passing messages to the backend
|
||||||
|
type DispatchClient interface {
|
||||||
|
SendMessage(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
func intToColour(colour int) (C.int, C.int, C.int, C.int) {
|
||||||
|
var alpha = C.int(colour & 0xFF)
|
||||||
|
var blue = C.int((colour >> 8) & 0xFF)
|
||||||
|
var green = C.int((colour >> 16) & 0xFF)
|
||||||
|
var red = C.int((colour >> 24) & 0xFF)
|
||||||
|
return red, green, blue, alpha
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the application
|
||||||
|
func (a *Application) Run(incomingDispatcher Dispatcher, bindings string) error {
|
||||||
|
title := a.string2CString(a.config.Title)
|
||||||
|
width := C.int(a.config.Width)
|
||||||
|
height := C.int(a.config.Height)
|
||||||
|
resizable := a.bool2Cint(!a.config.DisableResize)
|
||||||
|
devtools := a.bool2Cint(a.config.DevTools)
|
||||||
|
fullscreen := a.bool2Cint(a.config.Fullscreen)
|
||||||
|
startHidden := a.bool2Cint(a.config.StartHidden)
|
||||||
|
logLevel := C.int(a.config.LogLevel)
|
||||||
|
app := C.NewApplication(title, width, height, resizable, devtools, fullscreen, startHidden, logLevel)
|
||||||
|
|
||||||
|
// Save app reference
|
||||||
|
a.app = unsafe.Pointer(app)
|
||||||
|
|
||||||
|
// Set Min Window Size
|
||||||
|
minWidth := C.int(a.config.MinWidth)
|
||||||
|
minHeight := C.int(a.config.MinHeight)
|
||||||
|
C.SetMinWindowSize(a.app, minWidth, minHeight)
|
||||||
|
|
||||||
|
// Set Max Window Size
|
||||||
|
maxWidth := C.int(a.config.MaxWidth)
|
||||||
|
maxHeight := C.int(a.config.MaxHeight)
|
||||||
|
C.SetMaxWindowSize(a.app, maxWidth, maxHeight)
|
||||||
|
|
||||||
|
// Set debug if needed
|
||||||
|
C.SetDebug(app, a.bool2Cint(DEBUG))
|
||||||
|
|
||||||
|
// TODO: Move frameless to Linux options
|
||||||
|
// if a.config.Frameless {
|
||||||
|
// C.DisableFrame(a.app)
|
||||||
|
// }
|
||||||
|
|
||||||
|
if a.config.RGBA != 0 {
|
||||||
|
r, g, b, alpha := intToColour(a.config.RGBA)
|
||||||
|
C.SetColour(a.app, r, g, b, alpha)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Escape bindings so C doesn't freak out
|
||||||
|
bindings = strings.ReplaceAll(bindings, `"`, `\"`)
|
||||||
|
|
||||||
|
// Set bindings
|
||||||
|
C.SetBindings(app, a.string2CString(bindings))
|
||||||
|
|
||||||
|
// save the dispatcher in a package variable so that the C callbacks
|
||||||
|
// can access it
|
||||||
|
dispatcher = incomingDispatcher.RegisterClient(newClient(a))
|
||||||
|
|
||||||
|
// Process platform settings
|
||||||
|
a.processPlatformSettings()
|
||||||
|
|
||||||
|
// Check we could initialise the application
|
||||||
|
if app != nil {
|
||||||
|
// Yes - Save memory reference and run app, cleaning up afterwards
|
||||||
|
a.saveMemoryReference(unsafe.Pointer(app))
|
||||||
|
C.Run(app, 0, nil)
|
||||||
|
} else {
|
||||||
|
// Oh no! We couldn't initialise the application
|
||||||
|
a.logger.Fatal("Cannot initialise Application.")
|
||||||
|
}
|
||||||
|
|
||||||
|
a.freeMemory()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// messageFromWindowCallback is called by any messages sent in
|
||||||
|
// webkit to window.external.invoke. It relays the message on to
|
||||||
|
// the dispatcher.
|
||||||
|
//export messageFromWindowCallback
|
||||||
|
func messageFromWindowCallback(data *C.char) {
|
||||||
|
dispatcher.DispatchMessage(C.GoString(data))
|
||||||
|
}
|
||||||
35
v2/internal/ffenestri/ffenestri.h
Normal file
35
v2/internal/ffenestri/ffenestri.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#ifndef __FFENESTRI_H__
|
||||||
|
#define __FFENESTRI_H__
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
extern void *NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden, int logLevel);
|
||||||
|
extern void SetMinWindowSize(void *app, int minWidth, int minHeight);
|
||||||
|
extern void SetMaxWindowSize(void *app, int maxWidth, int maxHeight);
|
||||||
|
extern void Run(void *app, int argc, char **argv);
|
||||||
|
extern void DestroyApplication(void *app);
|
||||||
|
extern void SetDebug(void *app, int flag);
|
||||||
|
extern void SetBindings(void *app, const char *bindings);
|
||||||
|
extern void ExecJS(void *app, const char *script);
|
||||||
|
extern void Hide(void *app);
|
||||||
|
extern void Show(void *app);
|
||||||
|
extern void Center(void *app);
|
||||||
|
extern void Maximise(void *app);
|
||||||
|
extern void Unmaximise(void *app);
|
||||||
|
extern void ToggleMaximise(void *app);
|
||||||
|
extern void Minimise(void *app);
|
||||||
|
extern void Unminimise(void *app);
|
||||||
|
extern void ToggleMinimise(void *app);
|
||||||
|
extern void SetColour(void *app, int red, int green, int blue, int alpha);
|
||||||
|
extern void SetSize(void *app, int width, int height);
|
||||||
|
extern void SetPosition(void *app, int x, int y);
|
||||||
|
extern void Quit(void *app);
|
||||||
|
extern void SetTitle(void *app, const char *title);
|
||||||
|
extern void Fullscreen(void *app);
|
||||||
|
extern void UnFullscreen(void *app);
|
||||||
|
extern void ToggleFullscreen(void *app);
|
||||||
|
extern void DisableFrame(void *app);
|
||||||
|
extern void OpenDialog(void *appPointer, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int allowFiles, int allowDirs, int allowMultiple, int showHiddenFiles, int canCreateDirectories, int resolveAliases, int treatPackagesAsDirectories);
|
||||||
|
extern void SaveDialog(void *appPointer, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int showHiddenFiles, int canCreateDirectories, int treatPackagesAsDirectories);
|
||||||
|
extern void DarkModeEnabled(void *appPointer, char *callbackID);
|
||||||
|
#endif
|
||||||
156
v2/internal/ffenestri/ffenestri_client.go
Normal file
156
v2/internal/ffenestri/ffenestri_client.go
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
package ffenestri
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
#cgo linux CFLAGS: -DFFENESTRI_LINUX=1
|
||||||
|
#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "ffenestri.h"
|
||||||
|
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Client is our implentation of messageDispatcher.Client
|
||||||
|
type Client struct {
|
||||||
|
app *Application
|
||||||
|
logger logger.CustomLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
func newClient(app *Application) *Client {
|
||||||
|
return &Client{
|
||||||
|
app: app,
|
||||||
|
logger: app.logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quit the application
|
||||||
|
func (c *Client) Quit() {
|
||||||
|
c.app.logger.Trace("Got shutdown message")
|
||||||
|
C.Quit(c.app.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotifyEvent will pass on the event message to the frontend
|
||||||
|
func (c *Client) NotifyEvent(message string) {
|
||||||
|
eventMessage := `window.wails._.Notify(` + strconv.Quote(message) + `);`
|
||||||
|
c.app.logger.Trace("eventMessage = %+v", eventMessage)
|
||||||
|
C.ExecJS(c.app.app, c.app.string2CString(eventMessage))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CallResult contains the result of the call from JS
|
||||||
|
func (c *Client) CallResult(message string) {
|
||||||
|
callbackMessage := `window.wails._.Callback(` + strconv.Quote(message) + `);`
|
||||||
|
c.app.logger.Trace("callbackMessage = %+v", callbackMessage)
|
||||||
|
C.ExecJS(c.app.app, c.app.string2CString(callbackMessage))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WindowSetTitle sets the window title to the given string
|
||||||
|
func (c *Client) WindowSetTitle(title string) {
|
||||||
|
C.SetTitle(c.app.app, c.app.string2CString(title))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WindowFullscreen will set the window to be fullscreen
|
||||||
|
func (c *Client) WindowFullscreen() {
|
||||||
|
C.Fullscreen(c.app.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WindowUnFullscreen will unfullscreen the window
|
||||||
|
func (c *Client) WindowUnFullscreen() {
|
||||||
|
C.UnFullscreen(c.app.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WindowShow will show the window
|
||||||
|
func (c *Client) WindowShow() {
|
||||||
|
C.Show(c.app.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WindowHide will hide the window
|
||||||
|
func (c *Client) WindowHide() {
|
||||||
|
C.Hide(c.app.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WindowCenter will hide the window
|
||||||
|
func (c *Client) WindowCenter() {
|
||||||
|
C.Center(c.app.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WindowMaximise will maximise the window
|
||||||
|
func (c *Client) WindowMaximise() {
|
||||||
|
C.Maximise(c.app.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WindowMinimise will minimise the window
|
||||||
|
func (c *Client) WindowMinimise() {
|
||||||
|
C.Minimise(c.app.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WindowUnmaximise will unmaximise the window
|
||||||
|
func (c *Client) WindowUnmaximise() {
|
||||||
|
C.Unmaximise(c.app.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WindowUnminimise will unminimise the window
|
||||||
|
func (c *Client) WindowUnminimise() {
|
||||||
|
C.Unminimise(c.app.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WindowPosition will position the window to x,y on the
|
||||||
|
// monitor that the window is mostly on
|
||||||
|
func (c *Client) WindowPosition(x int, y int) {
|
||||||
|
C.SetPosition(c.app.app, C.int(x), C.int(y))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WindowSize will resize the window to the given
|
||||||
|
// width and height
|
||||||
|
func (c *Client) WindowSize(width int, height int) {
|
||||||
|
C.SetSize(c.app.app, C.int(width), C.int(height))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WindowSetColour sets the window colour
|
||||||
|
func (c *Client) WindowSetColour(colour int) {
|
||||||
|
r, g, b, a := intToColour(colour)
|
||||||
|
C.SetColour(c.app.app, r, g, b, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenDialog will open a dialog with the given title and filter
|
||||||
|
func (c *Client) OpenDialog(dialogOptions *options.OpenDialog, callbackID string) {
|
||||||
|
C.OpenDialog(c.app.app,
|
||||||
|
c.app.string2CString(callbackID),
|
||||||
|
c.app.string2CString(dialogOptions.Title),
|
||||||
|
c.app.string2CString(dialogOptions.Filters),
|
||||||
|
c.app.string2CString(dialogOptions.DefaultFilename),
|
||||||
|
c.app.string2CString(dialogOptions.DefaultDirectory),
|
||||||
|
c.app.bool2Cint(dialogOptions.AllowFiles),
|
||||||
|
c.app.bool2Cint(dialogOptions.AllowDirectories),
|
||||||
|
c.app.bool2Cint(dialogOptions.AllowMultiple),
|
||||||
|
c.app.bool2Cint(dialogOptions.ShowHiddenFiles),
|
||||||
|
c.app.bool2Cint(dialogOptions.CanCreateDirectories),
|
||||||
|
c.app.bool2Cint(dialogOptions.ResolveAliases),
|
||||||
|
c.app.bool2Cint(dialogOptions.TreatPackagesAsDirectories),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveDialog will open a dialog with the given title and filter
|
||||||
|
func (c *Client) SaveDialog(dialogOptions *options.SaveDialog, callbackID string) {
|
||||||
|
C.SaveDialog(c.app.app,
|
||||||
|
c.app.string2CString(callbackID),
|
||||||
|
c.app.string2CString(dialogOptions.Title),
|
||||||
|
c.app.string2CString(dialogOptions.Filters),
|
||||||
|
c.app.string2CString(dialogOptions.DefaultFilename),
|
||||||
|
c.app.string2CString(dialogOptions.DefaultDirectory),
|
||||||
|
c.app.bool2Cint(dialogOptions.ShowHiddenFiles),
|
||||||
|
c.app.bool2Cint(dialogOptions.CanCreateDirectories),
|
||||||
|
c.app.bool2Cint(dialogOptions.TreatPackagesAsDirectories),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DarkModeEnabled(callbackID string) {
|
||||||
|
C.DarkModeEnabled(c.app.app, c.app.string2CString(callbackID))
|
||||||
|
}
|
||||||
1050
v2/internal/ffenestri/ffenestri_darwin.c
Normal file
1050
v2/internal/ffenestri/ffenestri_darwin.c
Normal file
File diff suppressed because it is too large
Load Diff
67
v2/internal/ffenestri/ffenestri_darwin.go
Normal file
67
v2/internal/ffenestri/ffenestri_darwin.go
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
package ffenestri
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo darwin CFLAGS: -DFFENESTRI_DARWIN=1
|
||||||
|
#cgo darwin LDFLAGS: -framework WebKit -lobjc
|
||||||
|
|
||||||
|
extern void TitlebarAppearsTransparent(void *);
|
||||||
|
extern void HideTitle(void *);
|
||||||
|
extern void HideTitleBar(void *);
|
||||||
|
extern void FullSizeContent(void *);
|
||||||
|
extern void UseToolbar(void *);
|
||||||
|
extern void HideToolbarSeparator(void *);
|
||||||
|
extern void DisableFrame(void *);
|
||||||
|
extern void SetAppearance(void *, const char *);
|
||||||
|
extern void WebviewIsTransparent(void *);
|
||||||
|
extern void SetWindowBackgroundIsTranslucent(void *);
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
func (a *Application) processPlatformSettings() {
|
||||||
|
|
||||||
|
mac := a.config.Mac
|
||||||
|
titlebar := mac.TitleBar
|
||||||
|
|
||||||
|
// HideTitle
|
||||||
|
if titlebar.HideTitle {
|
||||||
|
C.HideTitle(a.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HideTitleBar
|
||||||
|
if titlebar.HideTitleBar {
|
||||||
|
C.HideTitleBar(a.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Full Size Content
|
||||||
|
if titlebar.FullSizeContent {
|
||||||
|
C.FullSizeContent(a.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toolbar
|
||||||
|
if titlebar.UseToolbar {
|
||||||
|
C.UseToolbar(a.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
if titlebar.HideToolbarSeparator {
|
||||||
|
C.HideToolbarSeparator(a.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
if titlebar.TitlebarAppearsTransparent {
|
||||||
|
C.TitlebarAppearsTransparent(a.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process window Appearance
|
||||||
|
if mac.Appearance != "" {
|
||||||
|
C.SetAppearance(a.app, a.string2CString(string(mac.Appearance)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the webview should be transparent
|
||||||
|
if mac.WebviewIsTransparent {
|
||||||
|
C.WebviewIsTransparent(a.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if window should be translucent
|
||||||
|
if mac.WindowBackgroundIsTranslucent {
|
||||||
|
C.SetWindowBackgroundIsTranslucent(a.app)
|
||||||
|
}
|
||||||
|
}
|
||||||
984
v2/internal/ffenestri/ffenestri_linux.c
Normal file
984
v2/internal/ffenestri/ffenestri_linux.c
Normal file
@@ -0,0 +1,984 @@
|
|||||||
|
|
||||||
|
#ifndef __FFENESTRI_LINUX_H__
|
||||||
|
#define __FFENESTRI_LINUX_H__
|
||||||
|
|
||||||
|
#include "gtk/gtk.h"
|
||||||
|
#include "webkit2/webkit2.h"
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
// References to assets
|
||||||
|
extern const unsigned char *assets[];
|
||||||
|
extern const unsigned char runtime;
|
||||||
|
extern const char *icon[];
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
#define PRIMARY_MOUSE_BUTTON 1
|
||||||
|
#define MIDDLE_MOUSE_BUTTON 2
|
||||||
|
#define SECONDARY_MOUSE_BUTTON 3
|
||||||
|
|
||||||
|
// MAIN DEBUG FLAG
|
||||||
|
int debug;
|
||||||
|
|
||||||
|
// Credit: https://stackoverflow.com/a/8465083
|
||||||
|
char *concat(const char *s1, const char *s2)
|
||||||
|
{
|
||||||
|
const size_t len1 = strlen(s1);
|
||||||
|
const size_t len2 = strlen(s2);
|
||||||
|
char *result = malloc(len1 + len2 + 1);
|
||||||
|
memcpy(result, s1, len1);
|
||||||
|
memcpy(result + len1, s2, len2 + 1);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug works like sprintf but mutes if the global debug flag is true
|
||||||
|
// Credit: https://stackoverflow.com/a/20639708
|
||||||
|
void Debug(char *message, ...)
|
||||||
|
{
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
char *temp = concat("TRACE | Ffenestri (C) | ", message);
|
||||||
|
message = concat(temp, "\n");
|
||||||
|
free(temp);
|
||||||
|
va_list args;
|
||||||
|
va_start(args, message);
|
||||||
|
vprintf(message, args);
|
||||||
|
free(message);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void messageFromWindowCallback(const char *);
|
||||||
|
typedef void (*ffenestriCallback)(const char *);
|
||||||
|
|
||||||
|
struct Application
|
||||||
|
{
|
||||||
|
|
||||||
|
// Gtk Data
|
||||||
|
GtkApplication *application;
|
||||||
|
GtkWindow *mainWindow;
|
||||||
|
GtkWidget *webView;
|
||||||
|
int signalInvoke;
|
||||||
|
int signalWindowDrag;
|
||||||
|
int signalButtonPressed;
|
||||||
|
int signalButtonReleased;
|
||||||
|
int signalLoadChanged;
|
||||||
|
|
||||||
|
// Saves the events for the drag mouse button
|
||||||
|
GdkEventButton *dragButtonEvent;
|
||||||
|
|
||||||
|
// The number of the default drag button
|
||||||
|
int dragButton;
|
||||||
|
|
||||||
|
// Window Data
|
||||||
|
const char *title;
|
||||||
|
char *id;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int resizable;
|
||||||
|
int devtools;
|
||||||
|
int startHidden;
|
||||||
|
int fullscreen;
|
||||||
|
int minWidth;
|
||||||
|
int minHeight;
|
||||||
|
int maxWidth;
|
||||||
|
int maxHeight;
|
||||||
|
int frame;
|
||||||
|
|
||||||
|
// User Data
|
||||||
|
char *HTML;
|
||||||
|
|
||||||
|
// Callback
|
||||||
|
ffenestriCallback sendMessageToBackend;
|
||||||
|
|
||||||
|
// Bindings
|
||||||
|
const char *bindings;
|
||||||
|
|
||||||
|
// Lock - used for sync operations (Should we be using g_mutex?)
|
||||||
|
int lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
void *NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden)
|
||||||
|
{
|
||||||
|
// Setup main application struct
|
||||||
|
struct Application *result = malloc(sizeof(struct Application));
|
||||||
|
result->title = title;
|
||||||
|
result->width = width;
|
||||||
|
result->height = height;
|
||||||
|
result->resizable = resizable;
|
||||||
|
result->devtools = devtools;
|
||||||
|
result->fullscreen = fullscreen;
|
||||||
|
result->minWidth = 0;
|
||||||
|
result->minHeight = 0;
|
||||||
|
result->maxWidth = 0;
|
||||||
|
result->maxHeight = 0;
|
||||||
|
result->frame = 1;
|
||||||
|
result->startHidden = startHidden;
|
||||||
|
|
||||||
|
// Default drag button is PRIMARY
|
||||||
|
result->dragButton = PRIMARY_MOUSE_BUTTON;
|
||||||
|
|
||||||
|
result->sendMessageToBackend = (ffenestriCallback)messageFromWindowCallback;
|
||||||
|
|
||||||
|
// Create a unique ID based on the current unix timestamp
|
||||||
|
char temp[11];
|
||||||
|
sprintf(&temp[0], "%d", (int)time(NULL));
|
||||||
|
result->id = concat("wails.app", &temp[0]);
|
||||||
|
|
||||||
|
// Create the main GTK application
|
||||||
|
GApplicationFlags flags = G_APPLICATION_FLAGS_NONE;
|
||||||
|
result->application = gtk_application_new(result->id, flags);
|
||||||
|
|
||||||
|
// Return the application struct
|
||||||
|
return (void *)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DestroyApplication(struct Application *app)
|
||||||
|
{
|
||||||
|
Debug("Destroying Application");
|
||||||
|
|
||||||
|
g_application_quit(G_APPLICATION(app->application));
|
||||||
|
|
||||||
|
// Release the GTK ID string
|
||||||
|
if (app->id != NULL)
|
||||||
|
{
|
||||||
|
free(app->id);
|
||||||
|
app->id = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug("Almost a double free for app->id");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free the bindings
|
||||||
|
if (app->bindings != NULL)
|
||||||
|
{
|
||||||
|
free((void *)app->bindings);
|
||||||
|
app->bindings = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug("Almost a double free for app->bindings");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disconnect signal handlers
|
||||||
|
WebKitUserContentManager *manager = webkit_web_view_get_user_content_manager((WebKitWebView *)app->webView);
|
||||||
|
g_signal_handler_disconnect(manager, app->signalInvoke);
|
||||||
|
if( app->frame == 0) {
|
||||||
|
g_signal_handler_disconnect(manager, app->signalWindowDrag);
|
||||||
|
g_signal_handler_disconnect(app->webView, app->signalButtonPressed);
|
||||||
|
g_signal_handler_disconnect(app->webView, app->signalButtonReleased);
|
||||||
|
}
|
||||||
|
g_signal_handler_disconnect(app->webView, app->signalLoadChanged);
|
||||||
|
|
||||||
|
// Release the main GTK Application
|
||||||
|
if (app->application != NULL)
|
||||||
|
{
|
||||||
|
g_object_unref(app->application);
|
||||||
|
app->application = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug("Almost a double free for app->application");
|
||||||
|
}
|
||||||
|
Debug("Finished Destroying Application");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quit will stop the gtk application and free up all the memory
|
||||||
|
// used by the application
|
||||||
|
void Quit(struct Application *app)
|
||||||
|
{
|
||||||
|
Debug("Quit Called");
|
||||||
|
gtk_window_close((GtkWindow *)app->mainWindow);
|
||||||
|
g_application_quit((GApplication *)app->application);
|
||||||
|
DestroyApplication(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTitle sets the main window title to the given string
|
||||||
|
void SetTitle(struct Application *app, const char *title)
|
||||||
|
{
|
||||||
|
gtk_window_set_title(app->mainWindow, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fullscreen sets the main window to be fullscreen
|
||||||
|
void Fullscreen(struct Application *app)
|
||||||
|
{
|
||||||
|
gtk_window_fullscreen(app->mainWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnFullscreen resets the main window after a fullscreen
|
||||||
|
void UnFullscreen(struct Application *app)
|
||||||
|
{
|
||||||
|
gtk_window_unfullscreen(app->mainWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMinMaxSize(struct Application *app)
|
||||||
|
{
|
||||||
|
GdkGeometry size;
|
||||||
|
size.min_width = size.min_height = size.max_width = size.max_height = 0;
|
||||||
|
int flags = 0;
|
||||||
|
if (app->maxHeight > 0 && app->maxWidth > 0)
|
||||||
|
{
|
||||||
|
size.max_height = app->maxHeight;
|
||||||
|
size.max_width = app->maxWidth;
|
||||||
|
flags |= GDK_HINT_MAX_SIZE;
|
||||||
|
}
|
||||||
|
if (app->minHeight > 0 && app->minWidth > 0)
|
||||||
|
{
|
||||||
|
size.min_height = app->minHeight;
|
||||||
|
size.min_width = app->minWidth;
|
||||||
|
flags |= GDK_HINT_MIN_SIZE;
|
||||||
|
}
|
||||||
|
gtk_window_set_geometry_hints(app->mainWindow, NULL, &size, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *fileDialogInternal(struct Application *app, GtkFileChooserAction chooserAction, char **args) {
|
||||||
|
GtkFileChooserNative *native;
|
||||||
|
GtkFileChooserAction action = chooserAction;
|
||||||
|
gint res;
|
||||||
|
char *filename;
|
||||||
|
|
||||||
|
char *title = args[0];
|
||||||
|
char *filter = args[1];
|
||||||
|
|
||||||
|
native = gtk_file_chooser_native_new(title,
|
||||||
|
app->mainWindow,
|
||||||
|
action,
|
||||||
|
"_Open",
|
||||||
|
"_Cancel");
|
||||||
|
|
||||||
|
GtkFileChooser *chooser = GTK_FILE_CHOOSER(native);
|
||||||
|
|
||||||
|
// If we have filters, process them
|
||||||
|
if (filter[0] != '\0') {
|
||||||
|
GtkFileFilter *file_filter = gtk_file_filter_new();
|
||||||
|
gchar **filters = g_strsplit(filter, ",", -1);
|
||||||
|
gint i;
|
||||||
|
for(i = 0; filters && filters[i]; i++) {
|
||||||
|
gtk_file_filter_add_pattern(file_filter, filters[i]);
|
||||||
|
// Debug("Adding filter pattern: %s\n", filters[i]);
|
||||||
|
}
|
||||||
|
gtk_file_filter_set_name(file_filter, filter);
|
||||||
|
gtk_file_chooser_add_filter(chooser, file_filter);
|
||||||
|
g_strfreev(filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = gtk_native_dialog_run(GTK_NATIVE_DIALOG(native));
|
||||||
|
if (res == GTK_RESPONSE_ACCEPT)
|
||||||
|
{
|
||||||
|
filename = gtk_file_chooser_get_filename(chooser);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref(native);
|
||||||
|
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
// openFileDialogInternal opens a dialog to select a file
|
||||||
|
// NOTE: The result is a string that will need to be freed!
|
||||||
|
char *openFileDialogInternal(struct Application *app, char **args)
|
||||||
|
{
|
||||||
|
return fileDialogInternal(app, GTK_FILE_CHOOSER_ACTION_OPEN, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// saveFileDialogInternal opens a dialog to select a file
|
||||||
|
// NOTE: The result is a string that will need to be freed!
|
||||||
|
char *saveFileDialogInternal(struct Application *app, char **args)
|
||||||
|
{
|
||||||
|
return fileDialogInternal(app, GTK_FILE_CHOOSER_ACTION_SAVE, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// openDirectoryDialogInternal opens a dialog to select a directory
|
||||||
|
// NOTE: The result is a string that will need to be freed!
|
||||||
|
char *openDirectoryDialogInternal(struct Application *app, char **args)
|
||||||
|
{
|
||||||
|
return fileDialogInternal(app, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetMinWindowSize(struct Application *app, int minWidth, int minHeight)
|
||||||
|
{
|
||||||
|
app->minWidth = minWidth;
|
||||||
|
app->minHeight = minHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetMaxWindowSize(struct Application *app, int maxWidth, int maxHeight)
|
||||||
|
{
|
||||||
|
app->maxWidth = maxWidth;
|
||||||
|
app->maxHeight = maxHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetColour sets the colour of the webview to the given colour string
|
||||||
|
int SetColour(struct Application *app, const char *colourString)
|
||||||
|
{
|
||||||
|
GdkRGBA rgba;
|
||||||
|
gboolean result = gdk_rgba_parse(&rgba, colourString);
|
||||||
|
if (result == FALSE)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Debug("Setting webview colour to: %s", colourString);
|
||||||
|
webkit_web_view_get_background_color((WebKitWebView *)(app->webView), &rgba);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableFrame disables the window frame
|
||||||
|
void DisableFrame(struct Application *app)
|
||||||
|
{
|
||||||
|
app->frame = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void syncCallback(GObject *source_object,
|
||||||
|
GAsyncResult *res,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct Application *app = (struct Application *)data;
|
||||||
|
app->lock = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void syncEval(struct Application *app, const gchar *script)
|
||||||
|
{
|
||||||
|
|
||||||
|
WebKitWebView *webView = (WebKitWebView *)(app->webView);
|
||||||
|
|
||||||
|
// wait for lock to free
|
||||||
|
while (app->lock == 1)
|
||||||
|
{
|
||||||
|
g_main_context_iteration(0, true);
|
||||||
|
}
|
||||||
|
// Set lock
|
||||||
|
app->lock = 1;
|
||||||
|
|
||||||
|
webkit_web_view_run_javascript(
|
||||||
|
webView,
|
||||||
|
script,
|
||||||
|
NULL, syncCallback, (void*)app);
|
||||||
|
|
||||||
|
while (app->lock == 1)
|
||||||
|
{
|
||||||
|
g_main_context_iteration(0, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void asyncEval(WebKitWebView *webView, const gchar *script)
|
||||||
|
{
|
||||||
|
webkit_web_view_run_javascript(
|
||||||
|
webView,
|
||||||
|
script,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*dispatchMethod)(struct Application *app, void *);
|
||||||
|
|
||||||
|
struct dispatchData
|
||||||
|
{
|
||||||
|
struct Application *app;
|
||||||
|
dispatchMethod method;
|
||||||
|
void *args;
|
||||||
|
};
|
||||||
|
|
||||||
|
gboolean executeMethod(gpointer data)
|
||||||
|
{
|
||||||
|
struct dispatchData *d = (struct dispatchData *)data;
|
||||||
|
(d->method)(d->app, d->args);
|
||||||
|
g_free(d);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExecJS(struct Application *app, char *js)
|
||||||
|
{
|
||||||
|
struct dispatchData *data = (struct dispatchData *)g_new(struct dispatchData, 1);
|
||||||
|
data->method = (dispatchMethod)syncEval;
|
||||||
|
data->args = js;
|
||||||
|
data->app = app;
|
||||||
|
|
||||||
|
gdk_threads_add_idle(executeMethod, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef char *(*dialogMethod)(struct Application *app, void *);
|
||||||
|
|
||||||
|
struct dialogCall
|
||||||
|
{
|
||||||
|
struct Application *app;
|
||||||
|
dialogMethod method;
|
||||||
|
void *args;
|
||||||
|
void *filter;
|
||||||
|
char *result;
|
||||||
|
int done;
|
||||||
|
};
|
||||||
|
|
||||||
|
gboolean executeMethodWithReturn(gpointer data)
|
||||||
|
{
|
||||||
|
struct dialogCall *d = (struct dialogCall *)data;
|
||||||
|
|
||||||
|
d->result = (d->method)(d->app, d->args);
|
||||||
|
d->done = 1;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *OpenFileDialog(struct Application *app, char *title, char *filter)
|
||||||
|
{
|
||||||
|
struct dialogCall *data = (struct dialogCall *)g_new(struct dialogCall, 1);
|
||||||
|
data->result = NULL;
|
||||||
|
data->done = 0;
|
||||||
|
data->method = (dialogMethod)openFileDialogInternal;
|
||||||
|
const char* dialogArgs[]={ title, filter };
|
||||||
|
data->args = dialogArgs;
|
||||||
|
data->app = app;
|
||||||
|
|
||||||
|
gdk_threads_add_idle(executeMethodWithReturn, data);
|
||||||
|
|
||||||
|
while (data->done == 0)
|
||||||
|
{
|
||||||
|
usleep(100000);
|
||||||
|
}
|
||||||
|
g_free(data);
|
||||||
|
return data->result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *SaveFileDialog(struct Application *app, char *title, char *filter)
|
||||||
|
{
|
||||||
|
struct dialogCall *data = (struct dialogCall *)g_new(struct dialogCall, 1);
|
||||||
|
data->result = NULL;
|
||||||
|
data->done = 0;
|
||||||
|
data->method = (dialogMethod)saveFileDialogInternal;
|
||||||
|
const char* dialogArgs[]={ title, filter };
|
||||||
|
data->args = dialogArgs;
|
||||||
|
data->app = app;
|
||||||
|
|
||||||
|
gdk_threads_add_idle(executeMethodWithReturn, data);
|
||||||
|
|
||||||
|
while (data->done == 0)
|
||||||
|
{
|
||||||
|
usleep(100000);
|
||||||
|
}
|
||||||
|
Debug("Dialog done");
|
||||||
|
Debug("Result = %s\n", data->result);
|
||||||
|
|
||||||
|
g_free(data);
|
||||||
|
// Fingers crossed this wasn't freed by g_free above
|
||||||
|
return data->result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *OpenDirectoryDialog(struct Application *app, char *title, char *filter)
|
||||||
|
{
|
||||||
|
struct dialogCall *data = (struct dialogCall *)g_new(struct dialogCall, 1);
|
||||||
|
data->result = NULL;
|
||||||
|
data->done = 0;
|
||||||
|
data->method = (dialogMethod)openDirectoryDialogInternal;
|
||||||
|
const char* dialogArgs[]={ title, filter };
|
||||||
|
data->args = dialogArgs;
|
||||||
|
data->app = app;
|
||||||
|
|
||||||
|
gdk_threads_add_idle(executeMethodWithReturn, data);
|
||||||
|
|
||||||
|
while (data->done == 0)
|
||||||
|
{
|
||||||
|
usleep(100000);
|
||||||
|
}
|
||||||
|
Debug("Directory Dialog done");
|
||||||
|
Debug("Result = %s\n", data->result);
|
||||||
|
g_free(data);
|
||||||
|
// Fingers crossed this wasn't freed by g_free above
|
||||||
|
return data->result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the icon to the XPM stored in icon
|
||||||
|
void setIcon(struct Application *app)
|
||||||
|
{
|
||||||
|
GdkPixbuf *appIcon = gdk_pixbuf_new_from_xpm_data((const char **)icon);
|
||||||
|
gtk_window_set_icon(app->mainWindow, appIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load_finished_cb(WebKitWebView *webView,
|
||||||
|
WebKitLoadEvent load_event,
|
||||||
|
struct Application *app)
|
||||||
|
{
|
||||||
|
switch (load_event)
|
||||||
|
{
|
||||||
|
// case WEBKIT_LOAD_STARTED:
|
||||||
|
// /* New load, we have now a provisional URI */
|
||||||
|
// // printf("Start downloading %s\n", webkit_web_view_get_uri(web_view));
|
||||||
|
// /* Here we could start a spinner or update the
|
||||||
|
// * location bar with the provisional URI */
|
||||||
|
// break;
|
||||||
|
// case WEBKIT_LOAD_REDIRECTED:
|
||||||
|
// // printf("Redirected to: %s\n", webkit_web_view_get_uri(web_view));
|
||||||
|
// break;
|
||||||
|
// case WEBKIT_LOAD_COMMITTED:
|
||||||
|
// /* The load is being performed. Current URI is
|
||||||
|
// * the final one and it won't change unless a new
|
||||||
|
// * load is requested or a navigation within the
|
||||||
|
// * same page is performed */
|
||||||
|
// // printf("Loading: %s\n", webkit_web_view_get_uri(web_view));
|
||||||
|
// break;
|
||||||
|
case WEBKIT_LOAD_FINISHED:
|
||||||
|
/* Load finished, we can now stop the spinner */
|
||||||
|
// printf("Finished loading: %s\n", webkit_web_view_get_uri(web_view));
|
||||||
|
|
||||||
|
// Bindings
|
||||||
|
Debug("Binding Methods");
|
||||||
|
syncEval(app, app->bindings);
|
||||||
|
|
||||||
|
// Runtime
|
||||||
|
Debug("Setting up Wails runtime");
|
||||||
|
syncEval(app, &runtime);
|
||||||
|
|
||||||
|
// Loop over assets
|
||||||
|
int index = 1;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
// Get next asset pointer
|
||||||
|
const char *asset = assets[index];
|
||||||
|
|
||||||
|
// If we have no more assets, break
|
||||||
|
if (asset == 0x00)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sync eval the asset
|
||||||
|
syncEval(app, asset);
|
||||||
|
index++;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set the icon
|
||||||
|
setIcon(app);
|
||||||
|
|
||||||
|
// Setup fullscreen
|
||||||
|
if (app->fullscreen)
|
||||||
|
{
|
||||||
|
Debug("Going fullscreen");
|
||||||
|
Fullscreen(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup resize
|
||||||
|
gtk_window_resize(GTK_WINDOW(app->mainWindow), app->width, app->height);
|
||||||
|
|
||||||
|
if (app->resizable)
|
||||||
|
{
|
||||||
|
gtk_window_set_default_size(GTK_WINDOW(app->mainWindow), app->width, app->height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gtk_widget_set_size_request(GTK_WIDGET(app->mainWindow), app->width, app->height);
|
||||||
|
gtk_window_resize(GTK_WINDOW(app->mainWindow), app->width, app->height);
|
||||||
|
// Fix the min/max to the window size for good measure
|
||||||
|
app->minHeight = app->maxHeight = app->height;
|
||||||
|
app->minWidth = app->maxWidth = app->width;
|
||||||
|
}
|
||||||
|
gtk_window_set_resizable(GTK_WINDOW(app->mainWindow), app->resizable ? TRUE : FALSE);
|
||||||
|
setMinMaxSize(app);
|
||||||
|
|
||||||
|
// Centre by default
|
||||||
|
gtk_window_set_position(app->mainWindow, GTK_WIN_POS_CENTER);
|
||||||
|
|
||||||
|
// Show window and focus
|
||||||
|
if( app->startHidden == 0) {
|
||||||
|
gtk_widget_show_all(GTK_WIDGET(app->mainWindow));
|
||||||
|
gtk_widget_grab_focus(app->webView);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean disable_context_menu_cb(
|
||||||
|
WebKitWebView *web_view,
|
||||||
|
WebKitContextMenu *context_menu,
|
||||||
|
GdkEvent *event,
|
||||||
|
WebKitHitTestResult *hit_test_result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printEvent(const char *message, GdkEventButton *event)
|
||||||
|
{
|
||||||
|
Debug("%s: [button:%d] [x:%f] [y:%f] [time:%d]",
|
||||||
|
message,
|
||||||
|
event->button,
|
||||||
|
event->x_root,
|
||||||
|
event->y_root,
|
||||||
|
event->time);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void dragWindow(WebKitUserContentManager *contentManager,
|
||||||
|
WebKitJavascriptResult *result,
|
||||||
|
struct Application *app)
|
||||||
|
{
|
||||||
|
// If we get this message erroneously, ignore
|
||||||
|
if (app->dragButtonEvent == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore non-toplevel widgets
|
||||||
|
GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(app->webView));
|
||||||
|
if (!GTK_IS_WINDOW(window))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initiate the drag
|
||||||
|
printEvent("Starting drag with event", app->dragButtonEvent);
|
||||||
|
|
||||||
|
gtk_window_begin_move_drag(app->mainWindow,
|
||||||
|
app->dragButton,
|
||||||
|
app->dragButtonEvent->x_root,
|
||||||
|
app->dragButtonEvent->y_root,
|
||||||
|
app->dragButtonEvent->time);
|
||||||
|
// Clear the event
|
||||||
|
app->dragButtonEvent = NULL;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean buttonPress(GtkWidget *widget, GdkEventButton *event, struct Application *app)
|
||||||
|
{
|
||||||
|
if (event->type == GDK_BUTTON_PRESS && event->button == app->dragButton)
|
||||||
|
{
|
||||||
|
app->dragButtonEvent = event;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean buttonRelease(GtkWidget *widget, GdkEventButton *event, struct Application *app)
|
||||||
|
{
|
||||||
|
if (event->type == GDK_BUTTON_RELEASE && event->button == app->dragButton)
|
||||||
|
{
|
||||||
|
app->dragButtonEvent = NULL;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sendMessageToBackend(WebKitUserContentManager *contentManager,
|
||||||
|
WebKitJavascriptResult *result,
|
||||||
|
struct Application *app)
|
||||||
|
{
|
||||||
|
#if WEBKIT_MAJOR_VERSION >= 2 && WEBKIT_MINOR_VERSION >= 22
|
||||||
|
JSCValue *value = webkit_javascript_result_get_js_value(result);
|
||||||
|
char *message = jsc_value_to_string(value);
|
||||||
|
#else
|
||||||
|
JSGlobalContextRef context = webkit_javascript_result_get_global_context(result);
|
||||||
|
JSValueRef value = webkit_javascript_result_get_value(result);
|
||||||
|
JSStringRef js = JSValueToStringCopy(context, value, NULL);
|
||||||
|
size_t messageSize = JSStringGetMaximumUTF8CStringSize(js);
|
||||||
|
char *message = g_new(char, messageSize);
|
||||||
|
JSStringGetUTF8CString(js, message, messageSize);
|
||||||
|
JSStringRelease(js);
|
||||||
|
#endif
|
||||||
|
app->sendMessageToBackend(message);
|
||||||
|
g_free(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetDebug(struct Application *app, int flag)
|
||||||
|
{
|
||||||
|
debug = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCurrentMonitorGeometry gets the geometry of the monitor
|
||||||
|
// that the window is mostly on.
|
||||||
|
GdkRectangle getCurrentMonitorGeometry(GtkWindow *window) {
|
||||||
|
// Get the monitor that the window is currently on
|
||||||
|
GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(window));
|
||||||
|
GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(window));
|
||||||
|
GdkMonitor *monitor = gdk_display_get_monitor_at_window (display, gdk_window);
|
||||||
|
|
||||||
|
// Get the geometry of the monitor
|
||||||
|
GdkRectangle result;
|
||||||
|
gdk_monitor_get_geometry (monitor,&result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************
|
||||||
|
* Window Position *
|
||||||
|
*******************/
|
||||||
|
|
||||||
|
// Position holds an x/y corrdinate
|
||||||
|
struct Position {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal call for setting the position of the window.
|
||||||
|
void setPositionInternal(struct Application *app, struct Position *pos) {
|
||||||
|
|
||||||
|
// Get the monitor geometry
|
||||||
|
GdkRectangle m = getCurrentMonitorGeometry(app->mainWindow);
|
||||||
|
|
||||||
|
// Move the window relative to the monitor
|
||||||
|
gtk_window_move(app->mainWindow, m.x + pos->x, m.y + pos->y);
|
||||||
|
|
||||||
|
// Free memory
|
||||||
|
free(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPosition sets the position of the window to the given x/y
|
||||||
|
// coordinates. The x/y values are relative to the monitor
|
||||||
|
// the window is mostly on.
|
||||||
|
void SetPosition(struct Application *app, int x, int y) {
|
||||||
|
struct dispatchData *data = (struct dispatchData *)g_new(struct dispatchData, 1);
|
||||||
|
data->method = (dispatchMethod)setPositionInternal;
|
||||||
|
struct Position *pos = malloc(sizeof(struct Position));
|
||||||
|
pos->x = x;
|
||||||
|
pos->y = y;
|
||||||
|
data->args = pos;
|
||||||
|
data->app = app;
|
||||||
|
|
||||||
|
gdk_threads_add_idle(executeMethod, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************
|
||||||
|
* Window Size *
|
||||||
|
***************/
|
||||||
|
|
||||||
|
// Size holds a width/height
|
||||||
|
struct Size {
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal call for setting the size of the window.
|
||||||
|
void setSizeInternal(struct Application *app, struct Size *size) {
|
||||||
|
gtk_window_resize(app->mainWindow, size->width, size->height);
|
||||||
|
free(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSize sets the size of the window to the given width/height
|
||||||
|
void SetSize(struct Application *app, int width, int height) {
|
||||||
|
struct dispatchData *data = (struct dispatchData *)g_new(struct dispatchData, 1);
|
||||||
|
data->method = (dispatchMethod)setSizeInternal;
|
||||||
|
struct Size *size = malloc(sizeof(struct Size));
|
||||||
|
size->width = width;
|
||||||
|
size->height = height;
|
||||||
|
data->args = size;
|
||||||
|
data->app = app;
|
||||||
|
|
||||||
|
gdk_threads_add_idle(executeMethod, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// centerInternal will center the main window on the monitor it is mostly in
|
||||||
|
void centerInternal(struct Application *app)
|
||||||
|
{
|
||||||
|
// Get the geometry of the monitor
|
||||||
|
GdkRectangle m = getCurrentMonitorGeometry(app->mainWindow);
|
||||||
|
|
||||||
|
// Get the window width/height
|
||||||
|
int windowWidth, windowHeight;
|
||||||
|
gtk_window_get_size(app->mainWindow, &windowWidth, &windowHeight);
|
||||||
|
|
||||||
|
// Place the window at the center of the monitor
|
||||||
|
gtk_window_move(app->mainWindow, ((m.width - windowWidth) / 2) + m.x, ((m.height - windowHeight) / 2) + m.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Center the window
|
||||||
|
void Center(struct Application *app) {
|
||||||
|
|
||||||
|
// Setup a call to centerInternal on the main thread
|
||||||
|
struct dispatchData *data = (struct dispatchData *)g_new(struct dispatchData, 1);
|
||||||
|
data->method = (dispatchMethod)centerInternal;
|
||||||
|
data->app = app;
|
||||||
|
|
||||||
|
// Add call to main thread
|
||||||
|
gdk_threads_add_idle(executeMethod, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// hideInternal hides the main window
|
||||||
|
void hideInternal(struct Application *app) {
|
||||||
|
gtk_widget_hide (GTK_WIDGET(app->mainWindow));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide places the hideInternal method onto the main thread for execution
|
||||||
|
void Hide(struct Application *app) {
|
||||||
|
|
||||||
|
// Setup a call to hideInternal on the main thread
|
||||||
|
struct dispatchData *data = (struct dispatchData *)g_new(struct dispatchData, 1);
|
||||||
|
data->method = (dispatchMethod)hideInternal;
|
||||||
|
data->app = app;
|
||||||
|
|
||||||
|
// Add call to main thread
|
||||||
|
gdk_threads_add_idle(executeMethod, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// showInternal shows the main window
|
||||||
|
void showInternal(struct Application *app) {
|
||||||
|
gtk_widget_show_all(GTK_WIDGET(app->mainWindow));
|
||||||
|
gtk_widget_grab_focus(app->webView);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show places the showInternal method onto the main thread for execution
|
||||||
|
void Show(struct Application *app) {
|
||||||
|
struct dispatchData *data = (struct dispatchData *)g_new(struct dispatchData, 1);
|
||||||
|
data->method = (dispatchMethod)showInternal;
|
||||||
|
data->app = app;
|
||||||
|
|
||||||
|
gdk_threads_add_idle(executeMethod, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// maximiseInternal maximises the main window
|
||||||
|
void maximiseInternal(struct Application *app) {
|
||||||
|
gtk_window_maximize(GTK_WIDGET(app->mainWindow));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maximise places the maximiseInternal method onto the main thread for execution
|
||||||
|
void Maximise(struct Application *app) {
|
||||||
|
|
||||||
|
// Setup a call to maximiseInternal on the main thread
|
||||||
|
struct dispatchData *data = (struct dispatchData *)g_new(struct dispatchData, 1);
|
||||||
|
data->method = (dispatchMethod)maximiseInternal;
|
||||||
|
data->app = app;
|
||||||
|
|
||||||
|
// Add call to main thread
|
||||||
|
gdk_threads_add_idle(executeMethod, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmaximiseInternal unmaximises the main window
|
||||||
|
void unmaximiseInternal(struct Application *app) {
|
||||||
|
gtk_window_unmaximize(GTK_WIDGET(app->mainWindow));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmaximise places the unmaximiseInternal method onto the main thread for execution
|
||||||
|
void Unmaximise(struct Application *app) {
|
||||||
|
|
||||||
|
// Setup a call to unmaximiseInternal on the main thread
|
||||||
|
struct dispatchData *data = (struct dispatchData *)g_new(struct dispatchData, 1);
|
||||||
|
data->method = (dispatchMethod)unmaximiseInternal;
|
||||||
|
data->app = app;
|
||||||
|
|
||||||
|
// Add call to main thread
|
||||||
|
gdk_threads_add_idle(executeMethod, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// minimiseInternal minimises the main window
|
||||||
|
void minimiseInternal(struct Application *app) {
|
||||||
|
gtk_window_iconify(app->mainWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minimise places the minimiseInternal method onto the main thread for execution
|
||||||
|
void Minimise(struct Application *app) {
|
||||||
|
|
||||||
|
// Setup a call to minimiseInternal on the main thread
|
||||||
|
struct dispatchData *data = (struct dispatchData *)g_new(struct dispatchData, 1);
|
||||||
|
data->method = (dispatchMethod)minimiseInternal;
|
||||||
|
data->app = app;
|
||||||
|
|
||||||
|
// Add call to main thread
|
||||||
|
gdk_threads_add_idle(executeMethod, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// unminimiseInternal unminimises the main window
|
||||||
|
void unminimiseInternal(struct Application *app) {
|
||||||
|
gtk_window_present(app->mainWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unminimise places the unminimiseInternal method onto the main thread for execution
|
||||||
|
void Unminimise(struct Application *app) {
|
||||||
|
|
||||||
|
// Setup a call to unminimiseInternal on the main thread
|
||||||
|
struct dispatchData *data = (struct dispatchData *)g_new(struct dispatchData, 1);
|
||||||
|
data->method = (dispatchMethod)unminimiseInternal;
|
||||||
|
data->app = app;
|
||||||
|
|
||||||
|
// Add call to main thread
|
||||||
|
gdk_threads_add_idle(executeMethod, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SetBindings(struct Application *app, const char *bindings)
|
||||||
|
{
|
||||||
|
const char *temp = concat("window.wailsbindings = \"", bindings);
|
||||||
|
const char *jscall = concat(temp, "\";");
|
||||||
|
free((void *)temp);
|
||||||
|
app->bindings = jscall;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is called when the close button on the window is pressed
|
||||||
|
gboolean close_button_pressed(GtkWidget *widget,
|
||||||
|
GdkEvent *event,
|
||||||
|
struct Application *app)
|
||||||
|
{
|
||||||
|
app->sendMessageToBackend("WC"); // Window Close
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setupWindow(struct Application *app)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Create the window
|
||||||
|
GtkWidget *mainWindow = gtk_application_window_new(app->application);
|
||||||
|
// Save reference
|
||||||
|
app->mainWindow = GTK_WINDOW(mainWindow);
|
||||||
|
|
||||||
|
// Setup frame
|
||||||
|
gtk_window_set_decorated((GtkWindow *)mainWindow, app->frame);
|
||||||
|
|
||||||
|
// Setup title
|
||||||
|
gtk_window_set_title(GTK_WINDOW(mainWindow), app->title);
|
||||||
|
|
||||||
|
// Setup script handler
|
||||||
|
WebKitUserContentManager *contentManager = webkit_user_content_manager_new();
|
||||||
|
|
||||||
|
// Setup the invoke handler
|
||||||
|
webkit_user_content_manager_register_script_message_handler(contentManager, "external");
|
||||||
|
app->signalInvoke = g_signal_connect(contentManager, "script-message-received::external", G_CALLBACK(sendMessageToBackend), app);
|
||||||
|
|
||||||
|
// Setup the window drag handler if this is a frameless app
|
||||||
|
if ( app->frame == 0 ) {
|
||||||
|
webkit_user_content_manager_register_script_message_handler(contentManager, "windowDrag");
|
||||||
|
app->signalWindowDrag = g_signal_connect(contentManager, "script-message-received::windowDrag", G_CALLBACK(dragWindow), app);
|
||||||
|
// Setup the mouse handlers
|
||||||
|
app->signalButtonPressed = g_signal_connect(app->webView, "button-press-event", G_CALLBACK(buttonPress), app);
|
||||||
|
app->signalButtonReleased = g_signal_connect(app->webView, "button-release-event", G_CALLBACK(buttonRelease), app);
|
||||||
|
}
|
||||||
|
GtkWidget *webView = webkit_web_view_new_with_user_content_manager(contentManager);
|
||||||
|
|
||||||
|
// Save reference
|
||||||
|
app->webView = webView;
|
||||||
|
|
||||||
|
// Add the webview to the window
|
||||||
|
gtk_container_add(GTK_CONTAINER(mainWindow), webView);
|
||||||
|
|
||||||
|
|
||||||
|
// Load default HTML
|
||||||
|
app->signalLoadChanged = g_signal_connect(G_OBJECT(webView), "load-changed", G_CALLBACK(load_finished_cb), app);
|
||||||
|
|
||||||
|
// Load the user's HTML
|
||||||
|
// assets[0] is the HTML because the asset array is bundled like that by convention
|
||||||
|
webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webView), assets[0]);
|
||||||
|
|
||||||
|
// Check if we want to enable the dev tools
|
||||||
|
if (app->devtools)
|
||||||
|
{
|
||||||
|
WebKitSettings *settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webView));
|
||||||
|
// webkit_settings_set_enable_write_console_messages_to_stdout(settings, true);
|
||||||
|
webkit_settings_set_enable_developer_extras(settings, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_signal_connect(G_OBJECT(webView), "context-menu", G_CALLBACK(disable_context_menu_cb), app);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen for close button signal
|
||||||
|
g_signal_connect(GTK_WIDGET(mainWindow), "delete-event", G_CALLBACK(close_button_pressed), app);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void activate(GtkApplication* _, struct Application *app)
|
||||||
|
{
|
||||||
|
setupWindow(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Run(struct Application *app, int argc, char **argv)
|
||||||
|
{
|
||||||
|
g_signal_connect(app->application, "activate", G_CALLBACK(activate), app);
|
||||||
|
g_application_run(G_APPLICATION(app->application), argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
1383
v2/internal/ffenestri/json.c
Normal file
1383
v2/internal/ffenestri/json.c
Normal file
File diff suppressed because it is too large
Load Diff
119
v2/internal/ffenestri/json.h
Normal file
119
v2/internal/ffenestri/json.h
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) 2011 Joseph A. Adams (joeyadams3.14159@gmail.com)
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
Source: http://git.ozlabs.org/?p=ccan;a=tree;f=ccan/json;hb=HEAD
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CCAN_JSON_H
|
||||||
|
#define CCAN_JSON_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
JSON_NULL,
|
||||||
|
JSON_BOOL,
|
||||||
|
JSON_STRING,
|
||||||
|
JSON_NUMBER,
|
||||||
|
JSON_ARRAY,
|
||||||
|
JSON_OBJECT,
|
||||||
|
} JsonTag;
|
||||||
|
|
||||||
|
typedef struct JsonNode JsonNode;
|
||||||
|
|
||||||
|
struct JsonNode
|
||||||
|
{
|
||||||
|
/* only if parent is an object or array (NULL otherwise) */
|
||||||
|
JsonNode *parent;
|
||||||
|
JsonNode *prev, *next;
|
||||||
|
|
||||||
|
/* only if parent is an object (NULL otherwise) */
|
||||||
|
char *key; /* Must be valid UTF-8. */
|
||||||
|
|
||||||
|
JsonTag tag;
|
||||||
|
union {
|
||||||
|
/* JSON_BOOL */
|
||||||
|
bool bool_;
|
||||||
|
|
||||||
|
/* JSON_STRING */
|
||||||
|
char *string_; /* Must be valid UTF-8. */
|
||||||
|
|
||||||
|
/* JSON_NUMBER */
|
||||||
|
double number_;
|
||||||
|
|
||||||
|
/* JSON_ARRAY */
|
||||||
|
/* JSON_OBJECT */
|
||||||
|
struct {
|
||||||
|
JsonNode *head, *tail;
|
||||||
|
} children;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/*** Encoding, decoding, and validation ***/
|
||||||
|
|
||||||
|
JsonNode *json_decode (const char *json);
|
||||||
|
char *json_encode (const JsonNode *node);
|
||||||
|
char *json_encode_string (const char *str);
|
||||||
|
char *json_stringify (const JsonNode *node, const char *space);
|
||||||
|
void json_delete (JsonNode *node);
|
||||||
|
|
||||||
|
bool json_validate (const char *json);
|
||||||
|
|
||||||
|
/*** Lookup and traversal ***/
|
||||||
|
|
||||||
|
JsonNode *json_find_element (JsonNode *array, int index);
|
||||||
|
JsonNode *json_find_member (JsonNode *object, const char *key);
|
||||||
|
|
||||||
|
JsonNode *json_first_child (const JsonNode *node);
|
||||||
|
|
||||||
|
#define json_foreach(i, object_or_array) \
|
||||||
|
for ((i) = json_first_child(object_or_array); \
|
||||||
|
(i) != NULL; \
|
||||||
|
(i) = (i)->next)
|
||||||
|
|
||||||
|
/*** Construction and manipulation ***/
|
||||||
|
|
||||||
|
JsonNode *json_mknull(void);
|
||||||
|
JsonNode *json_mkbool(bool b);
|
||||||
|
JsonNode *json_mkstring(const char *s);
|
||||||
|
JsonNode *json_mknumber(double n);
|
||||||
|
JsonNode *json_mkarray(void);
|
||||||
|
JsonNode *json_mkobject(void);
|
||||||
|
|
||||||
|
void json_append_element(JsonNode *array, JsonNode *element);
|
||||||
|
void json_prepend_element(JsonNode *array, JsonNode *element);
|
||||||
|
void json_append_member(JsonNode *object, const char *key, JsonNode *value);
|
||||||
|
void json_prepend_member(JsonNode *object, const char *key, JsonNode *value);
|
||||||
|
|
||||||
|
void json_remove_from_parent(JsonNode *node);
|
||||||
|
|
||||||
|
/*** Debugging ***/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for structure and encoding problems in a JsonNode or its descendents.
|
||||||
|
*
|
||||||
|
* If a problem is detected, return false, writing a description of the problem
|
||||||
|
* to errmsg (unless errmsg is NULL).
|
||||||
|
*/
|
||||||
|
bool json_check(const JsonNode *node, char errmsg[256]);
|
||||||
|
|
||||||
|
#endif
|
||||||
202
v2/internal/fs/fs.go
Normal file
202
v2/internal/fs/fs.go
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
package fs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/leaanthony/slicer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LocalDirectory gets the caller's file directory
|
||||||
|
// Equivalent to node's __DIRNAME
|
||||||
|
func LocalDirectory() string {
|
||||||
|
_, thisFile, _, _ := runtime.Caller(1)
|
||||||
|
return filepath.Dir(thisFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RelativeToCwd returns an absolute path based on the cwd
|
||||||
|
// and the given relative path
|
||||||
|
func RelativeToCwd(relativePath string) (string, error) {
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return filepath.Join(cwd, relativePath), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mkdir will create the given directory
|
||||||
|
func Mkdir(dirname string) error {
|
||||||
|
return os.Mkdir(dirname, 0755)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteFile will delete the given file
|
||||||
|
func DeleteFile(filename string) error {
|
||||||
|
return os.Remove(filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyFile from source to target
|
||||||
|
func CopyFile(source string, target string) error {
|
||||||
|
s, err := os.Open(source)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
d, err := os.Create(target)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := io.Copy(d, s); err != nil {
|
||||||
|
d.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return d.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DirExists - Returns true if the given path resolves to a directory on the filesystem
|
||||||
|
func DirExists(path string) bool {
|
||||||
|
fi, err := os.Lstat(path)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return fi.Mode().IsDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileExists returns a boolean value indicating whether
|
||||||
|
// the given file exists
|
||||||
|
func FileExists(path string) bool {
|
||||||
|
fi, err := os.Lstat(path)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return fi.Mode().IsRegular()
|
||||||
|
}
|
||||||
|
|
||||||
|
// RelativePath returns a qualified path created by joining the
|
||||||
|
// directory of the calling file and the given relative path.
|
||||||
|
//
|
||||||
|
// Example: RelativePath("..") in *this* file would give you '/path/to/wails2/v2/internal`
|
||||||
|
func RelativePath(relativepath string, optionalpaths ...string) string {
|
||||||
|
_, thisFile, _, _ := runtime.Caller(1)
|
||||||
|
localDir := filepath.Dir(thisFile)
|
||||||
|
|
||||||
|
// If we have optional paths, join them to the relativepath
|
||||||
|
if len(optionalpaths) > 0 {
|
||||||
|
paths := []string{relativepath}
|
||||||
|
paths = append(paths, optionalpaths...)
|
||||||
|
relativepath = filepath.Join(paths...)
|
||||||
|
}
|
||||||
|
result, err := filepath.Abs(filepath.Join(localDir, relativepath))
|
||||||
|
if err != nil {
|
||||||
|
// I'm allowing this for 1 reason only: It's fatal if the path
|
||||||
|
// supplied is wrong as it's only used internally in Wails. If we get
|
||||||
|
// that path wrong, we should know about it immediately. The other reason is
|
||||||
|
// that it cuts down a ton of unnecassary error handling.
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustLoadString attempts to load a string and will abort with a fatal message if
|
||||||
|
// something goes wrong
|
||||||
|
func MustLoadString(filename string) string {
|
||||||
|
data, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("FATAL: Unable to load file '%s': %s\n", filename, err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return *(*string)(unsafe.Pointer(&data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MD5File returns the md5sum of the given file
|
||||||
|
func MD5File(filename string) (string, error) {
|
||||||
|
f, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
h := md5.New()
|
||||||
|
if _, err := io.Copy(h, f); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%x", h.Sum(nil)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustMD5File will call MD5File and abort the program on error
|
||||||
|
func MustMD5File(filename string) string {
|
||||||
|
result, err := MD5File(filename)
|
||||||
|
if err != nil {
|
||||||
|
println("FATAL: Unable to MD5Sum file:", err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustWriteString will attempt to write the given data to the given filename
|
||||||
|
// It will abort the program in the event of a failure
|
||||||
|
func MustWriteString(filename string, data string) {
|
||||||
|
err := ioutil.WriteFile(filename, []byte(data), 0755)
|
||||||
|
if err != nil {
|
||||||
|
fatal("Unable to write file", filename, ":", err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fatal will print the optional messages and die
|
||||||
|
func fatal(message ...string) {
|
||||||
|
if len(message) > 0 {
|
||||||
|
print("FATAL:")
|
||||||
|
for text := range message {
|
||||||
|
print(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSubdirectories returns a list of subdirectories for the given root directory
|
||||||
|
func GetSubdirectories(rootDir string) (*slicer.StringSlicer, error) {
|
||||||
|
var result slicer.StringSlicer
|
||||||
|
|
||||||
|
// Iterate root dir
|
||||||
|
err := filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// If we have a directory, save it
|
||||||
|
if info.IsDir() {
|
||||||
|
result.Add(path)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return &result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func DirIsEmpty(dir string) (bool, error) {
|
||||||
|
|
||||||
|
if !DirExists(dir) {
|
||||||
|
return false, fmt.Errorf("DirIsEmpty called with a non-existant directory: %s", dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CREDIT: https://stackoverflow.com/a/30708914/8325411
|
||||||
|
f, err := os.Open(dir)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
_, err = f.Readdirnames(1) // Or f.Readdir(1)
|
||||||
|
if err == io.EOF {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, err // Either not empty or error, suits both cases
|
||||||
|
}
|
||||||
31
v2/internal/fs/fs_test.go
Normal file
31
v2/internal/fs/fs_test.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package fs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/matryer/is"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRelativePath(t *testing.T) {
|
||||||
|
|
||||||
|
is := is.New(t)
|
||||||
|
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
is.Equal(err, nil)
|
||||||
|
|
||||||
|
// Check current directory
|
||||||
|
actual := RelativePath(".")
|
||||||
|
is.Equal(actual, cwd)
|
||||||
|
|
||||||
|
// Check 2 parameters
|
||||||
|
actual = RelativePath("..", "fs")
|
||||||
|
is.Equal(actual, cwd)
|
||||||
|
|
||||||
|
// Check 3 parameters including filename
|
||||||
|
actual = RelativePath("..", "fs", "fs.go")
|
||||||
|
expected := filepath.Join(cwd, "fs.go")
|
||||||
|
is.Equal(actual, expected)
|
||||||
|
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user