mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-12-01 03:02:28 +03:00
feat(ui) webview impl on separate files (#32)
This commit is contained in:
parent
45ee86a47f
commit
9e6454155f
@ -2,12 +2,12 @@ use std::{env, path::PathBuf};
|
||||
|
||||
fn main() {
|
||||
let tauri_path = PathBuf::from("../../../ui");
|
||||
let mut tauri_impl_path = tauri_path.clone();
|
||||
|
||||
let mut build = cc::Build::new();
|
||||
|
||||
build
|
||||
.include(&tauri_path)
|
||||
.file("tauri.c")
|
||||
.flag_if_supported("-std=c11")
|
||||
.flag_if_supported("-w");
|
||||
|
||||
@ -20,11 +20,13 @@ fn main() {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
||||
if target.contains("windows") {
|
||||
tauri_impl_path.push("tauri-windows.c");
|
||||
build.define("WEBVIEW_WINAPI", None);
|
||||
for &lib in &["ole32", "comctl32", "oleaut32", "uuid", "gdi32"] {
|
||||
println!("cargo:rustc-link-lib={}", lib);
|
||||
}
|
||||
} else if target.contains("linux") || target.contains("bsd") {
|
||||
tauri_impl_path.push("tauri-gtk.c");
|
||||
let webkit = pkg_config::Config::new()
|
||||
.atleast_version("2.8")
|
||||
.probe("webkit2gtk-4.0")
|
||||
@ -35,6 +37,7 @@ fn main() {
|
||||
}
|
||||
build.define("WEBVIEW_GTK", None);
|
||||
} else if target.contains("apple") {
|
||||
tauri_impl_path.push("tauri-cocoa.m");
|
||||
build
|
||||
.define("WEBVIEW_COCOA", None)
|
||||
.flag("-x")
|
||||
@ -45,5 +48,9 @@ fn main() {
|
||||
panic!("unsupported target");
|
||||
}
|
||||
|
||||
build
|
||||
.file(tauri_impl_path.into_os_string().into_string().unwrap())
|
||||
.file("tauri.c");
|
||||
|
||||
build.compile("tauri");
|
||||
}
|
||||
|
@ -1,3 +1,14 @@
|
||||
#if defined(WEBVIEW_GTK)
|
||||
#include "tauri-gtk-webview.h"
|
||||
#elif defined(WEBVIEW_WINAPI)
|
||||
#define CINTERFACE
|
||||
#include "tauri-windows-webview.h"
|
||||
#elif defined(WEBVIEW_COCOA)
|
||||
#include "tauri-cocoa-webview.h"
|
||||
#else
|
||||
#error "Define one of: WEBVIEW_GTK, WEBVIEW_COCOA or WEBVIEW_WINAPI"
|
||||
#endif
|
||||
|
||||
#define WEBVIEW_IMPLEMENTATION
|
||||
#include "tauri.h"
|
||||
|
||||
|
11
ui/tauri-cocoa-webview.h
Normal file
11
ui/tauri-cocoa-webview.h
Normal file
@ -0,0 +1,11 @@
|
||||
#include <objc/objc-runtime.h>
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
#include <limits.h>
|
||||
|
||||
struct webview_priv {
|
||||
id pool;
|
||||
id window;
|
||||
id webview;
|
||||
id windowDelegate;
|
||||
int should_exit;
|
||||
};
|
636
ui/tauri-cocoa.m
Normal file
636
ui/tauri-cocoa.m
Normal file
@ -0,0 +1,636 @@
|
||||
#include "tauri-cocoa-webview.h"
|
||||
#include "tauri.h"
|
||||
|
||||
#define NSAlertStyleWarning 0
|
||||
#define NSAlertStyleCritical 2
|
||||
#define NSWindowStyleMaskResizable 8
|
||||
#define NSWindowStyleMaskMiniaturizable 4
|
||||
#define NSWindowStyleMaskTitled 1
|
||||
#define NSWindowStyleMaskClosable 2
|
||||
#define NSWindowStyleMaskFullScreen (1 << 14)
|
||||
#define NSViewWidthSizable 2
|
||||
#define NSViewHeightSizable 16
|
||||
#define NSBackingStoreBuffered 2
|
||||
#define NSEventMaskAny ULONG_MAX
|
||||
#define NSEventModifierFlagCommand (1 << 20)
|
||||
#define NSEventModifierFlagOption (1 << 19)
|
||||
#define NSAlertStyleInformational 1
|
||||
#define NSAlertFirstButtonReturn 1000
|
||||
#define WKNavigationActionPolicyDownload 2
|
||||
#define NSModalResponseOK 1
|
||||
#define WKNavigationActionPolicyDownload 2
|
||||
#define WKNavigationResponsePolicyAllow 1
|
||||
#define WKUserScriptInjectionTimeAtDocumentStart 0
|
||||
#define NSApplicationActivationPolicyRegular 0
|
||||
|
||||
static id get_nsstring(const char *c_str) {
|
||||
return objc_msgSend((id)objc_getClass("NSString"),
|
||||
sel_registerName("stringWithUTF8String:"), c_str);
|
||||
}
|
||||
|
||||
static id create_menu_item(id title, const char *action, const char *key) {
|
||||
id item =
|
||||
objc_msgSend((id)objc_getClass("NSMenuItem"), sel_registerName("alloc"));
|
||||
objc_msgSend(item, sel_registerName("initWithTitle:action:keyEquivalent:"),
|
||||
title, sel_registerName(action), get_nsstring(key));
|
||||
objc_msgSend(item, sel_registerName("autorelease"));
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
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 void webview_external_invoke(id self, SEL cmd, id contentController,
|
||||
id message) {
|
||||
struct webview *w =
|
||||
(struct webview *)objc_getAssociatedObject(contentController, "webview");
|
||||
if (w == NULL || w->external_invoke_cb == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
w->external_invoke_cb(w, (const char *)objc_msgSend(
|
||||
objc_msgSend(message, sel_registerName("body")),
|
||||
sel_registerName("UTF8String")));
|
||||
}
|
||||
|
||||
static void run_open_panel(id self, SEL cmd, id webView, id parameters,
|
||||
id frame, void (^completionHandler)(id)) {
|
||||
|
||||
id openPanel = objc_msgSend((id)objc_getClass("NSOpenPanel"),
|
||||
sel_registerName("openPanel"));
|
||||
|
||||
objc_msgSend(
|
||||
openPanel, sel_registerName("setAllowsMultipleSelection:"),
|
||||
objc_msgSend(parameters, sel_registerName("allowsMultipleSelection")));
|
||||
|
||||
objc_msgSend(openPanel, sel_registerName("setCanChooseFiles:"), 1);
|
||||
objc_msgSend(
|
||||
openPanel, sel_registerName("beginWithCompletionHandler:"), ^(id result) {
|
||||
if (result == (id)NSModalResponseOK) {
|
||||
completionHandler(objc_msgSend(openPanel, sel_registerName("URLs")));
|
||||
} else {
|
||||
completionHandler(nil);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void run_save_panel(id self, SEL cmd, id download, id filename,
|
||||
void (^completionHandler)(int allowOverwrite,
|
||||
id destination)) {
|
||||
id savePanel = objc_msgSend((id)objc_getClass("NSSavePanel"),
|
||||
sel_registerName("savePanel"));
|
||||
objc_msgSend(savePanel, sel_registerName("setCanCreateDirectories:"), 1);
|
||||
objc_msgSend(savePanel, sel_registerName("setNameFieldStringValue:"),
|
||||
filename);
|
||||
objc_msgSend(savePanel, sel_registerName("beginWithCompletionHandler:"),
|
||||
^(id result) {
|
||||
if (result == (id)NSModalResponseOK) {
|
||||
id url = objc_msgSend(savePanel, sel_registerName("URL"));
|
||||
id path = objc_msgSend(url, sel_registerName("path"));
|
||||
completionHandler(1, path);
|
||||
} else {
|
||||
completionHandler(NO, nil);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void run_confirmation_panel(id self, SEL cmd, id webView, id message,
|
||||
id frame, void (^completionHandler)(bool)) {
|
||||
|
||||
id alert =
|
||||
objc_msgSend((id)objc_getClass("NSAlert"), sel_registerName("new"));
|
||||
objc_msgSend(alert, sel_registerName("setIcon:"),
|
||||
objc_msgSend((id)objc_getClass("NSImage"),
|
||||
sel_registerName("imageNamed:"),
|
||||
get_nsstring("NSCaution")));
|
||||
objc_msgSend(alert, sel_registerName("setShowsHelp:"), 0);
|
||||
objc_msgSend(alert, sel_registerName("setInformativeText:"), message);
|
||||
objc_msgSend(alert, sel_registerName("addButtonWithTitle:"),
|
||||
get_nsstring("OK"));
|
||||
objc_msgSend(alert, sel_registerName("addButtonWithTitle:"),
|
||||
get_nsstring("Cancel"));
|
||||
if (objc_msgSend(alert, sel_registerName("runModal")) ==
|
||||
(id)NSAlertFirstButtonReturn) {
|
||||
completionHandler(true);
|
||||
} else {
|
||||
completionHandler(false);
|
||||
}
|
||||
objc_msgSend(alert, sel_registerName("release"));
|
||||
}
|
||||
|
||||
static void run_alert_panel(id self, SEL cmd, id webView, id message, id frame,
|
||||
void (^completionHandler)(void)) {
|
||||
id alert =
|
||||
objc_msgSend((id)objc_getClass("NSAlert"), sel_registerName("new"));
|
||||
objc_msgSend(alert, sel_registerName("setIcon:"),
|
||||
objc_msgSend((id)objc_getClass("NSImage"),
|
||||
sel_registerName("imageNamed:"),
|
||||
get_nsstring("NSCaution")));
|
||||
objc_msgSend(alert, sel_registerName("setShowsHelp:"), 0);
|
||||
objc_msgSend(alert, sel_registerName("setInformativeText:"), message);
|
||||
objc_msgSend(alert, sel_registerName("addButtonWithTitle:"),
|
||||
get_nsstring("OK"));
|
||||
objc_msgSend(alert, sel_registerName("runModal"));
|
||||
objc_msgSend(alert, sel_registerName("release"));
|
||||
completionHandler();
|
||||
}
|
||||
|
||||
static void download_failed(id self, SEL cmd, id download, id error) {
|
||||
printf("%s",
|
||||
(const char *)objc_msgSend(
|
||||
objc_msgSend(error, sel_registerName("localizedDescription")),
|
||||
sel_registerName("UTF8String")));
|
||||
}
|
||||
|
||||
static void make_nav_policy_decision(id self, SEL cmd, id webView, id response,
|
||||
void (^decisionHandler)(int)) {
|
||||
if (objc_msgSend(response, sel_registerName("canShowMIMEType")) == 0) {
|
||||
decisionHandler(WKNavigationActionPolicyDownload);
|
||||
} else {
|
||||
decisionHandler(WKNavigationResponsePolicyAllow);
|
||||
}
|
||||
}
|
||||
|
||||
WEBVIEW_API int webview_init(struct webview *w) {
|
||||
w->priv.pool = objc_msgSend((id)objc_getClass("NSAutoreleasePool"),
|
||||
sel_registerName("new"));
|
||||
objc_msgSend((id)objc_getClass("NSApplication"),
|
||||
sel_registerName("sharedApplication"));
|
||||
|
||||
Class __WKScriptMessageHandler = objc_allocateClassPair(
|
||||
objc_getClass("NSObject"), "__WKScriptMessageHandler", 0);
|
||||
class_addMethod(
|
||||
__WKScriptMessageHandler,
|
||||
sel_registerName("userContentController:didReceiveScriptMessage:"),
|
||||
(IMP)webview_external_invoke, "v@:@@");
|
||||
objc_registerClassPair(__WKScriptMessageHandler);
|
||||
|
||||
id scriptMessageHandler =
|
||||
objc_msgSend((id)__WKScriptMessageHandler, sel_registerName("new"));
|
||||
|
||||
/***
|
||||
_WKDownloadDelegate is an undocumented/private protocol with methods called
|
||||
from WKNavigationDelegate
|
||||
References:
|
||||
https://github.com/WebKit/webkit/blob/master/Source/WebKit/UIProcess/API/Cocoa/_WKDownload.h
|
||||
https://github.com/WebKit/webkit/blob/master/Source/WebKit/UIProcess/API/Cocoa/_WKDownloadDelegate.h
|
||||
https://github.com/WebKit/webkit/blob/master/Tools/TestWebKitAPI/Tests/WebKitCocoa/Download.mm
|
||||
***/
|
||||
|
||||
Class __WKDownloadDelegate = objc_allocateClassPair(
|
||||
objc_getClass("NSObject"), "__WKDownloadDelegate", 0);
|
||||
class_addMethod(
|
||||
__WKDownloadDelegate,
|
||||
sel_registerName("_download:decideDestinationWithSuggestedFilename:"
|
||||
"completionHandler:"),
|
||||
(IMP)run_save_panel, "v@:@@?");
|
||||
class_addMethod(__WKDownloadDelegate,
|
||||
sel_registerName("_download:didFailWithError:"),
|
||||
(IMP)download_failed, "v@:@@");
|
||||
objc_registerClassPair(__WKDownloadDelegate);
|
||||
id downloadDelegate =
|
||||
objc_msgSend((id)__WKDownloadDelegate, sel_registerName("new"));
|
||||
|
||||
Class __WKPreferences = objc_allocateClassPair(objc_getClass("WKPreferences"),
|
||||
"__WKPreferences", 0);
|
||||
objc_property_attribute_t type = {"T", "c"};
|
||||
objc_property_attribute_t ownership = {"N", ""};
|
||||
objc_property_attribute_t attrs[] = {type, ownership};
|
||||
class_replaceProperty(__WKPreferences, "developerExtrasEnabled", attrs, 2);
|
||||
objc_registerClassPair(__WKPreferences);
|
||||
id wkPref = objc_msgSend((id)__WKPreferences, sel_registerName("new"));
|
||||
objc_msgSend(wkPref, sel_registerName("setValue:forKey:"),
|
||||
objc_msgSend((id)objc_getClass("NSNumber"),
|
||||
sel_registerName("numberWithBool:"), !!w->debug),
|
||||
objc_msgSend((id)objc_getClass("NSString"),
|
||||
sel_registerName("stringWithUTF8String:"),
|
||||
"developerExtrasEnabled"));
|
||||
|
||||
id userController = objc_msgSend((id)objc_getClass("WKUserContentController"),
|
||||
sel_registerName("new"));
|
||||
objc_setAssociatedObject(userController, "webview", (id)(w),
|
||||
OBJC_ASSOCIATION_ASSIGN);
|
||||
objc_msgSend(
|
||||
userController, sel_registerName("addScriptMessageHandler:name:"),
|
||||
scriptMessageHandler,
|
||||
objc_msgSend((id)objc_getClass("NSString"),
|
||||
sel_registerName("stringWithUTF8String:"), "invoke"));
|
||||
|
||||
/***
|
||||
In order to maintain compatibility with the other 'webviews' we need to
|
||||
override window.external.invoke to call
|
||||
webkit.messageHandlers.invoke.postMessage
|
||||
***/
|
||||
|
||||
id windowExternalOverrideScript = objc_msgSend(
|
||||
(id)objc_getClass("WKUserScript"), sel_registerName("alloc"));
|
||||
objc_msgSend(
|
||||
windowExternalOverrideScript,
|
||||
sel_registerName("initWithSource:injectionTime:forMainFrameOnly:"),
|
||||
get_nsstring("window.external = this; invoke = function(arg){ "
|
||||
"webkit.messageHandlers.invoke.postMessage(arg); };"),
|
||||
WKUserScriptInjectionTimeAtDocumentStart, 0);
|
||||
|
||||
objc_msgSend(userController, sel_registerName("addUserScript:"),
|
||||
windowExternalOverrideScript);
|
||||
|
||||
id config = objc_msgSend((id)objc_getClass("WKWebViewConfiguration"),
|
||||
sel_registerName("new"));
|
||||
id processPool = objc_msgSend(config, sel_registerName("processPool"));
|
||||
objc_msgSend(processPool, sel_registerName("_setDownloadDelegate:"),
|
||||
downloadDelegate);
|
||||
objc_msgSend(config, sel_registerName("setProcessPool:"), processPool);
|
||||
objc_msgSend(config, sel_registerName("setUserContentController:"),
|
||||
userController);
|
||||
objc_msgSend(config, sel_registerName("setPreferences:"), wkPref);
|
||||
|
||||
Class __NSWindowDelegate = objc_allocateClassPair(objc_getClass("NSObject"),
|
||||
"__NSWindowDelegate", 0);
|
||||
class_addProtocol(__NSWindowDelegate, objc_getProtocol("NSWindowDelegate"));
|
||||
class_replaceMethod(__NSWindowDelegate, sel_registerName("windowWillClose:"),
|
||||
(IMP)webview_window_will_close, "v@:@");
|
||||
objc_registerClassPair(__NSWindowDelegate);
|
||||
|
||||
w->priv.windowDelegate =
|
||||
objc_msgSend((id)__NSWindowDelegate, sel_registerName("new"));
|
||||
|
||||
objc_setAssociatedObject(w->priv.windowDelegate, "webview", (id)(w),
|
||||
OBJC_ASSOCIATION_ASSIGN);
|
||||
|
||||
id nsTitle =
|
||||
objc_msgSend((id)objc_getClass("NSString"),
|
||||
sel_registerName("stringWithUTF8String:"), w->title);
|
||||
|
||||
CGRect r = CGRectMake(0, 0, w->width, w->height);
|
||||
|
||||
unsigned int style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
|
||||
NSWindowStyleMaskMiniaturizable;
|
||||
if (w->resizable) {
|
||||
style = style | NSWindowStyleMaskResizable;
|
||||
}
|
||||
|
||||
w->priv.window =
|
||||
objc_msgSend((id)objc_getClass("NSWindow"), sel_registerName("alloc"));
|
||||
objc_msgSend(w->priv.window,
|
||||
sel_registerName("initWithContentRect:styleMask:backing:defer:"),
|
||||
r, style, NSBackingStoreBuffered, 0);
|
||||
|
||||
objc_msgSend(w->priv.window, sel_registerName("autorelease"));
|
||||
objc_msgSend(w->priv.window, sel_registerName("setTitle:"), nsTitle);
|
||||
objc_msgSend(w->priv.window, sel_registerName("setDelegate:"),
|
||||
w->priv.windowDelegate);
|
||||
objc_msgSend(w->priv.window, sel_registerName("center"));
|
||||
|
||||
Class __WKUIDelegate =
|
||||
objc_allocateClassPair(objc_getClass("NSObject"), "__WKUIDelegate", 0);
|
||||
class_addProtocol(__WKUIDelegate, objc_getProtocol("WKUIDelegate"));
|
||||
class_addMethod(__WKUIDelegate,
|
||||
sel_registerName("webView:runOpenPanelWithParameters:"
|
||||
"initiatedByFrame:completionHandler:"),
|
||||
(IMP)run_open_panel, "v@:@@@?");
|
||||
class_addMethod(__WKUIDelegate,
|
||||
sel_registerName("webView:runJavaScriptAlertPanelWithMessage:"
|
||||
"initiatedByFrame:completionHandler:"),
|
||||
(IMP)run_alert_panel, "v@:@@@?");
|
||||
class_addMethod(
|
||||
__WKUIDelegate,
|
||||
sel_registerName("webView:runJavaScriptConfirmPanelWithMessage:"
|
||||
"initiatedByFrame:completionHandler:"),
|
||||
(IMP)run_confirmation_panel, "v@:@@@?");
|
||||
objc_registerClassPair(__WKUIDelegate);
|
||||
id uiDel = objc_msgSend((id)__WKUIDelegate, sel_registerName("new"));
|
||||
|
||||
Class __WKNavigationDelegate = objc_allocateClassPair(
|
||||
objc_getClass("NSObject"), "__WKNavigationDelegate", 0);
|
||||
class_addProtocol(__WKNavigationDelegate,
|
||||
objc_getProtocol("WKNavigationDelegate"));
|
||||
class_addMethod(
|
||||
__WKNavigationDelegate,
|
||||
sel_registerName(
|
||||
"webView:decidePolicyForNavigationResponse:decisionHandler:"),
|
||||
(IMP)make_nav_policy_decision, "v@:@@?");
|
||||
objc_registerClassPair(__WKNavigationDelegate);
|
||||
id navDel = objc_msgSend((id)__WKNavigationDelegate, sel_registerName("new"));
|
||||
|
||||
w->priv.webview =
|
||||
objc_msgSend((id)objc_getClass("WKWebView"), sel_registerName("alloc"));
|
||||
objc_msgSend(w->priv.webview,
|
||||
sel_registerName("initWithFrame:configuration:"), r, config);
|
||||
objc_msgSend(w->priv.webview, sel_registerName("setUIDelegate:"), uiDel);
|
||||
objc_msgSend(w->priv.webview, sel_registerName("setNavigationDelegate:"),
|
||||
navDel);
|
||||
|
||||
id nsURL = objc_msgSend((id)objc_getClass("NSURL"),
|
||||
sel_registerName("URLWithString:"),
|
||||
get_nsstring(webview_check_url(w->url)));
|
||||
|
||||
objc_msgSend(w->priv.webview, sel_registerName("loadRequest:"),
|
||||
objc_msgSend((id)objc_getClass("NSURLRequest"),
|
||||
sel_registerName("requestWithURL:"), nsURL));
|
||||
objc_msgSend(w->priv.webview, sel_registerName("setAutoresizesSubviews:"), 1);
|
||||
objc_msgSend(w->priv.webview, sel_registerName("setAutoresizingMask:"),
|
||||
(NSViewWidthSizable | NSViewHeightSizable));
|
||||
objc_msgSend(objc_msgSend(w->priv.window, sel_registerName("contentView")),
|
||||
sel_registerName("addSubview:"), w->priv.webview);
|
||||
objc_msgSend(w->priv.window, sel_registerName("orderFrontRegardless"));
|
||||
|
||||
objc_msgSend(objc_msgSend((id)objc_getClass("NSApplication"),
|
||||
sel_registerName("sharedApplication")),
|
||||
sel_registerName("setActivationPolicy:"),
|
||||
NSApplicationActivationPolicyRegular);
|
||||
|
||||
objc_msgSend(objc_msgSend((id)objc_getClass("NSApplication"),
|
||||
sel_registerName("sharedApplication")),
|
||||
sel_registerName("finishLaunching"));
|
||||
|
||||
objc_msgSend(objc_msgSend((id)objc_getClass("NSApplication"),
|
||||
sel_registerName("sharedApplication")),
|
||||
sel_registerName("activateIgnoringOtherApps:"), 1);
|
||||
|
||||
id menubar =
|
||||
objc_msgSend((id)objc_getClass("NSMenu"), sel_registerName("alloc"));
|
||||
objc_msgSend(menubar, sel_registerName("initWithTitle:"), get_nsstring(""));
|
||||
objc_msgSend(menubar, sel_registerName("autorelease"));
|
||||
|
||||
id appName = objc_msgSend(objc_msgSend((id)objc_getClass("NSProcessInfo"),
|
||||
sel_registerName("processInfo")),
|
||||
sel_registerName("processName"));
|
||||
|
||||
id appMenuItem =
|
||||
objc_msgSend((id)objc_getClass("NSMenuItem"), sel_registerName("alloc"));
|
||||
objc_msgSend(appMenuItem,
|
||||
sel_registerName("initWithTitle:action:keyEquivalent:"), appName,
|
||||
NULL, get_nsstring(""));
|
||||
|
||||
id appMenu =
|
||||
objc_msgSend((id)objc_getClass("NSMenu"), sel_registerName("alloc"));
|
||||
objc_msgSend(appMenu, sel_registerName("initWithTitle:"), appName);
|
||||
objc_msgSend(appMenu, sel_registerName("autorelease"));
|
||||
|
||||
objc_msgSend(appMenuItem, sel_registerName("setSubmenu:"), appMenu);
|
||||
objc_msgSend(menubar, sel_registerName("addItem:"), appMenuItem);
|
||||
|
||||
id title =
|
||||
objc_msgSend(get_nsstring("Hide "),
|
||||
sel_registerName("stringByAppendingString:"), appName);
|
||||
id item = create_menu_item(title, "hide:", "h");
|
||||
objc_msgSend(appMenu, sel_registerName("addItem:"), item);
|
||||
|
||||
item = create_menu_item(get_nsstring("Hide Others"),
|
||||
"hideOtherApplications:", "h");
|
||||
objc_msgSend(item, sel_registerName("setKeyEquivalentModifierMask:"),
|
||||
(NSEventModifierFlagOption | NSEventModifierFlagCommand));
|
||||
objc_msgSend(appMenu, sel_registerName("addItem:"), item);
|
||||
|
||||
item =
|
||||
create_menu_item(get_nsstring("Show All"), "unhideAllApplications:", "");
|
||||
objc_msgSend(appMenu, sel_registerName("addItem:"), item);
|
||||
|
||||
objc_msgSend(appMenu, sel_registerName("addItem:"),
|
||||
objc_msgSend((id)objc_getClass("NSMenuItem"),
|
||||
sel_registerName("separatorItem")));
|
||||
|
||||
title = objc_msgSend(get_nsstring("Quit "),
|
||||
sel_registerName("stringByAppendingString:"), appName);
|
||||
item = create_menu_item(title, "terminate:", "q");
|
||||
objc_msgSend(appMenu, sel_registerName("addItem:"), item);
|
||||
|
||||
id editMenuItem =
|
||||
objc_msgSend((id)objc_getClass("NSMenuItem"), sel_registerName("alloc"));
|
||||
objc_msgSend(editMenuItem,
|
||||
sel_registerName("initWithTitle:action:keyEquivalent:"), get_nsstring("Edit"),
|
||||
NULL, get_nsstring(""));
|
||||
|
||||
/***
|
||||
Edit menu
|
||||
***/
|
||||
|
||||
id editMenu =
|
||||
objc_msgSend((id)objc_getClass("NSMenu"), sel_registerName("alloc"));
|
||||
objc_msgSend(editMenu, sel_registerName("initWithTitle:"), get_nsstring("Edit"));
|
||||
objc_msgSend(editMenu, sel_registerName("autorelease"));
|
||||
|
||||
objc_msgSend(editMenuItem, sel_registerName("setSubmenu:"), editMenu);
|
||||
objc_msgSend(menubar, sel_registerName("addItem:"), editMenuItem);
|
||||
|
||||
item = create_menu_item(get_nsstring("Undo"), "undo:", "z");
|
||||
objc_msgSend(editMenu, sel_registerName("addItem:"), item);
|
||||
|
||||
item = create_menu_item(get_nsstring("Redo"), "redo:", "y");
|
||||
objc_msgSend(editMenu, sel_registerName("addItem:"), item);
|
||||
|
||||
item = objc_msgSend((id)objc_getClass("NSMenuItem"), sel_registerName("separatorItem"));
|
||||
objc_msgSend(editMenu, sel_registerName("addItem:"), item);
|
||||
|
||||
item = create_menu_item(get_nsstring("Cut"), "cut:", "x");
|
||||
objc_msgSend(editMenu, sel_registerName("addItem:"), item);
|
||||
|
||||
item = create_menu_item(get_nsstring("Copy"), "copy:", "c");
|
||||
objc_msgSend(editMenu, sel_registerName("addItem:"), item);
|
||||
|
||||
item = create_menu_item(get_nsstring("Paste"), "paste:", "v");
|
||||
objc_msgSend(editMenu, sel_registerName("addItem:"), item);
|
||||
|
||||
item = create_menu_item(get_nsstring("Select All"), "selectAll:", "a");
|
||||
objc_msgSend(editMenu, sel_registerName("addItem:"), item);
|
||||
|
||||
/***
|
||||
Finalize menubar
|
||||
***/
|
||||
|
||||
objc_msgSend(objc_msgSend((id)objc_getClass("NSApplication"),
|
||||
sel_registerName("sharedApplication")),
|
||||
sel_registerName("setMainMenu:"), menubar);
|
||||
|
||||
w->priv.should_exit = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
WEBVIEW_API int webview_loop(struct webview *w, int blocking) {
|
||||
id until = (blocking ? objc_msgSend((id)objc_getClass("NSDate"),
|
||||
sel_registerName("distantFuture"))
|
||||
: objc_msgSend((id)objc_getClass("NSDate"),
|
||||
sel_registerName("distantPast")));
|
||||
|
||||
id event = objc_msgSend(
|
||||
objc_msgSend((id)objc_getClass("NSApplication"),
|
||||
sel_registerName("sharedApplication")),
|
||||
sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"),
|
||||
ULONG_MAX, until,
|
||||
objc_msgSend((id)objc_getClass("NSString"),
|
||||
sel_registerName("stringWithUTF8String:"),
|
||||
"kCFRunLoopDefaultMode"),
|
||||
true);
|
||||
|
||||
if (event) {
|
||||
objc_msgSend(objc_msgSend((id)objc_getClass("NSApplication"),
|
||||
sel_registerName("sharedApplication")),
|
||||
sel_registerName("sendEvent:"), event);
|
||||
}
|
||||
|
||||
return w->priv.should_exit;
|
||||
}
|
||||
|
||||
WEBVIEW_API int webview_eval(struct webview *w, const char *js) {
|
||||
objc_msgSend(w->priv.webview,
|
||||
sel_registerName("evaluateJavaScript:completionHandler:"),
|
||||
get_nsstring(js), NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
WEBVIEW_API void webview_set_title(struct webview *w, const char *title) {
|
||||
objc_msgSend(w->priv.window, sel_registerName("setTitle"),
|
||||
get_nsstring(title));
|
||||
}
|
||||
|
||||
WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen) {
|
||||
unsigned long windowStyleMask = (unsigned long)objc_msgSend(
|
||||
w->priv.window, sel_registerName("styleMask"));
|
||||
int b = (((windowStyleMask & NSWindowStyleMaskFullScreen) ==
|
||||
NSWindowStyleMaskFullScreen)
|
||||
? 1
|
||||
: 0);
|
||||
if (b != fullscreen) {
|
||||
objc_msgSend(w->priv.window, sel_registerName("toggleFullScreen:"), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g,
|
||||
uint8_t b, uint8_t a) {
|
||||
|
||||
id color = objc_msgSend((id)objc_getClass("NSColor"),
|
||||
sel_registerName("colorWithRed:green:blue:alpha:"),
|
||||
(float)r / 255.0, (float)g / 255.0, (float)b / 255.0,
|
||||
(float)a / 255.0);
|
||||
|
||||
objc_msgSend(w->priv.window, sel_registerName("setBackgroundColor:"), color);
|
||||
|
||||
if (0.5 >= ((r / 255.0 * 299.0) + (g / 255.0 * 587.0) + (b / 255.0 * 114.0)) /
|
||||
1000.0) {
|
||||
objc_msgSend(w->priv.window, sel_registerName("setAppearance:"),
|
||||
objc_msgSend((id)objc_getClass("NSAppearance"),
|
||||
sel_registerName("appearanceNamed:"),
|
||||
get_nsstring("NSAppearanceNameVibrantDark")));
|
||||
} else {
|
||||
objc_msgSend(w->priv.window, sel_registerName("setAppearance:"),
|
||||
objc_msgSend((id)objc_getClass("NSAppearance"),
|
||||
sel_registerName("appearanceNamed:"),
|
||||
get_nsstring("NSAppearanceNameVibrantLight")));
|
||||
}
|
||||
objc_msgSend(w->priv.window, sel_registerName("setOpaque:"), 0);
|
||||
objc_msgSend(w->priv.window,
|
||||
sel_registerName("setTitlebarAppearsTransparent:"), 1);
|
||||
objc_msgSend(w->priv.webview, sel_registerName("_setDrawsBackground:"), 0);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ||
|
||||
dlgtype == WEBVIEW_DIALOG_TYPE_SAVE) {
|
||||
id panel = (id)objc_getClass("NSSavePanel");
|
||||
if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN) {
|
||||
id openPanel = objc_msgSend((id)objc_getClass("NSOpenPanel"),
|
||||
sel_registerName("openPanel"));
|
||||
if (flags & WEBVIEW_DIALOG_FLAG_DIRECTORY) {
|
||||
objc_msgSend(openPanel, sel_registerName("setCanChooseFiles:"), 0);
|
||||
objc_msgSend(openPanel, sel_registerName("setCanChooseDirectories:"),
|
||||
1);
|
||||
} else {
|
||||
objc_msgSend(openPanel, sel_registerName("setCanChooseFiles:"), 1);
|
||||
objc_msgSend(openPanel, sel_registerName("setCanChooseDirectories:"),
|
||||
0);
|
||||
}
|
||||
objc_msgSend(openPanel, sel_registerName("setResolvesAliases:"), 0);
|
||||
objc_msgSend(openPanel, sel_registerName("setAllowsMultipleSelection:"),
|
||||
0);
|
||||
panel = openPanel;
|
||||
} else {
|
||||
panel = objc_msgSend((id)objc_getClass("NSSavePanel"),
|
||||
sel_registerName("savePanel"));
|
||||
}
|
||||
|
||||
objc_msgSend(panel, sel_registerName("setCanCreateDirectories:"), 1);
|
||||
objc_msgSend(panel, sel_registerName("setShowsHiddenFiles:"), 1);
|
||||
objc_msgSend(panel, sel_registerName("setExtensionHidden:"), 0);
|
||||
objc_msgSend(panel, sel_registerName("setCanSelectHiddenExtension:"), 0);
|
||||
objc_msgSend(panel, sel_registerName("setTreatsFilePackagesAsDirectories:"),
|
||||
1);
|
||||
objc_msgSend(
|
||||
panel, sel_registerName("beginSheetModalForWindow:completionHandler:"),
|
||||
w->priv.window, ^(id result) {
|
||||
objc_msgSend(objc_msgSend((id)objc_getClass("NSApplication"),
|
||||
sel_registerName("sharedApplication")),
|
||||
sel_registerName("stopModalWithCode:"), result);
|
||||
});
|
||||
|
||||
if (objc_msgSend(objc_msgSend((id)objc_getClass("NSApplication"),
|
||||
sel_registerName("sharedApplication")),
|
||||
sel_registerName("runModalForWindow:"),
|
||||
panel) == (id)NSModalResponseOK) {
|
||||
id url = objc_msgSend(panel, sel_registerName("URL"));
|
||||
id path = objc_msgSend(url, sel_registerName("path"));
|
||||
const char *filename =
|
||||
(const char *)objc_msgSend(path, sel_registerName("UTF8String"));
|
||||
strlcpy(result, filename, resultsz);
|
||||
}
|
||||
} else if (dlgtype == WEBVIEW_DIALOG_TYPE_ALERT) {
|
||||
id a = objc_msgSend((id)objc_getClass("NSAlert"), sel_registerName("new"));
|
||||
switch (flags & WEBVIEW_DIALOG_FLAG_ALERT_MASK) {
|
||||
case WEBVIEW_DIALOG_FLAG_INFO:
|
||||
objc_msgSend(a, sel_registerName("setAlertStyle:"),
|
||||
NSAlertStyleInformational);
|
||||
break;
|
||||
case WEBVIEW_DIALOG_FLAG_WARNING:
|
||||
printf("Warning\n");
|
||||
objc_msgSend(a, sel_registerName("setAlertStyle:"), NSAlertStyleWarning);
|
||||
break;
|
||||
case WEBVIEW_DIALOG_FLAG_ERROR:
|
||||
printf("Error\n");
|
||||
objc_msgSend(a, sel_registerName("setAlertStyle:"), NSAlertStyleCritical);
|
||||
break;
|
||||
}
|
||||
objc_msgSend(a, sel_registerName("setShowsHelp:"), 0);
|
||||
objc_msgSend(a, sel_registerName("setShowsSuppressionButton:"), 0);
|
||||
objc_msgSend(a, sel_registerName("setMessageText:"), get_nsstring(title));
|
||||
objc_msgSend(a, sel_registerName("setInformativeText:"), get_nsstring(arg));
|
||||
objc_msgSend(a, sel_registerName("addButtonWithTitle:"),
|
||||
get_nsstring("OK"));
|
||||
objc_msgSend(a, sel_registerName("runModal"));
|
||||
objc_msgSend(a, sel_registerName("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) {
|
||||
id app = objc_msgSend((id)objc_getClass("NSApplication"),
|
||||
sel_registerName("sharedApplication"));
|
||||
objc_msgSend(app, sel_registerName("terminate:"), app);
|
||||
}
|
||||
|
||||
WEBVIEW_API void webview_print_log(const char *s) { printf("%s\n", s); }
|
14
ui/tauri-gtk-webview.h
Normal file
14
ui/tauri-gtk-webview.h
Normal file
@ -0,0 +1,14 @@
|
||||
#include <JavaScriptCore/JavaScript.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <webkit2/webkit2.h>
|
||||
|
||||
struct webview_priv {
|
||||
GtkWidget *window;
|
||||
GtkWidget *scroller;
|
||||
GtkWidget *webview;
|
||||
GtkWidget *inspector_window;
|
||||
GAsyncQueue *queue;
|
||||
int ready;
|
||||
int js_busy;
|
||||
int should_exit;
|
||||
};
|
244
ui/tauri-gtk.c
Normal file
244
ui/tauri-gtk.c
Normal file
@ -0,0 +1,244 @@
|
||||
#include "tauri-gtk-webview.h"
|
||||
#include "tauri.h"
|
||||
|
||||
static void external_message_received_cb(WebKitUserContentManager *m,
|
||||
WebKitJavascriptResult *r,
|
||||
gpointer arg) {
|
||||
(void)m;
|
||||
struct webview *w = (struct webview *)arg;
|
||||
if (w->external_invoke_cb == NULL) {
|
||||
return;
|
||||
}
|
||||
JSGlobalContextRef context = webkit_javascript_result_get_global_context(r);
|
||||
JSValueRef value = webkit_javascript_result_get_value(r);
|
||||
JSStringRef js = JSValueToStringCopy(context, value, NULL);
|
||||
size_t n = JSStringGetMaximumUTF8CStringSize(js);
|
||||
char *s = g_new(char, n);
|
||||
JSStringGetUTF8CString(js, s, n);
|
||||
w->external_invoke_cb(w, s);
|
||||
JSStringRelease(js);
|
||||
g_free(s);
|
||||
}
|
||||
|
||||
static void webview_load_changed_cb(WebKitWebView *webview,
|
||||
WebKitLoadEvent event, gpointer arg) {
|
||||
(void)webview;
|
||||
struct webview *w = (struct webview *)arg;
|
||||
if (event == WEBKIT_LOAD_FINISHED) {
|
||||
w->priv.ready = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void webview_destroy_cb(GtkWidget *widget, gpointer arg) {
|
||||
(void)widget;
|
||||
struct webview *w = (struct webview *)arg;
|
||||
webview_terminate(w);
|
||||
}
|
||||
|
||||
static gboolean webview_context_menu_cb(WebKitWebView *webview,
|
||||
GtkWidget *default_menu,
|
||||
WebKitHitTestResult *hit_test_result,
|
||||
gboolean triggered_with_keyboard,
|
||||
gpointer userdata) {
|
||||
(void)webview;
|
||||
(void)default_menu;
|
||||
(void)hit_test_result;
|
||||
(void)triggered_with_keyboard;
|
||||
(void)userdata;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WEBVIEW_API int webview_init(struct webview *w) {
|
||||
if (gtk_init_check(0, NULL) == FALSE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
w->priv.ready = 0;
|
||||
w->priv.should_exit = 0;
|
||||
w->priv.queue = g_async_queue_new();
|
||||
w->priv.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title(GTK_WINDOW(w->priv.window), w->title);
|
||||
|
||||
if (w->resizable) {
|
||||
gtk_window_set_default_size(GTK_WINDOW(w->priv.window), w->width,
|
||||
w->height);
|
||||
} else {
|
||||
gtk_widget_set_size_request(w->priv.window, w->width, w->height);
|
||||
}
|
||||
gtk_window_set_resizable(GTK_WINDOW(w->priv.window), !!w->resizable);
|
||||
gtk_window_set_position(GTK_WINDOW(w->priv.window), GTK_WIN_POS_CENTER);
|
||||
|
||||
w->priv.scroller = gtk_scrolled_window_new(NULL, NULL);
|
||||
gtk_container_add(GTK_CONTAINER(w->priv.window), w->priv.scroller);
|
||||
|
||||
WebKitUserContentManager *m = webkit_user_content_manager_new();
|
||||
webkit_user_content_manager_register_script_message_handler(m, "external");
|
||||
g_signal_connect(m, "script-message-received::external",
|
||||
G_CALLBACK(external_message_received_cb), w);
|
||||
|
||||
w->priv.webview = webkit_web_view_new_with_user_content_manager(m);
|
||||
webkit_web_view_load_uri(WEBKIT_WEB_VIEW(w->priv.webview),
|
||||
webview_check_url(w->url));
|
||||
g_signal_connect(G_OBJECT(w->priv.webview), "load-changed",
|
||||
G_CALLBACK(webview_load_changed_cb), w);
|
||||
gtk_container_add(GTK_CONTAINER(w->priv.scroller), w->priv.webview);
|
||||
|
||||
if (w->debug) {
|
||||
WebKitSettings *settings =
|
||||
webkit_web_view_get_settings(WEBKIT_WEB_VIEW(w->priv.webview));
|
||||
webkit_settings_set_enable_write_console_messages_to_stdout(settings, true);
|
||||
webkit_settings_set_enable_developer_extras(settings, true);
|
||||
} else {
|
||||
g_signal_connect(G_OBJECT(w->priv.webview), "context-menu",
|
||||
G_CALLBACK(webview_context_menu_cb), w);
|
||||
}
|
||||
|
||||
gtk_widget_show_all(w->priv.window);
|
||||
|
||||
webkit_web_view_run_javascript(
|
||||
WEBKIT_WEB_VIEW(w->priv.webview),
|
||||
"window.external={invoke:function(x){"
|
||||
"window.webkit.messageHandlers.external.postMessage(x);}}",
|
||||
NULL, NULL, NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(w->priv.window), "destroy",
|
||||
G_CALLBACK(webview_destroy_cb), w);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WEBVIEW_API int webview_loop(struct webview *w, int blocking) {
|
||||
gtk_main_iteration_do(blocking);
|
||||
return w->priv.should_exit;
|
||||
}
|
||||
|
||||
WEBVIEW_API void webview_set_title(struct webview *w, const char *title) {
|
||||
gtk_window_set_title(GTK_WINDOW(w->priv.window), title);
|
||||
}
|
||||
|
||||
WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen) {
|
||||
if (fullscreen) {
|
||||
gtk_window_fullscreen(GTK_WINDOW(w->priv.window));
|
||||
} else {
|
||||
gtk_window_unfullscreen(GTK_WINDOW(w->priv.window));
|
||||
}
|
||||
}
|
||||
|
||||
WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g,
|
||||
uint8_t b, uint8_t a) {
|
||||
GdkRGBA color = {r / 255.0, g / 255.0, b / 255.0, a / 255.0};
|
||||
webkit_web_view_set_background_color(WEBKIT_WEB_VIEW(w->priv.webview),
|
||||
&color);
|
||||
}
|
||||
|
||||
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) {
|
||||
GtkWidget *dlg;
|
||||
if (result != NULL) {
|
||||
result[0] = '\0';
|
||||
}
|
||||
if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ||
|
||||
dlgtype == WEBVIEW_DIALOG_TYPE_SAVE) {
|
||||
dlg = gtk_file_chooser_dialog_new(
|
||||
title, GTK_WINDOW(w->priv.window),
|
||||
(dlgtype == WEBVIEW_DIALOG_TYPE_OPEN
|
||||
? (flags & WEBVIEW_DIALOG_FLAG_DIRECTORY
|
||||
? GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
|
||||
: GTK_FILE_CHOOSER_ACTION_OPEN)
|
||||
: GTK_FILE_CHOOSER_ACTION_SAVE),
|
||||
"_Cancel", GTK_RESPONSE_CANCEL,
|
||||
(dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ? "_Open" : "_Save"),
|
||||
GTK_RESPONSE_ACCEPT, NULL);
|
||||
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dlg), FALSE);
|
||||
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dlg), FALSE);
|
||||
gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dlg), TRUE);
|
||||
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dlg), TRUE);
|
||||
gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dlg), TRUE);
|
||||
gint response = gtk_dialog_run(GTK_DIALOG(dlg));
|
||||
if (response == GTK_RESPONSE_ACCEPT) {
|
||||
gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dlg));
|
||||
g_strlcpy(result, filename, resultsz);
|
||||
g_free(filename);
|
||||
}
|
||||
gtk_widget_destroy(dlg);
|
||||
} else if (dlgtype == WEBVIEW_DIALOG_TYPE_ALERT) {
|
||||
GtkMessageType type = GTK_MESSAGE_OTHER;
|
||||
switch (flags & WEBVIEW_DIALOG_FLAG_ALERT_MASK) {
|
||||
case WEBVIEW_DIALOG_FLAG_INFO:
|
||||
type = GTK_MESSAGE_INFO;
|
||||
break;
|
||||
case WEBVIEW_DIALOG_FLAG_WARNING:
|
||||
type = GTK_MESSAGE_WARNING;
|
||||
break;
|
||||
case WEBVIEW_DIALOG_FLAG_ERROR:
|
||||
type = GTK_MESSAGE_ERROR;
|
||||
break;
|
||||
}
|
||||
dlg = gtk_message_dialog_new(GTK_WINDOW(w->priv.window), GTK_DIALOG_MODAL,
|
||||
type, GTK_BUTTONS_OK, "%s", title);
|
||||
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dlg), "%s",
|
||||
arg);
|
||||
gtk_dialog_run(GTK_DIALOG(dlg));
|
||||
gtk_widget_destroy(dlg);
|
||||
}
|
||||
}
|
||||
|
||||
static void webview_eval_finished(GObject *object, GAsyncResult *result,
|
||||
gpointer userdata) {
|
||||
(void)object;
|
||||
(void)result;
|
||||
struct webview *w = (struct webview *)userdata;
|
||||
w->priv.js_busy = 0;
|
||||
}
|
||||
|
||||
WEBVIEW_API int webview_eval(struct webview *w, const char *js) {
|
||||
while (w->priv.ready == 0) {
|
||||
g_main_context_iteration(NULL, TRUE);
|
||||
}
|
||||
w->priv.js_busy = 1;
|
||||
webkit_web_view_run_javascript(WEBKIT_WEB_VIEW(w->priv.webview), js, NULL,
|
||||
webview_eval_finished, w);
|
||||
while (w->priv.js_busy) {
|
||||
g_main_context_iteration(NULL, TRUE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean webview_dispatch_wrapper(gpointer userdata) {
|
||||
struct webview *w = (struct webview *)userdata;
|
||||
for (;;) {
|
||||
struct webview_dispatch_arg *arg =
|
||||
(struct webview_dispatch_arg *)g_async_queue_try_pop(w->priv.queue);
|
||||
if (arg == NULL) {
|
||||
break;
|
||||
}
|
||||
(arg->fn)(w, arg->arg);
|
||||
g_free(arg);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn,
|
||||
void *arg) {
|
||||
struct webview_dispatch_arg *context =
|
||||
(struct webview_dispatch_arg *)g_new(struct webview_dispatch_arg, 1);
|
||||
context->w = w;
|
||||
context->arg = arg;
|
||||
context->fn = fn;
|
||||
g_async_queue_lock(w->priv.queue);
|
||||
g_async_queue_push_unlocked(w->priv.queue, context);
|
||||
if (g_async_queue_length_unlocked(w->priv.queue) == 1) {
|
||||
gdk_threads_add_idle(webview_dispatch_wrapper, w);
|
||||
}
|
||||
g_async_queue_unlock(w->priv.queue);
|
||||
}
|
||||
|
||||
WEBVIEW_API void webview_terminate(struct webview *w) {
|
||||
w->priv.should_exit = 1;
|
||||
}
|
||||
|
||||
WEBVIEW_API void webview_exit(struct webview *w) { (void)w; }
|
||||
WEBVIEW_API void webview_print_log(const char *s) {
|
||||
fprintf(stderr, "%s\n", s);
|
||||
}
|
19
ui/tauri-windows-webview.h
Normal file
19
ui/tauri-windows-webview.h
Normal file
@ -0,0 +1,19 @@
|
||||
#define CINTERFACE
|
||||
#include <windows.h>
|
||||
|
||||
#include <commctrl.h>
|
||||
#include <exdisp.h>
|
||||
#include <mshtmhst.h>
|
||||
#include <mshtml.h>
|
||||
#include <shobjidl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
struct webview_priv {
|
||||
HWND hwnd;
|
||||
IOleObject **browser;
|
||||
BOOL is_fullscreen;
|
||||
DWORD saved_style;
|
||||
DWORD saved_ex_style;
|
||||
RECT saved_rect;
|
||||
};
|
1175
ui/tauri-windows.c
Normal file
1175
ui/tauri-windows.c
Normal file
File diff suppressed because it is too large
Load Diff
2111
ui/tauri.h
2111
ui/tauri.h
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user