Switch remote deploy to vendored source builds
Move remote deployment to a vendored source bundle built on the target host via Docker so redeploys no longer require local cross-compilation or host Go installation. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
102
vendor/github.com/wailsapp/wails/v2/pkg/application/application.go
generated
vendored
Normal file
102
vendor/github.com/wailsapp/wails/v2/pkg/application/application.go
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/app"
|
||||
"github.com/wailsapp/wails/v2/internal/signal"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
// Application is the main Wails application
|
||||
type Application struct {
|
||||
application *app.App
|
||||
options *options.App
|
||||
|
||||
// running flag
|
||||
running bool
|
||||
|
||||
shutdown sync.Once
|
||||
}
|
||||
|
||||
// NewWithOptions creates a new Application with the given options
|
||||
func NewWithOptions(options *options.App) *Application {
|
||||
if options == nil {
|
||||
return New()
|
||||
}
|
||||
return &Application{
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
// New creates a new Application with the default options
|
||||
func New() *Application {
|
||||
return &Application{
|
||||
options: &options.App{},
|
||||
}
|
||||
}
|
||||
|
||||
// SetApplicationMenu sets the application menu
|
||||
func (a *Application) SetApplicationMenu(appMenu *menu.Menu) {
|
||||
if a.running {
|
||||
a.application.SetApplicationMenu(appMenu)
|
||||
return
|
||||
}
|
||||
|
||||
a.options.Menu = appMenu
|
||||
}
|
||||
|
||||
// Run starts the application
|
||||
func (a *Application) Run() error {
|
||||
err := applicationInit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
application, err := app.CreateApp(a.options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.application = application
|
||||
|
||||
// Control-C handlers
|
||||
signal.OnShutdown(func() {
|
||||
a.application.Shutdown()
|
||||
})
|
||||
signal.Start()
|
||||
|
||||
a.running = true
|
||||
|
||||
err = a.application.Run()
|
||||
return err
|
||||
}
|
||||
|
||||
// Quit will shut down the application
|
||||
func (a *Application) Quit() {
|
||||
a.shutdown.Do(func() {
|
||||
a.application.Shutdown()
|
||||
})
|
||||
}
|
||||
|
||||
// Bind the given struct to the application
|
||||
func (a *Application) Bind(boundStruct any) {
|
||||
a.options.Bind = append(a.options.Bind, boundStruct)
|
||||
}
|
||||
|
||||
func (a *Application) On(eventType EventType, callback func()) {
|
||||
c := func(ctx context.Context) {
|
||||
callback()
|
||||
}
|
||||
|
||||
switch eventType {
|
||||
case StartUp:
|
||||
a.options.OnStartup = c
|
||||
case ShutDown:
|
||||
a.options.OnShutdown = c
|
||||
case DomReady:
|
||||
a.options.OnDomReady = c
|
||||
}
|
||||
}
|
||||
9
vendor/github.com/wailsapp/wails/v2/pkg/application/events.go
generated
vendored
Normal file
9
vendor/github.com/wailsapp/wails/v2/pkg/application/events.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package application
|
||||
|
||||
type EventType int
|
||||
|
||||
const (
|
||||
StartUp EventType = iota
|
||||
ShutDown
|
||||
DomReady
|
||||
)
|
||||
8
vendor/github.com/wailsapp/wails/v2/pkg/application/init.go
generated
vendored
Normal file
8
vendor/github.com/wailsapp/wails/v2/pkg/application/init.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package application
|
||||
|
||||
func applicationInit() error {
|
||||
return nil
|
||||
}
|
||||
16
vendor/github.com/wailsapp/wails/v2/pkg/application/init_windows.go
generated
vendored
Normal file
16
vendor/github.com/wailsapp/wails/v2/pkg/application/init_windows.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
//go:build windows
|
||||
|
||||
package application
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func applicationInit() error {
|
||||
status, r, err := syscall.NewLazyDLL("user32.dll").NewProc("SetProcessDPIAware").Call()
|
||||
if status == 0 {
|
||||
return fmt.Errorf("exit status %d: %v %v", status, r, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
205
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/assethandler.go
generated
vendored
Normal file
205
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/assethandler.go
generated
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
iofs "io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
||||
)
|
||||
|
||||
type Logger interface {
|
||||
Debug(message string, args ...interface{})
|
||||
Error(message string, args ...interface{})
|
||||
}
|
||||
|
||||
//go:embed defaultindex.html
|
||||
var defaultHTML []byte
|
||||
|
||||
const (
|
||||
indexHTML = "index.html"
|
||||
)
|
||||
|
||||
type assetHandler struct {
|
||||
fs iofs.FS
|
||||
handler http.Handler
|
||||
|
||||
logger Logger
|
||||
|
||||
retryMissingFiles bool
|
||||
}
|
||||
|
||||
func NewAssetHandler(options assetserver.Options, log Logger) (http.Handler, error) {
|
||||
vfs := options.Assets
|
||||
if vfs != nil {
|
||||
if _, err := vfs.Open("."); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
subDir, err := FindPathToFile(vfs, indexHTML)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
msg := "no `index.html` could be found in your Assets fs.FS"
|
||||
if embedFs, isEmbedFs := vfs.(embed.FS); isEmbedFs {
|
||||
rootFolder, _ := FindEmbedRootPath(embedFs)
|
||||
msg += fmt.Sprintf(", please make sure the embedded directory '%s' is correct and contains your assets", rootFolder)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf(msg)
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vfs, err = iofs.Sub(vfs, path.Clean(subDir))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var result http.Handler = &assetHandler{
|
||||
fs: vfs,
|
||||
handler: options.Handler,
|
||||
logger: log,
|
||||
}
|
||||
|
||||
if middleware := options.Middleware; middleware != nil {
|
||||
result = middleware(result)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (d *assetHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
url := req.URL.Path
|
||||
handler := d.handler
|
||||
if strings.EqualFold(req.Method, http.MethodGet) {
|
||||
filename := path.Clean(strings.TrimPrefix(url, "/"))
|
||||
|
||||
d.logDebug("Handling request '%s' (file='%s')", url, filename)
|
||||
if err := d.serveFSFile(rw, req, filename); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
if handler != nil {
|
||||
d.logDebug("File '%s' not found, serving '%s' by AssetHandler", filename, url)
|
||||
handler.ServeHTTP(rw, req)
|
||||
err = nil
|
||||
} else {
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
d.logError("Unable to handle request '%s': %s", url, err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
} else if handler != nil {
|
||||
d.logDebug("No GET request, serving '%s' by AssetHandler", url)
|
||||
handler.ServeHTTP(rw, req)
|
||||
} else {
|
||||
rw.WriteHeader(http.StatusMethodNotAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
// serveFSFile will try to load the file from the fs.FS and write it to the response
|
||||
func (d *assetHandler) serveFSFile(rw http.ResponseWriter, req *http.Request, filename string) error {
|
||||
if d.fs == nil {
|
||||
return os.ErrNotExist
|
||||
}
|
||||
|
||||
file, err := d.fs.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
statInfo, err := file.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
url := req.URL.Path
|
||||
isDirectoryPath := url == "" || url[len(url)-1] == '/'
|
||||
if statInfo.IsDir() {
|
||||
if !isDirectoryPath {
|
||||
// If the URL doesn't end in a slash normally a http.redirect should be done, but that currently doesn't work on
|
||||
// WebKit WebViews (macOS/Linux).
|
||||
// So we handle this as a specific error
|
||||
return fmt.Errorf("a directory has been requested without a trailing slash, please add a trailing slash to your request")
|
||||
}
|
||||
|
||||
filename = path.Join(filename, indexHTML)
|
||||
|
||||
file, err = d.fs.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
statInfo, err = file.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if isDirectoryPath {
|
||||
return fmt.Errorf("a file has been requested with a trailing slash, please remove the trailing slash from your request")
|
||||
}
|
||||
|
||||
var buf [512]byte
|
||||
var n int
|
||||
if _, haveType := rw.Header()[HeaderContentType]; !haveType {
|
||||
// Detect MimeType by sniffing the first 512 bytes
|
||||
n, err = file.Read(buf[:])
|
||||
if err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
// Do the custom MimeType sniffing even though http.ServeContent would do it in case
|
||||
// of an io.ReadSeeker. We would like to have a consistent behaviour in both cases.
|
||||
if contentType := GetMimetype(filename, buf[:n]); contentType != "" {
|
||||
rw.Header().Set(HeaderContentType, contentType)
|
||||
}
|
||||
}
|
||||
|
||||
if fileSeeker, _ := file.(io.ReadSeeker); fileSeeker != nil {
|
||||
if _, err := fileSeeker.Seek(0, io.SeekStart); err != nil {
|
||||
return fmt.Errorf("seeker can't seek")
|
||||
}
|
||||
|
||||
http.ServeContent(rw, req, statInfo.Name(), statInfo.ModTime(), fileSeeker)
|
||||
return nil
|
||||
}
|
||||
|
||||
size := strconv.FormatInt(statInfo.Size(), 10)
|
||||
rw.Header().Set(HeaderContentLength, size)
|
||||
|
||||
// Write the first 512 bytes used for MimeType sniffing
|
||||
_, err = io.Copy(rw, bytes.NewReader(buf[:n]))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Copy the remaining content of the file
|
||||
_, err = io.Copy(rw, file)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *assetHandler) logDebug(message string, args ...interface{}) {
|
||||
if d.logger != nil {
|
||||
d.logger.Debug("[AssetHandler] "+message, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *assetHandler) logError(message string, args ...interface{}) {
|
||||
if d.logger != nil {
|
||||
d.logger.Error("[AssetHandler] "+message, args...)
|
||||
}
|
||||
}
|
||||
84
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/assethandler_external.go
generated
vendored
Normal file
84
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/assethandler_external.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func NewProxyServer(proxyURL string) http.Handler {
|
||||
parsedURL, err := url.Parse(proxyURL)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return httputil.NewSingleHostReverseProxy(parsedURL)
|
||||
}
|
||||
|
||||
func NewExternalAssetsHandler(logger Logger, options assetserver.Options, url *url.URL) http.Handler {
|
||||
baseHandler := options.Handler
|
||||
|
||||
errSkipProxy := fmt.Errorf("skip proxying")
|
||||
|
||||
proxy := httputil.NewSingleHostReverseProxy(url)
|
||||
baseDirector := proxy.Director
|
||||
proxy.Director = func(r *http.Request) {
|
||||
baseDirector(r)
|
||||
if logger != nil {
|
||||
logger.Debug("[ExternalAssetHandler] Loading '%s'", r.URL)
|
||||
}
|
||||
}
|
||||
|
||||
proxy.ModifyResponse = func(res *http.Response) error {
|
||||
if baseHandler == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if res.StatusCode == http.StatusSwitchingProtocols {
|
||||
return nil
|
||||
}
|
||||
|
||||
if res.StatusCode == http.StatusNotFound || res.StatusCode == http.StatusMethodNotAllowed {
|
||||
return errSkipProxy
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
proxy.ErrorHandler = func(rw http.ResponseWriter, r *http.Request, err error) {
|
||||
if baseHandler != nil && errors.Is(err, errSkipProxy) {
|
||||
if logger != nil {
|
||||
logger.Debug("[ExternalAssetHandler] '%s' returned not found, using AssetHandler", r.URL)
|
||||
}
|
||||
baseHandler.ServeHTTP(rw, r)
|
||||
} else {
|
||||
if logger != nil {
|
||||
logger.Error("[ExternalAssetHandler] Proxy error: %v", err)
|
||||
}
|
||||
rw.WriteHeader(http.StatusBadGateway)
|
||||
}
|
||||
}
|
||||
|
||||
var result http.Handler = http.HandlerFunc(
|
||||
func(rw http.ResponseWriter, req *http.Request) {
|
||||
if req.Method == http.MethodGet {
|
||||
proxy.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
|
||||
if baseHandler != nil {
|
||||
baseHandler.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
|
||||
rw.WriteHeader(http.StatusMethodNotAllowed)
|
||||
})
|
||||
|
||||
if middleware := options.Middleware; middleware != nil {
|
||||
result = middleware(result)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
255
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/assetserver.go
generated
vendored
Normal file
255
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/assetserver.go
generated
vendored
Normal file
@@ -0,0 +1,255 @@
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
"html/template"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
||||
)
|
||||
|
||||
const (
|
||||
runtimeJSPath = "/wails/runtime.js"
|
||||
ipcJSPath = "/wails/ipc.js"
|
||||
runtimePath = "/wails/runtime"
|
||||
)
|
||||
|
||||
type RuntimeAssets interface {
|
||||
DesktopIPC() []byte
|
||||
WebsocketIPC() []byte
|
||||
RuntimeDesktopJS() []byte
|
||||
}
|
||||
|
||||
type RuntimeHandler interface {
|
||||
HandleRuntimeCall(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
type AssetServer struct {
|
||||
handler http.Handler
|
||||
runtimeJS []byte
|
||||
ipcJS func(*http.Request) []byte
|
||||
|
||||
logger Logger
|
||||
runtime RuntimeAssets
|
||||
|
||||
servingFromDisk bool
|
||||
appendSpinnerToBody bool
|
||||
|
||||
// Use http based runtime
|
||||
runtimeHandler RuntimeHandler
|
||||
|
||||
// plugin scripts
|
||||
pluginScripts map[string]string
|
||||
|
||||
assetServerWebView
|
||||
}
|
||||
|
||||
func NewAssetServerMainPage(bindingsJSON string, options *options.App, servingFromDisk bool, logger Logger, runtime RuntimeAssets) (*AssetServer, error) {
|
||||
assetOptions, err := BuildAssetServerConfig(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewAssetServer(bindingsJSON, assetOptions, servingFromDisk, logger, runtime)
|
||||
}
|
||||
|
||||
func NewAssetServer(bindingsJSON string, options assetserver.Options, servingFromDisk bool, logger Logger, runtime RuntimeAssets) (*AssetServer, error) {
|
||||
handler, err := NewAssetHandler(options, logger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewAssetServerWithHandler(handler, bindingsJSON, servingFromDisk, logger, runtime)
|
||||
}
|
||||
|
||||
func NewAssetServerWithHandler(handler http.Handler, bindingsJSON string, servingFromDisk bool, logger Logger, runtime RuntimeAssets) (*AssetServer, error) {
|
||||
|
||||
var buffer bytes.Buffer
|
||||
if bindingsJSON != "" {
|
||||
escapedBindingsJSON := template.JSEscapeString(bindingsJSON)
|
||||
buffer.WriteString(`window.wailsbindings='` + escapedBindingsJSON + `';` + "\n")
|
||||
}
|
||||
buffer.Write(runtime.RuntimeDesktopJS())
|
||||
|
||||
result := &AssetServer{
|
||||
handler: handler,
|
||||
runtimeJS: buffer.Bytes(),
|
||||
|
||||
// Check if we have been given a directory to serve assets from.
|
||||
// If so, this means we are in dev mode and are serving assets off disk.
|
||||
// We indicate this through the `servingFromDisk` flag to ensure requests
|
||||
// aren't cached in dev mode.
|
||||
servingFromDisk: servingFromDisk,
|
||||
logger: logger,
|
||||
runtime: runtime,
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (d *AssetServer) UseRuntimeHandler(handler RuntimeHandler) {
|
||||
d.runtimeHandler = handler
|
||||
}
|
||||
|
||||
func (d *AssetServer) AddPluginScript(pluginName string, script string) {
|
||||
if d.pluginScripts == nil {
|
||||
d.pluginScripts = make(map[string]string)
|
||||
}
|
||||
pluginName = strings.ReplaceAll(pluginName, "/", "_")
|
||||
pluginName = html.EscapeString(pluginName)
|
||||
pluginScriptName := fmt.Sprintf("/plugin_%s_%d.js", pluginName, rand.Intn(100000))
|
||||
d.pluginScripts[pluginScriptName] = script
|
||||
}
|
||||
|
||||
func (d *AssetServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
if isWebSocket(req) {
|
||||
// WebSockets are not supported by the AssetServer
|
||||
rw.WriteHeader(http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
|
||||
if d.servingFromDisk {
|
||||
rw.Header().Add(HeaderCacheControl, "no-cache")
|
||||
}
|
||||
|
||||
handler := d.handler
|
||||
if req.Method != http.MethodGet {
|
||||
handler.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
|
||||
path := req.URL.Path
|
||||
if path == runtimeJSPath {
|
||||
d.writeBlob(rw, path, d.runtimeJS)
|
||||
} else if path == runtimePath && d.runtimeHandler != nil {
|
||||
d.runtimeHandler.HandleRuntimeCall(rw, req)
|
||||
} else if path == ipcJSPath {
|
||||
content := d.runtime.DesktopIPC()
|
||||
if d.ipcJS != nil {
|
||||
content = d.ipcJS(req)
|
||||
}
|
||||
d.writeBlob(rw, path, content)
|
||||
|
||||
} else if script, ok := d.pluginScripts[path]; ok {
|
||||
d.writeBlob(rw, path, []byte(script))
|
||||
} else if d.isRuntimeInjectionMatch(path) {
|
||||
recorder := &bodyRecorder{
|
||||
ResponseWriter: rw,
|
||||
doRecord: func(code int, h http.Header) bool {
|
||||
if code == http.StatusNotFound {
|
||||
return true
|
||||
}
|
||||
|
||||
if code != http.StatusOK {
|
||||
return false
|
||||
}
|
||||
|
||||
return strings.Contains(h.Get(HeaderContentType), "text/html")
|
||||
},
|
||||
}
|
||||
|
||||
handler.ServeHTTP(recorder, req)
|
||||
|
||||
body := recorder.Body()
|
||||
if body == nil {
|
||||
// The body has been streamed and not recorded, we are finished
|
||||
return
|
||||
}
|
||||
|
||||
code := recorder.Code()
|
||||
switch code {
|
||||
case http.StatusOK:
|
||||
content, err := d.processIndexHTML(body.Bytes())
|
||||
if err != nil {
|
||||
d.serveError(rw, err, "Unable to processIndexHTML")
|
||||
return
|
||||
}
|
||||
d.writeBlob(rw, indexHTML, content)
|
||||
|
||||
case http.StatusNotFound:
|
||||
d.writeBlob(rw, indexHTML, defaultHTML)
|
||||
|
||||
default:
|
||||
rw.WriteHeader(code)
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
handler.ServeHTTP(rw, req)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *AssetServer) processIndexHTML(indexHTML []byte) ([]byte, error) {
|
||||
htmlNode, err := getHTMLNode(indexHTML)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if d.appendSpinnerToBody {
|
||||
err = appendSpinnerToBody(htmlNode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := insertScriptInHead(htmlNode, runtimeJSPath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := insertScriptInHead(htmlNode, ipcJSPath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Inject plugins
|
||||
for scriptName := range d.pluginScripts {
|
||||
if err := insertScriptInHead(htmlNode, scriptName); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var buffer bytes.Buffer
|
||||
err = html.Render(&buffer, htmlNode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
func (d *AssetServer) writeBlob(rw http.ResponseWriter, filename string, blob []byte) {
|
||||
err := serveFile(rw, filename, blob)
|
||||
if err != nil {
|
||||
d.serveError(rw, err, "Unable to write content %s", filename)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *AssetServer) serveError(rw http.ResponseWriter, err error, msg string, args ...interface{}) {
|
||||
args = append(args, err)
|
||||
d.logError(msg+": %s", args...)
|
||||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
func (d *AssetServer) logDebug(message string, args ...interface{}) {
|
||||
if d.logger != nil {
|
||||
d.logger.Debug("[AssetServer] "+message, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *AssetServer) logError(message string, args ...interface{}) {
|
||||
if d.logger != nil {
|
||||
d.logger.Error("[AssetServer] "+message, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (AssetServer) isRuntimeInjectionMatch(path string) bool {
|
||||
if path == "" {
|
||||
path = "/"
|
||||
}
|
||||
|
||||
return strings.HasSuffix(path, "/") ||
|
||||
strings.HasSuffix(path, "/"+indexHTML)
|
||||
}
|
||||
31
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/assetserver_dev.go
generated
vendored
Normal file
31
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/assetserver_dev.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
//go:build dev
|
||||
// +build dev
|
||||
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
The assetserver for the dev mode.
|
||||
Depending on the UserAgent it injects a websocket based IPC script into `index.html` or the default desktop IPC. The
|
||||
default desktop IPC is injected when the webview accesses the devserver.
|
||||
*/
|
||||
func NewDevAssetServer(handler http.Handler, bindingsJSON string, servingFromDisk bool, logger Logger, runtime RuntimeAssets) (*AssetServer, error) {
|
||||
result, err := NewAssetServerWithHandler(handler, bindingsJSON, servingFromDisk, logger, runtime)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result.appendSpinnerToBody = true
|
||||
result.ipcJS = func(req *http.Request) []byte {
|
||||
if strings.Contains(req.UserAgent(), WailsUserAgentValue) {
|
||||
return runtime.DesktopIPC()
|
||||
}
|
||||
return runtime.WebsocketIPC()
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
185
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/assetserver_webview.go
generated
vendored
Normal file
185
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/assetserver_webview.go
generated
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/assetserver/webview"
|
||||
)
|
||||
|
||||
type assetServerWebView struct {
|
||||
// ExpectedWebViewHost is checked against the Request Host of every WebViewRequest, other hosts won't be processed.
|
||||
ExpectedWebViewHost string
|
||||
|
||||
dispatchInit sync.Once
|
||||
dispatchReqC chan<- webview.Request
|
||||
dispatchWorkers int
|
||||
}
|
||||
|
||||
// ServeWebViewRequest processes the HTTP Request asynchronously by faking a golang HTTP Server.
|
||||
// The request will be finished with a StatusNotImplemented code if no handler has written to the response.
|
||||
// The AssetServer takes ownership of the request and the caller mustn't close it or access it in any other way.
|
||||
func (d *AssetServer) ServeWebViewRequest(req webview.Request) {
|
||||
d.dispatchInit.Do(func() {
|
||||
workers := d.dispatchWorkers
|
||||
if workers <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
workerC := make(chan webview.Request, workers*2)
|
||||
for i := 0; i < workers; i++ {
|
||||
go func() {
|
||||
for req := range workerC {
|
||||
d.processWebViewRequest(req)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
dispatchC := make(chan webview.Request)
|
||||
go queueingDispatcher(50, dispatchC, workerC)
|
||||
|
||||
d.dispatchReqC = dispatchC
|
||||
})
|
||||
|
||||
if d.dispatchReqC == nil {
|
||||
go d.processWebViewRequest(req)
|
||||
} else {
|
||||
d.dispatchReqC <- req
|
||||
}
|
||||
}
|
||||
|
||||
func (d *AssetServer) processWebViewRequest(r webview.Request) {
|
||||
uri, _ := r.URL()
|
||||
d.processWebViewRequestInternal(r)
|
||||
if err := r.Close(); err != nil {
|
||||
d.logError("Unable to call close for request for uri '%s'", uri)
|
||||
}
|
||||
}
|
||||
|
||||
// processWebViewRequestInternal processes the HTTP Request by faking a golang HTTP Server.
|
||||
// The request will be finished with a StatusNotImplemented code if no handler has written to the response.
|
||||
func (d *AssetServer) processWebViewRequestInternal(r webview.Request) {
|
||||
uri := "unknown"
|
||||
var err error
|
||||
|
||||
wrw := r.Response()
|
||||
defer func() {
|
||||
if err := wrw.Finish(); err != nil {
|
||||
d.logError("Error finishing request '%s': %s", uri, err)
|
||||
}
|
||||
}()
|
||||
|
||||
var rw http.ResponseWriter = &contentTypeSniffer{rw: wrw} // Make sure we have a Content-Type sniffer
|
||||
defer rw.WriteHeader(http.StatusNotImplemented) // This is a NOP when a handler has already written and set the status
|
||||
|
||||
uri, err = r.URL()
|
||||
if err != nil {
|
||||
d.logError("Error processing request, unable to get URL: %s (HttpResponse=500)", err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
method, err := r.Method()
|
||||
if err != nil {
|
||||
d.webviewRequestErrorHandler(uri, rw, fmt.Errorf("HTTP-Method: %w", err))
|
||||
return
|
||||
}
|
||||
|
||||
header, err := r.Header()
|
||||
if err != nil {
|
||||
d.webviewRequestErrorHandler(uri, rw, fmt.Errorf("HTTP-Header: %w", err))
|
||||
return
|
||||
}
|
||||
|
||||
body, err := r.Body()
|
||||
if err != nil {
|
||||
d.webviewRequestErrorHandler(uri, rw, fmt.Errorf("HTTP-Body: %w", err))
|
||||
return
|
||||
}
|
||||
|
||||
if body == nil {
|
||||
body = http.NoBody
|
||||
}
|
||||
defer body.Close()
|
||||
|
||||
req, err := http.NewRequest(method, uri, body)
|
||||
if err != nil {
|
||||
d.webviewRequestErrorHandler(uri, rw, fmt.Errorf("HTTP-Request: %w", err))
|
||||
return
|
||||
}
|
||||
|
||||
// For server requests, the URL is parsed from the URI supplied on the Request-Line as stored in RequestURI. For
|
||||
// most requests, fields other than Path and RawQuery will be empty. (See RFC 7230, Section 5.3)
|
||||
req.URL.Scheme = ""
|
||||
req.URL.Host = ""
|
||||
req.URL.Fragment = ""
|
||||
req.URL.RawFragment = ""
|
||||
|
||||
if url := req.URL; req.RequestURI == "" && url != nil {
|
||||
req.RequestURI = url.String()
|
||||
}
|
||||
|
||||
req.Header = header
|
||||
|
||||
if req.RemoteAddr == "" {
|
||||
// 192.0.2.0/24 is "TEST-NET" in RFC 5737
|
||||
req.RemoteAddr = "192.0.2.1:1234"
|
||||
}
|
||||
|
||||
if req.ContentLength == 0 {
|
||||
req.ContentLength = -1
|
||||
} else {
|
||||
size := strconv.FormatInt(req.ContentLength, 10)
|
||||
req.Header.Set(HeaderContentLength, size)
|
||||
}
|
||||
|
||||
if host := req.Header.Get(HeaderHost); host != "" {
|
||||
req.Host = host
|
||||
}
|
||||
|
||||
if expectedHost := d.ExpectedWebViewHost; expectedHost != "" && expectedHost != req.Host {
|
||||
d.webviewRequestErrorHandler(uri, rw, fmt.Errorf("expected host '%s' in request, but was '%s'", expectedHost, req.Host))
|
||||
return
|
||||
}
|
||||
|
||||
d.ServeHTTP(rw, req)
|
||||
}
|
||||
|
||||
func (d *AssetServer) webviewRequestErrorHandler(uri string, rw http.ResponseWriter, err error) {
|
||||
logInfo := uri
|
||||
if uri, err := url.ParseRequestURI(uri); err == nil {
|
||||
logInfo = strings.Replace(logInfo, fmt.Sprintf("%s://%s", uri.Scheme, uri.Host), "", 1)
|
||||
}
|
||||
|
||||
d.logError("Error processing request '%s': %s (HttpResponse=500)", logInfo, err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
func queueingDispatcher[T any](minQueueSize uint, inC <-chan T, outC chan<- T) {
|
||||
q := newRingqueue[T](minQueueSize)
|
||||
for {
|
||||
in, ok := <-inC
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
q.Add(in)
|
||||
for q.Len() != 0 {
|
||||
out, _ := q.Peek()
|
||||
select {
|
||||
case outC <- out:
|
||||
q.Remove()
|
||||
case in, ok := <-inC:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
q.Add(in)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
61
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/body_recorder.go
generated
vendored
Normal file
61
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/body_recorder.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type bodyRecorder struct {
|
||||
http.ResponseWriter
|
||||
doRecord func(code int, header http.Header) bool
|
||||
|
||||
body *bytes.Buffer
|
||||
code int
|
||||
wroteHeader bool
|
||||
}
|
||||
|
||||
func (rw *bodyRecorder) Write(buf []byte) (int, error) {
|
||||
rw.writeHeader(buf, http.StatusOK)
|
||||
if rw.body != nil {
|
||||
return rw.body.Write(buf)
|
||||
}
|
||||
return rw.ResponseWriter.Write(buf)
|
||||
}
|
||||
|
||||
func (rw *bodyRecorder) WriteHeader(code int) {
|
||||
rw.writeHeader(nil, code)
|
||||
}
|
||||
|
||||
func (rw *bodyRecorder) Code() int {
|
||||
return rw.code
|
||||
}
|
||||
|
||||
func (rw *bodyRecorder) Body() *bytes.Buffer {
|
||||
return rw.body
|
||||
}
|
||||
|
||||
func (rw *bodyRecorder) writeHeader(buf []byte, code int) {
|
||||
if rw.wroteHeader {
|
||||
return
|
||||
}
|
||||
|
||||
if rw.doRecord != nil {
|
||||
header := rw.Header()
|
||||
if len(buf) != 0 {
|
||||
if _, hasType := header[HeaderContentType]; !hasType {
|
||||
header.Set(HeaderContentType, http.DetectContentType(buf))
|
||||
}
|
||||
}
|
||||
|
||||
if rw.doRecord(code, header) {
|
||||
rw.body = bytes.NewBuffer(nil)
|
||||
}
|
||||
}
|
||||
|
||||
if rw.body == nil {
|
||||
rw.ResponseWriter.WriteHeader(code)
|
||||
}
|
||||
|
||||
rw.code = code
|
||||
rw.wroteHeader = true
|
||||
}
|
||||
135
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/common.go
generated
vendored
Normal file
135
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/common.go
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
func BuildAssetServerConfig(appOptions *options.App) (assetserver.Options, error) {
|
||||
var options assetserver.Options
|
||||
if opt := appOptions.AssetServer; opt != nil {
|
||||
if appOptions.Assets != nil || appOptions.AssetsHandler != nil {
|
||||
panic("It's not possible to use the deprecated Assets and AssetsHandler options and the new AssetServer option at the same time. Please migrate all your Assets options to the AssetServer option.")
|
||||
}
|
||||
|
||||
options = *opt
|
||||
} else {
|
||||
options = assetserver.Options{
|
||||
Assets: appOptions.Assets,
|
||||
Handler: appOptions.AssetsHandler,
|
||||
}
|
||||
}
|
||||
|
||||
return options, options.Validate()
|
||||
}
|
||||
|
||||
const (
|
||||
HeaderHost = "Host"
|
||||
HeaderContentType = "Content-Type"
|
||||
HeaderContentLength = "Content-Length"
|
||||
HeaderUserAgent = "User-Agent"
|
||||
HeaderCacheControl = "Cache-Control"
|
||||
HeaderUpgrade = "Upgrade"
|
||||
|
||||
WailsUserAgentValue = "wails.io"
|
||||
)
|
||||
|
||||
func serveFile(rw http.ResponseWriter, filename string, blob []byte) error {
|
||||
header := rw.Header()
|
||||
header.Set(HeaderContentLength, strconv.Itoa(len(blob)))
|
||||
if mimeType := header.Get(HeaderContentType); mimeType == "" {
|
||||
mimeType = GetMimetype(filename, blob)
|
||||
header.Set(HeaderContentType, mimeType)
|
||||
}
|
||||
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
_, err := io.Copy(rw, bytes.NewReader(blob))
|
||||
return err
|
||||
}
|
||||
|
||||
func createScriptNode(scriptName string) *html.Node {
|
||||
return &html.Node{
|
||||
Type: html.ElementNode,
|
||||
Data: "script",
|
||||
Attr: []html.Attribute{
|
||||
{
|
||||
Key: "src",
|
||||
Val: scriptName,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func createDivNode(id string) *html.Node {
|
||||
return &html.Node{
|
||||
Type: html.ElementNode,
|
||||
Data: "div",
|
||||
Attr: []html.Attribute{
|
||||
{
|
||||
Namespace: "",
|
||||
Key: "id",
|
||||
Val: id,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func insertScriptInHead(htmlNode *html.Node, scriptName string) error {
|
||||
headNode := findFirstTag(htmlNode, "head")
|
||||
if headNode == nil {
|
||||
return errors.New("cannot find head in HTML")
|
||||
}
|
||||
scriptNode := createScriptNode(scriptName)
|
||||
if headNode.FirstChild != nil {
|
||||
headNode.InsertBefore(scriptNode, headNode.FirstChild)
|
||||
} else {
|
||||
headNode.AppendChild(scriptNode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func appendSpinnerToBody(htmlNode *html.Node) error {
|
||||
bodyNode := findFirstTag(htmlNode, "body")
|
||||
if bodyNode == nil {
|
||||
return errors.New("cannot find body in HTML")
|
||||
}
|
||||
scriptNode := createDivNode("wails-spinner")
|
||||
bodyNode.AppendChild(scriptNode)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getHTMLNode(htmldata []byte) (*html.Node, error) {
|
||||
return html.Parse(bytes.NewReader(htmldata))
|
||||
}
|
||||
|
||||
func findFirstTag(htmlnode *html.Node, tagName string) *html.Node {
|
||||
var extractor func(*html.Node) *html.Node
|
||||
var result *html.Node
|
||||
extractor = func(node *html.Node) *html.Node {
|
||||
if node.Type == html.ElementNode && node.Data == tagName {
|
||||
return node
|
||||
}
|
||||
for child := node.FirstChild; child != nil; child = child.NextSibling {
|
||||
result := extractor(child)
|
||||
if result != nil {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
result = extractor(htmlnode)
|
||||
return result
|
||||
}
|
||||
|
||||
func isWebSocket(req *http.Request) bool {
|
||||
upgrade := req.Header.Get(HeaderUpgrade)
|
||||
return strings.EqualFold(upgrade, "websocket")
|
||||
}
|
||||
42
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/content_type_sniffer.go
generated
vendored
Normal file
42
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/content_type_sniffer.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type contentTypeSniffer struct {
|
||||
rw http.ResponseWriter
|
||||
|
||||
wroteHeader bool
|
||||
}
|
||||
|
||||
func (rw *contentTypeSniffer) Header() http.Header {
|
||||
return rw.rw.Header()
|
||||
}
|
||||
|
||||
func (rw *contentTypeSniffer) Write(buf []byte) (int, error) {
|
||||
rw.writeHeader(buf)
|
||||
return rw.rw.Write(buf)
|
||||
}
|
||||
|
||||
func (rw *contentTypeSniffer) WriteHeader(code int) {
|
||||
if rw.wroteHeader {
|
||||
return
|
||||
}
|
||||
|
||||
rw.rw.WriteHeader(code)
|
||||
rw.wroteHeader = true
|
||||
}
|
||||
|
||||
func (rw *contentTypeSniffer) writeHeader(b []byte) {
|
||||
if rw.wroteHeader {
|
||||
return
|
||||
}
|
||||
|
||||
m := rw.rw.Header()
|
||||
if _, hasType := m[HeaderContentType]; !hasType {
|
||||
m.Set(HeaderContentType, http.DetectContentType(b))
|
||||
}
|
||||
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
}
|
||||
39
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/defaultindex.html
generated
vendored
Normal file
39
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/defaultindex.html
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
75
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/fs.go
generated
vendored
Normal file
75
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/fs.go
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// FindEmbedRootPath finds the root path in the embed FS. It's the directory which contains all the files.
|
||||
func FindEmbedRootPath(fsys embed.FS) (string, error) {
|
||||
stopErr := fmt.Errorf("files or multiple dirs found")
|
||||
|
||||
fPath := ""
|
||||
err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d.IsDir() {
|
||||
fPath = path
|
||||
if entries, dErr := fs.ReadDir(fsys, path); dErr != nil {
|
||||
return dErr
|
||||
} else if len(entries) <= 1 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return stopErr
|
||||
})
|
||||
|
||||
if err != nil && err != stopErr {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fPath, nil
|
||||
}
|
||||
|
||||
func FindPathToFile(fsys fs.FS, file string) (string, error) {
|
||||
stat, _ := fs.Stat(fsys, file)
|
||||
if stat != nil {
|
||||
return ".", nil
|
||||
}
|
||||
var indexFiles []string
|
||||
err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.HasSuffix(path, file) {
|
||||
indexFiles = append(indexFiles, path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(indexFiles) > 1 {
|
||||
selected := indexFiles[0]
|
||||
for _, f := range indexFiles {
|
||||
if len(f) < len(selected) {
|
||||
selected = f
|
||||
}
|
||||
}
|
||||
path, _ := filepath.Split(selected)
|
||||
return path, nil
|
||||
}
|
||||
if len(indexFiles) > 0 {
|
||||
path, _ := filepath.Split(indexFiles[0])
|
||||
return path, nil
|
||||
}
|
||||
return "", fmt.Errorf("%s: %w", file, os.ErrNotExist)
|
||||
}
|
||||
67
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/mimecache.go
generated
vendored
Normal file
67
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/mimecache.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/wailsapp/mimetype"
|
||||
)
|
||||
|
||||
var (
|
||||
mimeCache = map[string]string{}
|
||||
mimeMutex sync.Mutex
|
||||
|
||||
// The list of builtin mime-types by extension as defined by
|
||||
// the golang standard lib package "mime"
|
||||
// The standard lib also takes into account mime type definitions from
|
||||
// etc files like '/etc/apache2/mime.types' but we want to have the
|
||||
// same behavivour on all platforms and not depend on some external file.
|
||||
mimeTypesByExt = map[string]string{
|
||||
".avif": "image/avif",
|
||||
".css": "text/css; charset=utf-8",
|
||||
".gif": "image/gif",
|
||||
".htm": "text/html; charset=utf-8",
|
||||
".html": "text/html; charset=utf-8",
|
||||
".jpeg": "image/jpeg",
|
||||
".jpg": "image/jpeg",
|
||||
".js": "text/javascript; charset=utf-8",
|
||||
".json": "application/json",
|
||||
".mjs": "text/javascript; charset=utf-8",
|
||||
".pdf": "application/pdf",
|
||||
".png": "image/png",
|
||||
".svg": "image/svg+xml",
|
||||
".wasm": "application/wasm",
|
||||
".webp": "image/webp",
|
||||
".xml": "text/xml; charset=utf-8",
|
||||
}
|
||||
)
|
||||
|
||||
func GetMimetype(filename string, data []byte) string {
|
||||
mimeMutex.Lock()
|
||||
defer mimeMutex.Unlock()
|
||||
|
||||
result := mimeTypesByExt[filepath.Ext(filename)]
|
||||
if result != "" {
|
||||
return result
|
||||
}
|
||||
|
||||
result = mimeCache[filename]
|
||||
if result != "" {
|
||||
return result
|
||||
}
|
||||
|
||||
detect := mimetype.Detect(data)
|
||||
if detect == nil {
|
||||
result = http.DetectContentType(data)
|
||||
} else {
|
||||
result = detect.String()
|
||||
}
|
||||
|
||||
if result == "" {
|
||||
result = "application/octet-stream"
|
||||
}
|
||||
|
||||
mimeCache[filename] = result
|
||||
return result
|
||||
}
|
||||
101
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/ringqueue.go
generated
vendored
Normal file
101
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/ringqueue.go
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
// Code from https://github.com/erikdubbelboer/ringqueue
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Erik Dubbelboer
|
||||
|
||||
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.
|
||||
*/
|
||||
package assetserver
|
||||
|
||||
type ringqueue[T any] struct {
|
||||
nodes []T
|
||||
head int
|
||||
tail int
|
||||
cnt int
|
||||
|
||||
minSize int
|
||||
}
|
||||
|
||||
func newRingqueue[T any](minSize uint) *ringqueue[T] {
|
||||
if minSize < 2 {
|
||||
minSize = 2
|
||||
}
|
||||
return &ringqueue[T]{
|
||||
nodes: make([]T, minSize),
|
||||
minSize: int(minSize),
|
||||
}
|
||||
}
|
||||
|
||||
func (q *ringqueue[T]) resize(n int) {
|
||||
nodes := make([]T, n)
|
||||
if q.head < q.tail {
|
||||
copy(nodes, q.nodes[q.head:q.tail])
|
||||
} else {
|
||||
copy(nodes, q.nodes[q.head:])
|
||||
copy(nodes[len(q.nodes)-q.head:], q.nodes[:q.tail])
|
||||
}
|
||||
|
||||
q.tail = q.cnt % n
|
||||
q.head = 0
|
||||
q.nodes = nodes
|
||||
}
|
||||
|
||||
func (q *ringqueue[T]) Add(i T) {
|
||||
if q.cnt == len(q.nodes) {
|
||||
// Also tested a grow rate of 1.5, see: http://stackoverflow.com/questions/2269063/buffer-growth-strategy
|
||||
// In Go this resulted in a higher memory usage.
|
||||
q.resize(q.cnt * 2)
|
||||
}
|
||||
q.nodes[q.tail] = i
|
||||
q.tail = (q.tail + 1) % len(q.nodes)
|
||||
q.cnt++
|
||||
}
|
||||
|
||||
func (q *ringqueue[T]) Peek() (T, bool) {
|
||||
if q.cnt == 0 {
|
||||
var none T
|
||||
return none, false
|
||||
}
|
||||
return q.nodes[q.head], true
|
||||
}
|
||||
|
||||
func (q *ringqueue[T]) Remove() (T, bool) {
|
||||
if q.cnt == 0 {
|
||||
var none T
|
||||
return none, false
|
||||
}
|
||||
i := q.nodes[q.head]
|
||||
q.head = (q.head + 1) % len(q.nodes)
|
||||
q.cnt--
|
||||
|
||||
if n := len(q.nodes) / 2; n > q.minSize && q.cnt <= n {
|
||||
q.resize(n)
|
||||
}
|
||||
|
||||
return i, true
|
||||
}
|
||||
|
||||
func (q *ringqueue[T]) Cap() int {
|
||||
return cap(q.nodes)
|
||||
}
|
||||
|
||||
func (q *ringqueue[T]) Len() int {
|
||||
return q.cnt
|
||||
}
|
||||
17
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/request.go
generated
vendored
Normal file
17
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/request.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package webview
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Request interface {
|
||||
URL() (string, error)
|
||||
Method() (string, error)
|
||||
Header() (http.Header, error)
|
||||
Body() (io.ReadCloser, error)
|
||||
|
||||
Response() ResponseWriter
|
||||
|
||||
Close() error
|
||||
}
|
||||
251
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/request_darwin.go
generated
vendored
Normal file
251
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/request_darwin.go
generated
vendored
Normal file
@@ -0,0 +1,251 @@
|
||||
//go:build darwin
|
||||
|
||||
package webview
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -x objective-c
|
||||
#cgo LDFLAGS: -framework Foundation -framework WebKit
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
#include <string.h>
|
||||
|
||||
static void URLSchemeTaskRetain(void *wkUrlSchemeTask) {
|
||||
id<WKURLSchemeTask> urlSchemeTask = (id<WKURLSchemeTask>) wkUrlSchemeTask;
|
||||
[urlSchemeTask retain];
|
||||
}
|
||||
|
||||
static void URLSchemeTaskRelease(void *wkUrlSchemeTask) {
|
||||
id<WKURLSchemeTask> urlSchemeTask = (id<WKURLSchemeTask>) wkUrlSchemeTask;
|
||||
[urlSchemeTask release];
|
||||
}
|
||||
|
||||
static const char * URLSchemeTaskRequestURL(void *wkUrlSchemeTask) {
|
||||
id<WKURLSchemeTask> urlSchemeTask = (id<WKURLSchemeTask>) wkUrlSchemeTask;
|
||||
@autoreleasepool {
|
||||
return [urlSchemeTask.request.URL.absoluteString UTF8String];
|
||||
}
|
||||
}
|
||||
|
||||
static const char * URLSchemeTaskRequestMethod(void *wkUrlSchemeTask) {
|
||||
id<WKURLSchemeTask> urlSchemeTask = (id<WKURLSchemeTask>) wkUrlSchemeTask;
|
||||
@autoreleasepool {
|
||||
return [urlSchemeTask.request.HTTPMethod UTF8String];
|
||||
}
|
||||
}
|
||||
|
||||
static const char * URLSchemeTaskRequestHeadersJSON(void *wkUrlSchemeTask) {
|
||||
id<WKURLSchemeTask> urlSchemeTask = (id<WKURLSchemeTask>) wkUrlSchemeTask;
|
||||
@autoreleasepool {
|
||||
NSData *headerData = [NSJSONSerialization dataWithJSONObject: urlSchemeTask.request.allHTTPHeaderFields options:0 error: nil];
|
||||
if (!headerData) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString* headerString = [[[NSString alloc] initWithData:headerData encoding:NSUTF8StringEncoding] autorelease];
|
||||
const char * headerJSON = [headerString UTF8String];
|
||||
|
||||
return strdup(headerJSON);
|
||||
}
|
||||
}
|
||||
|
||||
static bool URLSchemeTaskRequestBodyBytes(void *wkUrlSchemeTask, const void **body, int *bodyLen) {
|
||||
id<WKURLSchemeTask> urlSchemeTask = (id<WKURLSchemeTask>) wkUrlSchemeTask;
|
||||
@autoreleasepool {
|
||||
if (!urlSchemeTask.request.HTTPBody) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*body = urlSchemeTask.request.HTTPBody.bytes;
|
||||
*bodyLen = urlSchemeTask.request.HTTPBody.length;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool URLSchemeTaskRequestBodyStreamOpen(void *wkUrlSchemeTask) {
|
||||
id<WKURLSchemeTask> urlSchemeTask = (id<WKURLSchemeTask>) wkUrlSchemeTask;
|
||||
@autoreleasepool {
|
||||
if (!urlSchemeTask.request.HTTPBodyStream) {
|
||||
return false;
|
||||
}
|
||||
|
||||
[urlSchemeTask.request.HTTPBodyStream open];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static void URLSchemeTaskRequestBodyStreamClose(void *wkUrlSchemeTask) {
|
||||
id<WKURLSchemeTask> urlSchemeTask = (id<WKURLSchemeTask>) wkUrlSchemeTask;
|
||||
@autoreleasepool {
|
||||
if (!urlSchemeTask.request.HTTPBodyStream) {
|
||||
return;
|
||||
}
|
||||
|
||||
[urlSchemeTask.request.HTTPBodyStream close];
|
||||
}
|
||||
}
|
||||
|
||||
static int URLSchemeTaskRequestBodyStreamRead(void *wkUrlSchemeTask, void *buf, int bufLen) {
|
||||
id<WKURLSchemeTask> urlSchemeTask = (id<WKURLSchemeTask>) wkUrlSchemeTask;
|
||||
|
||||
@autoreleasepool {
|
||||
NSInputStream *stream = urlSchemeTask.request.HTTPBodyStream;
|
||||
if (!stream) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
NSStreamStatus status = stream.streamStatus;
|
||||
if (status == NSStreamStatusAtEnd || !stream.hasBytesAvailable) {
|
||||
return 0;
|
||||
} else if (status != NSStreamStatusOpen) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
return [stream read:buf maxLength:bufLen];
|
||||
}
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// NewRequest creates as new WebViewRequest based on a pointer to an `id<WKURLSchemeTask>`
|
||||
func NewRequest(wkURLSchemeTask unsafe.Pointer) Request {
|
||||
C.URLSchemeTaskRetain(wkURLSchemeTask)
|
||||
return newRequestFinalizer(&request{task: wkURLSchemeTask})
|
||||
}
|
||||
|
||||
var _ Request = &request{}
|
||||
|
||||
type request struct {
|
||||
task unsafe.Pointer
|
||||
|
||||
header http.Header
|
||||
body io.ReadCloser
|
||||
rw *responseWriter
|
||||
}
|
||||
|
||||
func (r *request) URL() (string, error) {
|
||||
return C.GoString(C.URLSchemeTaskRequestURL(r.task)), nil
|
||||
}
|
||||
|
||||
func (r *request) Method() (string, error) {
|
||||
return C.GoString(C.URLSchemeTaskRequestMethod(r.task)), nil
|
||||
}
|
||||
|
||||
func (r *request) Header() (http.Header, error) {
|
||||
if r.header != nil {
|
||||
return r.header, nil
|
||||
}
|
||||
|
||||
header := http.Header{}
|
||||
if cHeaders := C.URLSchemeTaskRequestHeadersJSON(r.task); cHeaders != nil {
|
||||
if headers := C.GoString(cHeaders); headers != "" {
|
||||
var h map[string]string
|
||||
if err := json.Unmarshal([]byte(headers), &h); err != nil {
|
||||
return nil, fmt.Errorf("unable to unmarshal request headers: %s", err)
|
||||
}
|
||||
|
||||
for k, v := range h {
|
||||
header.Add(k, v)
|
||||
}
|
||||
}
|
||||
C.free(unsafe.Pointer(cHeaders))
|
||||
}
|
||||
r.header = header
|
||||
return header, nil
|
||||
}
|
||||
|
||||
func (r *request) Body() (io.ReadCloser, error) {
|
||||
if r.body != nil {
|
||||
return r.body, nil
|
||||
}
|
||||
|
||||
var body unsafe.Pointer
|
||||
var bodyLen C.int
|
||||
if C.URLSchemeTaskRequestBodyBytes(r.task, &body, &bodyLen) {
|
||||
if body != nil && bodyLen > 0 {
|
||||
r.body = io.NopCloser(bytes.NewReader(C.GoBytes(body, bodyLen)))
|
||||
} else {
|
||||
r.body = http.NoBody
|
||||
}
|
||||
} else if C.URLSchemeTaskRequestBodyStreamOpen(r.task) {
|
||||
r.body = &requestBodyStreamReader{task: r.task}
|
||||
}
|
||||
|
||||
return r.body, nil
|
||||
}
|
||||
|
||||
func (r *request) Response() ResponseWriter {
|
||||
if r.rw != nil {
|
||||
return r.rw
|
||||
}
|
||||
|
||||
r.rw = &responseWriter{r: r}
|
||||
return r.rw
|
||||
}
|
||||
|
||||
func (r *request) Close() error {
|
||||
var err error
|
||||
if r.body != nil {
|
||||
err = r.body.Close()
|
||||
}
|
||||
err = r.Response().Finish()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
C.URLSchemeTaskRelease(r.task)
|
||||
return err
|
||||
}
|
||||
|
||||
var _ io.ReadCloser = &requestBodyStreamReader{}
|
||||
|
||||
type requestBodyStreamReader struct {
|
||||
task unsafe.Pointer
|
||||
closed bool
|
||||
}
|
||||
|
||||
// Read implements io.Reader
|
||||
func (r *requestBodyStreamReader) Read(p []byte) (n int, err error) {
|
||||
var content unsafe.Pointer
|
||||
var contentLen int
|
||||
if p != nil {
|
||||
content = unsafe.Pointer(&p[0])
|
||||
contentLen = len(p)
|
||||
}
|
||||
|
||||
res := C.URLSchemeTaskRequestBodyStreamRead(r.task, content, C.int(contentLen))
|
||||
if res > 0 {
|
||||
return int(res), nil
|
||||
}
|
||||
|
||||
switch res {
|
||||
case 0:
|
||||
return 0, io.EOF
|
||||
case -1:
|
||||
return 0, fmt.Errorf("body: stream error")
|
||||
case -2:
|
||||
return 0, fmt.Errorf("body: no stream defined")
|
||||
case -3:
|
||||
return 0, io.ErrClosedPipe
|
||||
default:
|
||||
return 0, fmt.Errorf("body: unknown error %d", res)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *requestBodyStreamReader) Close() error {
|
||||
if r.closed {
|
||||
return nil
|
||||
}
|
||||
r.closed = true
|
||||
|
||||
C.URLSchemeTaskRequestBodyStreamClose(r.task)
|
||||
return nil
|
||||
}
|
||||
40
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/request_finalizer.go
generated
vendored
Normal file
40
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/request_finalizer.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
package webview
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
var _ Request = &requestFinalizer{}
|
||||
|
||||
type requestFinalizer struct {
|
||||
Request
|
||||
closed int32
|
||||
}
|
||||
|
||||
// newRequestFinalizer returns a request with a runtime finalizer to make sure it will be closed from the finalizer
|
||||
// if it has not been already closed.
|
||||
// It also makes sure Close() of the wrapping request is only called once.
|
||||
func newRequestFinalizer(r Request) Request {
|
||||
rf := &requestFinalizer{Request: r}
|
||||
// Make sure to async release since it might block the finalizer goroutine for a longer period
|
||||
runtime.SetFinalizer(rf, func(obj *requestFinalizer) { rf.close(true) })
|
||||
return rf
|
||||
}
|
||||
|
||||
func (r *requestFinalizer) Close() error {
|
||||
return r.close(false)
|
||||
}
|
||||
|
||||
func (r *requestFinalizer) close(asyncRelease bool) error {
|
||||
if atomic.CompareAndSwapInt32(&r.closed, 0, 1) {
|
||||
runtime.SetFinalizer(r, nil)
|
||||
if asyncRelease {
|
||||
go r.Request.Close()
|
||||
return nil
|
||||
} else {
|
||||
return r.Request.Close()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
85
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/request_linux.go
generated
vendored
Normal file
85
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/request_linux.go
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package webview
|
||||
|
||||
/*
|
||||
#cgo linux pkg-config: gtk+-3.0 gio-unix-2.0
|
||||
#cgo !webkit2_41 pkg-config: webkit2gtk-4.0
|
||||
#cgo webkit2_41 pkg-config: webkit2gtk-4.1
|
||||
|
||||
#include "gtk/gtk.h"
|
||||
#include "webkit2/webkit2.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// NewRequest creates as new WebViewRequest based on a pointer to an `WebKitURISchemeRequest`
|
||||
func NewRequest(webKitURISchemeRequest unsafe.Pointer) Request {
|
||||
webkitReq := (*C.WebKitURISchemeRequest)(webKitURISchemeRequest)
|
||||
C.g_object_ref(C.gpointer(webkitReq))
|
||||
|
||||
req := &request{req: webkitReq}
|
||||
return newRequestFinalizer(req)
|
||||
}
|
||||
|
||||
var _ Request = &request{}
|
||||
|
||||
type request struct {
|
||||
req *C.WebKitURISchemeRequest
|
||||
|
||||
header http.Header
|
||||
body io.ReadCloser
|
||||
rw *responseWriter
|
||||
}
|
||||
|
||||
func (r *request) URL() (string, error) {
|
||||
return C.GoString(C.webkit_uri_scheme_request_get_uri(r.req)), nil
|
||||
}
|
||||
|
||||
func (r *request) Method() (string, error) {
|
||||
return webkit_uri_scheme_request_get_http_method(r.req), nil
|
||||
}
|
||||
|
||||
func (r *request) Header() (http.Header, error) {
|
||||
if r.header != nil {
|
||||
return r.header, nil
|
||||
}
|
||||
|
||||
r.header = webkit_uri_scheme_request_get_http_headers(r.req)
|
||||
return r.header, nil
|
||||
}
|
||||
|
||||
func (r *request) Body() (io.ReadCloser, error) {
|
||||
if r.body != nil {
|
||||
return r.body, nil
|
||||
}
|
||||
|
||||
r.body = webkit_uri_scheme_request_get_http_body(r.req)
|
||||
|
||||
return r.body, nil
|
||||
}
|
||||
|
||||
func (r *request) Response() ResponseWriter {
|
||||
if r.rw != nil {
|
||||
return r.rw
|
||||
}
|
||||
|
||||
r.rw = &responseWriter{req: r.req}
|
||||
return r.rw
|
||||
}
|
||||
|
||||
func (r *request) Close() error {
|
||||
var err error
|
||||
if r.body != nil {
|
||||
err = r.body.Close()
|
||||
}
|
||||
r.Response().Finish()
|
||||
C.g_object_unref(C.gpointer(r.req))
|
||||
return err
|
||||
}
|
||||
217
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/request_windows.go
generated
vendored
Normal file
217
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/request_windows.go
generated
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package webview
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/wailsapp/go-webview2/pkg/edge"
|
||||
)
|
||||
|
||||
// NewRequest creates as new WebViewRequest for chromium. This Method must be called from the Main-Thread!
|
||||
func NewRequest(env *edge.ICoreWebView2Environment, args *edge.ICoreWebView2WebResourceRequestedEventArgs, invokeSync func(fn func())) (Request, error) {
|
||||
req, err := args.GetRequest()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GetRequest failed: %s", err)
|
||||
}
|
||||
defer req.Release()
|
||||
|
||||
r := &request{
|
||||
invokeSync: invokeSync,
|
||||
}
|
||||
|
||||
code := http.StatusInternalServerError
|
||||
r.response, err = env.CreateWebResourceResponse(nil, code, http.StatusText(code), "")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("CreateWebResourceResponse failed: %s", err)
|
||||
}
|
||||
|
||||
if err := args.PutResponse(r.response); err != nil {
|
||||
r.finishResponse()
|
||||
return nil, fmt.Errorf("PutResponse failed: %s", err)
|
||||
}
|
||||
|
||||
r.deferral, err = args.GetDeferral()
|
||||
if err != nil {
|
||||
r.finishResponse()
|
||||
return nil, fmt.Errorf("GetDeferral failed: %s", err)
|
||||
}
|
||||
|
||||
r.url, r.urlErr = req.GetUri()
|
||||
r.method, r.methodErr = req.GetMethod()
|
||||
r.header, r.headerErr = getHeaders(req)
|
||||
|
||||
if content, err := req.GetContent(); err != nil {
|
||||
r.bodyErr = err
|
||||
} else if content != nil {
|
||||
// It is safe to access Content from another Thread: https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/threading-model#thread-safety
|
||||
r.body = &iStreamReleaseCloser{stream: content}
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
var _ Request = &request{}
|
||||
|
||||
type request struct {
|
||||
response *edge.ICoreWebView2WebResourceResponse
|
||||
deferral *edge.ICoreWebView2Deferral
|
||||
|
||||
url string
|
||||
urlErr error
|
||||
|
||||
method string
|
||||
methodErr error
|
||||
|
||||
header http.Header
|
||||
headerErr error
|
||||
|
||||
body io.ReadCloser
|
||||
bodyErr error
|
||||
rw *responseWriter
|
||||
|
||||
invokeSync func(fn func())
|
||||
}
|
||||
|
||||
func (r *request) URL() (string, error) {
|
||||
return r.url, r.urlErr
|
||||
}
|
||||
|
||||
func (r *request) Method() (string, error) {
|
||||
return r.method, r.methodErr
|
||||
}
|
||||
|
||||
func (r *request) Header() (http.Header, error) {
|
||||
return r.header, r.headerErr
|
||||
}
|
||||
|
||||
func (r *request) Body() (io.ReadCloser, error) {
|
||||
return r.body, r.bodyErr
|
||||
}
|
||||
|
||||
func (r *request) Response() ResponseWriter {
|
||||
if r.rw != nil {
|
||||
return r.rw
|
||||
}
|
||||
|
||||
r.rw = &responseWriter{req: r}
|
||||
return r.rw
|
||||
}
|
||||
|
||||
func (r *request) Close() error {
|
||||
var errs []error
|
||||
if r.body != nil {
|
||||
if err := r.body.Close(); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
r.body = nil
|
||||
}
|
||||
|
||||
if err := r.Response().Finish(); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
return combineErrs(errs)
|
||||
}
|
||||
|
||||
// finishResponse must be called on the main-thread
|
||||
func (r *request) finishResponse() error {
|
||||
var errs []error
|
||||
if r.response != nil {
|
||||
if err := r.response.Release(); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
r.response = nil
|
||||
}
|
||||
if r.deferral != nil {
|
||||
if err := r.deferral.Complete(); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
if err := r.deferral.Release(); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
r.deferral = nil
|
||||
}
|
||||
return combineErrs(errs)
|
||||
}
|
||||
|
||||
type iStreamReleaseCloser struct {
|
||||
stream *edge.IStream
|
||||
closed bool
|
||||
}
|
||||
|
||||
func (i *iStreamReleaseCloser) Read(p []byte) (int, error) {
|
||||
if i.closed {
|
||||
return 0, io.ErrClosedPipe
|
||||
}
|
||||
return i.stream.Read(p)
|
||||
}
|
||||
|
||||
func (i *iStreamReleaseCloser) Close() error {
|
||||
if i.closed {
|
||||
return nil
|
||||
}
|
||||
i.closed = true
|
||||
return i.stream.Release()
|
||||
}
|
||||
|
||||
func getHeaders(req *edge.ICoreWebView2WebResourceRequest) (http.Header, error) {
|
||||
header := http.Header{}
|
||||
headers, err := req.GetHeaders()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GetHeaders Error: %s", err)
|
||||
}
|
||||
defer headers.Release()
|
||||
|
||||
headersIt, err := headers.GetIterator()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GetIterator Error: %s", err)
|
||||
}
|
||||
defer headersIt.Release()
|
||||
|
||||
for {
|
||||
has, err := headersIt.HasCurrentHeader()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("HasCurrentHeader Error: %s", err)
|
||||
}
|
||||
if !has {
|
||||
break
|
||||
}
|
||||
|
||||
name, value, err := headersIt.GetCurrentHeader()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GetCurrentHeader Error: %s", err)
|
||||
}
|
||||
|
||||
header.Set(name, value)
|
||||
if _, err := headersIt.MoveNext(); err != nil {
|
||||
return nil, fmt.Errorf("MoveNext Error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// WebView2 has problems when a request returns a 304 status code and the WebView2 is going to hang for other
|
||||
// requests including IPC calls.
|
||||
// So prevent 304 status codes by removing the headers that are used in combinationwith caching.
|
||||
header.Del("If-Modified-Since")
|
||||
header.Del("If-None-Match")
|
||||
return header, nil
|
||||
}
|
||||
|
||||
func combineErrs(errs []error) error {
|
||||
// TODO use Go1.20 errors.Join
|
||||
if len(errs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
errStrings := make([]string, len(errs))
|
||||
for i, err := range errs {
|
||||
errStrings[i] = err.Error()
|
||||
}
|
||||
|
||||
return fmt.Errorf(strings.Join(errStrings, "\n"))
|
||||
}
|
||||
25
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/responsewriter.go
generated
vendored
Normal file
25
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/responsewriter.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package webview
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
HeaderContentLength = "Content-Length"
|
||||
HeaderContentType = "Content-Type"
|
||||
)
|
||||
|
||||
var (
|
||||
errRequestStopped = errors.New("request has been stopped")
|
||||
errResponseFinished = errors.New("response has been finished")
|
||||
)
|
||||
|
||||
// A ResponseWriter interface is used by an HTTP handler to
|
||||
// construct an HTTP response for the WebView.
|
||||
type ResponseWriter interface {
|
||||
http.ResponseWriter
|
||||
|
||||
// Finish the response and flush all data. A Finish after the request has already been finished has no effect.
|
||||
Finish() error
|
||||
}
|
||||
164
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/responsewriter_darwin.go
generated
vendored
Normal file
164
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/responsewriter_darwin.go
generated
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
//go:build darwin
|
||||
|
||||
package webview
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -x objective-c
|
||||
#cgo LDFLAGS: -framework Foundation -framework WebKit
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
typedef void (^schemeTaskCaller)(id<WKURLSchemeTask>);
|
||||
|
||||
static bool urlSchemeTaskCall(void *wkUrlSchemeTask, schemeTaskCaller fn) {
|
||||
id<WKURLSchemeTask> urlSchemeTask = (id<WKURLSchemeTask>) wkUrlSchemeTask;
|
||||
if (urlSchemeTask == nil) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@autoreleasepool {
|
||||
@try {
|
||||
fn(urlSchemeTask);
|
||||
} @catch (NSException *exception) {
|
||||
// This is very bad to detect a stopped schemeTask this should be implemented in a better way
|
||||
// But it seems to be very tricky to not deadlock when keeping a lock curing executing fn()
|
||||
// It seems like those call switch the thread back to the main thread and then deadlocks when they reentrant want
|
||||
// to get the lock again to start another request or stop it.
|
||||
if ([exception.reason isEqualToString: @"This task has already been stopped"]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@throw exception;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool URLSchemeTaskDidReceiveData(void *wkUrlSchemeTask, void* data, int datalength) {
|
||||
return urlSchemeTaskCall(
|
||||
wkUrlSchemeTask,
|
||||
^(id<WKURLSchemeTask> urlSchemeTask) {
|
||||
NSData *nsdata = [NSData dataWithBytes:data length:datalength];
|
||||
[urlSchemeTask didReceiveData:nsdata];
|
||||
});
|
||||
}
|
||||
|
||||
static bool URLSchemeTaskDidFinish(void *wkUrlSchemeTask) {
|
||||
return urlSchemeTaskCall(
|
||||
wkUrlSchemeTask,
|
||||
^(id<WKURLSchemeTask> urlSchemeTask) {
|
||||
[urlSchemeTask didFinish];
|
||||
});
|
||||
}
|
||||
|
||||
static bool URLSchemeTaskDidReceiveResponse(void *wkUrlSchemeTask, int statusCode, void *headersString, int headersStringLength) {
|
||||
return urlSchemeTaskCall(
|
||||
wkUrlSchemeTask,
|
||||
^(id<WKURLSchemeTask> urlSchemeTask) {
|
||||
NSData *nsHeadersJSON = [NSData dataWithBytes:headersString length:headersStringLength];
|
||||
NSDictionary *headerFields = [NSJSONSerialization JSONObjectWithData:nsHeadersJSON options: NSJSONReadingMutableContainers error: nil];
|
||||
NSHTTPURLResponse *response = [[[NSHTTPURLResponse alloc] initWithURL:urlSchemeTask.request.URL statusCode:statusCode HTTPVersion:@"HTTP/1.1" headerFields:headerFields] autorelease];
|
||||
|
||||
[urlSchemeTask didReceiveResponse:response];
|
||||
});
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var _ ResponseWriter = &responseWriter{}
|
||||
|
||||
type responseWriter struct {
|
||||
r *request
|
||||
|
||||
header http.Header
|
||||
wroteHeader bool
|
||||
|
||||
finished bool
|
||||
}
|
||||
|
||||
func (rw *responseWriter) Header() http.Header {
|
||||
if rw.header == nil {
|
||||
rw.header = http.Header{}
|
||||
}
|
||||
return rw.header
|
||||
}
|
||||
|
||||
func (rw *responseWriter) Write(buf []byte) (int, error) {
|
||||
if rw.finished {
|
||||
return 0, errResponseFinished
|
||||
}
|
||||
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
|
||||
var contentLen int
|
||||
if buf != nil {
|
||||
contentLen = len(buf)
|
||||
}
|
||||
|
||||
if contentLen > 0 {
|
||||
// Create a C array to hold the data
|
||||
cBuf := C.malloc(C.size_t(contentLen))
|
||||
if cBuf == nil {
|
||||
return 0, fmt.Errorf("memory allocation failed for %d bytes", contentLen)
|
||||
}
|
||||
defer C.free(cBuf)
|
||||
|
||||
// Copy the Go slice to the C array
|
||||
C.memcpy(cBuf, unsafe.Pointer(&buf[0]), C.size_t(contentLen))
|
||||
|
||||
if !C.URLSchemeTaskDidReceiveData(rw.r.task, cBuf, C.int(contentLen)) {
|
||||
return 0, errRequestStopped
|
||||
}
|
||||
} else {
|
||||
if !C.URLSchemeTaskDidReceiveData(rw.r.task, nil, 0) {
|
||||
return 0, errRequestStopped
|
||||
}
|
||||
}
|
||||
|
||||
return contentLen, nil
|
||||
}
|
||||
|
||||
func (rw *responseWriter) WriteHeader(code int) {
|
||||
if rw.wroteHeader || rw.finished {
|
||||
return
|
||||
}
|
||||
rw.wroteHeader = true
|
||||
|
||||
header := map[string]string{}
|
||||
for k := range rw.Header() {
|
||||
header[k] = rw.Header().Get(k)
|
||||
}
|
||||
headerData, _ := json.Marshal(header)
|
||||
|
||||
var headers unsafe.Pointer
|
||||
var headersLen int
|
||||
if len(headerData) != 0 {
|
||||
headers = unsafe.Pointer(&headerData[0])
|
||||
headersLen = len(headerData)
|
||||
}
|
||||
|
||||
C.URLSchemeTaskDidReceiveResponse(rw.r.task, C.int(code), headers, C.int(headersLen))
|
||||
}
|
||||
|
||||
func (rw *responseWriter) Finish() error {
|
||||
if !rw.wroteHeader {
|
||||
rw.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
if rw.finished {
|
||||
return nil
|
||||
}
|
||||
rw.finished = true
|
||||
|
||||
C.URLSchemeTaskDidFinish(rw.r.task)
|
||||
return nil
|
||||
}
|
||||
132
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/responsewriter_linux.go
generated
vendored
Normal file
132
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/responsewriter_linux.go
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package webview
|
||||
|
||||
/*
|
||||
#cgo linux pkg-config: gtk+-3.0 gio-unix-2.0
|
||||
#cgo !webkit2_41 pkg-config: webkit2gtk-4.0
|
||||
#cgo webkit2_41 pkg-config: webkit2gtk-4.1
|
||||
|
||||
#include "gtk/gtk.h"
|
||||
#include "webkit2/webkit2.h"
|
||||
#include "gio/gunixinputstream.h"
|
||||
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type responseWriter struct {
|
||||
req *C.WebKitURISchemeRequest
|
||||
|
||||
header http.Header
|
||||
wroteHeader bool
|
||||
finished bool
|
||||
|
||||
w io.WriteCloser
|
||||
wErr error
|
||||
}
|
||||
|
||||
func (rw *responseWriter) Header() http.Header {
|
||||
if rw.header == nil {
|
||||
rw.header = http.Header{}
|
||||
}
|
||||
return rw.header
|
||||
}
|
||||
|
||||
func (rw *responseWriter) Write(buf []byte) (int, error) {
|
||||
if rw.finished {
|
||||
return 0, errResponseFinished
|
||||
}
|
||||
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
if rw.wErr != nil {
|
||||
return 0, rw.wErr
|
||||
}
|
||||
return rw.w.Write(buf)
|
||||
}
|
||||
|
||||
func (rw *responseWriter) WriteHeader(code int) {
|
||||
if rw.wroteHeader || rw.finished {
|
||||
return
|
||||
}
|
||||
rw.wroteHeader = true
|
||||
|
||||
contentLength := int64(-1)
|
||||
if sLen := rw.Header().Get(HeaderContentLength); sLen != "" {
|
||||
if pLen, _ := strconv.ParseInt(sLen, 10, 64); pLen > 0 {
|
||||
contentLength = pLen
|
||||
}
|
||||
}
|
||||
|
||||
// We can't use os.Pipe here, because that returns files with a finalizer for closing the FD. But the control over the
|
||||
// read FD is given to the InputStream and will be closed there.
|
||||
// Furthermore we especially don't want to have the FD_CLOEXEC
|
||||
rFD, w, err := pipe()
|
||||
if err != nil {
|
||||
rw.finishWithError(http.StatusInternalServerError, fmt.Errorf("unable to open pipe: %s", err))
|
||||
return
|
||||
}
|
||||
rw.w = w
|
||||
|
||||
stream := C.g_unix_input_stream_new(C.int(rFD), C.gboolean(1))
|
||||
defer C.g_object_unref(C.gpointer(stream))
|
||||
|
||||
if err := webkit_uri_scheme_request_finish(rw.req, code, rw.Header(), stream, contentLength); err != nil {
|
||||
rw.finishWithError(http.StatusInternalServerError, fmt.Errorf("unable to finish request: %s", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (rw *responseWriter) Finish() error {
|
||||
if !rw.wroteHeader {
|
||||
rw.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
if rw.finished {
|
||||
return nil
|
||||
}
|
||||
rw.finished = true
|
||||
if rw.w != nil {
|
||||
rw.w.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rw *responseWriter) finishWithError(code int, err error) {
|
||||
if rw.w != nil {
|
||||
rw.w.Close()
|
||||
rw.w = &nopCloser{io.Discard}
|
||||
}
|
||||
rw.wErr = err
|
||||
|
||||
msg := C.CString(err.Error())
|
||||
gerr := C.g_error_new_literal(C.g_quark_from_string(msg), C.int(code), msg)
|
||||
C.webkit_uri_scheme_request_finish_error(rw.req, gerr)
|
||||
C.g_error_free(gerr)
|
||||
C.free(unsafe.Pointer(msg))
|
||||
}
|
||||
|
||||
type nopCloser struct {
|
||||
io.Writer
|
||||
}
|
||||
|
||||
func (nopCloser) Close() error { return nil }
|
||||
|
||||
func pipe() (r int, w *os.File, err error) {
|
||||
var p [2]int
|
||||
e := syscall.Pipe2(p[0:], 0)
|
||||
if e != nil {
|
||||
return 0, nil, fmt.Errorf("pipe2: %s", e)
|
||||
}
|
||||
|
||||
return p[0], os.NewFile(uintptr(p[1]), "|1"), nil
|
||||
}
|
||||
105
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/responsewriter_windows.go
generated
vendored
Normal file
105
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/responsewriter_windows.go
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package webview
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var _ http.ResponseWriter = &responseWriter{}
|
||||
|
||||
type responseWriter struct {
|
||||
req *request
|
||||
|
||||
header http.Header
|
||||
wroteHeader bool
|
||||
code int
|
||||
body *bytes.Buffer
|
||||
|
||||
finished bool
|
||||
}
|
||||
|
||||
func (rw *responseWriter) Header() http.Header {
|
||||
if rw.header == nil {
|
||||
rw.header = http.Header{}
|
||||
}
|
||||
return rw.header
|
||||
}
|
||||
|
||||
func (rw *responseWriter) Write(buf []byte) (int, error) {
|
||||
if rw.finished {
|
||||
return 0, errResponseFinished
|
||||
}
|
||||
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
|
||||
return rw.body.Write(buf)
|
||||
}
|
||||
|
||||
func (rw *responseWriter) WriteHeader(code int) {
|
||||
if rw.wroteHeader || rw.finished {
|
||||
return
|
||||
}
|
||||
rw.wroteHeader = true
|
||||
|
||||
if rw.body == nil {
|
||||
rw.body = &bytes.Buffer{}
|
||||
}
|
||||
|
||||
rw.code = code
|
||||
}
|
||||
|
||||
func (rw *responseWriter) Finish() error {
|
||||
if !rw.wroteHeader {
|
||||
rw.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
if rw.finished {
|
||||
return nil
|
||||
}
|
||||
rw.finished = true
|
||||
|
||||
var errs []error
|
||||
|
||||
code := rw.code
|
||||
if code == http.StatusNotModified {
|
||||
// WebView2 has problems when a request returns a 304 status code and the WebView2 is going to hang for other
|
||||
// requests including IPC calls.
|
||||
errs = append(errs, fmt.Errorf("AssetServer returned 304 - StatusNotModified which are going to hang WebView2, changed code to 505 - StatusInternalServerError"))
|
||||
code = http.StatusInternalServerError
|
||||
}
|
||||
|
||||
rw.req.invokeSync(func() {
|
||||
resp := rw.req.response
|
||||
|
||||
hdrs, err := resp.GetHeaders()
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("Resp.GetHeaders failed: %s", err))
|
||||
} else {
|
||||
for k, v := range rw.header {
|
||||
if err := hdrs.AppendHeader(k, strings.Join(v, ",")); err != nil {
|
||||
errs = append(errs, fmt.Errorf("Resp.AppendHeader failed: %s", err))
|
||||
}
|
||||
}
|
||||
hdrs.Release()
|
||||
}
|
||||
|
||||
if err := resp.PutStatusCode(code); err != nil {
|
||||
errs = append(errs, fmt.Errorf("Resp.PutStatusCode failed: %s", err))
|
||||
}
|
||||
|
||||
if err := resp.PutByteContent(rw.body.Bytes()); err != nil {
|
||||
errs = append(errs, fmt.Errorf("Resp.PutByteContent failed: %s", err))
|
||||
}
|
||||
|
||||
if err := rw.req.finishResponse(); err != nil {
|
||||
errs = append(errs, fmt.Errorf("Resp.finishResponse failed: %s", err))
|
||||
}
|
||||
})
|
||||
|
||||
return combineErrs(errs)
|
||||
}
|
||||
71
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/webkit2_36+.go
generated
vendored
Normal file
71
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/webkit2_36+.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
//go:build linux && (webkit2_36 || webkit2_40 || webkit2_41 )
|
||||
|
||||
package webview
|
||||
|
||||
/*
|
||||
#cgo linux pkg-config: gtk+-3.0
|
||||
#cgo !webkit2_41 pkg-config: webkit2gtk-4.0 libsoup-2.4
|
||||
#cgo webkit2_41 pkg-config: webkit2gtk-4.1 libsoup-3.0
|
||||
|
||||
#include "gtk/gtk.h"
|
||||
#include "webkit2/webkit2.h"
|
||||
#include "libsoup/soup.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func webkit_uri_scheme_request_get_http_method(req *C.WebKitURISchemeRequest) string {
|
||||
method := C.GoString(C.webkit_uri_scheme_request_get_http_method(req))
|
||||
return strings.ToUpper(method)
|
||||
}
|
||||
|
||||
func webkit_uri_scheme_request_get_http_headers(req *C.WebKitURISchemeRequest) http.Header {
|
||||
hdrs := C.webkit_uri_scheme_request_get_http_headers(req)
|
||||
|
||||
var iter C.SoupMessageHeadersIter
|
||||
C.soup_message_headers_iter_init(&iter, hdrs)
|
||||
|
||||
var name *C.char
|
||||
var value *C.char
|
||||
|
||||
h := http.Header{}
|
||||
for C.soup_message_headers_iter_next(&iter, &name, &value) != 0 {
|
||||
h.Add(C.GoString(name), C.GoString(value))
|
||||
}
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
func webkit_uri_scheme_request_finish(req *C.WebKitURISchemeRequest, code int, header http.Header, stream *C.GInputStream, streamLength int64) error {
|
||||
resp := C.webkit_uri_scheme_response_new(stream, C.gint64(streamLength))
|
||||
defer C.g_object_unref(C.gpointer(resp))
|
||||
|
||||
cReason := C.CString(http.StatusText(code))
|
||||
C.webkit_uri_scheme_response_set_status(resp, C.guint(code), cReason)
|
||||
C.free(unsafe.Pointer(cReason))
|
||||
|
||||
cMimeType := C.CString(header.Get(HeaderContentType))
|
||||
C.webkit_uri_scheme_response_set_content_type(resp, cMimeType)
|
||||
C.free(unsafe.Pointer(cMimeType))
|
||||
|
||||
hdrs := C.soup_message_headers_new(C.SOUP_MESSAGE_HEADERS_RESPONSE)
|
||||
for name, values := range header {
|
||||
cName := C.CString(name)
|
||||
for _, value := range values {
|
||||
cValue := C.CString(value)
|
||||
C.soup_message_headers_append(hdrs, cName, cValue)
|
||||
C.free(unsafe.Pointer(cValue))
|
||||
}
|
||||
C.free(unsafe.Pointer(cName))
|
||||
}
|
||||
|
||||
C.webkit_uri_scheme_response_set_http_headers(resp, hdrs)
|
||||
|
||||
C.webkit_uri_scheme_request_finish_with_response(req, resp)
|
||||
return nil
|
||||
}
|
||||
21
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/webkit2_36.go
generated
vendored
Normal file
21
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/webkit2_36.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
//go:build linux && webkit2_36
|
||||
|
||||
package webview
|
||||
|
||||
/*
|
||||
#cgo linux pkg-config: webkit2gtk-4.0
|
||||
|
||||
#include "webkit2/webkit2.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const Webkit2MinMinorVersion = 36
|
||||
|
||||
func webkit_uri_scheme_request_get_http_body(_ *C.WebKitURISchemeRequest) io.ReadCloser {
|
||||
return http.NoBody
|
||||
}
|
||||
85
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/webkit2_40+.go
generated
vendored
Normal file
85
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/webkit2_40+.go
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
//go:build linux && (webkit2_40 || webkit2_41)
|
||||
|
||||
package webview
|
||||
|
||||
/*
|
||||
#cgo linux pkg-config: gtk+-3.0 gio-unix-2.0
|
||||
#cgo !webkit2_41 pkg-config: webkit2gtk-4.0
|
||||
#cgo webkit2_41 pkg-config: webkit2gtk-4.1
|
||||
|
||||
#include "gtk/gtk.h"
|
||||
#include "webkit2/webkit2.h"
|
||||
#include "gio/gunixinputstream.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func webkit_uri_scheme_request_get_http_body(req *C.WebKitURISchemeRequest) io.ReadCloser {
|
||||
stream := C.webkit_uri_scheme_request_get_http_body(req)
|
||||
if stream == nil {
|
||||
return http.NoBody
|
||||
}
|
||||
return &webkitRequestBody{stream: stream}
|
||||
}
|
||||
|
||||
type webkitRequestBody struct {
|
||||
stream *C.GInputStream
|
||||
closed bool
|
||||
}
|
||||
|
||||
// Read implements io.Reader
|
||||
func (r *webkitRequestBody) Read(p []byte) (int, error) {
|
||||
if r.closed {
|
||||
return 0, io.ErrClosedPipe
|
||||
}
|
||||
|
||||
var content unsafe.Pointer
|
||||
var contentLen int
|
||||
if p != nil {
|
||||
content = unsafe.Pointer(&p[0])
|
||||
contentLen = len(p)
|
||||
}
|
||||
|
||||
var n C.gsize
|
||||
var gErr *C.GError
|
||||
res := C.g_input_stream_read_all(r.stream, content, C.gsize(contentLen), &n, nil, &gErr)
|
||||
if res == 0 {
|
||||
return 0, formatGError("stream read failed", gErr)
|
||||
} else if n == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return int(n), nil
|
||||
}
|
||||
|
||||
func (r *webkitRequestBody) Close() error {
|
||||
if r.closed {
|
||||
return nil
|
||||
}
|
||||
r.closed = true
|
||||
|
||||
// https://docs.gtk.org/gio/method.InputStream.close.html
|
||||
// Streams will be automatically closed when the last reference is dropped, but you might want to call this function
|
||||
// to make sure resources are released as early as possible.
|
||||
var err error
|
||||
var gErr *C.GError
|
||||
if C.g_input_stream_close(r.stream, nil, &gErr) == 0 {
|
||||
err = formatGError("stream close failed", gErr)
|
||||
}
|
||||
C.g_object_unref(C.gpointer(r.stream))
|
||||
r.stream = nil
|
||||
return err
|
||||
}
|
||||
|
||||
func formatGError(msg string, gErr *C.GError, args ...any) error {
|
||||
if gErr != nil && gErr.message != nil {
|
||||
msg += ": " + C.GoString(gErr.message)
|
||||
C.g_error_free(gErr)
|
||||
}
|
||||
return fmt.Errorf(msg, args...)
|
||||
}
|
||||
5
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/webkit2_40.go
generated
vendored
Normal file
5
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/webkit2_40.go
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
//go:build linux && webkit2_40
|
||||
|
||||
package webview
|
||||
|
||||
const Webkit2MinMinorVersion = 40
|
||||
5
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/webkit2_41.go
generated
vendored
Normal file
5
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/webkit2_41.go
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
//go:build linux && webkit2_41
|
||||
|
||||
package webview
|
||||
|
||||
const Webkit2MinMinorVersion = 41
|
||||
48
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/webkit2_legacy.go
generated
vendored
Normal file
48
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/webview/webkit2_legacy.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
//go:build linux && !(webkit2_36 || webkit2_40 || webkit2_41)
|
||||
|
||||
package webview
|
||||
|
||||
/*
|
||||
#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0
|
||||
|
||||
#include "gtk/gtk.h"
|
||||
#include "webkit2/webkit2.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const Webkit2MinMinorVersion = 0
|
||||
|
||||
func webkit_uri_scheme_request_get_http_method(_ *C.WebKitURISchemeRequest) string {
|
||||
return http.MethodGet
|
||||
}
|
||||
|
||||
func webkit_uri_scheme_request_get_http_headers(_ *C.WebKitURISchemeRequest) http.Header {
|
||||
// Fake some basic default headers that are needed if e.g. request are being proxied to the an external sever, like
|
||||
// we do in the devserver.
|
||||
h := http.Header{}
|
||||
h.Add("Accept", "*/*")
|
||||
h.Add("User-Agent", "wails.io/605.1.15")
|
||||
return h
|
||||
}
|
||||
|
||||
func webkit_uri_scheme_request_get_http_body(_ *C.WebKitURISchemeRequest) io.ReadCloser {
|
||||
return http.NoBody
|
||||
}
|
||||
|
||||
func webkit_uri_scheme_request_finish(req *C.WebKitURISchemeRequest, code int, header http.Header, stream *C.GInputStream, streamLength int64) error {
|
||||
if code != http.StatusOK {
|
||||
return fmt.Errorf("StatusCodes not supported: %d - %s", code, http.StatusText(code))
|
||||
}
|
||||
|
||||
cMimeType := C.CString(header.Get(HeaderContentType))
|
||||
C.webkit_uri_scheme_request_finish(req, stream, C.gint64(streamLength), cMimeType)
|
||||
C.free(unsafe.Pointer(cMimeType))
|
||||
return nil
|
||||
}
|
||||
49
vendor/github.com/wailsapp/wails/v2/pkg/logger/default.go
generated
vendored
Normal file
49
vendor/github.com/wailsapp/wails/v2/pkg/logger/default.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// DefaultLogger is a utility to log messages to a number of destinations
|
||||
type DefaultLogger struct{}
|
||||
|
||||
// NewDefaultLogger creates a new Logger.
|
||||
func NewDefaultLogger() Logger {
|
||||
return &DefaultLogger{}
|
||||
}
|
||||
|
||||
// Print works like Sprintf.
|
||||
func (l *DefaultLogger) Print(message string) {
|
||||
println(message)
|
||||
}
|
||||
|
||||
// Trace level logging. Works like Sprintf.
|
||||
func (l *DefaultLogger) Trace(message string) {
|
||||
println("TRA | " + message)
|
||||
}
|
||||
|
||||
// Debug level logging. Works like Sprintf.
|
||||
func (l *DefaultLogger) Debug(message string) {
|
||||
println("DEB | " + message)
|
||||
}
|
||||
|
||||
// Info level logging. Works like Sprintf.
|
||||
func (l *DefaultLogger) Info(message string) {
|
||||
println("INF | " + message)
|
||||
}
|
||||
|
||||
// Warning level logging. Works like Sprintf.
|
||||
func (l *DefaultLogger) Warning(message string) {
|
||||
println("WAR | " + message)
|
||||
}
|
||||
|
||||
// Error level logging. Works like Sprintf.
|
||||
func (l *DefaultLogger) Error(message string) {
|
||||
println("ERR | " + message)
|
||||
}
|
||||
|
||||
// Fatal level logging. Works like Sprintf.
|
||||
func (l *DefaultLogger) Fatal(message string) {
|
||||
println("FAT | " + message)
|
||||
os.Exit(1)
|
||||
}
|
||||
66
vendor/github.com/wailsapp/wails/v2/pkg/logger/filelogger.go
generated
vendored
Normal file
66
vendor/github.com/wailsapp/wails/v2/pkg/logger/filelogger.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
// FileLogger is a utility to log messages to a number of destinations
|
||||
type FileLogger struct {
|
||||
filename string
|
||||
}
|
||||
|
||||
// NewFileLogger creates a new Logger.
|
||||
func NewFileLogger(filename string) Logger {
|
||||
return &FileLogger{
|
||||
filename: filename,
|
||||
}
|
||||
}
|
||||
|
||||
// Print works like Sprintf.
|
||||
func (l *FileLogger) Print(message string) {
|
||||
f, err := os.OpenFile(l.filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if _, err := f.WriteString(message); err != nil {
|
||||
f.Close()
|
||||
log.Fatal(err)
|
||||
}
|
||||
f.Close()
|
||||
}
|
||||
|
||||
func (l *FileLogger) Println(message string) {
|
||||
l.Print(message + "\n")
|
||||
}
|
||||
|
||||
// Trace level logging. Works like Sprintf.
|
||||
func (l *FileLogger) Trace(message string) {
|
||||
l.Println("TRACE | " + message)
|
||||
}
|
||||
|
||||
// Debug level logging. Works like Sprintf.
|
||||
func (l *FileLogger) Debug(message string) {
|
||||
l.Println("DEBUG | " + message)
|
||||
}
|
||||
|
||||
// Info level logging. Works like Sprintf.
|
||||
func (l *FileLogger) Info(message string) {
|
||||
l.Println("INFO | " + message)
|
||||
}
|
||||
|
||||
// Warning level logging. Works like Sprintf.
|
||||
func (l *FileLogger) Warning(message string) {
|
||||
l.Println("WARN | " + message)
|
||||
}
|
||||
|
||||
// Error level logging. Works like Sprintf.
|
||||
func (l *FileLogger) Error(message string) {
|
||||
l.Println("ERROR | " + message)
|
||||
}
|
||||
|
||||
// Fatal level logging. Works like Sprintf.
|
||||
func (l *FileLogger) Fatal(message string) {
|
||||
l.Println("FATAL | " + message)
|
||||
os.Exit(1)
|
||||
}
|
||||
72
vendor/github.com/wailsapp/wails/v2/pkg/logger/logger.go
generated
vendored
Normal file
72
vendor/github.com/wailsapp/wails/v2/pkg/logger/logger.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// LogLevel is an unsigned 8bit int
|
||||
type LogLevel uint8
|
||||
|
||||
const (
|
||||
// TRACE level
|
||||
TRACE LogLevel = 1
|
||||
|
||||
// DEBUG level logging
|
||||
DEBUG LogLevel = 2
|
||||
|
||||
// INFO level logging
|
||||
INFO LogLevel = 3
|
||||
|
||||
// WARNING level logging
|
||||
WARNING LogLevel = 4
|
||||
|
||||
// ERROR level logging
|
||||
ERROR LogLevel = 5
|
||||
)
|
||||
|
||||
var logLevelMap = map[string]LogLevel{
|
||||
"trace": TRACE,
|
||||
"debug": DEBUG,
|
||||
"info": INFO,
|
||||
"warning": WARNING,
|
||||
"error": ERROR,
|
||||
}
|
||||
|
||||
func StringToLogLevel(input string) (LogLevel, error) {
|
||||
result, ok := logLevelMap[strings.ToLower(input)]
|
||||
if !ok {
|
||||
return ERROR, fmt.Errorf("invalid log level: %s", input)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// String returns the string representation of the LogLevel
|
||||
func (l LogLevel) String() string {
|
||||
switch l {
|
||||
case TRACE:
|
||||
return "trace"
|
||||
case DEBUG:
|
||||
return "debug"
|
||||
case INFO:
|
||||
return "info"
|
||||
case WARNING:
|
||||
return "warning"
|
||||
case ERROR:
|
||||
return "error"
|
||||
default:
|
||||
return "debug"
|
||||
}
|
||||
}
|
||||
|
||||
// Logger specifies the methods required to attach
|
||||
// a logger to a Wails application
|
||||
type Logger interface {
|
||||
Print(message string)
|
||||
Trace(message string)
|
||||
Debug(message string)
|
||||
Info(message string)
|
||||
Warning(message string)
|
||||
Error(message string)
|
||||
Fatal(message string)
|
||||
}
|
||||
10
vendor/github.com/wailsapp/wails/v2/pkg/menu/README.md
generated
vendored
Normal file
10
vendor/github.com/wailsapp/wails/v2/pkg/menu/README.md
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# Menus
|
||||
|
||||
Menu support is heavily inspired by Electron's approach.
|
||||
|
||||
## Features
|
||||
|
||||
* Supports Text, Checkbox, Radio, Submenu and Separator
|
||||
* Radio groups are defined as any number of adjacent radio items
|
||||
* UTF-8 menu labels
|
||||
* UTF-8 menu IDs
|
||||
8
vendor/github.com/wailsapp/wails/v2/pkg/menu/callback.go
generated
vendored
Normal file
8
vendor/github.com/wailsapp/wails/v2/pkg/menu/callback.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
package menu
|
||||
|
||||
type CallbackData struct {
|
||||
MenuItem *MenuItem
|
||||
// ContextData string
|
||||
}
|
||||
|
||||
type Callback func(*CallbackData)
|
||||
1559
vendor/github.com/wailsapp/wails/v2/pkg/menu/cols.go
generated
vendored
Normal file
1559
vendor/github.com/wailsapp/wails/v2/pkg/menu/cols.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
13
vendor/github.com/wailsapp/wails/v2/pkg/menu/contextmenu.go
generated
vendored
Normal file
13
vendor/github.com/wailsapp/wails/v2/pkg/menu/contextmenu.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package menu
|
||||
|
||||
type ContextMenu struct {
|
||||
ID string
|
||||
Menu *Menu
|
||||
}
|
||||
|
||||
func NewContextMenu(ID string, menu *Menu) *ContextMenu {
|
||||
return &ContextMenu{
|
||||
ID: ID,
|
||||
Menu: menu,
|
||||
}
|
||||
}
|
||||
104
vendor/github.com/wailsapp/wails/v2/pkg/menu/keys/keys.go
generated
vendored
Normal file
104
vendor/github.com/wailsapp/wails/v2/pkg/menu/keys/keys.go
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Modifier is actually a string
|
||||
type Modifier string
|
||||
|
||||
const (
|
||||
// CmdOrCtrlKey represents Command on Mac and Control on other platforms
|
||||
CmdOrCtrlKey Modifier = "cmdorctrl"
|
||||
// OptionOrAltKey represents Option on Mac and Alt on other platforms
|
||||
OptionOrAltKey Modifier = "optionoralt"
|
||||
// ShiftKey represents the shift key on all systems
|
||||
ShiftKey Modifier = "shift"
|
||||
// SuperKey represents Command on Mac and the Windows key on the other platforms
|
||||
// SuperKey Modifier = "super"
|
||||
// ControlKey represents the control key on all systems
|
||||
ControlKey Modifier = "ctrl"
|
||||
)
|
||||
|
||||
var modifierMap = map[string]Modifier{
|
||||
"cmdorctrl": CmdOrCtrlKey,
|
||||
"optionoralt": OptionOrAltKey,
|
||||
"shift": ShiftKey,
|
||||
//"super": SuperKey,
|
||||
"ctrl": ControlKey,
|
||||
}
|
||||
|
||||
func parseModifier(text string) (*Modifier, error) {
|
||||
lowertext := strings.ToLower(text)
|
||||
result, valid := modifierMap[lowertext]
|
||||
if !valid {
|
||||
return nil, fmt.Errorf("'%s' is not a valid modifier", text)
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// Accelerator holds the keyboard shortcut for a menu item
|
||||
type Accelerator struct {
|
||||
Key string
|
||||
Modifiers []Modifier
|
||||
}
|
||||
|
||||
// Key creates a standard key Accelerator
|
||||
func Key(key string) *Accelerator {
|
||||
return &Accelerator{
|
||||
Key: strings.ToLower(key),
|
||||
}
|
||||
}
|
||||
|
||||
// CmdOrCtrl creates a 'CmdOrCtrl' Accelerator
|
||||
func CmdOrCtrl(key string) *Accelerator {
|
||||
return &Accelerator{
|
||||
Key: strings.ToLower(key),
|
||||
Modifiers: []Modifier{CmdOrCtrlKey},
|
||||
}
|
||||
}
|
||||
|
||||
// OptionOrAlt creates a 'OptionOrAlt' Accelerator
|
||||
func OptionOrAlt(key string) *Accelerator {
|
||||
return &Accelerator{
|
||||
Key: strings.ToLower(key),
|
||||
Modifiers: []Modifier{OptionOrAltKey},
|
||||
}
|
||||
}
|
||||
|
||||
// Shift creates a 'Shift' Accelerator
|
||||
func Shift(key string) *Accelerator {
|
||||
return &Accelerator{
|
||||
Key: strings.ToLower(key),
|
||||
Modifiers: []Modifier{ShiftKey},
|
||||
}
|
||||
}
|
||||
|
||||
// Control creates a 'Control' Accelerator
|
||||
func Control(key string) *Accelerator {
|
||||
return &Accelerator{
|
||||
Key: strings.ToLower(key),
|
||||
Modifiers: []Modifier{ControlKey},
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//// Super creates a 'Super' Accelerator
|
||||
//func Super(key string) *Accelerator {
|
||||
// return &Accelerator{
|
||||
// Key: strings.ToLower(key),
|
||||
// Modifiers: []Modifier{SuperKey},
|
||||
// }
|
||||
//}
|
||||
|
||||
// Combo creates an Accelerator with multiple Modifiers
|
||||
func Combo(key string, modifier1 Modifier, modifier2 Modifier, rest ...Modifier) *Accelerator {
|
||||
result := &Accelerator{
|
||||
Key: key,
|
||||
Modifiers: []Modifier{modifier1, modifier2},
|
||||
}
|
||||
result.Modifiers = append(result.Modifiers, rest...)
|
||||
return result
|
||||
}
|
||||
26
vendor/github.com/wailsapp/wails/v2/pkg/menu/keys/macmodifiers.go
generated
vendored
Normal file
26
vendor/github.com/wailsapp/wails/v2/pkg/menu/keys/macmodifiers.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package keys
|
||||
|
||||
const (
|
||||
NSEventModifierFlagShift = 1 << 17 // Set if Shift key is pressed.
|
||||
NSEventModifierFlagControl = 1 << 18 // Set if Control key is pressed.
|
||||
NSEventModifierFlagOption = 1 << 19 // Set if Option or Alternate key is pressed.
|
||||
NSEventModifierFlagCommand = 1 << 20 // Set if Command key is pressed.
|
||||
)
|
||||
|
||||
var macModifierMap = map[Modifier]int{
|
||||
CmdOrCtrlKey: NSEventModifierFlagCommand,
|
||||
ControlKey: NSEventModifierFlagControl,
|
||||
OptionOrAltKey: NSEventModifierFlagOption,
|
||||
ShiftKey: NSEventModifierFlagShift,
|
||||
}
|
||||
|
||||
func ToMacModifier(accelerator *Accelerator) int {
|
||||
if accelerator == nil {
|
||||
return 0
|
||||
}
|
||||
result := 0
|
||||
for _, modifier := range accelerator.Modifiers {
|
||||
result |= macModifierMap[modifier]
|
||||
}
|
||||
return result
|
||||
}
|
||||
87
vendor/github.com/wailsapp/wails/v2/pkg/menu/keys/parser.go
generated
vendored
Normal file
87
vendor/github.com/wailsapp/wails/v2/pkg/menu/keys/parser.go
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
)
|
||||
|
||||
var namedKeys = slicer.String([]string{"backspace", "tab", "return", "enter", "escape", "left", "right", "up", "down", "space", "delete", "home", "end", "page up", "page down", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", "f32", "f33", "f34", "f35", "numlock"})
|
||||
|
||||
func parseKey(key string) (string, bool) {
|
||||
// Lowercase!
|
||||
key = strings.ToLower(key)
|
||||
|
||||
// Check special case
|
||||
if key == "plus" {
|
||||
return "+", true
|
||||
}
|
||||
|
||||
// Handle named keys
|
||||
if namedKeys.Contains(key) {
|
||||
return key, true
|
||||
}
|
||||
|
||||
// Check we only have a single character
|
||||
if len(key) != 1 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
runeKey := rune(key[0])
|
||||
|
||||
// This may be too inclusive
|
||||
if strconv.IsPrint(runeKey) {
|
||||
return key, true
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
||||
func Parse(shortcut string) (*Accelerator, error) {
|
||||
var result Accelerator
|
||||
|
||||
// Split the shortcut by +
|
||||
components := strings.Split(shortcut, "+")
|
||||
|
||||
// If we only have one it should be a key
|
||||
// We require components
|
||||
if len(components) == 0 {
|
||||
return nil, fmt.Errorf("no components given to validateComponents")
|
||||
}
|
||||
|
||||
// Keep track of modifiers we have processed
|
||||
var modifiersProcessed slicer.StringSlicer
|
||||
|
||||
// Check components
|
||||
for index, component := range components {
|
||||
|
||||
// If last component
|
||||
if index == len(components)-1 {
|
||||
processedkey, validKey := parseKey(component)
|
||||
if !validKey {
|
||||
return nil, fmt.Errorf("'%s' is not a valid key", component)
|
||||
}
|
||||
result.Key = processedkey
|
||||
continue
|
||||
}
|
||||
|
||||
// Not last component - needs to be modifier
|
||||
lowercaseComponent := strings.ToLower(component)
|
||||
thisModifier, valid := modifierMap[lowercaseComponent]
|
||||
if !valid {
|
||||
return nil, fmt.Errorf("'%s' is not a valid modifier", component)
|
||||
}
|
||||
// Needs to be unique
|
||||
if modifiersProcessed.Contains(lowercaseComponent) {
|
||||
return nil, fmt.Errorf("Modifier '%s' is defined twice for shortcut: %s", component, shortcut)
|
||||
}
|
||||
|
||||
// Save this data
|
||||
result.Modifiers = append(result.Modifiers, thisModifier)
|
||||
modifiersProcessed.Add(lowercaseComponent)
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
41
vendor/github.com/wailsapp/wails/v2/pkg/menu/keys/stringify.go
generated
vendored
Normal file
41
vendor/github.com/wailsapp/wails/v2/pkg/menu/keys/stringify.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
)
|
||||
|
||||
var modifierStringMap = map[string]map[Modifier]string{
|
||||
"windows": {
|
||||
CmdOrCtrlKey: "Ctrl",
|
||||
ControlKey: "Ctrl",
|
||||
OptionOrAltKey: "Alt",
|
||||
ShiftKey: "Shift",
|
||||
// SuperKey: "Win",
|
||||
},
|
||||
"darwin": {
|
||||
CmdOrCtrlKey: "Cmd",
|
||||
ControlKey: "Ctrl",
|
||||
OptionOrAltKey: "Option",
|
||||
ShiftKey: "Shift",
|
||||
// SuperKey: "Cmd",
|
||||
},
|
||||
"linux": {
|
||||
CmdOrCtrlKey: "Ctrl",
|
||||
ControlKey: "Ctrl",
|
||||
OptionOrAltKey: "Alt",
|
||||
ShiftKey: "Shift",
|
||||
// SuperKey: "Super",
|
||||
},
|
||||
}
|
||||
|
||||
func Stringify(accelerator *Accelerator, platform string) string {
|
||||
result := slicer.String()
|
||||
for _, modifier := range accelerator.Modifiers {
|
||||
result.Add(modifierStringMap[platform][modifier])
|
||||
}
|
||||
result.Deduplicate()
|
||||
result.Add(strings.ToUpper(accelerator.Key))
|
||||
return result.Join("+")
|
||||
}
|
||||
12
vendor/github.com/wailsapp/wails/v2/pkg/menu/mac.go
generated
vendored
Normal file
12
vendor/github.com/wailsapp/wails/v2/pkg/menu/mac.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
package menu
|
||||
|
||||
/*
|
||||
// DefaultMacMenu returns a default menu including the default
|
||||
// Application and Edit menus. Use `.Append()` to add to it.
|
||||
func DefaultMacMenu() *Menu {
|
||||
return NewMenuFromItems(
|
||||
AppMenu(),
|
||||
EditMenu(),
|
||||
)
|
||||
}
|
||||
*/
|
||||
75
vendor/github.com/wailsapp/wails/v2/pkg/menu/menu.go
generated
vendored
Normal file
75
vendor/github.com/wailsapp/wails/v2/pkg/menu/menu.go
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
package menu
|
||||
|
||||
import "github.com/wailsapp/wails/v2/pkg/menu/keys"
|
||||
|
||||
type Menu struct {
|
||||
Items []*MenuItem
|
||||
}
|
||||
|
||||
func NewMenu() *Menu {
|
||||
return &Menu{}
|
||||
}
|
||||
|
||||
func (m *Menu) Append(item *MenuItem) {
|
||||
m.Items = append(m.Items, item)
|
||||
}
|
||||
|
||||
// Merge will append the items in the given menu
|
||||
// into this menu
|
||||
func (m *Menu) Merge(menu *Menu) {
|
||||
m.Items = append(m.Items, menu.Items...)
|
||||
}
|
||||
|
||||
// AddText adds a TextMenu item to the menu
|
||||
func (m *Menu) AddText(label string, accelerator *keys.Accelerator, click Callback) *MenuItem {
|
||||
item := Text(label, accelerator, click)
|
||||
m.Append(item)
|
||||
return item
|
||||
}
|
||||
|
||||
// AddCheckbox adds a CheckboxMenu item to the menu
|
||||
func (m *Menu) AddCheckbox(label string, checked bool, accelerator *keys.Accelerator, click Callback) *MenuItem {
|
||||
item := Checkbox(label, checked, accelerator, click)
|
||||
m.Append(item)
|
||||
return item
|
||||
}
|
||||
|
||||
// AddRadio adds a radio item to the menu
|
||||
func (m *Menu) AddRadio(label string, checked bool, accelerator *keys.Accelerator, click Callback) *MenuItem {
|
||||
item := Radio(label, checked, accelerator, click)
|
||||
m.Append(item)
|
||||
return item
|
||||
}
|
||||
|
||||
// AddSeparator adds a separator to the menu
|
||||
func (m *Menu) AddSeparator() {
|
||||
item := Separator()
|
||||
m.Append(item)
|
||||
}
|
||||
|
||||
func (m *Menu) AddSubmenu(label string) *Menu {
|
||||
submenu := NewMenu()
|
||||
item := SubMenu(label, submenu)
|
||||
m.Append(item)
|
||||
return submenu
|
||||
}
|
||||
|
||||
func (m *Menu) Prepend(item *MenuItem) {
|
||||
m.Items = append([]*MenuItem{item}, m.Items...)
|
||||
}
|
||||
|
||||
func NewMenuFromItems(first *MenuItem, rest ...*MenuItem) *Menu {
|
||||
result := NewMenu()
|
||||
result.Append(first)
|
||||
for _, item := range rest {
|
||||
result.Append(item)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (m *Menu) setParent(menuItem *MenuItem) {
|
||||
for _, item := range m.Items {
|
||||
item.parent = menuItem
|
||||
}
|
||||
}
|
||||
329
vendor/github.com/wailsapp/wails/v2/pkg/menu/menuitem.go
generated
vendored
Normal file
329
vendor/github.com/wailsapp/wails/v2/pkg/menu/menuitem.go
generated
vendored
Normal file
@@ -0,0 +1,329 @@
|
||||
package menu
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/menu/keys"
|
||||
)
|
||||
|
||||
// MenuItem represents a menuitem contained in a menu
|
||||
type MenuItem struct {
|
||||
// Label is what appears as the menu text
|
||||
Label string
|
||||
// Role is a predefined menu type
|
||||
Role Role
|
||||
// Accelerator holds a representation of a key binding
|
||||
Accelerator *keys.Accelerator
|
||||
// Type of MenuItem, EG: Checkbox, Text, Separator, Radio, Submenu
|
||||
Type Type
|
||||
// Disabled makes the item unselectable
|
||||
Disabled bool
|
||||
// Hidden ensures that the item is not shown in the menu
|
||||
Hidden bool
|
||||
// Checked indicates if the item is selected (used by Checkbox and Radio types only)
|
||||
Checked bool
|
||||
// SubMenu contains a list of menu items that will be shown as a submenu
|
||||
// SubMenu []*MenuItem `json:"SubMenu,omitempty"`
|
||||
SubMenu *Menu
|
||||
|
||||
// Callback function when menu clicked
|
||||
Click Callback
|
||||
/*
|
||||
// Text Colour
|
||||
RGBA string
|
||||
|
||||
// Font
|
||||
FontSize int
|
||||
FontName string
|
||||
|
||||
// Image - base64 image data
|
||||
Image string
|
||||
|
||||
// MacTemplateImage indicates that on a Mac, this image is a template image
|
||||
MacTemplateImage bool
|
||||
|
||||
// MacAlternate indicates that this item is an alternative to the previous menu item
|
||||
MacAlternate bool
|
||||
|
||||
// Tooltip
|
||||
Tooltip string
|
||||
*/
|
||||
// This holds the menu item's parent.
|
||||
parent *MenuItem
|
||||
|
||||
// Used for locking when removing elements
|
||||
removeLock sync.Mutex
|
||||
}
|
||||
|
||||
// Parent returns the parent of the menu item.
|
||||
// If it is a top level menu then it returns nil.
|
||||
func (m *MenuItem) Parent() *MenuItem {
|
||||
return m.parent
|
||||
}
|
||||
|
||||
// Append will attempt to append the given menu item to
|
||||
// this item's submenu items. If this menu item is not a
|
||||
// submenu, then this method will not add the item and
|
||||
// simply return false.
|
||||
func (m *MenuItem) Append(item *MenuItem) bool {
|
||||
if !m.isSubMenu() {
|
||||
return false
|
||||
}
|
||||
item.parent = m
|
||||
m.SubMenu.Append(item)
|
||||
return true
|
||||
}
|
||||
|
||||
// Prepend will attempt to prepend the given menu item to
|
||||
// this item's submenu items. If this menu item is not a
|
||||
// submenu, then this method will not add the item and
|
||||
// simply return false.
|
||||
func (m *MenuItem) Prepend(item *MenuItem) bool {
|
||||
if !m.isSubMenu() {
|
||||
return false
|
||||
}
|
||||
item.parent = m
|
||||
m.SubMenu.Prepend(item)
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *MenuItem) Remove() {
|
||||
// Iterate my parent's children
|
||||
m.Parent().removeChild(m)
|
||||
}
|
||||
|
||||
func (m *MenuItem) removeChild(item *MenuItem) {
|
||||
m.removeLock.Lock()
|
||||
for index, child := range m.SubMenu.Items {
|
||||
if item == child {
|
||||
m.SubMenu.Items = append(m.SubMenu.Items[:index], m.SubMenu.Items[index+1:]...)
|
||||
}
|
||||
}
|
||||
m.removeLock.Unlock()
|
||||
}
|
||||
|
||||
// InsertAfter attempts to add the given item after this item in the parent
|
||||
// menu. If there is no parent menu (we are a top level menu) then false is
|
||||
// returned
|
||||
func (m *MenuItem) InsertAfter(item *MenuItem) bool {
|
||||
// We need to find my parent
|
||||
if m.parent == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Get my parent to insert the item
|
||||
return m.parent.insertNewItemAfterGivenItem(m, item)
|
||||
}
|
||||
|
||||
// InsertBefore attempts to add the given item before this item in the parent
|
||||
// menu. If there is no parent menu (we are a top level menu) then false is
|
||||
// returned
|
||||
func (m *MenuItem) InsertBefore(item *MenuItem) bool {
|
||||
// We need to find my parent
|
||||
if m.parent == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Get my parent to insert the item
|
||||
return m.parent.insertNewItemBeforeGivenItem(m, item)
|
||||
}
|
||||
|
||||
// insertNewItemAfterGivenItem will insert the given item after the given target
|
||||
// in this item's submenu. If we are not a submenu,
|
||||
// then something bad has happened :/
|
||||
func (m *MenuItem) insertNewItemAfterGivenItem(target *MenuItem,
|
||||
newItem *MenuItem,
|
||||
) bool {
|
||||
if !m.isSubMenu() {
|
||||
return false
|
||||
}
|
||||
|
||||
// Find the index of the target
|
||||
targetIndex := m.getItemIndex(target)
|
||||
if targetIndex == -1 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Insert element into slice
|
||||
return m.insertItemAtIndex(targetIndex+1, newItem)
|
||||
}
|
||||
|
||||
// insertNewItemBeforeGivenItem will insert the given item before the given
|
||||
// target in this item's submenu. If we are not a submenu, then something bad
|
||||
// has happened :/
|
||||
func (m *MenuItem) insertNewItemBeforeGivenItem(target *MenuItem,
|
||||
newItem *MenuItem,
|
||||
) bool {
|
||||
if !m.isSubMenu() {
|
||||
return false
|
||||
}
|
||||
|
||||
// Find the index of the target
|
||||
targetIndex := m.getItemIndex(target)
|
||||
if targetIndex == -1 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Insert element into slice
|
||||
return m.insertItemAtIndex(targetIndex, newItem)
|
||||
}
|
||||
|
||||
func (m *MenuItem) isSubMenu() bool {
|
||||
return m.Type == SubmenuType
|
||||
}
|
||||
|
||||
// getItemIndex returns the index of the given target relative to this menu
|
||||
func (m *MenuItem) getItemIndex(target *MenuItem) int {
|
||||
// This should only be called on submenus
|
||||
if !m.isSubMenu() {
|
||||
return -1
|
||||
}
|
||||
|
||||
// hunt down that bad boy
|
||||
for index, item := range m.SubMenu.Items {
|
||||
if item == target {
|
||||
return index
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
// insertItemAtIndex attempts to insert the given item into the submenu at
|
||||
// the given index
|
||||
// Credit: https://stackoverflow.com/a/61822301
|
||||
func (m *MenuItem) insertItemAtIndex(index int, target *MenuItem) bool {
|
||||
// If index is OOB, return false
|
||||
if index > len(m.SubMenu.Items) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Save parent reference
|
||||
target.parent = m
|
||||
|
||||
// If index is last item, then just regular append
|
||||
if index == len(m.SubMenu.Items) {
|
||||
m.SubMenu.Items = append(m.SubMenu.Items, target)
|
||||
return true
|
||||
}
|
||||
|
||||
m.SubMenu.Items = append(m.SubMenu.Items[:index+1], m.SubMenu.Items[index:]...)
|
||||
m.SubMenu.Items[index] = target
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *MenuItem) SetLabel(name string) {
|
||||
if m.Label == name {
|
||||
return
|
||||
}
|
||||
m.Label = name
|
||||
}
|
||||
|
||||
func (m *MenuItem) IsSeparator() bool {
|
||||
return m.Type == SeparatorType
|
||||
}
|
||||
|
||||
func (m *MenuItem) IsCheckbox() bool {
|
||||
return m.Type == CheckboxType
|
||||
}
|
||||
|
||||
func (m *MenuItem) Disable() *MenuItem {
|
||||
m.Disabled = true
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *MenuItem) Enable() *MenuItem {
|
||||
m.Disabled = false
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *MenuItem) OnClick(click Callback) *MenuItem {
|
||||
m.Click = click
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *MenuItem) SetAccelerator(acc *keys.Accelerator) *MenuItem {
|
||||
m.Accelerator = acc
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *MenuItem) SetChecked(value bool) *MenuItem {
|
||||
m.Checked = value
|
||||
if m.Type != RadioType {
|
||||
m.Type = CheckboxType
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *MenuItem) Hide() *MenuItem {
|
||||
m.Hidden = true
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *MenuItem) Show() *MenuItem {
|
||||
m.Hidden = false
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *MenuItem) IsRadio() bool {
|
||||
return m.Type == RadioType
|
||||
}
|
||||
|
||||
func Label(label string) *MenuItem {
|
||||
return &MenuItem{
|
||||
Type: TextType,
|
||||
Label: label,
|
||||
}
|
||||
}
|
||||
|
||||
// Text is a helper to create basic Text menu items
|
||||
func Text(label string, accelerator *keys.Accelerator, click Callback) *MenuItem {
|
||||
return &MenuItem{
|
||||
Label: label,
|
||||
Type: TextType,
|
||||
Accelerator: accelerator,
|
||||
Click: click,
|
||||
}
|
||||
}
|
||||
|
||||
// Separator provides a menu separator
|
||||
func Separator() *MenuItem {
|
||||
return &MenuItem{
|
||||
Type: SeparatorType,
|
||||
}
|
||||
}
|
||||
|
||||
// Radio is a helper to create basic Radio menu items with an accelerator
|
||||
func Radio(label string, selected bool, accelerator *keys.Accelerator, click Callback) *MenuItem {
|
||||
return &MenuItem{
|
||||
Label: label,
|
||||
Type: RadioType,
|
||||
Checked: selected,
|
||||
Accelerator: accelerator,
|
||||
Click: click,
|
||||
}
|
||||
}
|
||||
|
||||
// Checkbox is a helper to create basic Checkbox menu items
|
||||
func Checkbox(label string, checked bool, accelerator *keys.Accelerator, click Callback) *MenuItem {
|
||||
return &MenuItem{
|
||||
Label: label,
|
||||
Type: CheckboxType,
|
||||
Checked: checked,
|
||||
Accelerator: accelerator,
|
||||
Click: click,
|
||||
}
|
||||
}
|
||||
|
||||
// SubMenu is a helper to create Submenus
|
||||
func SubMenu(label string, menu *Menu) *MenuItem {
|
||||
result := &MenuItem{
|
||||
Label: label,
|
||||
SubMenu: menu,
|
||||
Type: SubmenuType,
|
||||
}
|
||||
|
||||
menu.setParent(result)
|
||||
|
||||
return result
|
||||
}
|
||||
214
vendor/github.com/wailsapp/wails/v2/pkg/menu/menuroles.go
generated
vendored
Normal file
214
vendor/github.com/wailsapp/wails/v2/pkg/menu/menuroles.go
generated
vendored
Normal file
@@ -0,0 +1,214 @@
|
||||
// Package menu provides all the functions and structs related to menus in a Wails application.
|
||||
// Heavily inspired by Electron (c) 2013-2020 Github Inc.
|
||||
// Electron License: https://github.com/electron/electron/blob/master/LICENSE
|
||||
package menu
|
||||
|
||||
// Role is a type to identify menu roles
|
||||
type Role int
|
||||
|
||||
// These constants need to be kept in sync with `v2/internal/frontend/desktop/darwin/Role.h`
|
||||
const (
|
||||
AppMenuRole Role = 1
|
||||
EditMenuRole = 2
|
||||
WindowMenuRole = 3
|
||||
// AboutRole Role = "about"
|
||||
// UndoRole Role = "undo"
|
||||
// RedoRole Role = "redo"
|
||||
// CutRole Role = "cut"
|
||||
// CopyRole Role = "copy"
|
||||
// PasteRole Role = "paste"
|
||||
// PasteAndMatchStyleRole Role = "pasteAndMatchStyle"
|
||||
// SelectAllRole Role = "selectAll"
|
||||
// DeleteRole Role = "delete"
|
||||
// MinimizeRole Role = "minimize"
|
||||
// QuitRole Role = "quit"
|
||||
// TogglefullscreenRole Role = "togglefullscreen"
|
||||
// FileMenuRole Role = "fileMenu"
|
||||
// ViewMenuRole Role = "viewMenu"
|
||||
// WindowMenuRole Role = "windowMenu"
|
||||
// HideRole Role = "hide"
|
||||
// HideOthersRole Role = "hideOthers"
|
||||
// UnhideRole Role = "unhide"
|
||||
// FrontRole Role = "front"
|
||||
// ZoomRole Role = "zoom"
|
||||
// WindowSubMenuRole Role = "windowSubMenu"
|
||||
// HelpSubMenuRole Role = "helpSubMenu"
|
||||
// SeparatorItemRole Role = "separatorItem"
|
||||
)
|
||||
|
||||
/*
|
||||
// About provides a MenuItem with the About role
|
||||
func About() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: AboutRole,
|
||||
}
|
||||
}
|
||||
|
||||
// Undo provides a MenuItem with the Undo role
|
||||
func Undo() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: UndoRole,
|
||||
}
|
||||
}
|
||||
|
||||
// Redo provides a MenuItem with the Redo role
|
||||
func Redo() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: RedoRole,
|
||||
}
|
||||
}
|
||||
|
||||
// Cut provides a MenuItem with the Cut role
|
||||
func Cut() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: CutRole,
|
||||
}
|
||||
}
|
||||
|
||||
// Copy provides a MenuItem with the Copy role
|
||||
func Copy() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: CopyRole,
|
||||
}
|
||||
}
|
||||
|
||||
// Paste provides a MenuItem with the Paste role
|
||||
func Paste() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: PasteRole,
|
||||
}
|
||||
}
|
||||
|
||||
// PasteAndMatchStyle provides a MenuItem with the PasteAndMatchStyle role
|
||||
func PasteAndMatchStyle() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: PasteAndMatchStyleRole,
|
||||
}
|
||||
}
|
||||
|
||||
// SelectAll provides a MenuItem with the SelectAll role
|
||||
func SelectAll() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: SelectAllRole,
|
||||
}
|
||||
}
|
||||
|
||||
// Delete provides a MenuItem with the Delete role
|
||||
func Delete() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: DeleteRole,
|
||||
}
|
||||
}
|
||||
|
||||
// Minimize provides a MenuItem with the Minimize role
|
||||
func Minimize() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: MinimizeRole,
|
||||
}
|
||||
}
|
||||
|
||||
// Quit provides a MenuItem with the Quit role
|
||||
func Quit() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: QuitRole,
|
||||
}
|
||||
}
|
||||
|
||||
// ToggleFullscreen provides a MenuItem with the ToggleFullscreen role
|
||||
func ToggleFullscreen() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: TogglefullscreenRole,
|
||||
}
|
||||
}
|
||||
|
||||
// FileMenu provides a MenuItem with the whole default "File" menu (Close / Quit)
|
||||
func FileMenu() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: FileMenuRole,
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// EditMenu provides a MenuItem with the whole default "Edit" menu (Undo, Copy, etc.).
|
||||
func EditMenu() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: EditMenuRole,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// ViewMenu provides a MenuItem with the whole default "View" menu (Reload, Toggle Developer Tools, etc.)
|
||||
func ViewMenu() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: ViewMenuRole,
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// WindowMenu provides a MenuItem with the whole default "Window" menu (Minimize, Zoom, etc.).
|
||||
// On MacOS currently all options in there won't work if the window is frameless.
|
||||
func WindowMenu() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: WindowMenuRole,
|
||||
}
|
||||
}
|
||||
|
||||
// These roles are Mac only
|
||||
|
||||
// AppMenu provides a MenuItem with the whole default "App" menu (About, Services, etc.)
|
||||
func AppMenu() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: AppMenuRole,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Hide provides a MenuItem that maps to the hide action.
|
||||
func Hide() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: HideRole,
|
||||
}
|
||||
}
|
||||
|
||||
// HideOthers provides a MenuItem that maps to the hideOtherApplications action.
|
||||
func HideOthers() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: HideOthersRole,
|
||||
}
|
||||
}
|
||||
|
||||
// UnHide provides a MenuItem that maps to the unHideAllApplications action.
|
||||
func UnHide() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: UnhideRole,
|
||||
}
|
||||
}
|
||||
|
||||
// Front provides a MenuItem that maps to the arrangeInFront action.
|
||||
func Front() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: FrontRole,
|
||||
}
|
||||
}
|
||||
|
||||
// Zoom provides a MenuItem that maps to the performZoom action.
|
||||
func Zoom() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: ZoomRole,
|
||||
}
|
||||
}
|
||||
|
||||
// WindowSubMenu provides a MenuItem with the "Window" submenu.
|
||||
func WindowSubMenu() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: WindowSubMenuRole,
|
||||
}
|
||||
}
|
||||
|
||||
// HelpSubMenu provides a MenuItem with the "Help" submenu.
|
||||
func HelpSubMenu() *MenuItem {
|
||||
return &MenuItem{
|
||||
Role: HelpSubMenuRole,
|
||||
}
|
||||
}
|
||||
*/
|
||||
261
vendor/github.com/wailsapp/wails/v2/pkg/menu/styledlabel.go
generated
vendored
Normal file
261
vendor/github.com/wailsapp/wails/v2/pkg/menu/styledlabel.go
generated
vendored
Normal file
@@ -0,0 +1,261 @@
|
||||
package menu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type TextStyle int
|
||||
|
||||
const (
|
||||
Bold TextStyle = 1 << 0
|
||||
Faint TextStyle = 1 << 1
|
||||
Italic TextStyle = 1 << 2
|
||||
Blinking TextStyle = 1 << 3
|
||||
Inversed TextStyle = 1 << 4
|
||||
Invisible TextStyle = 1 << 5
|
||||
Underlined TextStyle = 1 << 6
|
||||
Strikethrough TextStyle = 1 << 7
|
||||
)
|
||||
|
||||
type StyledText struct {
|
||||
Label string
|
||||
FgCol *Col
|
||||
BgCol *Col
|
||||
Style TextStyle
|
||||
}
|
||||
|
||||
func (s *StyledText) Bold() bool {
|
||||
return s.Style&Bold == Bold
|
||||
}
|
||||
|
||||
func (s *StyledText) Faint() bool {
|
||||
return s.Style&Faint == Faint
|
||||
}
|
||||
|
||||
func (s *StyledText) Italic() bool {
|
||||
return s.Style&Italic == Italic
|
||||
}
|
||||
|
||||
func (s *StyledText) Blinking() bool {
|
||||
return s.Style&Blinking == Blinking
|
||||
}
|
||||
|
||||
func (s *StyledText) Inversed() bool {
|
||||
return s.Style&Inversed == Inversed
|
||||
}
|
||||
|
||||
func (s *StyledText) Invisible() bool {
|
||||
return s.Style&Invisible == Invisible
|
||||
}
|
||||
|
||||
func (s *StyledText) Underlined() bool {
|
||||
return s.Style&Underlined == Underlined
|
||||
}
|
||||
|
||||
func (s *StyledText) Strikethrough() bool {
|
||||
return s.Style&Strikethrough == Strikethrough
|
||||
}
|
||||
|
||||
var ansiColorMap = map[string]map[string]*Col{
|
||||
"Normal": {
|
||||
"30": Cols[0],
|
||||
"31": Cols[1],
|
||||
"32": Cols[2],
|
||||
"33": Cols[3],
|
||||
"34": Cols[4],
|
||||
"35": Cols[5],
|
||||
"36": Cols[6],
|
||||
"37": Cols[7],
|
||||
},
|
||||
"Bold": {
|
||||
"30": Cols[8],
|
||||
"31": Cols[9],
|
||||
"32": Cols[10],
|
||||
"33": Cols[11],
|
||||
"34": Cols[12],
|
||||
"35": Cols[13],
|
||||
"36": Cols[14],
|
||||
"37": Cols[15],
|
||||
},
|
||||
"Faint": {
|
||||
"30": Cols[0],
|
||||
"31": Cols[1],
|
||||
"32": Cols[2],
|
||||
"33": Cols[3],
|
||||
"34": Cols[4],
|
||||
"35": Cols[5],
|
||||
"36": Cols[6],
|
||||
"37": Cols[7],
|
||||
},
|
||||
}
|
||||
|
||||
func ParseANSI(input string) ([]*StyledText, error) {
|
||||
var result []*StyledText
|
||||
invalid := fmt.Errorf("invalid ansi string")
|
||||
missingTerminator := fmt.Errorf("missing escape terminator 'm'")
|
||||
invalidTrueColorSequence := fmt.Errorf("invalid TrueColor sequence")
|
||||
invalid256ColSequence := fmt.Errorf("invalid 256 colour sequence")
|
||||
index := 0
|
||||
var currentStyledText *StyledText = &StyledText{}
|
||||
|
||||
if len(input) == 0 {
|
||||
return nil, invalid
|
||||
}
|
||||
|
||||
for {
|
||||
// Read all chars to next escape code
|
||||
esc := strings.Index(input, "\033[")
|
||||
|
||||
// If no more esc chars, save what's left and return
|
||||
if esc == -1 {
|
||||
text := input[index:]
|
||||
if len(text) > 0 {
|
||||
currentStyledText.Label = text
|
||||
result = append(result, currentStyledText)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
label := input[:esc]
|
||||
if len(label) > 0 {
|
||||
currentStyledText.Label = label
|
||||
result = append(result, currentStyledText)
|
||||
currentStyledText = &StyledText{
|
||||
Label: "",
|
||||
FgCol: currentStyledText.FgCol,
|
||||
BgCol: currentStyledText.BgCol,
|
||||
Style: currentStyledText.Style,
|
||||
}
|
||||
}
|
||||
input = input[esc:]
|
||||
// skip
|
||||
input = input[2:]
|
||||
|
||||
// Read in params
|
||||
endesc := strings.Index(input, "m")
|
||||
if endesc == -1 {
|
||||
return nil, missingTerminator
|
||||
}
|
||||
paramText := input[:endesc]
|
||||
input = input[endesc+1:]
|
||||
params := strings.Split(paramText, ";")
|
||||
colourMap := ansiColorMap["Normal"]
|
||||
skip := 0
|
||||
for index, param := range params {
|
||||
if skip > 0 {
|
||||
skip--
|
||||
continue
|
||||
}
|
||||
switch param {
|
||||
case "0":
|
||||
// Reset styles
|
||||
if len(params) == 1 {
|
||||
if len(currentStyledText.Label) > 0 {
|
||||
result = append(result, currentStyledText)
|
||||
currentStyledText = &StyledText{
|
||||
Label: "",
|
||||
FgCol: currentStyledText.FgCol,
|
||||
BgCol: currentStyledText.BgCol,
|
||||
Style: currentStyledText.Style,
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
currentStyledText.Style = 0
|
||||
currentStyledText.FgCol = nil
|
||||
currentStyledText.BgCol = nil
|
||||
case "1":
|
||||
// Bold
|
||||
colourMap = ansiColorMap["Bold"]
|
||||
currentStyledText.Style |= Bold
|
||||
case "2":
|
||||
// Dim/Feint
|
||||
colourMap = ansiColorMap["Faint"]
|
||||
currentStyledText.Style |= Faint
|
||||
case "3":
|
||||
// Italic
|
||||
currentStyledText.Style |= Italic
|
||||
case "4":
|
||||
// Underlined
|
||||
currentStyledText.Style |= Underlined
|
||||
case "5":
|
||||
// Blinking
|
||||
currentStyledText.Style |= Blinking
|
||||
case "7":
|
||||
// Inverse
|
||||
currentStyledText.Style |= Inversed
|
||||
case "8":
|
||||
// Invisible
|
||||
currentStyledText.Style |= Invisible
|
||||
case "9":
|
||||
// Strikethrough
|
||||
currentStyledText.Style |= Strikethrough
|
||||
case "30", "31", "32", "33", "34", "35", "36", "37":
|
||||
currentStyledText.FgCol = colourMap[param]
|
||||
case "40", "41", "42", "43", "44", "45", "46", "47":
|
||||
currentStyledText.BgCol = colourMap[param]
|
||||
case "38", "48":
|
||||
if len(params)-index < 2 {
|
||||
return nil, invalid
|
||||
}
|
||||
// 256 colours
|
||||
if params[index+1] == "5" {
|
||||
skip = 2
|
||||
colIndexText := params[index+2]
|
||||
colIndex, err := strconv.Atoi(colIndexText)
|
||||
if err != nil {
|
||||
return nil, invalid256ColSequence
|
||||
}
|
||||
if colIndex < 0 || colIndex > 255 {
|
||||
return nil, invalid256ColSequence
|
||||
}
|
||||
if param == "38" {
|
||||
currentStyledText.FgCol = Cols[colIndex]
|
||||
continue
|
||||
}
|
||||
currentStyledText.BgCol = Cols[colIndex]
|
||||
continue
|
||||
}
|
||||
// we must have 4 params left
|
||||
if len(params)-index < 4 {
|
||||
return nil, invalidTrueColorSequence
|
||||
}
|
||||
if params[index+1] != "2" {
|
||||
return nil, invalidTrueColorSequence
|
||||
}
|
||||
var r, g, b uint8
|
||||
ri, err := strconv.Atoi(params[index+2])
|
||||
if err != nil {
|
||||
return nil, invalidTrueColorSequence
|
||||
}
|
||||
gi, err := strconv.Atoi(params[index+3])
|
||||
if err != nil {
|
||||
return nil, invalidTrueColorSequence
|
||||
}
|
||||
bi, err := strconv.Atoi(params[index+4])
|
||||
if err != nil {
|
||||
return nil, invalidTrueColorSequence
|
||||
}
|
||||
if bi > 255 || gi > 255 || ri > 255 {
|
||||
return nil, invalidTrueColorSequence
|
||||
}
|
||||
if bi < 0 || gi < 0 || ri < 0 {
|
||||
return nil, invalidTrueColorSequence
|
||||
}
|
||||
r = uint8(ri)
|
||||
g = uint8(gi)
|
||||
b = uint8(bi)
|
||||
skip = 4
|
||||
colvalue := fmt.Sprintf("#%02x%02x%02x", r, g, b)
|
||||
if param == "38" {
|
||||
currentStyledText.FgCol = &Col{Hex: colvalue, Rgb: Rgb{r, g, b}}
|
||||
continue
|
||||
}
|
||||
currentStyledText.BgCol = &Col{Hex: colvalue}
|
||||
default:
|
||||
return nil, invalid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
42
vendor/github.com/wailsapp/wails/v2/pkg/menu/tray.go
generated
vendored
Normal file
42
vendor/github.com/wailsapp/wails/v2/pkg/menu/tray.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package menu
|
||||
|
||||
// TrayMenu are the options
|
||||
type TrayMenu struct {
|
||||
// Label is the text we wish to display in the tray
|
||||
Label string
|
||||
|
||||
// Image is the name of the tray icon we wish to display.
|
||||
// These are read up during build from <projectdir>/trayicons and
|
||||
// the filenames are used as IDs, minus the extension
|
||||
// EG: <projectdir>/trayicons/main.png can be referenced here with "main"
|
||||
// If the image is not a filename, it will be treated as base64 image data
|
||||
Image string
|
||||
|
||||
// MacTemplateImage indicates that on a Mac, this image is a template image
|
||||
MacTemplateImage bool
|
||||
|
||||
// Text Colour
|
||||
RGBA string
|
||||
|
||||
// Font
|
||||
FontSize int
|
||||
FontName string
|
||||
|
||||
// Tooltip
|
||||
Tooltip string
|
||||
|
||||
// Callback function when menu clicked
|
||||
// Click Callback `json:"-"`
|
||||
|
||||
// Disabled makes the item unselectable
|
||||
Disabled bool
|
||||
|
||||
// Menu is the initial menu we wish to use for the tray
|
||||
Menu *Menu
|
||||
|
||||
// OnOpen is called when the Menu is opened
|
||||
OnOpen func()
|
||||
|
||||
// OnClose is called when the Menu is closed
|
||||
OnClose func()
|
||||
}
|
||||
17
vendor/github.com/wailsapp/wails/v2/pkg/menu/type.go
generated
vendored
Normal file
17
vendor/github.com/wailsapp/wails/v2/pkg/menu/type.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package menu
|
||||
|
||||
// Type of the menu item
|
||||
type Type string
|
||||
|
||||
const (
|
||||
// TextType is the text menuitem type
|
||||
TextType Type = "Text"
|
||||
// SeparatorType is the Separator menuitem type
|
||||
SeparatorType Type = "Separator"
|
||||
// SubmenuType is the Submenu menuitem type
|
||||
SubmenuType Type = "Submenu"
|
||||
// CheckboxType is the Checkbox menuitem type
|
||||
CheckboxType Type = "Checkbox"
|
||||
// RadioType is the Radio menuitem type
|
||||
RadioType Type = "Radio"
|
||||
)
|
||||
13
vendor/github.com/wailsapp/wails/v2/pkg/menu/windows.go
generated
vendored
Normal file
13
vendor/github.com/wailsapp/wails/v2/pkg/menu/windows.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package menu
|
||||
|
||||
/*
|
||||
// DefaultWindowsMenu returns a default menu including the default
|
||||
// Application and Edit menus. Use `.Append()` to add to it.
|
||||
func DefaultWindowsMenu() *Menu {
|
||||
return NewMenuFromItems(
|
||||
FileMenu(),
|
||||
EditMenu(),
|
||||
WindowMenu(),
|
||||
)
|
||||
}
|
||||
*/
|
||||
20
vendor/github.com/wailsapp/wails/v2/pkg/options/assetserver/middleware.go
generated
vendored
Normal file
20
vendor/github.com/wailsapp/wails/v2/pkg/options/assetserver/middleware.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Middleware defines a HTTP middleware that can be applied to the AssetServer.
|
||||
// The handler passed as next is the next handler in the chain. One can decide to call the next handler
|
||||
// or implement a specialized handling.
|
||||
type Middleware func(next http.Handler) http.Handler
|
||||
|
||||
// ChainMiddleware allows chaining multiple middlewares to one middleware.
|
||||
func ChainMiddleware(middleware ...Middleware) Middleware {
|
||||
return func(h http.Handler) http.Handler {
|
||||
for i := len(middleware) - 1; i >= 0; i-- {
|
||||
h = middleware[i](h)
|
||||
}
|
||||
return h
|
||||
}
|
||||
}
|
||||
45
vendor/github.com/wailsapp/wails/v2/pkg/options/assetserver/options.go
generated
vendored
Normal file
45
vendor/github.com/wailsapp/wails/v2/pkg/options/assetserver/options.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Options defines the configuration of the AssetServer.
|
||||
type Options struct {
|
||||
// Assets defines the static assets to be used. A GET request is first tried to be served from this Assets. If the Assets returns
|
||||
// `os.ErrNotExist` for that file, the request handling will fallback to the Handler and tries to serve the GET
|
||||
// request from it.
|
||||
//
|
||||
// If set to nil, all GET requests will be forwarded to Handler.
|
||||
Assets fs.FS
|
||||
|
||||
// Handler will be called for every GET request that can't be served from Assets, due to `os.ErrNotExist`. Furthermore all
|
||||
// non GET requests will always be served from this Handler.
|
||||
//
|
||||
// If not defined, the result is the following in cases where the Handler would have been called:
|
||||
// GET request: `http.StatusNotFound`
|
||||
// Other request: `http.StatusMethodNotAllowed`
|
||||
Handler http.Handler
|
||||
|
||||
// Middleware is a HTTP Middleware which allows to hook into the AssetServer request chain. It allows to skip the default
|
||||
// request handler dynamically, e.g. implement specialized Routing etc.
|
||||
// The Middleware is called to build a new `http.Handler` used by the AssetSever and it also receives the default
|
||||
// handler used by the AssetServer as an argument.
|
||||
//
|
||||
// If not defined, the default AssetServer request chain is executed.
|
||||
//
|
||||
// Multiple Middlewares can be chained together with:
|
||||
// ChainMiddleware(middleware ...Middleware) Middleware
|
||||
Middleware Middleware
|
||||
}
|
||||
|
||||
// Validate the options
|
||||
func (o Options) Validate() error {
|
||||
if o.Assets == nil && o.Handler == nil && o.Middleware == nil {
|
||||
return fmt.Errorf("AssetServer options invalid: either Assets, Handler or Middleware must be set")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
7
vendor/github.com/wailsapp/wails/v2/pkg/options/debug.go
generated
vendored
Normal file
7
vendor/github.com/wailsapp/wails/v2/pkg/options/debug.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
package options
|
||||
|
||||
// Debug options which are taken into account in debug builds.
|
||||
type Debug struct {
|
||||
// OpenInspectorOnStartup opens the inspector on startup of the app.
|
||||
OpenInspectorOnStartup bool
|
||||
}
|
||||
56
vendor/github.com/wailsapp/wails/v2/pkg/options/linux/linux.go
generated
vendored
Normal file
56
vendor/github.com/wailsapp/wails/v2/pkg/options/linux/linux.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
package linux
|
||||
|
||||
// WebviewGpuPolicy values used for determining the webview's hardware acceleration policy.
|
||||
type WebviewGpuPolicy int
|
||||
|
||||
const (
|
||||
// WebviewGpuPolicyAlways Hardware acceleration is always enabled.
|
||||
WebviewGpuPolicyAlways WebviewGpuPolicy = iota
|
||||
// WebviewGpuPolicyOnDemand Hardware acceleration is enabled/disabled as request by web contents.
|
||||
WebviewGpuPolicyOnDemand
|
||||
// WebviewGpuPolicyNever Hardware acceleration is always disabled.
|
||||
WebviewGpuPolicyNever
|
||||
)
|
||||
|
||||
// Options specific to Linux builds
|
||||
type Options struct {
|
||||
// Icon Sets up the icon representing the window. This icon is used when the window is minimized
|
||||
// (also known as iconified).
|
||||
Icon []byte
|
||||
|
||||
// WindowIsTranslucent sets the window's background to transparent when enabled.
|
||||
WindowIsTranslucent bool
|
||||
|
||||
// Messages are messages that can be customised
|
||||
Messages *Messages
|
||||
|
||||
// WebviewGpuPolicy used for determining the hardware acceleration policy for the webview.
|
||||
// - WebviewGpuPolicyAlways
|
||||
// - WebviewGpuPolicyOnDemand
|
||||
// - WebviewGpuPolicyNever
|
||||
//
|
||||
// Due to https://github.com/wailsapp/wails/issues/2977, if options.Linux is nil
|
||||
// in the call to wails.Run(), WebviewGpuPolicy is set by default to WebviewGpuPolicyNever.
|
||||
// Client code may override this behavior by passing a non-nil Options and set
|
||||
// WebviewGpuPolicy as needed.
|
||||
WebviewGpuPolicy WebviewGpuPolicy
|
||||
|
||||
// ProgramName is used to set the program's name for the window manager via GTK's g_set_prgname().
|
||||
//This name should not be localized. [see the docs]
|
||||
//
|
||||
//When a .desktop file is created this value helps with window grouping and desktop icons when the .desktop file's Name
|
||||
//property differs form the executable's filename.
|
||||
//
|
||||
//[see the docs]: https://docs.gtk.org/glib/func.set_prgname.html
|
||||
ProgramName string
|
||||
}
|
||||
|
||||
type Messages struct {
|
||||
WebKit2GTKMinRequired string
|
||||
}
|
||||
|
||||
func DefaultMessages() *Messages {
|
||||
return &Messages{
|
||||
WebKit2GTKMinRequired: "This application requires at least WebKit2GTK %s to be installed.",
|
||||
}
|
||||
}
|
||||
23
vendor/github.com/wailsapp/wails/v2/pkg/options/mac/appearance.go
generated
vendored
Normal file
23
vendor/github.com/wailsapp/wails/v2/pkg/options/mac/appearance.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
package mac
|
||||
|
||||
// AppearanceType is a type of Appearance for Cocoa windows
|
||||
type AppearanceType string
|
||||
|
||||
const (
|
||||
// DefaultAppearance uses the default system value
|
||||
DefaultAppearance AppearanceType = ""
|
||||
// NSAppearanceNameAqua - The standard light system appearance.
|
||||
NSAppearanceNameAqua AppearanceType = "NSAppearanceNameAqua"
|
||||
// NSAppearanceNameDarkAqua - The standard dark system appearance.
|
||||
NSAppearanceNameDarkAqua AppearanceType = "NSAppearanceNameDarkAqua"
|
||||
// NSAppearanceNameVibrantLight - The light vibrant appearance
|
||||
NSAppearanceNameVibrantLight AppearanceType = "NSAppearanceNameVibrantLight"
|
||||
// NSAppearanceNameAccessibilityHighContrastAqua - A high-contrast version of the standard light system appearance.
|
||||
NSAppearanceNameAccessibilityHighContrastAqua AppearanceType = "NSAppearanceNameAccessibilityHighContrastAqua"
|
||||
// NSAppearanceNameAccessibilityHighContrastDarkAqua - A high-contrast version of the standard dark system appearance.
|
||||
NSAppearanceNameAccessibilityHighContrastDarkAqua AppearanceType = "NSAppearanceNameAccessibilityHighContrastDarkAqua"
|
||||
// NSAppearanceNameAccessibilityHighContrastVibrantLight - A high-contrast version of the light vibrant appearance.
|
||||
NSAppearanceNameAccessibilityHighContrastVibrantLight AppearanceType = "NSAppearanceNameAccessibilityHighContrastVibrantLight"
|
||||
// NSAppearanceNameAccessibilityHighContrastVibrantDark - A high-contrast version of the dark vibrant appearance.
|
||||
NSAppearanceNameAccessibilityHighContrastVibrantDark AppearanceType = "NSAppearanceNameAccessibilityHighContrastVibrantDark"
|
||||
)
|
||||
31
vendor/github.com/wailsapp/wails/v2/pkg/options/mac/mac.go
generated
vendored
Normal file
31
vendor/github.com/wailsapp/wails/v2/pkg/options/mac/mac.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
package mac
|
||||
|
||||
//type ActivationPolicy int
|
||||
//
|
||||
//const (
|
||||
// NSApplicationActivationPolicyRegular ActivationPolicy = 0
|
||||
// NSApplicationActivationPolicyAccessory ActivationPolicy = 1
|
||||
// NSApplicationActivationPolicyProhibited ActivationPolicy = 2
|
||||
//)
|
||||
|
||||
type AboutInfo struct {
|
||||
Title string
|
||||
Message string
|
||||
Icon []byte
|
||||
}
|
||||
|
||||
// Options are options specific to Mac
|
||||
type Options struct {
|
||||
TitleBar *TitleBar
|
||||
Appearance AppearanceType
|
||||
ContentProtection bool
|
||||
WebviewIsTransparent bool
|
||||
WindowIsTranslucent bool
|
||||
Preferences *Preferences
|
||||
DisableZoom bool
|
||||
// ActivationPolicy ActivationPolicy
|
||||
About *AboutInfo
|
||||
OnFileOpen func(filePath string) `json:"-"`
|
||||
OnUrlOpen func(filePath string) `json:"-"`
|
||||
// URLHandlers map[string]func(string)
|
||||
}
|
||||
21
vendor/github.com/wailsapp/wails/v2/pkg/options/mac/preferences.go
generated
vendored
Normal file
21
vendor/github.com/wailsapp/wails/v2/pkg/options/mac/preferences.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
package mac
|
||||
|
||||
import "github.com/leaanthony/u"
|
||||
|
||||
var (
|
||||
Enabled = u.True
|
||||
Disabled = u.False
|
||||
)
|
||||
|
||||
// Preferences allows to set webkit preferences
|
||||
type Preferences struct {
|
||||
// A Boolean value that indicates whether pressing the tab key changes the focus to links and form controls.
|
||||
// Set to false by default.
|
||||
TabFocusesLinks u.Bool
|
||||
// A Boolean value that indicates whether to allow people to select or otherwise interact with text.
|
||||
// Set to true by default.
|
||||
TextInteractionEnabled u.Bool
|
||||
// A Boolean value that indicates whether a web view can display content full screen.
|
||||
// Set to false by default
|
||||
FullscreenEnabled u.Bool
|
||||
}
|
||||
52
vendor/github.com/wailsapp/wails/v2/pkg/options/mac/titlebar.go
generated
vendored
Normal file
52
vendor/github.com/wailsapp/wails/v2/pkg/options/mac/titlebar.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
package mac
|
||||
|
||||
// TitleBar contains options for the Mac titlebar
|
||||
type TitleBar struct {
|
||||
TitlebarAppearsTransparent bool
|
||||
HideTitle bool
|
||||
HideTitleBar bool
|
||||
FullSizeContent bool
|
||||
UseToolbar bool
|
||||
HideToolbarSeparator bool
|
||||
}
|
||||
|
||||
// TitleBarDefault results in the default Mac Titlebar
|
||||
func TitleBarDefault() *TitleBar {
|
||||
return &TitleBar{
|
||||
TitlebarAppearsTransparent: false,
|
||||
HideTitle: false,
|
||||
HideTitleBar: false,
|
||||
FullSizeContent: false,
|
||||
UseToolbar: false,
|
||||
HideToolbarSeparator: false,
|
||||
}
|
||||
}
|
||||
|
||||
// Credit: Comments from Electron site
|
||||
|
||||
// TitleBarHidden results in a hidden title bar and a full size content window,
|
||||
// yet the title bar still has the standard window controls (“traffic lights”)
|
||||
// in the top left.
|
||||
func TitleBarHidden() *TitleBar {
|
||||
return &TitleBar{
|
||||
TitlebarAppearsTransparent: true,
|
||||
HideTitle: true,
|
||||
HideTitleBar: false,
|
||||
FullSizeContent: true,
|
||||
UseToolbar: false,
|
||||
HideToolbarSeparator: false,
|
||||
}
|
||||
}
|
||||
|
||||
// TitleBarHiddenInset results in a hidden title bar with an alternative look where
|
||||
// the traffic light buttons are slightly more inset from the window edge.
|
||||
func TitleBarHiddenInset() *TitleBar {
|
||||
return &TitleBar{
|
||||
TitlebarAppearsTransparent: true,
|
||||
HideTitle: true,
|
||||
HideTitleBar: false,
|
||||
FullSizeContent: true,
|
||||
UseToolbar: true,
|
||||
HideToolbarSeparator: true,
|
||||
}
|
||||
}
|
||||
276
vendor/github.com/wailsapp/wails/v2/pkg/options/options.go
generated
vendored
Normal file
276
vendor/github.com/wailsapp/wails/v2/pkg/options/options.go
generated
vendored
Normal file
@@ -0,0 +1,276 @@
|
||||
package options
|
||||
|
||||
import (
|
||||
"context"
|
||||
"html"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/linux"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/windows"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||
)
|
||||
|
||||
type WindowStartState int
|
||||
|
||||
const (
|
||||
Normal WindowStartState = 0
|
||||
Maximised WindowStartState = 1
|
||||
Minimised WindowStartState = 2
|
||||
Fullscreen WindowStartState = 3
|
||||
)
|
||||
|
||||
type Experimental struct{}
|
||||
|
||||
// App contains options for creating the App
|
||||
type App struct {
|
||||
Title string
|
||||
Width int
|
||||
Height int
|
||||
DisableResize bool
|
||||
Fullscreen bool
|
||||
Frameless bool
|
||||
MinWidth int
|
||||
MinHeight int
|
||||
MaxWidth int
|
||||
MaxHeight int
|
||||
StartHidden bool
|
||||
HideWindowOnClose bool
|
||||
AlwaysOnTop bool
|
||||
// BackgroundColour is the background colour of the window
|
||||
// You can use the options.NewRGB and options.NewRGBA functions to create a new colour
|
||||
BackgroundColour *RGBA
|
||||
// Deprecated: Use AssetServer.Assets instead.
|
||||
Assets fs.FS
|
||||
// Deprecated: Use AssetServer.Handler instead.
|
||||
AssetsHandler http.Handler
|
||||
// AssetServer configures the Assets for the application
|
||||
AssetServer *assetserver.Options
|
||||
Menu *menu.Menu
|
||||
Logger logger.Logger `json:"-"`
|
||||
LogLevel logger.LogLevel
|
||||
LogLevelProduction logger.LogLevel
|
||||
OnStartup func(ctx context.Context) `json:"-"`
|
||||
OnDomReady func(ctx context.Context) `json:"-"`
|
||||
OnShutdown func(ctx context.Context) `json:"-"`
|
||||
OnBeforeClose func(ctx context.Context) (prevent bool) `json:"-"`
|
||||
Bind []interface{}
|
||||
EnumBind []interface{}
|
||||
WindowStartState WindowStartState
|
||||
|
||||
// ErrorFormatter overrides the formatting of errors returned by backend methods
|
||||
ErrorFormatter ErrorFormatter
|
||||
|
||||
// CSS property to test for draggable elements. Default "--wails-draggable"
|
||||
CSSDragProperty string
|
||||
|
||||
// The CSS Value that the CSSDragProperty must have to be draggable, EG: "drag"
|
||||
CSSDragValue string
|
||||
|
||||
// EnableDefaultContextMenu enables the browser's default context-menu in production
|
||||
// This menu is already enabled in development and debug builds
|
||||
EnableDefaultContextMenu bool
|
||||
|
||||
// EnableFraudulentWebsiteDetection enables scan services for fraudulent content, such as malware or phishing attempts.
|
||||
// These services might send information from your app like URLs navigated to and possibly other content to cloud
|
||||
// services of Apple and Microsoft.
|
||||
EnableFraudulentWebsiteDetection bool
|
||||
|
||||
SingleInstanceLock *SingleInstanceLock
|
||||
|
||||
Windows *windows.Options
|
||||
Mac *mac.Options
|
||||
Linux *linux.Options
|
||||
|
||||
// Experimental options
|
||||
Experimental *Experimental
|
||||
|
||||
// Debug options for debug builds. These options will be ignored in a production build.
|
||||
Debug Debug
|
||||
|
||||
// DragAndDrop options for drag and drop behavior
|
||||
DragAndDrop *DragAndDrop
|
||||
|
||||
// DisablePanicRecovery disables the panic recovery system in messages processing
|
||||
DisablePanicRecovery bool
|
||||
|
||||
// List of additional allowed origins for bindings in format "https://*.myapp.com,https://example.com"
|
||||
BindingsAllowedOrigins string
|
||||
}
|
||||
|
||||
type ErrorFormatter func(error) any
|
||||
|
||||
type RGBA struct {
|
||||
R uint8 `json:"r"`
|
||||
G uint8 `json:"g"`
|
||||
B uint8 `json:"b"`
|
||||
A uint8 `json:"a"`
|
||||
}
|
||||
|
||||
// NewRGBA creates a new RGBA struct with the given values
|
||||
func NewRGBA(r, g, b, a uint8) *RGBA {
|
||||
return &RGBA{
|
||||
R: r,
|
||||
G: g,
|
||||
B: b,
|
||||
A: a,
|
||||
}
|
||||
}
|
||||
|
||||
// NewRGB creates a new RGBA struct with the given values and Alpha set to 255
|
||||
func NewRGB(r, g, b uint8) *RGBA {
|
||||
return &RGBA{
|
||||
R: r,
|
||||
G: g,
|
||||
B: b,
|
||||
A: 255,
|
||||
}
|
||||
}
|
||||
|
||||
// MergeDefaults will set the minimum default values for an application
|
||||
func MergeDefaults(appoptions *App) {
|
||||
// Do set defaults
|
||||
if appoptions.Width <= 0 {
|
||||
appoptions.Width = 1024
|
||||
}
|
||||
if appoptions.Height <= 0 {
|
||||
appoptions.Height = 768
|
||||
}
|
||||
if appoptions.Logger == nil {
|
||||
appoptions.Logger = logger.NewDefaultLogger()
|
||||
}
|
||||
if appoptions.LogLevel == 0 {
|
||||
appoptions.LogLevel = logger.INFO
|
||||
}
|
||||
if appoptions.LogLevelProduction == 0 {
|
||||
appoptions.LogLevelProduction = logger.ERROR
|
||||
}
|
||||
if appoptions.CSSDragProperty == "" {
|
||||
appoptions.CSSDragProperty = "--wails-draggable"
|
||||
}
|
||||
if appoptions.CSSDragValue == "" {
|
||||
appoptions.CSSDragValue = "drag"
|
||||
}
|
||||
if appoptions.DragAndDrop == nil {
|
||||
appoptions.DragAndDrop = &DragAndDrop{}
|
||||
}
|
||||
if appoptions.DragAndDrop.CSSDropProperty == "" {
|
||||
appoptions.DragAndDrop.CSSDropProperty = "--wails-drop-target"
|
||||
}
|
||||
if appoptions.DragAndDrop.CSSDropValue == "" {
|
||||
appoptions.DragAndDrop.CSSDropValue = "drop"
|
||||
}
|
||||
if appoptions.BackgroundColour == nil {
|
||||
appoptions.BackgroundColour = &RGBA{
|
||||
R: 255,
|
||||
G: 255,
|
||||
B: 255,
|
||||
A: 255,
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure max and min are valid
|
||||
processMinMaxConstraints(appoptions)
|
||||
|
||||
// Default menus
|
||||
processMenus(appoptions)
|
||||
|
||||
// Process Drag Options
|
||||
processDragOptions(appoptions)
|
||||
}
|
||||
|
||||
type SingleInstanceLock struct {
|
||||
// uniqueId that will be used for setting up messaging between instances
|
||||
UniqueId string
|
||||
OnSecondInstanceLaunch func(secondInstanceData SecondInstanceData)
|
||||
}
|
||||
|
||||
type SecondInstanceData struct {
|
||||
Args []string
|
||||
WorkingDirectory string
|
||||
}
|
||||
|
||||
type DragAndDrop struct {
|
||||
|
||||
// EnableFileDrop enables wails' drag and drop functionality that returns the dropped in files' absolute paths.
|
||||
EnableFileDrop bool
|
||||
|
||||
// Disable webview's drag and drop functionality.
|
||||
//
|
||||
// It can be used to prevent accidental file opening of dragged in files in the webview, when there is no need for drag and drop.
|
||||
DisableWebViewDrop bool
|
||||
|
||||
// CSS property to test for drag and drop target elements. Default "--wails-drop-target"
|
||||
CSSDropProperty string
|
||||
|
||||
// The CSS Value that the CSSDropProperty must have to be a valid drop target. Default "drop"
|
||||
CSSDropValue string
|
||||
}
|
||||
|
||||
func NewSecondInstanceData() (*SecondInstanceData, error) {
|
||||
ex, err := os.Executable()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
workingDirectory := filepath.Dir(ex)
|
||||
|
||||
return &SecondInstanceData{
|
||||
Args: os.Args[1:],
|
||||
WorkingDirectory: workingDirectory,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func processMenus(appoptions *App) {
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
if appoptions.Menu == nil {
|
||||
items := []*menu.MenuItem{
|
||||
menu.EditMenu(),
|
||||
}
|
||||
if !appoptions.Frameless {
|
||||
items = append(items, menu.WindowMenu()) // Current options in Window Menu only work if not frameless
|
||||
}
|
||||
|
||||
appoptions.Menu = menu.NewMenuFromItems(menu.AppMenu(), items...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func processMinMaxConstraints(appoptions *App) {
|
||||
if appoptions.MinWidth > 0 && appoptions.MaxWidth > 0 {
|
||||
if appoptions.MinWidth > appoptions.MaxWidth {
|
||||
appoptions.MinWidth = appoptions.MaxWidth
|
||||
}
|
||||
}
|
||||
if appoptions.MinHeight > 0 && appoptions.MaxHeight > 0 {
|
||||
if appoptions.MinHeight > appoptions.MaxHeight {
|
||||
appoptions.MinHeight = appoptions.MaxHeight
|
||||
}
|
||||
}
|
||||
// Ensure width and height are limited if max/min is set
|
||||
if appoptions.Width < appoptions.MinWidth {
|
||||
appoptions.Width = appoptions.MinWidth
|
||||
}
|
||||
if appoptions.MaxWidth > 0 && appoptions.Width > appoptions.MaxWidth {
|
||||
appoptions.Width = appoptions.MaxWidth
|
||||
}
|
||||
if appoptions.Height < appoptions.MinHeight {
|
||||
appoptions.Height = appoptions.MinHeight
|
||||
}
|
||||
if appoptions.MaxHeight > 0 && appoptions.Height > appoptions.MaxHeight {
|
||||
appoptions.Height = appoptions.MaxHeight
|
||||
}
|
||||
}
|
||||
|
||||
func processDragOptions(appoptions *App) {
|
||||
appoptions.CSSDragProperty = html.EscapeString(appoptions.CSSDragProperty)
|
||||
appoptions.CSSDragValue = html.EscapeString(appoptions.CSSDragValue)
|
||||
}
|
||||
167
vendor/github.com/wailsapp/wails/v2/pkg/options/windows/windows.go
generated
vendored
Normal file
167
vendor/github.com/wailsapp/wails/v2/pkg/options/windows/windows.go
generated
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
package windows
|
||||
|
||||
type Theme int
|
||||
|
||||
type Messages struct {
|
||||
InstallationRequired string
|
||||
UpdateRequired string
|
||||
MissingRequirements string
|
||||
Webview2NotInstalled string
|
||||
Error string
|
||||
FailedToInstall string
|
||||
DownloadPage string
|
||||
PressOKToInstall string
|
||||
ContactAdmin string
|
||||
InvalidFixedWebview2 string
|
||||
WebView2ProcessCrash string
|
||||
}
|
||||
|
||||
const (
|
||||
// SystemDefault will use whatever the system theme is. The application will follow system theme changes.
|
||||
SystemDefault Theme = 0
|
||||
// Dark Mode
|
||||
Dark Theme = 1
|
||||
// Light Mode
|
||||
Light Theme = 2
|
||||
)
|
||||
|
||||
type BackdropType int32
|
||||
|
||||
const (
|
||||
Auto BackdropType = 0
|
||||
None BackdropType = 1
|
||||
Mica BackdropType = 2
|
||||
Acrylic BackdropType = 3
|
||||
Tabbed BackdropType = 4
|
||||
)
|
||||
|
||||
const (
|
||||
// Default is 0, which means no changes to the default Windows DLL search behavior
|
||||
DLLSearchDefault uint32 = 0
|
||||
// LoadLibrary flags for determining from where to search for a DLL
|
||||
DLLSearchDontResolveDllReferences uint32 = 0x1 // windows.DONT_RESOLVE_DLL_REFERENCES
|
||||
DLLSearchAsDataFile uint32 = 0x2 // windows.LOAD_LIBRARY_AS_DATAFILE
|
||||
DLLSearchWithAlteredPath uint32 = 0x8 // windows.LOAD_WITH_ALTERED_SEARCH_PATH
|
||||
DLLSearchIgnoreCodeAuthzLevel uint32 = 0x10 // windows.LOAD_IGNORE_CODE_AUTHZ_LEVEL
|
||||
DLLSearchAsImageResource uint32 = 0x20 // windows.LOAD_LIBRARY_AS_IMAGE_RESOURCE
|
||||
DLLSearchAsDataFileExclusive uint32 = 0x40 // windows.LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE
|
||||
DLLSearchRequireSignedTarget uint32 = 0x80 // windows.LOAD_LIBRARY_REQUIRE_SIGNED_TARGET
|
||||
DLLSearchDllLoadDir uint32 = 0x100 // windows.LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
|
||||
DLLSearchApplicationDir uint32 = 0x200 // windows.LOAD_LIBRARY_SEARCH_APPLICATION_DIR
|
||||
DLLSearchUserDirs uint32 = 0x400 // windows.LOAD_LIBRARY_SEARCH_USER_DIRS
|
||||
DLLSearchSystem32 uint32 = 0x800 // windows.LOAD_LIBRARY_SEARCH_SYSTEM32
|
||||
DLLSearchDefaultDirs uint32 = 0x1000 // windows.LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
|
||||
DLLSearchSafeCurrentDirs uint32 = 0x2000 // windows.LOAD_LIBRARY_SAFE_CURRENT_DIRS
|
||||
DLLSearchSystem32NoForwarder uint32 = 0x4000 // windows.LOAD_LIBRARY_SEARCH_SYSTEM32_NO_FORWARDER
|
||||
DLLSearchOsIntegrityContinuity uint32 = 0x8000 // windows.LOAD_LIBRARY_OS_INTEGRITY_CONTINUITY
|
||||
)
|
||||
|
||||
func RGB(r, g, b uint8) int32 {
|
||||
col := int32(b)
|
||||
col = col<<8 | int32(g)
|
||||
col = col<<8 | int32(r)
|
||||
return col
|
||||
}
|
||||
|
||||
// ThemeSettings contains optional colours to use.
|
||||
// They may be set using the hex values: 0x00BBGGRR
|
||||
type ThemeSettings struct {
|
||||
DarkModeTitleBar int32
|
||||
DarkModeTitleBarInactive int32
|
||||
DarkModeTitleText int32
|
||||
DarkModeTitleTextInactive int32
|
||||
DarkModeBorder int32
|
||||
DarkModeBorderInactive int32
|
||||
LightModeTitleBar int32
|
||||
LightModeTitleBarInactive int32
|
||||
LightModeTitleText int32
|
||||
LightModeTitleTextInactive int32
|
||||
LightModeBorder int32
|
||||
LightModeBorderInactive int32
|
||||
}
|
||||
|
||||
// Options are options specific to Windows
|
||||
type Options struct {
|
||||
ContentProtection bool
|
||||
WebviewIsTransparent bool
|
||||
WindowIsTranslucent bool
|
||||
DisableWindowIcon bool
|
||||
|
||||
IsZoomControlEnabled bool
|
||||
ZoomFactor float64
|
||||
|
||||
DisablePinchZoom bool
|
||||
|
||||
// Disable all window decorations in Frameless mode, which means no "Aero Shadow" and no "Rounded Corner" will be shown.
|
||||
// "Rounded Corners" are only available on Windows 11.
|
||||
DisableFramelessWindowDecorations bool
|
||||
|
||||
// Path where the WebView2 stores the user data. If empty %APPDATA%\[BinaryName.exe] will be used.
|
||||
// If the path is not valid, a messagebox will be displayed with the error and the app will exit with error code.
|
||||
WebviewUserDataPath string
|
||||
|
||||
// Path to the directory with WebView2 executables. If empty WebView2 installed in the system will be used.
|
||||
WebviewBrowserPath string
|
||||
|
||||
// Dark/Light or System Default Theme
|
||||
Theme Theme
|
||||
|
||||
// Custom settings for dark/light mode
|
||||
CustomTheme *ThemeSettings
|
||||
|
||||
// Select the type of translucent backdrop. Requires Windows 11 22621 or later.
|
||||
BackdropType BackdropType
|
||||
|
||||
// User messages that can be customised
|
||||
Messages *Messages
|
||||
|
||||
// ResizeDebounceMS is the amount of time to debounce redraws of webview2
|
||||
// when resizing the window
|
||||
ResizeDebounceMS uint16
|
||||
|
||||
// OnSuspend is called when Windows enters low power mode
|
||||
OnSuspend func()
|
||||
|
||||
// OnResume is called when Windows resumes from low power mode
|
||||
OnResume func()
|
||||
|
||||
// WebviewGpuIsDisabled is used to enable / disable GPU acceleration for the webview
|
||||
WebviewGpuIsDisabled bool
|
||||
|
||||
// WebviewDisableRendererCodeIntegrity disables the `RendererCodeIntegrity` of WebView2. Some Security Endpoint
|
||||
// Protection Software inject themself into the WebView2 with unsigned or wrongly signed dlls, which is not allowed
|
||||
// and will stop the WebView2 processes. Those security software need an update to fix this issue or one can disable
|
||||
// the integrity check with this flag.
|
||||
//
|
||||
// The event viewer log contains `Code Integrity Errors` like mentioned here: https://github.com/MicrosoftEdge/WebView2Feedback/issues/2051
|
||||
//
|
||||
// !! Please keep in mind when disabling this feature, this also allows malicious software to inject into the WebView2 !!
|
||||
WebviewDisableRendererCodeIntegrity bool
|
||||
|
||||
// Configure whether swipe gestures should be enabled
|
||||
EnableSwipeGestures bool
|
||||
|
||||
// Class name for the window. If empty, 'wailsWindow' will be used.
|
||||
WindowClassName string
|
||||
|
||||
// DLLSearchPaths controls which directories are searched when loading DLLs
|
||||
// Set to 0 for default behavior, or combine multiple flags with bitwise OR
|
||||
// Example: DLLSearchApplicationDir | DLLSearchSystem32
|
||||
DLLSearchPaths uint32
|
||||
}
|
||||
|
||||
func DefaultMessages() *Messages {
|
||||
return &Messages{
|
||||
InstallationRequired: "The WebView2 runtime is required. Press Ok to download and install. Note: The installer will download silently so please wait.",
|
||||
UpdateRequired: "The WebView2 runtime needs updating. Press Ok to download and install. Note: The installer will download silently so please wait.",
|
||||
MissingRequirements: "Missing Requirements",
|
||||
Webview2NotInstalled: "WebView2 runtime not installed",
|
||||
Error: "Error",
|
||||
FailedToInstall: "The runtime failed to install correctly. Please try again.",
|
||||
DownloadPage: "This application requires the WebView2 runtime. Press OK to open the download page. Minimum version required: ",
|
||||
PressOKToInstall: "Press Ok to install.",
|
||||
ContactAdmin: "The WebView2 runtime is required to run this application. Please contact your system administrator.",
|
||||
InvalidFixedWebview2: "The WebView2 runtime is manually specified, but It is not valid. Check minimum required version and webview2 path.",
|
||||
WebView2ProcessCrash: "The WebView2 process crashed and the application needs to be restarted.",
|
||||
}
|
||||
}
|
||||
11
vendor/github.com/wailsapp/wails/v2/pkg/runtime/browser.go
generated
vendored
Normal file
11
vendor/github.com/wailsapp/wails/v2/pkg/runtime/browser.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// BrowserOpenURL uses the system default browser to open the url
|
||||
func BrowserOpenURL(ctx context.Context, url string) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.BrowserOpenURL(url)
|
||||
}
|
||||
13
vendor/github.com/wailsapp/wails/v2/pkg/runtime/clipboard.go
generated
vendored
Normal file
13
vendor/github.com/wailsapp/wails/v2/pkg/runtime/clipboard.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package runtime
|
||||
|
||||
import "context"
|
||||
|
||||
func ClipboardGetText(ctx context.Context) (string, error) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
return appFrontend.ClipboardGetText()
|
||||
}
|
||||
|
||||
func ClipboardSetText(ctx context.Context, text string) error {
|
||||
appFrontend := getFrontend(ctx)
|
||||
return appFrontend.ClipboardSetText(text)
|
||||
}
|
||||
80
vendor/github.com/wailsapp/wails/v2/pkg/runtime/dialog.go
generated
vendored
Normal file
80
vendor/github.com/wailsapp/wails/v2/pkg/runtime/dialog.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
"github.com/wailsapp/wails/v2/internal/fs"
|
||||
)
|
||||
|
||||
// FileFilter defines a filter for dialog boxes
|
||||
type FileFilter = frontend.FileFilter
|
||||
|
||||
// OpenDialogOptions contains the options for the OpenDialogOptions runtime method
|
||||
type OpenDialogOptions = frontend.OpenDialogOptions
|
||||
|
||||
// SaveDialogOptions contains the options for the SaveDialog runtime method
|
||||
type SaveDialogOptions = frontend.SaveDialogOptions
|
||||
|
||||
type DialogType = frontend.DialogType
|
||||
|
||||
const (
|
||||
InfoDialog = frontend.InfoDialog
|
||||
WarningDialog = frontend.WarningDialog
|
||||
ErrorDialog = frontend.ErrorDialog
|
||||
QuestionDialog = frontend.QuestionDialog
|
||||
)
|
||||
|
||||
// MessageDialogOptions contains the options for the Message dialogs, EG Info, Warning, etc runtime methods
|
||||
type MessageDialogOptions = frontend.MessageDialogOptions
|
||||
|
||||
// OpenDirectoryDialog prompts the user to select a directory
|
||||
func OpenDirectoryDialog(ctx context.Context, dialogOptions OpenDialogOptions) (string, error) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
if dialogOptions.DefaultDirectory != "" {
|
||||
if !fs.DirExists(dialogOptions.DefaultDirectory) {
|
||||
return "", fmt.Errorf("default directory '%s' does not exist", dialogOptions.DefaultDirectory)
|
||||
}
|
||||
}
|
||||
return appFrontend.OpenDirectoryDialog(dialogOptions)
|
||||
}
|
||||
|
||||
// OpenFileDialog prompts the user to select a file
|
||||
func OpenFileDialog(ctx context.Context, dialogOptions OpenDialogOptions) (string, error) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
if dialogOptions.DefaultDirectory != "" {
|
||||
if !fs.DirExists(dialogOptions.DefaultDirectory) {
|
||||
return "", fmt.Errorf("default directory '%s' does not exist", dialogOptions.DefaultDirectory)
|
||||
}
|
||||
}
|
||||
return appFrontend.OpenFileDialog(dialogOptions)
|
||||
}
|
||||
|
||||
// OpenMultipleFilesDialog prompts the user to select a file
|
||||
func OpenMultipleFilesDialog(ctx context.Context, dialogOptions OpenDialogOptions) ([]string, error) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
if dialogOptions.DefaultDirectory != "" {
|
||||
if !fs.DirExists(dialogOptions.DefaultDirectory) {
|
||||
return nil, fmt.Errorf("default directory '%s' does not exist", dialogOptions.DefaultDirectory)
|
||||
}
|
||||
}
|
||||
return appFrontend.OpenMultipleFilesDialog(dialogOptions)
|
||||
}
|
||||
|
||||
// SaveFileDialog prompts the user to select a file
|
||||
func SaveFileDialog(ctx context.Context, dialogOptions SaveDialogOptions) (string, error) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
if dialogOptions.DefaultDirectory != "" {
|
||||
if !fs.DirExists(dialogOptions.DefaultDirectory) {
|
||||
return "", fmt.Errorf("default directory '%s' does not exist", dialogOptions.DefaultDirectory)
|
||||
}
|
||||
}
|
||||
return appFrontend.SaveFileDialog(dialogOptions)
|
||||
}
|
||||
|
||||
// MessageDialog show a message dialog to the user
|
||||
func MessageDialog(ctx context.Context, dialogOptions MessageDialogOptions) (string, error) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
return appFrontend.MessageDialog(dialogOptions)
|
||||
}
|
||||
37
vendor/github.com/wailsapp/wails/v2/pkg/runtime/draganddrop.go
generated
vendored
Normal file
37
vendor/github.com/wailsapp/wails/v2/pkg/runtime/draganddrop.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// OnFileDrop returns a slice of file path strings when a drop is finished.
|
||||
func OnFileDrop(ctx context.Context, callback func(x, y int, paths []string)) {
|
||||
if callback == nil {
|
||||
LogError(ctx, "OnFileDrop called with a nil callback")
|
||||
return
|
||||
}
|
||||
EventsOn(ctx, "wails:file-drop", func(optionalData ...interface{}) {
|
||||
if len(optionalData) != 3 {
|
||||
callback(0, 0, nil)
|
||||
}
|
||||
x, ok := optionalData[0].(int)
|
||||
if !ok {
|
||||
LogError(ctx, fmt.Sprintf("invalid x coordinate in drag and drop: %v", optionalData[0]))
|
||||
}
|
||||
y, ok := optionalData[1].(int)
|
||||
if !ok {
|
||||
LogError(ctx, fmt.Sprintf("invalid y coordinate in drag and drop: %v", optionalData[1]))
|
||||
}
|
||||
paths, ok := optionalData[2].([]string)
|
||||
if !ok {
|
||||
LogError(ctx, fmt.Sprintf("invalid path data in drag and drop: %v", optionalData[2]))
|
||||
}
|
||||
callback(x, y, paths)
|
||||
})
|
||||
}
|
||||
|
||||
// OnFileDropOff removes the drag and drop listeners and handlers.
|
||||
func OnFileDropOff(ctx context.Context) {
|
||||
EventsOff(ctx, "wails:file-drop")
|
||||
}
|
||||
49
vendor/github.com/wailsapp/wails/v2/pkg/runtime/events.go
generated
vendored
Normal file
49
vendor/github.com/wailsapp/wails/v2/pkg/runtime/events.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// EventsOn registers a listener for the given event name. It returns a function to cancel the listener
|
||||
func EventsOn(ctx context.Context, eventName string, callback func(optionalData ...interface{})) func() {
|
||||
events := getEvents(ctx)
|
||||
return events.On(eventName, callback)
|
||||
}
|
||||
|
||||
// EventsOff unregisters a listener for the given event name, optionally multiple listeners can be unregistered via `additionalEventNames`
|
||||
func EventsOff(ctx context.Context, eventName string, additionalEventNames ...string) {
|
||||
events := getEvents(ctx)
|
||||
events.Off(eventName)
|
||||
|
||||
if len(additionalEventNames) > 0 {
|
||||
for _, eventName := range additionalEventNames {
|
||||
events.Off(eventName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// EventsOff unregisters a listener for the given event name, optionally multiple listeners can be unregistered via `additionalEventNames`
|
||||
func EventsOffAll(ctx context.Context) {
|
||||
events := getEvents(ctx)
|
||||
events.OffAll()
|
||||
}
|
||||
|
||||
// EventsOnce registers a listener for the given event name. After the first callback, the
|
||||
// listener is deleted. It returns a function to cancel the listener
|
||||
func EventsOnce(ctx context.Context, eventName string, callback func(optionalData ...interface{})) func() {
|
||||
events := getEvents(ctx)
|
||||
return events.Once(eventName, callback)
|
||||
}
|
||||
|
||||
// EventsOnMultiple registers a listener for the given event name, that may be called a maximum of 'counter' times. It returns a function
|
||||
// to cancel the listener
|
||||
func EventsOnMultiple(ctx context.Context, eventName string, callback func(optionalData ...interface{}), counter int) func() {
|
||||
events := getEvents(ctx)
|
||||
return events.OnMultiple(eventName, callback, counter)
|
||||
}
|
||||
|
||||
// EventsEmit pass through
|
||||
func EventsEmit(ctx context.Context, eventName string, optionalData ...interface{}) {
|
||||
events := getEvents(ctx)
|
||||
events.Emit(eventName, optionalData...)
|
||||
}
|
||||
105
vendor/github.com/wailsapp/wails/v2/pkg/runtime/log.go
generated
vendored
Normal file
105
vendor/github.com/wailsapp/wails/v2/pkg/runtime/log.go
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||
)
|
||||
|
||||
// LogPrint prints a Print level message
|
||||
func LogPrint(ctx context.Context, message string) {
|
||||
myLogger := getLogger(ctx)
|
||||
myLogger.Print(message)
|
||||
}
|
||||
|
||||
// LogTrace prints a Trace level message
|
||||
func LogTrace(ctx context.Context, message string) {
|
||||
myLogger := getLogger(ctx)
|
||||
myLogger.Trace(message)
|
||||
}
|
||||
|
||||
// LogDebug prints a Debug level message
|
||||
func LogDebug(ctx context.Context, message string) {
|
||||
myLogger := getLogger(ctx)
|
||||
myLogger.Debug(message)
|
||||
}
|
||||
|
||||
// LogInfo prints a Info level message
|
||||
func LogInfo(ctx context.Context, message string) {
|
||||
myLogger := getLogger(ctx)
|
||||
myLogger.Info(message)
|
||||
}
|
||||
|
||||
// LogWarning prints a Warning level message
|
||||
func LogWarning(ctx context.Context, message string) {
|
||||
myLogger := getLogger(ctx)
|
||||
myLogger.Warning(message)
|
||||
}
|
||||
|
||||
// LogError prints a Error level message
|
||||
func LogError(ctx context.Context, message string) {
|
||||
myLogger := getLogger(ctx)
|
||||
myLogger.Error(message)
|
||||
}
|
||||
|
||||
// LogFatal prints a Fatal level message
|
||||
func LogFatal(ctx context.Context, message string) {
|
||||
myLogger := getLogger(ctx)
|
||||
myLogger.Fatal(message)
|
||||
}
|
||||
|
||||
// LogPrintf prints a Print level message
|
||||
func LogPrintf(ctx context.Context, format string, args ...interface{}) {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
myLogger := getLogger(ctx)
|
||||
myLogger.Print(msg)
|
||||
}
|
||||
|
||||
// LogTracef prints a Trace level message
|
||||
func LogTracef(ctx context.Context, format string, args ...interface{}) {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
myLogger := getLogger(ctx)
|
||||
myLogger.Trace(msg)
|
||||
}
|
||||
|
||||
// LogDebugf prints a Debug level message
|
||||
func LogDebugf(ctx context.Context, format string, args ...interface{}) {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
myLogger := getLogger(ctx)
|
||||
myLogger.Debug(msg)
|
||||
}
|
||||
|
||||
// LogInfof prints a Info level message
|
||||
func LogInfof(ctx context.Context, format string, args ...interface{}) {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
myLogger := getLogger(ctx)
|
||||
myLogger.Info(msg)
|
||||
}
|
||||
|
||||
// LogWarningf prints a Warning level message
|
||||
func LogWarningf(ctx context.Context, format string, args ...interface{}) {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
myLogger := getLogger(ctx)
|
||||
myLogger.Warning(msg)
|
||||
}
|
||||
|
||||
// LogErrorf prints a Error level message
|
||||
func LogErrorf(ctx context.Context, format string, args ...interface{}) {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
myLogger := getLogger(ctx)
|
||||
myLogger.Error(msg)
|
||||
}
|
||||
|
||||
// LogFatalf prints a Fatal level message
|
||||
func LogFatalf(ctx context.Context, format string, args ...interface{}) {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
myLogger := getLogger(ctx)
|
||||
myLogger.Fatal(msg)
|
||||
}
|
||||
|
||||
// LogSetLogLevel sets the log level
|
||||
func LogSetLogLevel(ctx context.Context, level logger.LogLevel) {
|
||||
myLogger := getLogger(ctx)
|
||||
myLogger.SetLogLevel(level)
|
||||
}
|
||||
17
vendor/github.com/wailsapp/wails/v2/pkg/runtime/menu.go
generated
vendored
Normal file
17
vendor/github.com/wailsapp/wails/v2/pkg/runtime/menu.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
)
|
||||
|
||||
func MenuSetApplicationMenu(ctx context.Context, menu *menu.Menu) {
|
||||
frontend := getFrontend(ctx)
|
||||
frontend.MenuSetApplicationMenu(menu)
|
||||
}
|
||||
|
||||
func MenuUpdateApplicationMenu(ctx context.Context) {
|
||||
frontend := getFrontend(ctx)
|
||||
frontend.MenuUpdateApplicationMenu()
|
||||
}
|
||||
136
vendor/github.com/wailsapp/wails/v2/pkg/runtime/notifications.go
generated
vendored
Normal file
136
vendor/github.com/wailsapp/wails/v2/pkg/runtime/notifications.go
generated
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
)
|
||||
|
||||
// NotificationOptions contains configuration for a notification.
|
||||
type NotificationOptions = frontend.NotificationOptions
|
||||
|
||||
// NotificationAction represents an action button for a notification.
|
||||
type NotificationAction = frontend.NotificationAction
|
||||
|
||||
// NotificationCategory groups actions for notifications.
|
||||
type NotificationCategory = frontend.NotificationCategory
|
||||
|
||||
// NotificationResponse represents the response sent by interacting with a notification.
|
||||
type NotificationResponse = frontend.NotificationResponse
|
||||
|
||||
// NotificationResult represents the result of a notification response,
|
||||
// returning the response or any errors that occurred.
|
||||
type NotificationResult = frontend.NotificationResult
|
||||
|
||||
// InitializeNotifications initializes the notification service for the application.
|
||||
// This must be called before sending any notifications. On macOS, this also ensures
|
||||
// the notification delegate is properly initialized.
|
||||
func InitializeNotifications(ctx context.Context) error {
|
||||
fe := getFrontend(ctx)
|
||||
return fe.InitializeNotifications()
|
||||
}
|
||||
|
||||
// CleanupNotifications cleans up notification resources and releases any held connections.
|
||||
// This should be called when shutting down the application to properly release resources
|
||||
// (primarily needed on Linux to close D-Bus connections).
|
||||
func CleanupNotifications(ctx context.Context) {
|
||||
fe := getFrontend(ctx)
|
||||
fe.CleanupNotifications()
|
||||
}
|
||||
|
||||
// IsNotificationAvailable checks if notifications are available on the current platform.
|
||||
func IsNotificationAvailable(ctx context.Context) bool {
|
||||
fe := getFrontend(ctx)
|
||||
return fe.IsNotificationAvailable()
|
||||
}
|
||||
|
||||
// RequestNotificationAuthorization requests notification authorization from the user.
|
||||
// On macOS, this prompts the user to allow notifications. On other platforms, this
|
||||
// always returns true. Returns true if authorization was granted, false otherwise.
|
||||
func RequestNotificationAuthorization(ctx context.Context) (bool, error) {
|
||||
fe := getFrontend(ctx)
|
||||
return fe.RequestNotificationAuthorization()
|
||||
}
|
||||
|
||||
// CheckNotificationAuthorization checks the current notification authorization status.
|
||||
// On macOS, this checks if the app has notification permissions. On other platforms,
|
||||
// this always returns true.
|
||||
func CheckNotificationAuthorization(ctx context.Context) (bool, error) {
|
||||
fe := getFrontend(ctx)
|
||||
return fe.CheckNotificationAuthorization()
|
||||
}
|
||||
|
||||
// SendNotification sends a basic notification with the given options.
|
||||
// The notification will display with the provided title, subtitle (if supported),
|
||||
// and body text.
|
||||
func SendNotification(ctx context.Context, options NotificationOptions) error {
|
||||
fe := getFrontend(ctx)
|
||||
return fe.SendNotification(options)
|
||||
}
|
||||
|
||||
// SendNotificationWithActions sends a notification with action buttons.
|
||||
// A NotificationCategory must be registered first using RegisterNotificationCategory.
|
||||
// The options.CategoryID must match a previously registered category ID.
|
||||
// If the category is not found, a basic notification will be sent instead.
|
||||
func SendNotificationWithActions(ctx context.Context, options NotificationOptions) error {
|
||||
fe := getFrontend(ctx)
|
||||
return fe.SendNotificationWithActions(options)
|
||||
}
|
||||
|
||||
// RegisterNotificationCategory registers a notification category that can be used
|
||||
// with SendNotificationWithActions. Categories define the action buttons and optional
|
||||
// reply fields that will appear on notifications.
|
||||
func RegisterNotificationCategory(ctx context.Context, category NotificationCategory) error {
|
||||
fe := getFrontend(ctx)
|
||||
return fe.RegisterNotificationCategory(category)
|
||||
}
|
||||
|
||||
// RemoveNotificationCategory removes a previously registered notification category.
|
||||
func RemoveNotificationCategory(ctx context.Context, categoryId string) error {
|
||||
fe := getFrontend(ctx)
|
||||
return fe.RemoveNotificationCategory(categoryId)
|
||||
}
|
||||
|
||||
// RemoveAllPendingNotifications removes all pending notifications from the notification center.
|
||||
// On Windows, this is a no-op as the platform manages notification lifecycle automatically.
|
||||
func RemoveAllPendingNotifications(ctx context.Context) error {
|
||||
fe := getFrontend(ctx)
|
||||
return fe.RemoveAllPendingNotifications()
|
||||
}
|
||||
|
||||
// RemovePendingNotification removes a specific pending notification by its identifier.
|
||||
// On Windows, this is a no-op as the platform manages notification lifecycle automatically.
|
||||
func RemovePendingNotification(ctx context.Context, identifier string) error {
|
||||
fe := getFrontend(ctx)
|
||||
return fe.RemovePendingNotification(identifier)
|
||||
}
|
||||
|
||||
// RemoveAllDeliveredNotifications removes all delivered notifications from the notification center.
|
||||
// On Windows, this is a no-op as the platform manages notification lifecycle automatically.
|
||||
func RemoveAllDeliveredNotifications(ctx context.Context) error {
|
||||
fe := getFrontend(ctx)
|
||||
return fe.RemoveAllDeliveredNotifications()
|
||||
}
|
||||
|
||||
// RemoveDeliveredNotification removes a specific delivered notification by its identifier.
|
||||
// On Windows, this is a no-op as the platform manages notification lifecycle automatically.
|
||||
func RemoveDeliveredNotification(ctx context.Context, identifier string) error {
|
||||
fe := getFrontend(ctx)
|
||||
return fe.RemoveDeliveredNotification(identifier)
|
||||
}
|
||||
|
||||
// RemoveNotification removes a notification by its identifier.
|
||||
// This is a convenience function that works across platforms. On macOS, use the
|
||||
// more specific RemovePendingNotification or RemoveDeliveredNotification functions.
|
||||
func RemoveNotification(ctx context.Context, identifier string) error {
|
||||
fe := getFrontend(ctx)
|
||||
return fe.RemoveNotification(identifier)
|
||||
}
|
||||
|
||||
// OnNotificationResponse registers a callback function that will be invoked when
|
||||
// a user interacts with a notification (e.g., clicks an action button or the notification itself).
|
||||
// The callback receives a NotificationResult containing the response details or any errors.
|
||||
func OnNotificationResponse(ctx context.Context, callback func(result NotificationResult)) {
|
||||
fe := getFrontend(ctx)
|
||||
fe.OnNotificationResponse(callback)
|
||||
}
|
||||
107
vendor/github.com/wailsapp/wails/v2/pkg/runtime/runtime.go
generated
vendored
Normal file
107
vendor/github.com/wailsapp/wails/v2/pkg/runtime/runtime.go
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
goruntime "runtime"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
)
|
||||
|
||||
const contextError = `An invalid context was passed. This method requires the specific context given in the lifecycle hooks:
|
||||
https://wails.io/docs/reference/runtime/intro`
|
||||
|
||||
func getFrontend(ctx context.Context) frontend.Frontend {
|
||||
if ctx == nil {
|
||||
pc, _, _, _ := goruntime.Caller(1)
|
||||
funcName := goruntime.FuncForPC(pc).Name()
|
||||
log.Fatalf("cannot call '%s': %s", funcName, contextError)
|
||||
}
|
||||
result := ctx.Value("frontend")
|
||||
if result != nil {
|
||||
return result.(frontend.Frontend)
|
||||
}
|
||||
pc, _, _, _ := goruntime.Caller(1)
|
||||
funcName := goruntime.FuncForPC(pc).Name()
|
||||
log.Fatalf("cannot call '%s': %s", funcName, contextError)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getLogger(ctx context.Context) *logger.Logger {
|
||||
if ctx == nil {
|
||||
pc, _, _, _ := goruntime.Caller(1)
|
||||
funcName := goruntime.FuncForPC(pc).Name()
|
||||
log.Fatalf("cannot call '%s': %s", funcName, contextError)
|
||||
}
|
||||
result := ctx.Value("logger")
|
||||
if result != nil {
|
||||
return result.(*logger.Logger)
|
||||
}
|
||||
pc, _, _, _ := goruntime.Caller(1)
|
||||
funcName := goruntime.FuncForPC(pc).Name()
|
||||
log.Fatalf("cannot call '%s': %s", funcName, contextError)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getEvents(ctx context.Context) frontend.Events {
|
||||
if ctx == nil {
|
||||
pc, _, _, _ := goruntime.Caller(1)
|
||||
funcName := goruntime.FuncForPC(pc).Name()
|
||||
log.Fatalf("cannot call '%s': %s", funcName, contextError)
|
||||
}
|
||||
result := ctx.Value("events")
|
||||
if result != nil {
|
||||
return result.(frontend.Events)
|
||||
}
|
||||
pc, _, _, _ := goruntime.Caller(1)
|
||||
funcName := goruntime.FuncForPC(pc).Name()
|
||||
log.Fatalf("cannot call '%s': %s", funcName, contextError)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Quit the application
|
||||
func Quit(ctx context.Context) {
|
||||
if ctx == nil {
|
||||
log.Fatalf("Error calling 'runtime.Quit': %s", contextError)
|
||||
}
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.Quit()
|
||||
}
|
||||
|
||||
// Hide the application
|
||||
func Hide(ctx context.Context) {
|
||||
if ctx == nil {
|
||||
log.Fatalf("Error calling 'runtime.Hide': %s", contextError)
|
||||
}
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.Hide()
|
||||
}
|
||||
|
||||
// Show the application if it is hidden
|
||||
func Show(ctx context.Context) {
|
||||
if ctx == nil {
|
||||
log.Fatalf("Error calling 'runtime.Show': %s", contextError)
|
||||
}
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.Show()
|
||||
}
|
||||
|
||||
// EnvironmentInfo contains information about the environment
|
||||
type EnvironmentInfo struct {
|
||||
BuildType string `json:"buildType"`
|
||||
Platform string `json:"platform"`
|
||||
Arch string `json:"arch"`
|
||||
}
|
||||
|
||||
// Environment returns information about the environment
|
||||
func Environment(ctx context.Context) EnvironmentInfo {
|
||||
var result EnvironmentInfo
|
||||
buildType := ctx.Value("buildtype")
|
||||
if buildType != nil {
|
||||
result.BuildType = buildType.(string)
|
||||
}
|
||||
result.Platform = goruntime.GOOS
|
||||
result.Arch = goruntime.GOARCH
|
||||
return result
|
||||
}
|
||||
15
vendor/github.com/wailsapp/wails/v2/pkg/runtime/screen.go
generated
vendored
Normal file
15
vendor/github.com/wailsapp/wails/v2/pkg/runtime/screen.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
)
|
||||
|
||||
type Screen = frontend.Screen
|
||||
|
||||
// ScreenGetAll returns all screens
|
||||
func ScreenGetAll(ctx context.Context) ([]Screen, error) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
return appFrontend.ScreenGetAll()
|
||||
}
|
||||
65
vendor/github.com/wailsapp/wails/v2/pkg/runtime/signal_linux.go
generated
vendored
Normal file
65
vendor/github.com/wailsapp/wails/v2/pkg/runtime/signal_linux.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
//go:build linux
|
||||
|
||||
package runtime
|
||||
|
||||
/*
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static void fix_signal(int signum)
|
||||
{
|
||||
struct sigaction st;
|
||||
|
||||
if (sigaction(signum, NULL, &st) < 0) {
|
||||
return;
|
||||
}
|
||||
st.sa_flags |= SA_ONSTACK;
|
||||
sigaction(signum, &st, NULL);
|
||||
}
|
||||
|
||||
static void fix_all_signals()
|
||||
{
|
||||
#if defined(SIGSEGV)
|
||||
fix_signal(SIGSEGV);
|
||||
#endif
|
||||
#if defined(SIGBUS)
|
||||
fix_signal(SIGBUS);
|
||||
#endif
|
||||
#if defined(SIGFPE)
|
||||
fix_signal(SIGFPE);
|
||||
#endif
|
||||
#if defined(SIGABRT)
|
||||
fix_signal(SIGABRT);
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// ResetSignalHandlers resets signal handlers to allow panic recovery.
|
||||
//
|
||||
// On Linux, WebKit (used for the webview) may install signal handlers without
|
||||
// the SA_ONSTACK flag, which prevents Go from properly recovering from panics
|
||||
// caused by nil pointer dereferences or other memory access violations.
|
||||
//
|
||||
// Call this function immediately before code that might panic to ensure
|
||||
// the signal handlers are properly configured for Go's panic recovery mechanism.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// go func() {
|
||||
// defer func() {
|
||||
// if err := recover(); err != nil {
|
||||
// log.Printf("Recovered from panic: %v", err)
|
||||
// }
|
||||
// }()
|
||||
// runtime.ResetSignalHandlers()
|
||||
// // Code that might panic...
|
||||
// }()
|
||||
//
|
||||
// Note: This function only has an effect on Linux. On other platforms,
|
||||
// it is a no-op.
|
||||
func ResetSignalHandlers() {
|
||||
C.fix_all_signals()
|
||||
}
|
||||
18
vendor/github.com/wailsapp/wails/v2/pkg/runtime/signal_other.go
generated
vendored
Normal file
18
vendor/github.com/wailsapp/wails/v2/pkg/runtime/signal_other.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
//go:build !linux
|
||||
|
||||
package runtime
|
||||
|
||||
// ResetSignalHandlers resets signal handlers to allow panic recovery.
|
||||
//
|
||||
// On Linux, WebKit (used for the webview) may install signal handlers without
|
||||
// the SA_ONSTACK flag, which prevents Go from properly recovering from panics
|
||||
// caused by nil pointer dereferences or other memory access violations.
|
||||
//
|
||||
// Call this function immediately before code that might panic to ensure
|
||||
// the signal handlers are properly configured for Go's panic recovery mechanism.
|
||||
//
|
||||
// Note: This function only has an effect on Linux. On other platforms,
|
||||
// it is a no-op.
|
||||
func ResetSignalHandlers() {
|
||||
// No-op on non-Linux platforms
|
||||
}
|
||||
186
vendor/github.com/wailsapp/wails/v2/pkg/runtime/window.go
generated
vendored
Normal file
186
vendor/github.com/wailsapp/wails/v2/pkg/runtime/window.go
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
// WindowSetTitle sets the title of the window
|
||||
func WindowSetTitle(ctx context.Context, title string) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowSetTitle(title)
|
||||
}
|
||||
|
||||
// WindowFullscreen makes the window fullscreen
|
||||
func WindowFullscreen(ctx context.Context) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowFullscreen()
|
||||
}
|
||||
|
||||
// WindowUnfullscreen makes the window UnFullscreen
|
||||
func WindowUnfullscreen(ctx context.Context) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowUnfullscreen()
|
||||
}
|
||||
|
||||
// WindowCenter the window on the current screen
|
||||
func WindowCenter(ctx context.Context) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowCenter()
|
||||
}
|
||||
|
||||
// WindowReload will reload the window contents
|
||||
func WindowReload(ctx context.Context) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowReload()
|
||||
}
|
||||
|
||||
// WindowReloadApp will reload the application
|
||||
func WindowReloadApp(ctx context.Context) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowReloadApp()
|
||||
}
|
||||
|
||||
func WindowSetSystemDefaultTheme(ctx context.Context) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowSetSystemDefaultTheme()
|
||||
}
|
||||
|
||||
func WindowSetLightTheme(ctx context.Context) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowSetLightTheme()
|
||||
}
|
||||
|
||||
func WindowSetDarkTheme(ctx context.Context) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowSetDarkTheme()
|
||||
}
|
||||
|
||||
// WindowShow shows the window if hidden
|
||||
func WindowShow(ctx context.Context) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowShow()
|
||||
}
|
||||
|
||||
// WindowHide the window
|
||||
func WindowHide(ctx context.Context) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowHide()
|
||||
}
|
||||
|
||||
// WindowSetSize sets the size of the window
|
||||
func WindowSetSize(ctx context.Context, width int, height int) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowSetSize(width, height)
|
||||
}
|
||||
|
||||
func WindowGetSize(ctx context.Context) (int, int) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
return appFrontend.WindowGetSize()
|
||||
}
|
||||
|
||||
// WindowSetMinSize sets the minimum size of the window
|
||||
func WindowSetMinSize(ctx context.Context, width int, height int) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowSetMinSize(width, height)
|
||||
}
|
||||
|
||||
// WindowSetMaxSize sets the maximum size of the window
|
||||
func WindowSetMaxSize(ctx context.Context, width int, height int) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowSetMaxSize(width, height)
|
||||
}
|
||||
|
||||
// WindowSetAlwaysOnTop sets the window AlwaysOnTop or not on top
|
||||
func WindowSetAlwaysOnTop(ctx context.Context, b bool) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowSetAlwaysOnTop(b)
|
||||
}
|
||||
|
||||
// WindowSetPosition sets the position of the window
|
||||
func WindowSetPosition(ctx context.Context, x int, y int) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowSetPosition(x, y)
|
||||
}
|
||||
|
||||
func WindowGetPosition(ctx context.Context) (int, int) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
return appFrontend.WindowGetPosition()
|
||||
}
|
||||
|
||||
// WindowMaximise the window
|
||||
func WindowMaximise(ctx context.Context) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowMaximise()
|
||||
}
|
||||
|
||||
// WindowToggleMaximise the window
|
||||
func WindowToggleMaximise(ctx context.Context) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowToggleMaximise()
|
||||
}
|
||||
|
||||
// WindowUnmaximise the window
|
||||
func WindowUnmaximise(ctx context.Context) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowUnmaximise()
|
||||
}
|
||||
|
||||
// WindowMinimise the window
|
||||
func WindowMinimise(ctx context.Context) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowMinimise()
|
||||
}
|
||||
|
||||
// WindowUnminimise the window
|
||||
func WindowUnminimise(ctx context.Context) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowUnminimise()
|
||||
}
|
||||
|
||||
// WindowIsFullscreen get the window state is window Fullscreen
|
||||
func WindowIsFullscreen(ctx context.Context) bool {
|
||||
appFrontend := getFrontend(ctx)
|
||||
return appFrontend.WindowIsFullscreen()
|
||||
}
|
||||
|
||||
// WindowIsMaximised get the window state is window Maximised
|
||||
func WindowIsMaximised(ctx context.Context) bool {
|
||||
appFrontend := getFrontend(ctx)
|
||||
return appFrontend.WindowIsMaximised()
|
||||
}
|
||||
|
||||
// WindowIsMinimised get the window state is window Minimised
|
||||
func WindowIsMinimised(ctx context.Context) bool {
|
||||
appFrontend := getFrontend(ctx)
|
||||
return appFrontend.WindowIsMinimised()
|
||||
}
|
||||
|
||||
// WindowIsNormal get the window state is window Normal
|
||||
func WindowIsNormal(ctx context.Context) bool {
|
||||
appFrontend := getFrontend(ctx)
|
||||
return appFrontend.WindowIsNormal()
|
||||
}
|
||||
|
||||
// WindowExecJS executes the given Js in the window
|
||||
func WindowExecJS(ctx context.Context, js string) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.ExecJS(js)
|
||||
}
|
||||
|
||||
func WindowSetBackgroundColour(ctx context.Context, R, G, B, A uint8) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
col := &options.RGBA{
|
||||
R: R,
|
||||
G: G,
|
||||
B: B,
|
||||
A: A,
|
||||
}
|
||||
appFrontend.WindowSetBackgroundColour(col)
|
||||
}
|
||||
|
||||
func WindowPrint(ctx context.Context) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowPrint()
|
||||
}
|
||||
Reference in New Issue
Block a user