From f73506c4962599e99625f5cc588f732ac5d7df16 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Fri, 11 Sep 2020 11:45:58 +1000 Subject: [PATCH] Skel code in place --- lib/renderer/webview/memory.go | 27 ++ lib/renderer/webview/webview.go | 73 +++ lib/renderer/webview/webview_darwin.go | 354 +------------- lib/renderer/webview/webview_darwin.h | 640 +------------------------ 4 files changed, 124 insertions(+), 970 deletions(-) create mode 100644 lib/renderer/webview/memory.go create mode 100644 lib/renderer/webview/webview.go diff --git a/lib/renderer/webview/memory.go b/lib/renderer/webview/memory.go new file mode 100644 index 00000000..1ebc8525 --- /dev/null +++ b/lib/renderer/webview/memory.go @@ -0,0 +1,27 @@ +package webview + +/* +#include +*/ +import "C" + +import "unsafe" + +// This is our allocated C Memory +var memory []unsafe.Pointer + +func saveMemoryReference(mem unsafe.Pointer) { + memory = append(memory, mem) +} + +func freeMemory() { + for _, mem := range memory { + C.free(mem) + } +} + +func string2CString(str string) *C.char { + result := C.CString(str) + saveMemoryReference(unsafe.Pointer(result)) + return result +} diff --git a/lib/renderer/webview/webview.go b/lib/renderer/webview/webview.go new file mode 100644 index 00000000..eacf8b9c --- /dev/null +++ b/lib/renderer/webview/webview.go @@ -0,0 +1,73 @@ +package webview + +import "C" + +// DialogType is an enumeration of all supported system dialog types +type DialogType int + +const ( + // DialogTypeOpen is a system file open dialog + DialogTypeOpen DialogType = iota + // DialogTypeSave is a system file save dialog + DialogTypeSave + // DialogTypeAlert is a system alert dialog (message box) + DialogTypeAlert +) + +// WebView is our webview interface +type WebView interface { + // Run() starts the main UI loop until the user closes the webview window or + // Terminate() is called. + Run() + // Loop() runs a single iteration of the main UI. + Loop(blocking bool) bool + // SetTitle() changes window title. This method must be called from the main + // thread only. See Dispatch() for more details. + SetTitle(title string) + // SetFullscreen() controls window full-screen mode. This method must be + // called from the main thread only. See Dispatch() for more details. + SetFullscreen(fullscreen bool) + // SetColor() changes window background color. This method must be called from + // the main thread only. See Dispatch() for more details. + SetColor(r, g, b, a uint8) + // Eval() evaluates an arbitrary JS code inside the webview. This method must + // be called from the main thread only. See Dispatch() for more details. + Eval(js string) error + // InjectJS() injects an arbitrary block of CSS code using the JS API. This + // method must be called from the main thread only. See Dispatch() for more + // details. + InjectCSS(css string) + // Dialog() opens a system dialog of the given type and title. String + // argument can be provided for certain dialogs, such as alert boxes. For + // alert boxes argument is a message inside the dialog box. + Dialog(dlgType DialogType, flags int, title string, arg string, filter string) string + // Terminate() breaks the main UI loop. This method must be called from the main thread + // only. See Dispatch() for more details. + Terminate() + // Dispatch() schedules some arbitrary function to be executed on the main UI + // thread. This may be helpful if you want to run some JavaScript from + // background threads/goroutines, or to terminate the app. + Dispatch(func()) + // Exit() closes the window and cleans up the resources. Use Terminate() to + // forcefully break out of the main UI loop. + Exit() +} + +type ExternalInvokeCallbackFunc func(w WebView, data string) + +type Settings struct { + // WebView main window title + Title string + // URL to open in a webview + URL string + // Window width in pixels + Width int + // Window height in pixels + Height int + // Allows/disallows window resizing + Resizable bool + // Enable debugging tools (Linux/BSD/MacOS, on Windows use Firebug) + Debug bool + // A callback that is executed when JavaScript calls "window.external.invoke()" + ExternalInvokeCallback ExternalInvokeCallbackFunc +} diff --git a/lib/renderer/webview/webview_darwin.go b/lib/renderer/webview/webview_darwin.go index c2b87715..f0158705 100755 --- a/lib/renderer/webview/webview_darwin.go +++ b/lib/renderer/webview/webview_darwin.go @@ -1,211 +1,11 @@ -// Package webview implements Go bindings to https://github.com/zserge/webview C library. -// It is a modified version of webview.go from that repository -// Bindings closely repeat the C APIs and include both, a simplified -// single-function API to just open a full-screen webview window, and a more -// advanced and featureful set of APIs, including Go-to-JavaScript bindings. -// -// The library uses gtk-webkit, Cocoa/Webkit and MSHTML (IE8..11) as a browser -// engine and supports Linux, MacOS and Windows 7..10 respectively. -// package webview /* - -#cgo darwin CFLAGS: -x objective-c -#cgo darwin LDFLAGS: -framework Cocoa -framework WebKit - -#include -#include -#define WEBVIEW_STATIC -#define WEBVIEW_IMPLEMENTATION - #include "webview_darwin.h" - -extern void _webviewExternalInvokeCallback(void *, void *); - -static inline void CgoWebViewFree(void *w) { - free((void *)((struct webview *)w)->title); - free((void *)((struct webview *)w)->url); - free(w); -} - -static inline void *CgoWebViewCreate(int width, int height, char *title, char *url, int resizable, int debug) { - struct webview *w = (struct webview *) calloc(1, sizeof(*w)); - w->width = width; - w->height = height; - w->title = title; - w->url = url; - w->resizable = resizable; - w->debug = debug; - w->external_invoke_cb = (webview_external_invoke_cb_t) _webviewExternalInvokeCallback; - if (webview_init(w) != 0) { - CgoWebViewFree(w); - return NULL; - } - return (void *)w; -} - -static inline int CgoWebViewLoop(void *w, int blocking) { - return webview_loop((struct webview *)w, blocking); -} - -static inline void CgoWebViewTerminate(void *w) { - webview_terminate((struct webview *)w); -} - -static inline void CgoWebViewExit(void *w) { - webview_exit((struct webview *)w); -} - -static inline void CgoWebViewSetTitle(void *w, char *title) { - webview_set_title((struct webview *)w, title); -} - -static inline void CgoWebViewSetFullscreen(void *w, int fullscreen) { - webview_set_fullscreen((struct webview *)w, fullscreen); -} - -static inline void CgoWebViewSetColor(void *w, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - webview_set_color((struct webview *)w, r, g, b, a); -} - -static inline void CgoDialog(void *w, int dlgtype, int flags, -char *title, char *arg, char *res, size_t ressz, char *filter) { - webview_dialog(w, dlgtype, flags, - (const char*)title, (const char*) arg, res, ressz, filter); -} - -static inline int CgoWebViewEval(void *w, char *js) { - return webview_eval((struct webview *)w, js); -} - -static inline void CgoWebViewInjectCSS(void *w, char *css) { - webview_inject_css((struct webview *)w, css); -} - -extern void _webviewDispatchGoCallback(void *); -static inline void _webview_dispatch_cb(struct webview *w, void *arg) { - _webviewDispatchGoCallback(arg); -} -static inline void CgoWebViewDispatch(void *w, uintptr_t arg) { - webview_dispatch((struct webview *)w, _webview_dispatch_cb, (void *)arg); -} */ import "C" -import ( - "errors" - "runtime" - "sync" - "unsafe" -) -func init() { - // Ensure that main.main is called from the main thread - runtime.LockOSThread() -} - -// Open is a simplified API to open a single native window with a full-size webview in -// it. It can be helpful if you want to communicate with the core app using XHR -// or WebSockets (as opposed to using JavaScript bindings). -// -// Window appearance can be customized using title, width, height and resizable parameters. -// URL must be provided and can user either a http or https protocol, or be a -// local file:// URL. On some platforms "data:" URLs are also supported -// (Linux/MacOS). -func Open(title, url string, w, h int, resizable bool) error { - titleStr := C.CString(title) - defer C.free(unsafe.Pointer(titleStr)) - urlStr := C.CString(url) - defer C.free(unsafe.Pointer(urlStr)) - resize := C.int(0) - if resizable { - resize = C.int(1) - } - - r := C.webview(titleStr, urlStr, C.int(w), C.int(h), resize) - if r != 0 { - return errors.New("failed to create webview") - } - return nil -} - -// ExternalInvokeCallbackFunc is a function type that is called every time -// "window.external.invoke()" is called from JavaScript. Data is the only -// obligatory string parameter passed into the "invoke(data)" function from -// JavaScript. To pass more complex data serialized JSON or base64 encoded -// string can be used. -type ExternalInvokeCallbackFunc func(w WebView, data string) - -// Settings is a set of parameters to customize the initial WebView appearance -// and behavior. It is passed into the webview.New() constructor. -type Settings struct { - // WebView main window title - Title string - // URL to open in a webview - URL string - // Window width in pixels - Width int - // Window height in pixels - Height int - // Allows/disallows window resizing - Resizable bool - // Enable debugging tools (Linux/BSD/MacOS, on Windows use Firebug) - Debug bool - // A callback that is executed when JavaScript calls "window.external.invoke()" - ExternalInvokeCallback ExternalInvokeCallbackFunc -} - -// WebView is an interface that wraps the basic methods for controlling the UI -// loop, handling multithreading and providing JavaScript bindings. -type WebView interface { - // Run() starts the main UI loop until the user closes the webview window or - // Terminate() is called. - Run() - // Loop() runs a single iteration of the main UI. - Loop(blocking bool) bool - // SetTitle() changes window title. This method must be called from the main - // thread only. See Dispatch() for more details. - SetTitle(title string) - // SetFullscreen() controls window full-screen mode. This method must be - // called from the main thread only. See Dispatch() for more details. - SetFullscreen(fullscreen bool) - // SetColor() changes window background color. This method must be called from - // the main thread only. See Dispatch() for more details. - SetColor(r, g, b, a uint8) - // Eval() evaluates an arbitrary JS code inside the webview. This method must - // be called from the main thread only. See Dispatch() for more details. - Eval(js string) error - // InjectJS() injects an arbitrary block of CSS code using the JS API. This - // method must be called from the main thread only. See Dispatch() for more - // details. - InjectCSS(css string) - // Dialog() opens a system dialog of the given type and title. String - // argument can be provided for certain dialogs, such as alert boxes. For - // alert boxes argument is a message inside the dialog box. - Dialog(dlgType DialogType, flags int, title string, arg string, filter string) string - // Terminate() breaks the main UI loop. This method must be called from the main thread - // only. See Dispatch() for more details. - Terminate() - // Dispatch() schedules some arbitrary function to be executed on the main UI - // thread. This may be helpful if you want to run some JavaScript from - // background threads/goroutines, or to terminate the app. - Dispatch(func()) - // Exit() closes the window and cleans up the resources. Use Terminate() to - // forcefully break out of the main UI loop. - Exit() -} - -// DialogType is an enumeration of all supported system dialog types -type DialogType int - -const ( - // DialogTypeOpen is a system file open dialog - DialogTypeOpen DialogType = iota - // DialogTypeSave is a system file save dialog - DialogTypeSave - // DialogTypeAlert is a system alert dialog (message box) - DialogTypeAlert -) +import "unsafe" const ( // DialogFlagFile is a normal file picker dialog @@ -220,150 +20,38 @@ const ( DialogFlagError = C.WEBVIEW_DIALOG_FLAG_ERROR ) -var ( - m sync.Mutex - index uintptr - fns = map[uintptr]func(){} - cbs = map[WebView]ExternalInvokeCallbackFunc{} -) - -type webview struct { - w unsafe.Pointer +type MacWebView struct { + app unsafe.Pointer } -var _ WebView = &webview{} - -func boolToInt(b bool) int { - if b { - return 1 - } - return 0 -} - -// NewWebview creates and opens a new webview window using the given settings. The -// returned object implements the WebView interface. This function returns nil -// if a window can not be created. func NewWebview(settings Settings) WebView { - if settings.Width == 0 { - settings.Width = 640 - } - if settings.Height == 0 { - settings.Height = 480 - } - if settings.Title == "" { - settings.Title = "WebView" - } - w := &webview{} - w.w = C.CgoWebViewCreate(C.int(settings.Width), C.int(settings.Height), - C.CString(settings.Title), C.CString(settings.URL), - C.int(boolToInt(settings.Resizable)), C.int(boolToInt(settings.Debug))) - m.Lock() - if settings.ExternalInvokeCallback != nil { - cbs[w] = settings.ExternalInvokeCallback - } else { - cbs[w] = func(w WebView, data string) {} - } - m.Unlock() - return w + return &MacWebView{} } -func (w *webview) Loop(blocking bool) bool { - block := C.int(0) - if blocking { - block = 1 - } - return C.CgoWebViewLoop(w.w, block) == 0 +func (w *MacWebView) Dialog(dlgType DialogType, flags int, title string, arg string, filter string) string { + // TBD + return "" } -func (w *webview) Run() { - for w.Loop(true) { - } +func (w *MacWebView) Dispatch(func()) { + // TBD } -func (w *webview) Exit() { - C.CgoWebViewExit(w.w) -} - -func (w *webview) Dispatch(f func()) { - m.Lock() - for ; fns[index] != nil; index++ { - } - fns[index] = f - m.Unlock() - C.CgoWebViewDispatch(w.w, C.uintptr_t(index)) -} - -func (w *webview) SetTitle(title string) { - p := C.CString(title) - defer C.free(unsafe.Pointer(p)) - C.CgoWebViewSetTitle(w.w, p) -} - -func (w *webview) SetColor(r, g, b, a uint8) { - C.CgoWebViewSetColor(w.w, C.uint8_t(r), C.uint8_t(g), C.uint8_t(b), C.uint8_t(a)) -} - -func (w *webview) SetFullscreen(fullscreen bool) { - C.CgoWebViewSetFullscreen(w.w, C.int(boolToInt(fullscreen))) -} - -func (w *webview) Dialog(dlgType DialogType, flags int, title string, arg string, filter string) string { - const maxPath = 4096 - titlePtr := C.CString(title) - defer C.free(unsafe.Pointer(titlePtr)) - argPtr := C.CString(arg) - defer C.free(unsafe.Pointer(argPtr)) - resultPtr := (*C.char)(C.calloc((C.size_t)(unsafe.Sizeof((*C.char)(nil))), (C.size_t)(maxPath))) - defer C.free(unsafe.Pointer(resultPtr)) - filterPtr := C.CString(filter) - defer C.free(unsafe.Pointer(filterPtr)) - C.CgoDialog(w.w, C.int(dlgType), C.int(flags), titlePtr, - argPtr, resultPtr, C.size_t(maxPath), filterPtr) - return C.GoString(resultPtr) -} - -func (w *webview) Eval(js string) error { - p := C.CString(js) - defer C.free(unsafe.Pointer(p)) - switch C.CgoWebViewEval(w.w, p) { - case -1: - return errors.New("evaluation failed") - } +func (w *MacWebView) Eval(js string) error { + // TBD return nil } -func (w *webview) InjectCSS(css string) { - p := C.CString(css) - defer C.free(unsafe.Pointer(p)) - C.CgoWebViewInjectCSS(w.w, p) +func (w *MacWebView) Exit() { + // TBD } -func (w *webview) Terminate() { - C.CgoWebViewTerminate(w.w) -} - -//export _webviewDispatchGoCallback -func _webviewDispatchGoCallback(index unsafe.Pointer) { - var f func() - m.Lock() - f = fns[uintptr(index)] - delete(fns, uintptr(index)) - m.Unlock() - f() -} - -//export _webviewExternalInvokeCallback -func _webviewExternalInvokeCallback(w unsafe.Pointer, data unsafe.Pointer) { - m.Lock() - var ( - cb ExternalInvokeCallbackFunc - wv WebView - ) - for wv, cb = range cbs { - if wv.(*webview).w == w { - break - } - } - m.Unlock() - cb(wv, C.GoString((*C.char)(data))) +func (w *MacWebView) Run() {} +func (w *MacWebView) Loop(blocking bool) bool { + return true } +func (w *MacWebView) SetTitle(title string) {} +func (w *MacWebView) SetFullscreen(fullscreen bool) {} +func (w *MacWebView) SetColor(r, g, b, a uint8) {} +func (w *MacWebView) InjectCSS(css string) {} +func (w *MacWebView) Terminate() {} diff --git a/lib/renderer/webview/webview_darwin.h b/lib/renderer/webview/webview_darwin.h index bc2fa231..8c9be364 100644 --- a/lib/renderer/webview/webview_darwin.h +++ b/lib/renderer/webview/webview_darwin.h @@ -1,82 +1,6 @@ -/* - * MIT License - * - * Copyright (c) 2017 Serge Zaitsev - * - * 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. - */ -#ifndef WEBVIEW_H -#define WEBVIEW_H -#ifdef __cplusplus -extern "C" -{ -#endif - -#ifdef WEBVIEW_STATIC -#define WEBVIEW_API static -#else -#define WEBVIEW_API extern -#endif - -#include -#include -#include - -#import -#import -#import - -struct webview_priv -{ - NSAutoreleasePool *pool; - NSWindow *window; - WebView *webview; - id delegate; - int should_exit; -}; - - struct webview; - - typedef void (*webview_external_invoke_cb_t)(struct webview *w, - const char *arg); - - struct webview - { - const char *url; - const char *title; - int width; - int height; - int resizable; - int transparentTitlebar; - int debug; - webview_external_invoke_cb_t external_invoke_cb; - struct webview_priv priv; - void *userdata; - }; - - enum webview_dialog_type - { - WEBVIEW_DIALOG_TYPE_OPEN = 0, - WEBVIEW_DIALOG_TYPE_SAVE = 1, - WEBVIEW_DIALOG_TYPE_ALERT = 2 - }; +#ifndef WEBVIEW_DARWIN +#define WEBVIEW_DARWIN #define WEBVIEW_DIALOG_FLAG_FILE (0 << 0) #define WEBVIEW_DIALOG_FLAG_DIRECTORY (1 << 0) @@ -86,562 +10,4 @@ struct webview_priv #define WEBVIEW_DIALOG_FLAG_ERROR (3 << 1) #define WEBVIEW_DIALOG_FLAG_ALERT_MASK (3 << 1) -typedef void (*webview_dispatch_fn)(struct webview *w, void *arg); - -struct webview_dispatch_arg -{ - webview_dispatch_fn fn; - struct webview *w; - void *arg; -}; - -#define DEFAULT_URL \ -"data:text/" \ -"html,%3C%21DOCTYPE%20html%3E%0A%3Chtml%20lang=%22en%22%3E%0A%3Chead%3E%" \ -"3Cmeta%20charset=%22utf-8%22%3E%3Cmeta%20http-equiv=%22IE=edge%22%" \ -"20content=%22IE=edge%22%3E%3C%2Fhead%3E%0A%3Cbody%3E%3Cdiv%20id=%22app%22%" \ -"3E%3C%2Fdiv%3E%3Cscript%20type=%22text%2Fjavascript%22%3E%3C%2Fscript%3E%" \ -"3C%2Fbody%3E%0A%3C%2Fhtml%3E" - -#define CSS_INJECT_FUNCTION \ -"(function(e){var " \ -"t=document.createElement('style'),d=document.head||document." \ -"getElementsByTagName('head')[0];t.setAttribute('type','text/" \ -"css'),t.styleSheet?t.styleSheet.cssText=e:t.appendChild(document." \ -"createTextNode(e)),d.appendChild(t)})" - -static const char *webview_check_url(const char *url) -{ - if (url == NULL || strlen(url) == 0) - { - return DEFAULT_URL; - } - return url; -} - -WEBVIEW_API int webview(const char *title, const char *url, int width, - int height, int resizable); - -WEBVIEW_API int webview_init(struct webview *w); -WEBVIEW_API int webview_loop(struct webview *w, int blocking); -WEBVIEW_API int webview_eval(struct webview *w, const char *js); -WEBVIEW_API int webview_inject_css(struct webview *w, const char *css); -WEBVIEW_API void webview_set_title(struct webview *w, const char *title); -WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen); -WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g, - uint8_t b, uint8_t a); -WEBVIEW_API void webview_dialog(struct webview *w, - enum webview_dialog_type dlgtype, int flags, - const char *title, const char *arg, - char *result, size_t resultsz, char *filter); -WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn, - void *arg); -WEBVIEW_API void webview_terminate(struct webview *w); -WEBVIEW_API void webview_exit(struct webview *w); -WEBVIEW_API void webview_debug(const char *format, ...); -WEBVIEW_API void webview_print_log(const char *s); - -WEBVIEW_API int webview(const char *title, const char *url, int width, - int height, int resizable) -{ - struct webview webview; - memset(&webview, 0, sizeof(webview)); - webview.title = title; - webview.url = url; - webview.width = width; - webview.height = height; - webview.resizable = resizable; - int r = webview_init(&webview); - if (r != 0) - { - return r; - } - while (webview_loop(&webview, 1) == 0) - { - } - webview_exit(&webview); - return 0; -} - -WEBVIEW_API void webview_debug(const char *format, ...) -{ - char buf[4096]; - va_list ap; - va_start(ap, format); - vsnprintf(buf, sizeof(buf), format, ap); - webview_print_log(buf); - va_end(ap); -} - -static int webview_js_encode(const char *s, char *esc, size_t n) -{ - int r = 1; /* At least one byte for trailing zero */ - for (; *s; s++) - { - const unsigned char c = *s; - if (c >= 0x20 && c < 0x80 && strchr("<>\\'\"", c) == NULL) - { - if (n > 0) - { - *esc++ = c; - n--; - } - r++; - } - else - { - if (n > 0) - { - snprintf(esc, n, "\\x%02x", (int)c); - esc += 4; - n -= 4; - } - r += 4; - } - } - return r; -} - -WEBVIEW_API int webview_inject_css(struct webview *w, const char *css) -{ - int n = webview_js_encode(css, NULL, 0); - char *esc = (char *)calloc(1, sizeof(CSS_INJECT_FUNCTION) + n + 4); - if (esc == NULL) - { - return -1; - } - char *js = (char *)calloc(1, n); - webview_js_encode(css, js, n); - snprintf(esc, sizeof(CSS_INJECT_FUNCTION) + n + 4, "%s(\"%s\")", - CSS_INJECT_FUNCTION, js); - int r = webview_eval(w, esc); - free(js); - free(esc); - return r; -} - -#if (!defined MAC_OS_X_VERSION_10_12) || \ - MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12 -#define NSAlertStyleWarning NSWarningAlertStyle -#define NSAlertStyleCritical NSCriticalAlertStyle -#define NSWindowStyleMaskResizable NSResizableWindowMask -#define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask -#define NSWindowStyleMaskTitled NSTitledWindowMask -#define NSWindowStyleMaskClosable NSClosableWindowMask -#define NSWindowStyleMaskFullScreen NSFullScreenWindowMask -#define NSEventMaskAny NSAnyEventMask -#define NSEventModifierFlagCommand NSCommandKeyMask -#define NSEventModifierFlagOption NSAlternateKeyMask -#define NSAlertStyleInformational NSInformationalAlertStyle -#endif /* MAC_OS_X_VERSION_10_12 */ -#if (!defined MAC_OS_X_VERSION_10_13) || \ - MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13 -#define NSModalResponseOK NSFileHandlingPanelOKButton -#endif /* MAC_OS_X_VERSION_10_12, MAC_OS_X_VERSION_10_13 */ -static void webview_window_will_close(id self, SEL cmd, id notification) -{ - struct webview *w = - (struct webview *)objc_getAssociatedObject(self, "webview"); - webview_terminate(w); -} - -static BOOL webview_is_selector_excluded_from_web_script(id self, SEL cmd, - SEL selector) -{ - return selector != @selector(invoke:); -} - -static NSString *webview_webscript_name_for_selector(id self, SEL cmd, - SEL selector) -{ - return selector == @selector(invoke:) ? @"invoke" : nil; -} - -static void webview_did_clear_window_object(id self, SEL cmd, id webview, - id script, id frame) -{ - [script setValue:self forKey:@"external"]; -} - -static void webview_run_input_open_panel(id self, SEL cmd, id webview, - id listener, BOOL allowMultiple) -{ - char filename[256] = ""; - struct webview *w = - (struct webview *)objc_getAssociatedObject(self, "webview"); - - webview_dialog(w, WEBVIEW_DIALOG_TYPE_OPEN, WEBVIEW_DIALOG_FLAG_FILE, "", "", - filename, 255, ""); - filename[255] = '\0'; - if (strlen(filename) > 0) - { - [listener chooseFilename:[NSString stringWithUTF8String:filename]]; - } - else - { - [listener cancel]; - } -} - -static void webview_external_invoke(id self, SEL cmd, id arg) -{ - struct webview *w = - (struct webview *)objc_getAssociatedObject(self, "webview"); - if (w == NULL || w->external_invoke_cb == NULL) - { - return; - } - if ([arg isKindOfClass:[NSString class]] == NO) - { - return; - } - w->external_invoke_cb(w, [(NSString *)(arg) UTF8String]); -} - -WEBVIEW_API int webview_init(struct webview *w) -{ - w->priv.pool = [[NSAutoreleasePool alloc] init]; - [NSApplication sharedApplication]; - - Class webViewDelegateClass = - objc_allocateClassPair([NSObject class], "WebViewDelegate", 0); - class_addMethod(webViewDelegateClass, sel_registerName("windowWillClose:"), - (IMP)webview_window_will_close, "v@:@"); - class_addMethod(object_getClass(webViewDelegateClass), - sel_registerName("isSelectorExcludedFromWebScript:"), - (IMP)webview_is_selector_excluded_from_web_script, "c@::"); - class_addMethod(object_getClass(webViewDelegateClass), - sel_registerName("webScriptNameForSelector:"), - (IMP)webview_webscript_name_for_selector, "c@::"); - class_addMethod(webViewDelegateClass, - sel_registerName("webView:didClearWindowObject:forFrame:"), - (IMP)webview_did_clear_window_object, "v@:@@@"); - class_addMethod( - webViewDelegateClass, - sel_registerName("webView:runOpenPanelForFileButtonWithResultListener:" - "allowMultipleFiles:"), - (IMP)webview_run_input_open_panel, "v@:@@c"); - class_addMethod(webViewDelegateClass, sel_registerName("invoke:"), - (IMP)webview_external_invoke, "v@:@"); - objc_registerClassPair(webViewDelegateClass); - - w->priv.delegate = [[webViewDelegateClass alloc] init]; - objc_setAssociatedObject(w->priv.delegate, "webview", (id)(w), - OBJC_ASSOCIATION_ASSIGN); - - NSRect r = NSMakeRect(0, 0, w->width, w->height); - NSUInteger style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | - NSWindowStyleMaskMiniaturizable; - if (w->resizable) - { - style = style | NSWindowStyleMaskResizable; - // style = style | NSTexturedBackgroundWindowMask; - // style = style | NSUnifiedTitleAndToolbarWindowMask; - } - - // Transparent title bar - // if (w->transparentTitlebar) { - // style = style | NSFullSizeContentViewWindowMask | NSUnifiedTitleAndToolbarWindowMask | NSTexturedBackgroundWindowMask; - // } - - w->priv.window = [[NSWindow alloc] initWithContentRect:r - styleMask:style - backing:NSBackingStoreBuffered - defer:NO]; - [w->priv.window autorelease]; - - // Title - NSString *nsTitle = [NSString stringWithUTF8String:w->title]; - [w->priv.window setTitle:nsTitle]; - - [w->priv.window setDelegate:w->priv.delegate]; - [w->priv.window center]; - - // NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"wat"]; - // toolbar.showsBaselineSeparator = NO; - // [w->priv.window setToolbar:toolbar]; - - // if (w->transparentTitlebar) { - - // // Configure window look with hidden toolbar - // [w->priv.window setTitlebarAppearsTransparent:YES]; - // [w->priv.window setTitleVisibility:NSWindowTitleHidden]; - // // w->priv.window.isMovableByWindowBackground = true; - // } - - [[NSUserDefaults standardUserDefaults] setBool:!!w->debug - forKey:@"WebKitDeveloperExtras"]; - [[NSUserDefaults standardUserDefaults] synchronize]; - w->priv.webview = - [[WebView alloc] initWithFrame:r - frameName:@"WebView" - groupName:nil]; - NSURL *nsURL = [NSURL - URLWithString:[NSString stringWithUTF8String:webview_check_url(w->url)]]; - [[w->priv.webview mainFrame] loadRequest:[NSURLRequest requestWithURL:nsURL]]; - - [w->priv.webview setAutoresizesSubviews:YES]; - [w->priv.webview - setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - w->priv.webview.frameLoadDelegate = w->priv.delegate; - w->priv.webview.UIDelegate = w->priv.delegate; - [[w->priv.window contentView] addSubview:w->priv.webview]; - [w->priv.window orderFrontRegardless]; - - // Disable scrolling - make this configurable - // [[[w->priv.webview mainFrame] frameView] setAllowsScrolling:NO]; - - // ----> Enables WebGL but won't pass the app store guidelines - // - // WebPreferences *p = [w->priv.webview preferences]; - // if ([p respondsToSelector:@selector(setWebGLEnabled:)]) { - // [p setWebGLEnabled:YES]; - // } - - [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; - [NSApp finishLaunching]; - [NSApp activateIgnoringOtherApps:YES]; - - NSMenu *menubar = [[[NSMenu alloc] initWithTitle:@""] autorelease]; - - NSMenuItem *appMenuItem = - [[[NSMenuItem alloc] initWithTitle:@"wails app" action:NULL keyEquivalent:@""] - autorelease]; - NSMenu *appMenu = [[[NSMenu alloc] initWithTitle:@"wails app"] autorelease]; - [appMenuItem setSubmenu:appMenu]; - [menubar addItem:appMenuItem]; - - NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:@"Hide" - action:@selector(hide:) - keyEquivalent:@"h"] autorelease]; - [appMenu addItem:item]; - item = [[[NSMenuItem alloc] initWithTitle:@"Hide Others" - action:@selector(hideOtherApplications:) - keyEquivalent:@"h"] autorelease]; - [item setKeyEquivalentModifierMask:(NSEventModifierFlagOption | - NSEventModifierFlagCommand)]; - [appMenu addItem:item]; - item = [[[NSMenuItem alloc] initWithTitle:@"Show All" - action:@selector(unhideAllApplications:) - keyEquivalent:@""] autorelease]; - [appMenu addItem:item]; - [appMenu addItem:[NSMenuItem separatorItem]]; - - NSMenuItem *editMenuItem = - [[[NSMenuItem alloc] initWithTitle:@"Edit" action:NULL keyEquivalent:@""] - autorelease]; - NSMenu *editMenu = [[[NSMenu alloc] initWithTitle:@"Edit"] autorelease]; - [editMenuItem setSubmenu:editMenu]; - [menubar addItem:editMenuItem]; - - item = [[[NSMenuItem alloc] initWithTitle:@"Cut" - action:@selector(cut:) - keyEquivalent:@"x"] autorelease]; - [editMenu addItem:item]; - - item = [[[NSMenuItem alloc] initWithTitle:@"Copy" - action:@selector(copy:) - keyEquivalent:@"c"] autorelease]; - [editMenu addItem:item]; - - item = [[[NSMenuItem alloc] initWithTitle:@"Paste" - action:@selector(paste:) - keyEquivalent:@"v"] autorelease]; - [editMenu addItem:item]; - - item = [[[NSMenuItem alloc] initWithTitle:@"Select All" - action:@selector(selectAll:) - keyEquivalent:@"a"] autorelease]; - [editMenu addItem:item]; - - [appMenu addItem:[NSMenuItem separatorItem]]; - - item = [[[NSMenuItem alloc] initWithTitle:@"Quit" - action:@selector(terminate:) - keyEquivalent:@"q"] autorelease]; - [appMenu addItem:item]; - - [NSApp setMainMenu:menubar]; - - w->priv.should_exit = 0; - return 0; -} - -WEBVIEW_API int webview_loop(struct webview *w, int blocking) -{ - NSDate *until = (blocking ? [NSDate distantFuture] : [NSDate distantPast]); - NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny - untilDate:until - inMode:NSDefaultRunLoopMode - dequeue:YES]; - if (event) - { - [NSApp sendEvent:event]; - } - return w->priv.should_exit; -} - -WEBVIEW_API int webview_eval(struct webview *w, const char *js) -{ - NSString *nsJS = [NSString stringWithUTF8String:js]; - [[w->priv.webview windowScriptObject] evaluateWebScript:nsJS]; - return 0; -} - -WEBVIEW_API void webview_set_title(struct webview *w, const char *title) -{ - NSString *nsTitle = [NSString stringWithUTF8String:title]; - [w->priv.window setTitle:nsTitle]; -} - -WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen) -{ - int b = ((([w->priv.window styleMask] & NSWindowStyleMaskFullScreen) == - NSWindowStyleMaskFullScreen) - ? 1 - : 0); - if (b != fullscreen) - { - [w->priv.window toggleFullScreen:nil]; - } -} - -WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g, - uint8_t b, uint8_t a) -{ - [w->priv.window setBackgroundColor:[NSColor colorWithRed:(CGFloat)r / 255.0 - green:(CGFloat)g / 255.0 - blue:(CGFloat)b / 255.0 - alpha:(CGFloat)a / 255.0]]; - if (0.5 >= ((r / 255.0 * 299.0) + (g / 255.0 * 587.0) + (b / 255.0 * 114.0)) / - 1000.0) - { - [w->priv.window - setAppearance:[NSAppearance - appearanceNamed:NSAppearanceNameVibrantDark]]; - } - else - { - [w->priv.window - setAppearance:[NSAppearance - appearanceNamed:NSAppearanceNameVibrantLight]]; - } - [w->priv.window setOpaque:NO]; - [w->priv.window setTitlebarAppearsTransparent:YES]; - [w->priv.webview setDrawsBackground:NO]; -} - -WEBVIEW_API void webview_dialog(struct webview *w, - enum webview_dialog_type dlgtype, int flags, - const char *title, const char *arg, - char *result, size_t resultsz, char *filter) -{ - if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN || - dlgtype == WEBVIEW_DIALOG_TYPE_SAVE) - { - NSSavePanel *panel; - NSString *filter_str = [NSString stringWithUTF8String:filter]; - filter_str = [filter_str stringByReplacingOccurrencesOfString:@"*." - withString:@""]; - NSArray *fileTypes = [filter_str componentsSeparatedByString:@","]; - if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN) - { - NSOpenPanel *openPanel = [NSOpenPanel openPanel]; - if (flags & WEBVIEW_DIALOG_FLAG_DIRECTORY) - { - [openPanel setCanChooseFiles:NO]; - [openPanel setCanChooseDirectories:YES]; - } - else - { - [openPanel setCanChooseFiles:YES]; - [openPanel setCanChooseDirectories:NO]; - if(filter[0] != NULL) - { - [openPanel setAllowedFileTypes:fileTypes]; - } - } - [openPanel setResolvesAliases:NO]; - [openPanel setAllowsMultipleSelection:NO]; - panel = openPanel; - } - else - { - panel = [NSSavePanel savePanel]; - } - [panel setCanCreateDirectories:YES]; - [panel setShowsHiddenFiles:YES]; - [panel setExtensionHidden:NO]; - [panel setCanSelectHiddenExtension:NO]; - if(filter[0] != NULL) - { - [panel setAllowedFileTypes:fileTypes]; - } - [panel setTreatsFilePackagesAsDirectories:YES]; - [panel beginSheetModalForWindow:w->priv.window - completionHandler:^(NSInteger result) { - [NSApp stopModalWithCode:result]; - }]; - if ([NSApp runModalForWindow:panel] == NSModalResponseOK) - { - const char *filename = [[[panel URL] path] UTF8String]; - strlcpy(result, filename, resultsz); - } - } - else if (dlgtype == WEBVIEW_DIALOG_TYPE_ALERT) - { - NSAlert *a = [NSAlert new]; - switch (flags & WEBVIEW_DIALOG_FLAG_ALERT_MASK) - { - case WEBVIEW_DIALOG_FLAG_INFO: - [a setAlertStyle:NSAlertStyleInformational]; - break; - case WEBVIEW_DIALOG_FLAG_WARNING: - NSLog(@"warning"); - [a setAlertStyle:NSAlertStyleWarning]; - break; - case WEBVIEW_DIALOG_FLAG_ERROR: - NSLog(@"error"); - [a setAlertStyle:NSAlertStyleCritical]; - break; - } - [a setShowsHelp:NO]; - [a setShowsSuppressionButton:NO]; - [a setMessageText:[NSString stringWithUTF8String:title]]; - [a setInformativeText:[NSString stringWithUTF8String:arg]]; - [a addButtonWithTitle:@"OK"]; - [a runModal]; - [a release]; - } -} - -static void webview_dispatch_cb(void *arg) -{ - struct webview_dispatch_arg *context = (struct webview_dispatch_arg *)arg; - (context->fn)(context->w, context->arg); - free(context); -} - -WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn, - void *arg) -{ - struct webview_dispatch_arg *context = (struct webview_dispatch_arg *)malloc( - sizeof(struct webview_dispatch_arg)); - context->w = w; - context->arg = arg; - context->fn = fn; - dispatch_async_f(dispatch_get_main_queue(), context, webview_dispatch_cb); -} - -WEBVIEW_API void webview_terminate(struct webview *w) -{ - w->priv.should_exit = 1; -} -WEBVIEW_API void webview_exit(struct webview *w) { [NSApp terminate:NSApp]; } - WEBVIEW_API void webview_print_log(const char *s) { NSLog(@"%s", s); } - -#ifdef __cplusplus -} -#endif - -#endif /* WEBVIEW_H */ +#endif \ No newline at end of file