diff --git a/CMakeLists.txt b/CMakeLists.txt old mode 100644 new mode 100755 index f26dba046..d6f75cf2b --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,8 +4,7 @@ project(webview) if(APPLE) set(WEBVIEW_COMPILE_DEFS "-DWEBVIEW_COCOA=1") - set(WEBVIEW_COMPILE_OPTS "-ObjC") - set(WEBVIEW_LIBS "-framework Cocoa" "-framework WebKit") + set(WEBVIEW_LIBS "-framework WebKit") elseif(WIN32) set(WEBVIEW_COMPILE_DEFS "-DWEBVIEW_WINAPI=1") set(WEBVIEW_LIBS "ole32 comctl32 oleaut32 uuid") @@ -28,9 +27,6 @@ target_link_libraries(webview ${WEBVIEW_LIBS}) add_executable(webview_test WIN32 MACOSX_BUNDLE webview_test.cc) set_target_properties(webview_test PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED YES CXX_EXTENSIONS NO) find_package(Threads) -if(APPLE) - target_compile_options(webview_test PUBLIC "-ObjC++") -endif() target_link_libraries(webview_test PRIVATE webview ${CMAKE_THREAD_LIBS_INIT}) enable_testing () add_test(NAME webview_test COMMAND webview_test) diff --git a/README.md b/README.md old mode 100644 new mode 100755 index acb6c7851..9ebba7e87 --- a/README.md +++ b/README.md @@ -208,7 +208,7 @@ Build it: # Linux $ cc main.c -DWEBVIEW_GTK=1 `pkg-config --cflags --libs gtk+-3.0 webkit2gtk-4.0` -o webview-example # MacOS -$ cc main.c -DWEBVIEW_COCOA=1 -x objective-c -framework Cocoa -framework WebKit -o webview-example +$ cc main.c -DWEBVIEW_COCOA=1 -framework WebKit -o webview-example # Windows (mingw) $ cc main.c -DWEBVIEW_WINAPI=1 -lole32 -lcomctl32 -loleaut32 -luuid -mwindows -o webview-example.exe ``` diff --git a/examples/minimal/CMakeLists.txt b/examples/minimal/CMakeLists.txt old mode 100644 new mode 100755 index d388b984b..3a5422451 --- a/examples/minimal/CMakeLists.txt +++ b/examples/minimal/CMakeLists.txt @@ -4,7 +4,4 @@ project(minimal) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../.. ${CMAKE_CURRENT_BINARY_DIR}/webview) add_executable(minimal WIN32 MACOSX_BUNDLE main.c) -if (APPLE) - target_compile_options(minimal PRIVATE "-ObjC") -endif() target_link_libraries(minimal PUBLIC webview) diff --git a/examples/minimal/Makefile b/examples/minimal/Makefile index 4fb13beed..e649db6b6 100644 --- a/examples/minimal/Makefile +++ b/examples/minimal/Makefile @@ -11,8 +11,8 @@ else ifeq ($(shell uname -s),Linux) WEBVIEW_CFLAGS := -DWEBVIEW_GTK=1 $(shell pkg-config --cflags gtk+-3.0 webkit2gtk-4.0) WEBVIEW_LDFLAGS := $(shell pkg-config --libs gtk+-3.0 webkit2gtk-4.0) else ifeq ($(shell uname -s),Darwin) - WEBVIEW_CFLAGS := -DWEBVIEW_COCOA=1 -x objective-c - WEBVIEW_LDFLAGS := -framework Cocoa -framework WebKit + WEBVIEW_CFLAGS := -DWEBVIEW_COCOA=1 + WEBVIEW_LDFLAGS := -framework WebKit endif $(TARGET): main.c diff --git a/examples/timer-cxx/CMakeLists.txt b/examples/timer-cxx/CMakeLists.txt old mode 100644 new mode 100755 index 1bb12c696..6511eb9fe --- a/examples/timer-cxx/CMakeLists.txt +++ b/examples/timer-cxx/CMakeLists.txt @@ -6,9 +6,6 @@ set(CMAKE_CXX_STANDARD 11) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../.. ${CMAKE_CURRENT_BINARY_DIR}/webview) add_executable(timer WIN32 MACOSX_BUNDLE main.cc) -if (APPLE) - set_source_files_properties(main.cc PROPERTIES COMPILE_FLAGS "-x objective-c++") -endif() find_package(Threads REQUIRED) target_link_libraries(timer PUBLIC webview ${CMAKE_THREAD_LIBS_INIT}) diff --git a/webview.go b/webview.go old mode 100644 new mode 100755 index ef1d0246d..09665217a --- a/webview.go +++ b/webview.go @@ -17,8 +17,8 @@ package webview #cgo windows CFLAGS: -DWEBVIEW_WINAPI=1 #cgo windows LDFLAGS: -lole32 -lcomctl32 -loleaut32 -luuid -lgdi32 -#cgo darwin CFLAGS: -DWEBVIEW_COCOA=1 -x objective-c -#cgo darwin LDFLAGS: -framework Cocoa -framework WebKit +#cgo darwin CFLAGS: -DWEBVIEW_COCOA=1 +#cgo darwin LDFLAGS: -framework WebKit #include #include diff --git a/webview.h b/webview.h index b296321de..b574ea121 100644 --- a/webview.h +++ b/webview.h @@ -74,14 +74,14 @@ struct webview_priv { RECT saved_rect; }; #elif defined(WEBVIEW_COCOA) -#import -#import -#import +#include +#include +#include struct webview_priv { - NSAutoreleasePool *pool; - NSWindow *window; - WKWebView *webview; + id pool; + id window; + id webview; id windowDelegate; int should_exit; }; @@ -427,8 +427,8 @@ WEBVIEW_API void webview_dialog(struct webview *w, static void webview_eval_finished(GObject *object, GAsyncResult *result, gpointer userdata) { - (void) object; - (void) result; + (void)object; + (void)result; struct webview *w = (struct webview *)userdata; w->priv.js_busy = 0; } @@ -504,7 +504,9 @@ typedef struct { _IOleInPlaceFrameEx frame; } _IOleInPlaceSiteEx; -typedef struct { IDocHostUIHandler ui; } _IDocHostUIHandlerEx; +typedef struct { + IDocHostUIHandler ui; +} _IDocHostUIHandlerEx; typedef struct { IOleClientSite client; @@ -1592,24 +1594,43 @@ WEBVIEW_API void webview_print_log(const char *s) { OutputDebugString(s); } #endif /* WEBVIEW_WINAPI */ #if defined(WEBVIEW_COCOA) -#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 */ +#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"); @@ -1618,110 +1639,131 @@ static void webview_window_will_close(id self, SEL cmd, id notification) { static void webview_external_invoke(id self, SEL cmd, id contentController, id message) { - WKScriptMessage *scriptMessage = message; struct webview *w = (struct webview *)objc_getAssociatedObject(contentController, "webview"); if (w == NULL || w->external_invoke_cb == NULL) { return; } - if ([scriptMessage.body isKindOfClass:[NSString class]] == NO) { - return; - } - w->external_invoke_cb(w, [(NSString *)(scriptMessage.body)UTF8String]); + 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 params, id frame, - void (^completionHandler)(id)) { - WKOpenPanelParameters *parameters = (WKOpenPanelParameters *)params; - NSOpenPanel *openPanel = [NSOpenPanel openPanel]; - [openPanel setAllowsMultipleSelection:parameters.allowsMultipleSelection]; - [openPanel setCanChooseFiles:YES]; - [openPanel beginWithCompletionHandler:^(NSInteger result) { - if (result == NSModalResponseOK) { - completionHandler([openPanel URLs]); - } else { - completionHandler(nil); - } - }]; +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)(BOOL allowOverwrite, - NSString *destination)) { - NSSavePanel *savePanel = [NSSavePanel savePanel]; - savePanel.canCreateDirectories = YES; - savePanel.nameFieldStringValue = filename; - [savePanel beginWithCompletionHandler:^(NSInteger result) { - if (result == NSModalResponseOK) { - NSString *path = [[savePanel URL] path]; - completionHandler(YES, path); - } else { - completionHandler(NO, nil); - } - }]; + 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)) { - NSAlert *alert = [NSAlert new]; - [alert setIcon:[NSImage imageNamed:NSImageNameCaution]]; - [alert setShowsHelp:NO]; - [alert setInformativeText:(NSString *)message]; - [alert addButtonWithTitle:@"OK"]; - [alert addButtonWithTitle:@"Cancel"]; - if ([alert runModal] == NSAlertFirstButtonReturn) { + + 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); } - [alert release]; + objc_msgSend(alert, sel_registerName("release")); } static void run_alert_panel(id self, SEL cmd, id webView, id message, id frame, void (^completionHandler)(void)) { - NSAlert *alert = [NSAlert new]; - [alert setIcon:[NSImage imageNamed:NSImageNameCaution]]; - [alert setShowsHelp:NO]; - [alert setInformativeText:(NSString *)message]; - [alert addButtonWithTitle:@"OK"]; - [alert runModal]; - [alert release]; + 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", [[(NSError *)error localizedDescription] UTF8String]); + 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)(WKNavigationResponsePolicy)) { - WKNavigationResponse *wkResponse = (WKNavigationResponse *)response; - - // WKNavigationResponsePolicyAllow + 1 = _WKNavigationActionPolicyDownload - if (!wkResponse.canShowMIMEType) { - decisionHandler( - (WKNavigationResponsePolicy)(WKNavigationResponsePolicyAllow + 1)); +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 = [[NSAutoreleasePool alloc] init]; - [NSApplication sharedApplication]; + w->priv.pool = objc_msgSend((id)objc_getClass("NSAutoreleasePool"), + sel_registerName("new")); + objc_msgSend((id)objc_getClass("NSApplication"), + sel_registerName("sharedApplication")); - Class scriptMessageHandlerClass = - objc_allocateClassPair([NSObject class], "ScriptMessageHandler", 0); + Class __WKScriptMessageHandler = objc_allocateClassPair( + objc_getClass("NSObject"), "__WKScriptMessageHandler", 0); class_addMethod( - scriptMessageHandlerClass, + __WKScriptMessageHandler, sel_registerName("userContentController:didReceiveScriptMessage:"), (IMP)webview_external_invoke, "v@:@@"); - objc_registerClassPair(scriptMessageHandlerClass); + objc_registerClassPair(__WKScriptMessageHandler); - id scriptMessageHandler = [[scriptMessageHandlerClass alloc] init]; - WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]; + id scriptMessageHandler = + objc_msgSend((id)__WKScriptMessageHandler, sel_registerName("new")); /*** _WKDownloadDelegate is an undocumented/private protocol with methods called @@ -1731,6 +1773,7 @@ WEBVIEW_API int webview_init(struct webview *w) { 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( @@ -1742,72 +1785,98 @@ WEBVIEW_API int webview_init(struct webview *w) { sel_registerName("_download:didFailWithError:"), (IMP)download_failed, "v@:@@"); objc_registerClassPair(__WKDownloadDelegate); - id downloadDelegate = [[__WKDownloadDelegate alloc] init]; - objc_msgSend(config.processPool, sel_registerName("_setDownloadDelegate:"), - downloadDelegate); + id downloadDelegate = + objc_msgSend((id)__WKDownloadDelegate, sel_registerName("new")); - Class __WKPreferences = - objc_allocateClassPair(objc_getClass("WKPreferences"), "__WKPreferences", 0); + 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 = [[__WKPreferences alloc] init]; - [wkPref setValue:[NSNumber numberWithBool:!!w->debug] - forKey:@"developerExtrasEnabled"]; - - WKUserContentController *userController = - [[WKUserContentController alloc] init]; + 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); - [userController addScriptMessageHandler:scriptMessageHandler name:@"invoke"]; + 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 ***/ - WKUserScript *windowExternalOverrideScript = [[WKUserScript alloc] - initWithSource:@"window.external = this; invoke = function(arg) " - @"{webkit.messageHandlers.invoke.postMessage(arg);};" - injectionTime:WKUserScriptInjectionTimeAtDocumentStart - forMainFrameOnly:NO]; - [userController addUserScript:windowExternalOverrideScript]; - - config.userContentController = userController; - config.preferences = wkPref; - - Class windowDelegateClass = - objc_allocateClassPair([NSObject class], "WindowDelegate", 0); - class_addProtocol(windowDelegateClass, objc_getProtocol("NSWindowDelegate")); - class_replaceMethod(windowDelegateClass, sel_registerName("windowWillClose:"), + + 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(windowDelegateClass); + objc_registerClassPair(__NSWindowDelegate); - w->priv.windowDelegate = [[windowDelegateClass alloc] init]; + w->priv.windowDelegate = + objc_msgSend((id)__NSWindowDelegate, sel_registerName("new")); objc_setAssociatedObject(w->priv.windowDelegate, "webview", (id)(w), OBJC_ASSOCIATION_ASSIGN); - NSString *nsTitle = [NSString stringWithUTF8String:w->title]; - NSRect r = NSMakeRect(0, 0, w->width, w->height); + id nsTitle = + objc_msgSend((id)objc_getClass("NSString"), + sel_registerName("stringWithUTF8String:"), w->title); - NSUInteger style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | - NSWindowStyleMaskMiniaturizable; + CGRect r = CGRectMake(0, 0, w->width, w->height); + + unsigned int style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | + NSWindowStyleMaskMiniaturizable; if (w->resizable) { style = style | NSWindowStyleMaskResizable; } - w->priv.window = [[NSWindow alloc] initWithContentRect:r - styleMask:style - backing:NSBackingStoreBuffered - defer:NO]; + 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); - [w->priv.window autorelease]; - [w->priv.window setTitle:nsTitle]; - [w->priv.window setDelegate:w->priv.windowDelegate]; - [w->priv.window center]; + 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); @@ -1826,7 +1895,7 @@ WEBVIEW_API int webview_init(struct webview *w) { "initiatedByFrame:completionHandler:"), (IMP)run_confirmation_panel, "v@:@@@?"); objc_registerClassPair(__WKUIDelegate); - id uiDel = [[__WKUIDelegate alloc] init]; + id uiDel = objc_msgSend((id)__WKUIDelegate, sel_registerName("new")); Class __WKNavigationDelegate = objc_allocateClassPair( objc_getClass("NSObject"), "__WKNavigationDelegate", 0); @@ -1838,116 +1907,174 @@ WEBVIEW_API int webview_init(struct webview *w) { "webView:decidePolicyForNavigationResponse:decisionHandler:"), (IMP)make_nav_policy_decision, "v@:@@?"); objc_registerClassPair(__WKNavigationDelegate); - id navDel = [[__WKNavigationDelegate alloc] init]; - - w->priv.webview = [[WKWebView alloc] initWithFrame:r configuration:config]; - w->priv.webview.UIDelegate = uiDel; - w->priv.webview.navigationDelegate = navDel; - - NSURL *nsURL = [NSURL - URLWithString:[NSString stringWithUTF8String:webview_check_url(w->url)]]; - [w->priv.webview loadRequest:[NSURLRequest requestWithURL:nsURL]]; - - [w->priv.webview setAutoresizesSubviews:YES]; - [w->priv.webview - setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - [[w->priv.window contentView] addSubview:w->priv.webview]; - [w->priv.window orderFrontRegardless]; - - [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; - [NSApp finishLaunching]; - [NSApp activateIgnoringOtherApps:YES]; - - NSMenu *menubar = [[[NSMenu alloc] initWithTitle:@""] autorelease]; - - NSString *appName = [[NSProcessInfo processInfo] processName]; - NSMenuItem *appMenuItem = - [[[NSMenuItem alloc] initWithTitle:appName action:NULL keyEquivalent:@""] - autorelease]; - NSMenu *appMenu = [[[NSMenu alloc] initWithTitle:appName] autorelease]; - [appMenuItem setSubmenu:appMenu]; - [menubar addItem:appMenuItem]; - - NSString *title = [@"Hide " stringByAppendingString:appName]; - NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:title - 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]]; - - title = [@"Quit " stringByAppendingString:appName]; - item = [[[NSMenuItem alloc] initWithTitle:title - action:@selector(terminate:) - keyEquivalent:@"q"] autorelease]; - [appMenu addItem:item]; - - [NSApp setMainMenu:menubar]; + 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); + + 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) { - NSDate *until = (blocking ? [NSDate distantFuture] : [NSDate distantPast]); - NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny - untilDate:until - inMode:NSDefaultRunLoopMode - dequeue:YES]; + 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) { - [NSApp sendEvent: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) { - NSString *nsJS = [NSString stringWithUTF8String:js]; - [w->priv.webview evaluateJavaScript:nsJS completionHandler:NULL]; + 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) { - NSString *nsTitle = [NSString stringWithUTF8String:title]; - [w->priv.window setTitle:nsTitle]; + objc_msgSend(w->priv.window, sel_registerName("setTitle"), + get_nsstring(title)); } WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen) { - int b = ((([w->priv.window styleMask] & NSWindowStyleMaskFullScreen) == + unsigned long windowStyleMask = (unsigned long)objc_msgSend( + w->priv.window, sel_registerName("styleMask")); + int b = (((windowStyleMask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen) ? 1 : 0); if (b != fullscreen) { - [w->priv.window toggleFullScreen:nil]; + 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) { - [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]]; + + 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) { - [w->priv.window - setAppearance:[NSAppearance - appearanceNamed:NSAppearanceNameVibrantDark]]; + objc_msgSend(w->priv.window, sel_registerName("setAppearance:"), + objc_msgSend((id)objc_getClass("NSAppearance"), + sel_registerName("appearanceNamed:"), + get_nsstring("NSAppearanceNameVibrantDark"))); } else { - [w->priv.window - setAppearance:[NSAppearance - appearanceNamed:NSAppearanceNameVibrantLight]]; + objc_msgSend(w->priv.window, sel_registerName("setAppearance:"), + objc_msgSend((id)objc_getClass("NSAppearance"), + sel_registerName("appearanceNamed:"), + get_nsstring("NSAppearanceNameVibrantLight"))); } - [w->priv.window setOpaque:NO]; - [w->priv.window setTitlebarAppearsTransparent:YES]; + objc_msgSend(w->priv.window, sel_registerName("setOpaque:"), 0); + objc_msgSend(w->priv.window, + sel_registerName("setTitlebarAppearsTransparent:"), 1); } WEBVIEW_API void webview_dialog(struct webview *w, @@ -1956,57 +2083,76 @@ WEBVIEW_API void webview_dialog(struct webview *w, char *result, size_t resultsz) { if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN || dlgtype == WEBVIEW_DIALOG_TYPE_SAVE) { - NSSavePanel *panel; + id panel = (id)objc_getClass("NSSavePanel"); if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN) { - NSOpenPanel *openPanel = [NSOpenPanel openPanel]; + id openPanel = objc_msgSend((id)objc_getClass("NSOpenPanel"), + sel_registerName("openPanel")); if (flags & WEBVIEW_DIALOG_FLAG_DIRECTORY) { - [openPanel setCanChooseFiles:NO]; - [openPanel setCanChooseDirectories:YES]; + objc_msgSend(openPanel, sel_registerName("setCanChooseFiles:"), 0); + objc_msgSend(openPanel, sel_registerName("setCanChooseDirectories:"), + 1); } else { - [openPanel setCanChooseFiles:YES]; - [openPanel setCanChooseDirectories:NO]; + objc_msgSend(openPanel, sel_registerName("setCanChooseFiles:"), 1); + objc_msgSend(openPanel, sel_registerName("setCanChooseDirectories:"), + 0); } - [openPanel setResolvesAliases:NO]; - [openPanel setAllowsMultipleSelection:NO]; + objc_msgSend(openPanel, sel_registerName("setResolvesAliases:"), 0); + objc_msgSend(openPanel, sel_registerName("setAllowsMultipleSelection:"), + 0); panel = openPanel; } else { - panel = [NSSavePanel savePanel]; + panel = objc_msgSend((id)objc_getClass("NSSavePanel"), + sel_registerName("savePanel")); } - [panel setCanCreateDirectories:YES]; - [panel setShowsHiddenFiles:YES]; - [panel setExtensionHidden:NO]; - [panel setCanSelectHiddenExtension:NO]; - [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]; + + 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) { - NSAlert *a = [NSAlert new]; + id a = objc_msgSend((id)objc_getClass("NSAlert"), sel_registerName("new")); switch (flags & WEBVIEW_DIALOG_FLAG_ALERT_MASK) { case WEBVIEW_DIALOG_FLAG_INFO: - [a setAlertStyle:NSAlertStyleInformational]; + objc_msgSend(a, sel_registerName("setAlertStyle:"), + NSAlertStyleInformational); break; case WEBVIEW_DIALOG_FLAG_WARNING: - NSLog(@"warning"); - [a setAlertStyle:NSAlertStyleWarning]; + printf("Warning\n"); + objc_msgSend(a, sel_registerName("setAlertStyle:"), NSAlertStyleWarning); break; case WEBVIEW_DIALOG_FLAG_ERROR: - NSLog(@"error"); - [a setAlertStyle:NSAlertStyleCritical]; + printf("Error\n"); + objc_msgSend(a, sel_registerName("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]; + 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")); } } @@ -2029,8 +2175,14 @@ WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn, 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); } + +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); } #endif /* WEBVIEW_COCOA */