tauri/ui/tauri-cocoa.m
2019-09-12 15:37:40 -04:00

637 lines
27 KiB
Objective-C

#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); }