diff --git a/v2/Taskfile.yaml b/v2/Taskfile.yaml index 32a32e0f..526dd097 100644 --- a/v2/Taskfile.yaml +++ b/v2/Taskfile.yaml @@ -4,6 +4,7 @@ version: "3" tasks: release: + summary: Release a new version of Task. Call with `task v2:release -- ` dir: tools/release cmds: - go run release.go {{.CLI_ARGS}} diff --git a/v2/cmd/wails/internal/dev/dev.go b/v2/cmd/wails/internal/dev/dev.go index 8b7f1903..80d7a6d8 100644 --- a/v2/cmd/wails/internal/dev/dev.go +++ b/v2/cmd/wails/internal/dev/dev.go @@ -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 { diff --git a/v2/cmd/wails/internal/dev/watcher.go b/v2/cmd/wails/internal/dev/watcher.go index 19caf0df..1406f0c1 100644 --- a/v2/cmd/wails/internal/dev/watcher.go +++ b/v2/cmd/wails/internal/dev/watcher.go @@ -38,7 +38,6 @@ func initialiseWatcher(cwd string) (*fsnotify.Watcher, error) { if err != nil { return nil, err } - println("watching: " + dir) } return watcher, nil } diff --git a/v2/cmd/wails/internal/version.txt b/v2/cmd/wails/internal/version.txt index 8c99f59f..7433fb30 100644 --- a/v2/cmd/wails/internal/version.txt +++ b/v2/cmd/wails/internal/version.txt @@ -1 +1 @@ -v2.5.1 \ No newline at end of file +v2.6.0 \ No newline at end of file diff --git a/v2/cmd/wails/wails b/v2/cmd/wails/wails new file mode 100644 index 00000000..75251b41 Binary files /dev/null and b/v2/cmd/wails/wails differ diff --git a/v2/internal/app/app_devtools.go b/v2/internal/app/app_devtools.go index e28a1e08..fc3b7090 100644 --- a/v2/internal/app/app_devtools.go +++ b/v2/internal/app/app_devtools.go @@ -1,7 +1,7 @@ -//go:build devtools - -package app - -func IsDevtoolsEnabled() bool { - return true -} +//go:build devtools + +package app + +func IsDevtoolsEnabled() bool { + return true +} diff --git a/v2/internal/app/app_devtools_not.go b/v2/internal/app/app_devtools_not.go index a2cfd4e5..2855d800 100644 --- a/v2/internal/app/app_devtools_not.go +++ b/v2/internal/app/app_devtools_not.go @@ -1,7 +1,7 @@ -//go:build !devtools - -package app - -func IsDevtoolsEnabled() bool { - return false -} +//go:build !devtools + +package app + +func IsDevtoolsEnabled() bool { + return false +} diff --git a/v2/internal/frontend/desktop/darwin/Application.h b/v2/internal/frontend/desktop/darwin/Application.h index 4239da93..8be3826d 100644 --- a/v2/internal/frontend/desktop/darwin/Application.h +++ b/v2/internal/frontend/desktop/darwin/Application.h @@ -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); diff --git a/v2/internal/frontend/desktop/darwin/Application.m b/v2/internal/frontend/desktop/darwin/Application.m index 2c08002d..082018f6 100644 --- a/v2/internal/frontend/desktop/darwin/Application.m +++ b/v2/internal/frontend/desktop/darwin/Application.m @@ -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]; + ) + } +} \ No newline at end of file diff --git a/v2/internal/frontend/desktop/darwin/frontend.go b/v2/internal/frontend/desktop/darwin/frontend.go index c0dd2702..bfe470b4 100644 --- a/v2/internal/frontend/desktop/darwin/frontend.go +++ b/v2/internal/frontend/desktop/darwin/frontend.go @@ -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"` diff --git a/v2/internal/frontend/desktop/darwin/window.go b/v2/internal/frontend/desktop/darwin/window.go index c4fb9c0f..2586b1b4 100644 --- a/v2/internal/frontend/desktop/darwin/window.go +++ b/v2/internal/frontend/desktop/darwin/window.go @@ -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) +} diff --git a/v2/internal/frontend/desktop/linux/frontend.go b/v2/internal/frontend/desktop/linux/frontend.go index 654edae1..7a25df4a 100644 --- a/v2/internal/frontend/desktop/linux/frontend.go +++ b/v2/internal/frontend/desktop/linux/frontend.go @@ -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"` diff --git a/v2/internal/frontend/desktop/linux/window.c b/v2/internal/frontend/desktop/linux/window.c index 82ab3b85..a70a3be8 100644 --- a/v2/internal/frontend/desktop/linux/window.c +++ b/v2/internal/frontend/desktop/linux/window.c @@ -4,6 +4,7 @@ #include #include #include +#include #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); } diff --git a/v2/internal/frontend/desktop/linux/window.go b/v2/internal/frontend/desktop/linux/window.go index d4329513..6d9b256f 100644 --- a/v2/internal/frontend/desktop/linux/window.go +++ b/v2/internal/frontend/desktop/linux/window.go @@ -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)) diff --git a/v2/internal/frontend/desktop/linux/window.h b/v2/internal/frontend/desktop/linux/window.h index d600b698..eabcdd1e 100644 --- a/v2/internal/frontend/desktop/linux/window.h +++ b/v2/internal/frontend/desktop/linux/window.h @@ -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 diff --git a/v2/internal/frontend/desktop/windows/frontend.go b/v2/internal/frontend/desktop/windows/frontend.go index 76cecbc9..dabd1e2c 100644 --- a/v2/internal/frontend/desktop/windows/frontend.go +++ b/v2/internal/frontend/desktop/windows/frontend.go @@ -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 diff --git a/v2/internal/frontend/frontend.go b/v2/internal/frontend/frontend.go index 63807da6..27eb4a2e 100644 --- a/v2/internal/frontend/frontend.go +++ b/v2/internal/frontend/frontend.go @@ -121,6 +121,7 @@ type Frontend interface { WindowIsNormal() bool WindowIsFullscreen() bool WindowClose() + WindowPrint() //Screen ScreenGetAll() ([]Screen, error) diff --git a/v2/internal/platform/win32/menu.go b/v2/internal/platform/win32/menu.go new file mode 100644 index 00000000..f0588641 --- /dev/null +++ b/v2/internal/platform/win32/menu.go @@ -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) +} diff --git a/v2/pkg/assetserver/assetserver_webview.go b/v2/pkg/assetserver/assetserver_webview.go index fe65acd3..7fad1b01 100644 --- a/v2/pkg/assetserver/assetserver_webview.go +++ b/v2/pkg/assetserver/assetserver_webview.go @@ -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 { diff --git a/v2/pkg/assetserver/webview/request_linux_purego.go b/v2/pkg/assetserver/webview/request_linux_purego.go deleted file mode 100644 index bf724a55..00000000 --- a/v2/pkg/assetserver/webview/request_linux_purego.go +++ /dev/null @@ -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 -} diff --git a/v2/pkg/assetserver/webview/responsewriter_linux_purego.go b/v2/pkg/assetserver/webview/responsewriter_linux_purego.go deleted file mode 100644 index c62f54a5..00000000 --- a/v2/pkg/assetserver/webview/responsewriter_linux_purego.go +++ /dev/null @@ -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 -} diff --git a/v2/pkg/assetserver/webview/webkit2_36+_purego.go b/v2/pkg/assetserver/webview/webkit2_36+_purego.go deleted file mode 100644 index 2386868c..00000000 --- a/v2/pkg/assetserver/webview/webkit2_36+_purego.go +++ /dev/null @@ -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 -} diff --git a/v2/pkg/assetserver/webview/webkit2_40+_purego.go b/v2/pkg/assetserver/webview/webkit2_40+_purego.go deleted file mode 100644 index 1088be25..00000000 --- a/v2/pkg/assetserver/webview/webkit2_40+_purego.go +++ /dev/null @@ -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...) -} diff --git a/v2/pkg/assetserver/webview/webkit2_legacy_purego.go b/v2/pkg/assetserver/webview/webkit2_legacy_purego.go deleted file mode 100644 index 2e88864c..00000000 --- a/v2/pkg/assetserver/webview/webkit2_legacy_purego.go +++ /dev/null @@ -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 -} diff --git a/v2/pkg/commands/build/build.go b/v2/pkg/commands/build/build.go index 774e97c2..65d55aa9 100644 --- a/v2/pkg/commands/build/build.go +++ b/v2/pkg/commands/build/build.go @@ -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 diff --git a/v2/pkg/options/systemtray.go b/v2/pkg/options/systemtray.go deleted file mode 100644 index 117abb4d..00000000 --- a/v2/pkg/options/systemtray.go +++ /dev/null @@ -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 -} diff --git a/v2/pkg/runtime/window.go b/v2/pkg/runtime/window.go index ca28e9d3..62345e2e 100644 --- a/v2/pkg/runtime/window.go +++ b/v2/pkg/runtime/window.go @@ -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() +}