mirror of
https://github.com/wailsapp/wails.git
synced 2026-03-14 14:45:49 +01:00
Merge latest v2 changes
This commit is contained in:
parent
95b8ceb87a
commit
9584a2ce5a
27 changed files with 232 additions and 552 deletions
|
|
@ -4,6 +4,7 @@ version: "3"
|
|||
|
||||
tasks:
|
||||
release:
|
||||
summary: Release a new version of Task. Call with `task v2:release -- <version>`
|
||||
dir: tools/release
|
||||
cmds:
|
||||
- go run release.go {{.CLI_ARGS}}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
|
@ -138,20 +139,6 @@ func Application(f *flags.Dev, logger *clilogger.CLILogger) error {
|
|||
}
|
||||
}
|
||||
|
||||
// create the project files watcher
|
||||
watcher, err := initialiseWatcher(cwd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func(watcher *fsnotify.Watcher) {
|
||||
err := watcher.Close()
|
||||
if err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}(watcher)
|
||||
|
||||
logutils.LogGreen("Watching (sub)/directory: %s", cwd)
|
||||
logutils.LogGreen("Using DevServer URL: %s", f.DevServerURL())
|
||||
if f.FrontendDevServerURL != "" {
|
||||
logutils.LogGreen("Using Frontend DevServer URL: %s", f.FrontendDevServerURL)
|
||||
|
|
@ -165,7 +152,10 @@ func Application(f *flags.Dev, logger *clilogger.CLILogger) error {
|
|||
}()
|
||||
|
||||
// Watch for changes and trigger restartApp()
|
||||
debugBinaryProcess = doWatcherLoop(buildOptions, debugBinaryProcess, f, watcher, exitCodeChannel, quitChannel, f.DevServerURL(), legacyUseDevServerInsteadofCustomScheme)
|
||||
debugBinaryProcess, err = doWatcherLoop(cwd, buildOptions, debugBinaryProcess, f, exitCodeChannel, quitChannel, f.DevServerURL(), legacyUseDevServerInsteadofCustomScheme)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Kill the current program if running and remove dev binary
|
||||
if err := killProcessAndCleanupBinary(debugBinaryProcess, appBinary); err != nil {
|
||||
|
|
@ -318,9 +308,6 @@ func restartApp(buildOptions *build.Options, debugBinaryProcess *process.Process
|
|||
os.Setenv("assetdir", f.AssetDir)
|
||||
os.Setenv("devserver", f.DevServer)
|
||||
os.Setenv("frontenddevserverurl", f.FrontendDevServerURL)
|
||||
if legacyUseDevServerInsteadofCustomScheme {
|
||||
os.Setenv("legacyusedevsererinsteadofcustomscheme", "true")
|
||||
}
|
||||
|
||||
// Start up new binary with correct args
|
||||
newProcess := process.NewProcess(appBinary, args...)
|
||||
|
|
@ -340,7 +327,23 @@ func restartApp(buildOptions *build.Options, debugBinaryProcess *process.Process
|
|||
}
|
||||
|
||||
// doWatcherLoop is the main watch loop that runs while dev is active
|
||||
func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Process, f *flags.Dev, watcher *fsnotify.Watcher, exitCodeChannel chan int, quitChannel chan os.Signal, devServerURL *url.URL, legacyUseDevServerInsteadofCustomScheme bool) *process.Process {
|
||||
func doWatcherLoop(cwd string, buildOptions *build.Options, debugBinaryProcess *process.Process, f *flags.Dev, exitCodeChannel chan int, quitChannel chan os.Signal, devServerURL *url.URL, legacyUseDevServerInsteadofCustomScheme bool) (*process.Process, error) {
|
||||
// create the project files watcher
|
||||
watcher, err := initialiseWatcher(cwd)
|
||||
if err != nil {
|
||||
logutils.LogRed("Unable to create filesystem watcher. Reloads will not occur.")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer func(watcher *fsnotify.Watcher) {
|
||||
err := watcher.Close()
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
}(watcher)
|
||||
|
||||
logutils.LogGreen("Watching (sub)/directory: %s", cwd)
|
||||
|
||||
// Main Loop
|
||||
var extensionsThatTriggerARebuild = sliceToMap(strings.Split(f.Extensions, ","))
|
||||
var dirsThatTriggerAReload []string
|
||||
|
|
@ -354,6 +357,12 @@ func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Proc
|
|||
continue
|
||||
}
|
||||
dirsThatTriggerAReload = append(dirsThatTriggerAReload, thePath)
|
||||
err = watcher.Add(thePath)
|
||||
if err != nil {
|
||||
logutils.LogRed("Unable to watch path: %s due to error %v", thePath, err)
|
||||
} else {
|
||||
logutils.LogGreen("Watching (sub)/directory: %s", thePath)
|
||||
}
|
||||
}
|
||||
|
||||
quit := false
|
||||
|
|
@ -502,7 +511,7 @@ func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Proc
|
|||
quit = true
|
||||
}
|
||||
}
|
||||
return debugBinaryProcess
|
||||
return debugBinaryProcess, nil
|
||||
}
|
||||
|
||||
func joinPath(url *url.URL, subPath string) string {
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ func initialiseWatcher(cwd string) (*fsnotify.Watcher, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
println("watching: " + dir)
|
||||
}
|
||||
return watcher, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
v2.5.1
|
||||
v2.6.0
|
||||
BIN
v2/cmd/wails/wails
Normal file
BIN
v2/cmd/wails/wails
Normal file
Binary file not shown.
|
|
@ -1,7 +1,7 @@
|
|||
//go:build devtools
|
||||
|
||||
package app
|
||||
|
||||
func IsDevtoolsEnabled() bool {
|
||||
return true
|
||||
}
|
||||
//go:build devtools
|
||||
|
||||
package app
|
||||
|
||||
func IsDevtoolsEnabled() bool {
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//go:build !devtools
|
||||
|
||||
package app
|
||||
|
||||
func IsDevtoolsEnabled() bool {
|
||||
return false
|
||||
}
|
||||
//go:build !devtools
|
||||
|
||||
package app
|
||||
|
||||
func IsDevtoolsEnabled() bool {
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ void ShowApplication(void* ctx);
|
|||
void SetBackgroundColour(void* ctx, int r, int g, int b, int a);
|
||||
void ExecJS(void* ctx, const char*);
|
||||
void Quit(void*);
|
||||
void WindowPrint(void* ctx);
|
||||
|
||||
const char* GetSize(void *ctx);
|
||||
const char* GetPosition(void *ctx);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#import "WailsContext.h"
|
||||
#import "Application.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "WindowDelegate.h"
|
||||
#import "WailsMenu.h"
|
||||
#import "WailsMenuItem.h"
|
||||
|
||||
|
|
@ -384,3 +385,36 @@ void ReleaseContext(void *inctx) {
|
|||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
[ctx release];
|
||||
}
|
||||
|
||||
// Credit: https://stackoverflow.com/q/33319295
|
||||
void WindowPrint(void *inctx) {
|
||||
|
||||
// Check if macOS 11.0 or newer
|
||||
if (@available(macOS 11.0, *)) {
|
||||
ON_MAIN_THREAD(
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
WKWebView* webView = ctx.webview;
|
||||
|
||||
// I think this should be exposed as a config
|
||||
// It directly affects the printed output/PDF
|
||||
NSPrintInfo *pInfo = [NSPrintInfo sharedPrintInfo];
|
||||
pInfo.horizontalPagination = NSPrintingPaginationModeAutomatic;
|
||||
pInfo.verticalPagination = NSPrintingPaginationModeAutomatic;
|
||||
pInfo.verticallyCentered = YES;
|
||||
pInfo.horizontallyCentered = YES;
|
||||
pInfo.orientation = NSPaperOrientationLandscape;
|
||||
pInfo.leftMargin = 0;
|
||||
pInfo.rightMargin = 0;
|
||||
pInfo.topMargin = 0;
|
||||
pInfo.bottomMargin = 0;
|
||||
|
||||
NSPrintOperation *po = [webView printOperationWithPrintInfo:pInfo];
|
||||
po.showsPrintPanel = YES;
|
||||
po.showsProgressPanel = YES;
|
||||
|
||||
po.view.frame = webView.bounds;
|
||||
|
||||
[po runOperationModalForWindow:ctx.mainWindow delegate:ctx.mainWindow.delegate didRunSelector:nil contextInfo:nil];
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -286,6 +286,10 @@ func (f *Frontend) Quit() {
|
|||
f.mainWindow.Quit()
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowPrint() {
|
||||
f.mainWindow.Print()
|
||||
}
|
||||
|
||||
type EventNotify struct {
|
||||
Name string `json:"name"`
|
||||
Data []interface{} `json:"data"`
|
||||
|
|
|
|||
|
|
@ -263,3 +263,7 @@ func (w *Window) SetApplicationMenu(inMenu *menu.Menu) {
|
|||
func (w *Window) UpdateApplicationMenu() {
|
||||
C.UpdateApplicationMenu(w.context)
|
||||
}
|
||||
|
||||
func (w Window) Print() {
|
||||
C.WindowPrint(w.context)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -362,6 +362,10 @@ func (f *Frontend) Quit() {
|
|||
f.mainWindow.Quit()
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowPrint() {
|
||||
f.ExecJS("window.print();")
|
||||
}
|
||||
|
||||
type EventNotify struct {
|
||||
Name string `json:"name"`
|
||||
Data []interface{} `json:"data"`
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <locale.h>
|
||||
#include "window.h"
|
||||
|
||||
// These are the x,y,time & button of the last mouse down event
|
||||
|
|
@ -145,20 +146,39 @@ void SetBackgroundColour(void *data)
|
|||
{
|
||||
// set webview's background color
|
||||
RGBAOptions *options = (RGBAOptions *)data;
|
||||
|
||||
GdkRGBA colour = {options->r / 255.0, options->g / 255.0, options->b / 255.0, options->a / 255.0};
|
||||
if (options->windowIsTranslucent != NULL && options->windowIsTranslucent == TRUE)
|
||||
{
|
||||
colour.alpha = 0.0;
|
||||
}
|
||||
webkit_web_view_set_background_color(WEBKIT_WEB_VIEW(options->webview), &colour);
|
||||
|
||||
// set window's background color
|
||||
GtkWidget *window = GTK_WIDGET(options->window);
|
||||
gchar *str = g_strdup_printf("window {background-color: rgba(%d, %d, %d, %d);}", options->r, options->g, options->b, options->a);
|
||||
// Get the name of the current locale
|
||||
char *old_locale, *saved_locale;
|
||||
old_locale = setlocale(LC_ALL, NULL);
|
||||
|
||||
// Copy the name so it won’t be clobbered by setlocale.
|
||||
saved_locale = strdup(old_locale);
|
||||
if (saved_locale == NULL)
|
||||
return;
|
||||
|
||||
//Now change the locale to english for so printf always converts floats with a dot decimal separator
|
||||
setlocale(LC_ALL, "en_US.UTF-8");
|
||||
gchar *str = g_strdup_printf("#webview-box {background-color: rgba(%d, %d, %d, %1.1f);}", options->r, options->g, options->b, options->a / 255.0);
|
||||
|
||||
//Restore the original locale.
|
||||
setlocale(LC_ALL, saved_locale);
|
||||
free(saved_locale);
|
||||
|
||||
if (windowCssProvider == NULL)
|
||||
{
|
||||
windowCssProvider = gtk_css_provider_new();
|
||||
gtk_style_context_add_provider(
|
||||
gtk_widget_get_style_context(window),
|
||||
gtk_widget_get_style_context(GTK_WIDGET(options->webviewBox)),
|
||||
GTK_STYLE_PROVIDER(windowCssProvider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
g_object_unref(windowCssProvider);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ type Window struct {
|
|||
webview unsafe.Pointer
|
||||
applicationMenu *menu.Menu
|
||||
menubar *C.GtkWidget
|
||||
webviewBox *C.GtkWidget
|
||||
vbox *C.GtkWidget
|
||||
accels *C.GtkAccelGroup
|
||||
minWidth, minHeight, maxWidth, maxHeight int
|
||||
|
|
@ -72,6 +73,11 @@ func NewWindow(appoptions *options.App, debug bool, devtools bool) *Window {
|
|||
C.g_object_ref_sink(C.gpointer(gtkWindow))
|
||||
result.gtkWindow = unsafe.Pointer(gtkWindow)
|
||||
|
||||
webviewName := C.CString("webview-box")
|
||||
defer C.free(unsafe.Pointer(webviewName))
|
||||
result.webviewBox = C.gtk_box_new(C.GTK_ORIENTATION_VERTICAL, 0)
|
||||
C.gtk_widget_set_name(result.webviewBox, webviewName)
|
||||
|
||||
result.vbox = C.gtk_box_new(C.GTK_ORIENTATION_VERTICAL, 0)
|
||||
C.gtk_container_add(result.asGTKContainer(), result.vbox)
|
||||
|
||||
|
|
@ -265,13 +271,18 @@ func (w *Window) IsNormal() bool {
|
|||
}
|
||||
|
||||
func (w *Window) SetBackgroundColour(r uint8, g uint8, b uint8, a uint8) {
|
||||
windowIsTranslucent := false
|
||||
if w.appoptions.Linux != nil && w.appoptions.Linux.WindowIsTranslucent {
|
||||
windowIsTranslucent = true
|
||||
}
|
||||
data := C.RGBAOptions{
|
||||
r: C.uchar(r),
|
||||
g: C.uchar(g),
|
||||
b: C.uchar(b),
|
||||
a: C.uchar(a),
|
||||
webview: w.webview,
|
||||
window: w.gtkWindow,
|
||||
r: C.uchar(r),
|
||||
g: C.uchar(g),
|
||||
b: C.uchar(b),
|
||||
a: C.uchar(a),
|
||||
webview: w.webview,
|
||||
webviewBox: unsafe.Pointer(w.webviewBox),
|
||||
windowIsTranslucent: gtkBool(windowIsTranslucent),
|
||||
}
|
||||
invokeOnMainThread(func() { C.SetBackgroundColour(unsafe.Pointer(&data)) })
|
||||
|
||||
|
|
@ -288,7 +299,9 @@ func (w *Window) Run(url string) {
|
|||
if w.menubar != nil {
|
||||
C.gtk_box_pack_start(C.GTKBOX(unsafe.Pointer(w.vbox)), w.menubar, 0, 0, 0)
|
||||
}
|
||||
C.gtk_box_pack_start(C.GTKBOX(unsafe.Pointer(w.vbox)), C.GTKWIDGET(w.webview), 1, 1, 0)
|
||||
|
||||
C.gtk_box_pack_start(C.GTKBOX(unsafe.Pointer(w.webviewBox)), C.GTKWIDGET(w.webview), 1, 1, 0)
|
||||
C.gtk_box_pack_start(C.GTKBOX(unsafe.Pointer(w.vbox)), w.webviewBox, 1, 1, 0)
|
||||
_url := C.CString(url)
|
||||
C.LoadIndex(w.webview, _url)
|
||||
defer C.free(unsafe.Pointer(_url))
|
||||
|
|
|
|||
|
|
@ -55,7 +55,8 @@ typedef struct RGBAOptions
|
|||
uint8_t b;
|
||||
uint8_t a;
|
||||
void *webview;
|
||||
void *window;
|
||||
void *webviewBox;
|
||||
gboolean windowIsTranslucent;
|
||||
} RGBAOptions;
|
||||
|
||||
typedef struct SetTitleArgs
|
||||
|
|
|
|||
|
|
@ -425,6 +425,10 @@ func (f *Frontend) Quit() {
|
|||
f.mainWindow.Invoke(winc.Exit)
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowPrint() {
|
||||
f.ExecJS("window.print();")
|
||||
}
|
||||
|
||||
func (f *Frontend) setupChromium() {
|
||||
chromium := f.chromium
|
||||
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ type Frontend interface {
|
|||
WindowIsNormal() bool
|
||||
WindowIsFullscreen() bool
|
||||
WindowClose()
|
||||
WindowPrint()
|
||||
|
||||
//Screen
|
||||
ScreenGetAll() ([]Screen, error)
|
||||
|
|
|
|||
82
v2/internal/platform/win32/menu.go
Normal file
82
v2/internal/platform/win32/menu.go
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
//go:build windows
|
||||
|
||||
package win32
|
||||
|
||||
type Menu HMENU
|
||||
type PopupMenu Menu
|
||||
|
||||
func CreatePopupMenu() PopupMenu {
|
||||
ret, _, _ := procCreatePopupMenu.Call(0, 0, 0, 0)
|
||||
return PopupMenu(ret)
|
||||
}
|
||||
|
||||
func (m Menu) Destroy() bool {
|
||||
ret, _, _ := procDestroyMenu.Call(uintptr(m))
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func (p PopupMenu) Destroy() bool {
|
||||
return Menu(p).Destroy()
|
||||
}
|
||||
|
||||
func (p PopupMenu) Track(flags uint, x, y int, wnd HWND) bool {
|
||||
ret, _, _ := procTrackPopupMenu.Call(
|
||||
uintptr(p),
|
||||
uintptr(flags),
|
||||
uintptr(x),
|
||||
uintptr(y),
|
||||
0,
|
||||
uintptr(wnd),
|
||||
0,
|
||||
)
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func (p PopupMenu) Append(flags uintptr, id uintptr, text string) bool {
|
||||
return Menu(p).Append(flags, id, text)
|
||||
}
|
||||
|
||||
func (m Menu) Append(flags uintptr, id uintptr, text string) bool {
|
||||
ret, _, _ := procAppendMenuW.Call(
|
||||
uintptr(m),
|
||||
flags,
|
||||
id,
|
||||
MustStringToUTF16uintptr(text),
|
||||
)
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func (p PopupMenu) Check(id uintptr, checked bool) bool {
|
||||
return Menu(p).Check(id, checked)
|
||||
}
|
||||
|
||||
func (m Menu) Check(id uintptr, check bool) bool {
|
||||
var checkState uint = MF_UNCHECKED
|
||||
if check {
|
||||
checkState = MF_CHECKED
|
||||
}
|
||||
return CheckMenuItem(HMENU(m), id, checkState) != 0
|
||||
}
|
||||
|
||||
func (m Menu) CheckRadio(startID int, endID int, selectedID int) bool {
|
||||
ret, _, _ := procCheckMenuRadioItem.Call(
|
||||
uintptr(m),
|
||||
uintptr(startID),
|
||||
uintptr(endID),
|
||||
uintptr(selectedID),
|
||||
MF_BYCOMMAND)
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func CheckMenuItem(menu HMENU, id uintptr, flags uint) uint {
|
||||
ret, _, _ := procCheckMenuItem.Call(
|
||||
uintptr(menu),
|
||||
id,
|
||||
uintptr(flags),
|
||||
)
|
||||
return uint(ret)
|
||||
}
|
||||
|
||||
func (p PopupMenu) CheckRadio(startID, endID, selectedID int) bool {
|
||||
return Menu(p).CheckRadio(startID, endID, selectedID)
|
||||
}
|
||||
|
|
@ -115,10 +115,6 @@ func (d *AssetServer) processWebViewRequest(r webview.Request) {
|
|||
req.RemoteAddr = "192.0.2.1:1234"
|
||||
}
|
||||
|
||||
if req.RequestURI == "" && req.URL != nil {
|
||||
req.RequestURI = req.URL.String()
|
||||
}
|
||||
|
||||
if req.ContentLength == 0 {
|
||||
req.ContentLength, _ = strconv.ParseInt(req.Header.Get(HeaderContentLength), 10, 64)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,94 +0,0 @@
|
|||
//go:build linux && purego
|
||||
// +build linux,purego
|
||||
|
||||
package webview
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/ebitengine/purego"
|
||||
)
|
||||
|
||||
// NewRequest creates as new WebViewRequest based on a pointer to an `WebKitURISchemeRequest`
|
||||
//
|
||||
// Please make sure to call Release() when finished using the request.
|
||||
func NewRequest(webKitURISchemeRequest uintptr) Request {
|
||||
webkitReq := webKitURISchemeRequest
|
||||
req := &request{req: webkitReq}
|
||||
req.AddRef()
|
||||
return req
|
||||
}
|
||||
|
||||
var _ Request = &request{}
|
||||
|
||||
type request struct {
|
||||
req uintptr
|
||||
|
||||
header http.Header
|
||||
body io.ReadCloser
|
||||
rw *responseWriter
|
||||
}
|
||||
|
||||
func (r *request) AddRef() error {
|
||||
var objectRef func(uintptr)
|
||||
purego.RegisterLibFunc(&objectRef, gtk, "g_object_ref")
|
||||
objectRef(r.req)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *request) Release() error {
|
||||
var objectUnref func(uintptr)
|
||||
purego.RegisterLibFunc(&objectUnref, gtk, "g_object_unref")
|
||||
objectUnref(r.req)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *request) URL() (string, error) {
|
||||
var getUri func(uintptr) string
|
||||
purego.RegisterLibFunc(&getUri, webkit, "webkit_uri_scheme_request_get_uri")
|
||||
return getUri(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
|
||||
}
|
||||
|
||||
// WebKit2GTK has currently no support for request bodies.
|
||||
r.body = http.NoBody
|
||||
|
||||
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()
|
||||
r.Release()
|
||||
return err
|
||||
}
|
||||
|
|
@ -1,174 +0,0 @@
|
|||
//go:build linux && purego
|
||||
// +build linux,purego
|
||||
|
||||
package webview
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"github.com/ebitengine/purego"
|
||||
)
|
||||
|
||||
const (
|
||||
gtk3 = "libgtk-3.so"
|
||||
gtk4 = "libgtk-4.so"
|
||||
)
|
||||
|
||||
var (
|
||||
gtk uintptr
|
||||
webkit uintptr
|
||||
version int
|
||||
)
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
// gtk, err = purego.Dlopen(gtk4, purego.RTLD_NOW|purego.RTLD_GLOBAL)
|
||||
// if err == nil {
|
||||
// version = 4
|
||||
// return
|
||||
// }
|
||||
// log.Println("Failed to open GTK4: Falling back to GTK3")
|
||||
gtk, err = purego.Dlopen(gtk3, purego.RTLD_NOW|purego.RTLD_GLOBAL)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
version = 3
|
||||
|
||||
var webkit4 string = "libwebkit2gtk-4.1.so"
|
||||
webkit, err = purego.Dlopen(webkit4, purego.RTLD_NOW|purego.RTLD_GLOBAL)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
type responseWriter struct {
|
||||
req uintptr
|
||||
|
||||
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) {
|
||||
// TODO? Is this ever called? I don't think so!
|
||||
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
|
||||
|
||||
var newStream func(int, bool) uintptr
|
||||
purego.RegisterLibFunc(&newStream, gtk, "g_unix_input_stream_new")
|
||||
var unRef func(uintptr)
|
||||
purego.RegisterLibFunc(&unRef, gtk, "g_object_unref")
|
||||
stream := newStream(rFD, true)
|
||||
|
||||
/* var reqFinish func(uintptr, uintptr, uintptr, uintptr, int64) int
|
||||
purego.RegisterLibFunc(&reqFinish, webkit, "webkit_uri_scheme_request_finish")
|
||||
|
||||
header := rw.Header()
|
||||
defer unRef(stream)
|
||||
if err := reqFinish(rw.req, code, header, stream, contentLength); err != nil {
|
||||
rw.finishWithError(http.StatusInternalServerError, fmt.Errorf("unable to finish request: %s", err))
|
||||
}
|
||||
*/
|
||||
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() {
|
||||
if !rw.wroteHeader {
|
||||
rw.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
if rw.finished {
|
||||
return
|
||||
}
|
||||
rw.finished = true
|
||||
if rw.w != nil {
|
||||
rw.w.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (rw *responseWriter) finishWithError(code int, err error) {
|
||||
if rw.w != nil {
|
||||
rw.w.Close()
|
||||
rw.w = &nopCloser{io.Discard}
|
||||
}
|
||||
rw.wErr = err
|
||||
|
||||
var newLiteral func(uint32, string, int, string) uintptr // is this correct?
|
||||
purego.RegisterLibFunc(&newLiteral, gtk, "g_error_new_literal")
|
||||
var newQuark func(string) uintptr
|
||||
purego.RegisterLibFunc(&newQuark, gtk, "g_quark_from_string")
|
||||
var freeError func(uintptr)
|
||||
purego.RegisterLibFunc(&freeError, gtk, "g_error_free")
|
||||
var finishError func(uintptr, uintptr)
|
||||
purego.RegisterLibFunc(&finishError, webkit, "webkit_uri_scheme_request_finish_error")
|
||||
|
||||
msg := string(err.Error())
|
||||
//gquark := newQuark(msg)
|
||||
gerr := newLiteral(1, msg, code, msg)
|
||||
finishError(rw.req, gerr)
|
||||
freeError(gerr)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
//go:build linux && (webkit2_36 || webkit2_40) && purego
|
||||
|
||||
package webview
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/ebitengine/purego"
|
||||
)
|
||||
|
||||
func webkit_uri_scheme_request_get_http_method(req uintptr) string {
|
||||
var getMethod func(uintptr) string
|
||||
purego.RegisterLibFunc(&getMethod, gtk, "webkit_uri_scheme_request_get_http_method")
|
||||
return strings.ToUpper(getMethod(req))
|
||||
}
|
||||
|
||||
func webkit_uri_scheme_request_get_http_headers(req uintptr) http.Header {
|
||||
var getHeaders func(uintptr) uintptr
|
||||
purego.RegisterLibFunc(&getUri, webkit, "webkit_uri_scheme_request_get_http_headers")
|
||||
|
||||
hdrs := getHeaders(req)
|
||||
|
||||
var headersIterInit func(uintptr, uintptr) uintptr
|
||||
purego.RegisterLibFunc(&headersIterInit, gtk, "soup_message_headers_iter_init")
|
||||
|
||||
// TODO: How do we get a struct?
|
||||
/*
|
||||
typedef struct {
|
||||
SoupMessageHeaders *hdrs;
|
||||
int index_common;
|
||||
int index_uncommon;
|
||||
} SoupMessageHeadersIterReal;
|
||||
*/
|
||||
iter := make([]byte, 12)
|
||||
headersIterInit(&iter, hdrs)
|
||||
|
||||
var iterNext func(uintptr, *string, *string) int
|
||||
purego.RegisterLibFunc(&iterNext, gtk, "soup_message_headers_iter_next")
|
||||
|
||||
var name string
|
||||
var value string
|
||||
h := http.Header{}
|
||||
|
||||
for iterNext(&iter, &name, &value) != 0 {
|
||||
h.Add(name, value)
|
||||
}
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
func webkit_uri_scheme_request_finish(req uintptr, code int, header http.Header, stream uintptr, streamLength int64) error {
|
||||
|
||||
var newResponse func(uintptr, int64) string
|
||||
purego.RegisterLibFunc(&newResponse, webkit, "webkit_uri_scheme_response_new")
|
||||
var unRef func(uintptr)
|
||||
purego.RegisterLibFunc(&unRef, gtk, "g_object_unref")
|
||||
|
||||
resp := newResponse(stream, streamLength)
|
||||
defer unRef(resp)
|
||||
|
||||
var setStatus func(uintptr, int, string)
|
||||
purego.RegisterLibFunc(&unRef, webkit, "webkit_uri_scheme_response_set_status")
|
||||
|
||||
setStatus(resp, code, cReason)
|
||||
|
||||
var setContentType func(uintptr, string)
|
||||
purego.RegisterLibFunc(&unRef, webkit, "webkit_uri_scheme_response_set_content_type")
|
||||
|
||||
setContentType(resp, header.Get(HeaderContentType))
|
||||
|
||||
soup := gtk
|
||||
var soupHeadersNew func(int) uintptr
|
||||
purego.RegisterLibFunc(&unRef, soup, "soup_message_headers_new")
|
||||
var soupHeadersAppend func(uintptr, string, string)
|
||||
purego.RegisterLibFunc(&unRef, soup, "soup_message_headers_append")
|
||||
|
||||
hdrs := soupHeadersNew(SOUP_MESSAGE_HEADERS_RESPONSE)
|
||||
for name, values := range header {
|
||||
for _, value := range values {
|
||||
soupHeadersAppend(hdrs, name, value)
|
||||
}
|
||||
}
|
||||
|
||||
var setHttpHeaders func(uintptr, uintptr)
|
||||
purego.RegisterLibFunc(&unRef, webkit, "webkit_uri_scheme_response_set_http_headers")
|
||||
|
||||
setHttpHeaders(resp, hdrs)
|
||||
var finishWithResponse func(uintptr, uintptr)
|
||||
purego.RegisterLibFunc(&unRef, webkit, "webkit_uri_scheme_request_finish_with_response")
|
||||
finishWithResponse(req, resp)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
//go:build linux && webkit2_40 && purego
|
||||
|
||||
package webview
|
||||
|
||||
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...)
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
//go:build linux && !(webkit2_36 || webkit2_40) && purego
|
||||
|
||||
package webview
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/ebitengine/purego"
|
||||
)
|
||||
|
||||
const Webkit2MinMinorVersion = 0
|
||||
|
||||
func webkit_uri_scheme_request_get_http_method(_ uintptr) string {
|
||||
return http.MethodGet
|
||||
}
|
||||
|
||||
func webkit_uri_scheme_request_get_http_headers(_ uintptr) http.Header {
|
||||
return http.Header{}
|
||||
}
|
||||
|
||||
func webkit_uri_scheme_request_get_http_body(_ uintptr) io.ReadCloser {
|
||||
return http.NoBody
|
||||
}
|
||||
|
||||
func webkit_uri_scheme_request_finish(req uintptr, code int, header http.Header, stream uintptr, streamLength int64) error {
|
||||
if code != http.StatusOK {
|
||||
return fmt.Errorf("StatusCodes not supported: %d - %s", code, http.StatusText(code))
|
||||
}
|
||||
|
||||
var requestFinish func(uintptr, uintptr, int64, string)
|
||||
purego.RegisterLibFunc(&requestFinish, webkit, "webkit_uri_scheme_request_finish")
|
||||
requestFinish(req, stream, streamLength, header.Get(HeaderContentType))
|
||||
return nil
|
||||
}
|
||||
|
|
@ -209,7 +209,7 @@ func printBulletPoint(text string, args ...any) {
|
|||
fatal(err.Error())
|
||||
}
|
||||
t = strings.Trim(t, "\n\r")
|
||||
pterm.Printfln(t, args...)
|
||||
pterm.Printf(t, args...)
|
||||
}
|
||||
|
||||
func GenerateBindings(buildOptions *Options) error {
|
||||
|
|
@ -374,7 +374,7 @@ func execPostBuildHook(outputLogger *clilogger.CLILogger, options *Options, hook
|
|||
|
||||
}
|
||||
|
||||
func executeBuildHook(outputLogger *clilogger.CLILogger, options *Options, hookIdentifier string, argReplacements map[string]string, buildHook string, hookName string) error {
|
||||
func executeBuildHook(_ *clilogger.CLILogger, options *Options, hookIdentifier string, argReplacements map[string]string, buildHook string, hookName string) error {
|
||||
if !options.ProjectData.RunNonNativeBuildHooks {
|
||||
if hookIdentifier == "" {
|
||||
// That's the global hook
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
package options
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
)
|
||||
|
||||
// SystemTray contains options for the system tray
|
||||
type SystemTray struct {
|
||||
LightModeIcon *SystemTrayIcon
|
||||
DarkModeIcon *SystemTrayIcon
|
||||
Title string
|
||||
Tooltip string
|
||||
StartHidden bool
|
||||
Menu *menu.Menu
|
||||
OnLeftClick func()
|
||||
OnRightClick func()
|
||||
OnLeftDoubleClick func()
|
||||
OnRightDoubleClick func()
|
||||
OnMenuClose func()
|
||||
OnMenuOpen func()
|
||||
}
|
||||
|
||||
// SystemTrayIcon represents a system tray icon
|
||||
type SystemTrayIcon struct {
|
||||
Data []byte
|
||||
}
|
||||
|
|
@ -179,3 +179,8 @@ func WindowSetBackgroundColour(ctx context.Context, R, G, B, A uint8) {
|
|||
}
|
||||
appFrontend.WindowSetBackgroundColour(col)
|
||||
}
|
||||
|
||||
func WindowPrint(ctx context.Context) {
|
||||
appFrontend := getFrontend(ctx)
|
||||
appFrontend.WindowPrint()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue