Skip to content

Commit

Permalink
fix: Use new prototypes for objc_msgSend (#432)
Browse files Browse the repository at this point in the history
  • Loading branch information
rajivshah3 committed Jan 22, 2021
1 parent 0f8224c commit 7b1b723
Showing 1 changed file with 112 additions and 65 deletions.
177 changes: 112 additions & 65 deletions webview.h
Expand Up @@ -553,7 +553,6 @@ using browser_engine = gtk_webkit_engine;
// ====================================================================
//

#define OBJC_OLD_DISPATCH_PROTOTYPES 1
#include <CoreGraphics/CoreGraphics.h>
#include <objc/objc-runtime.h>

Expand All @@ -574,16 +573,18 @@ namespace webview {
id operator"" _cls(const char *s, std::size_t) { return (id)objc_getClass(s); }
SEL operator"" _sel(const char *s, std::size_t) { return sel_registerName(s); }
id operator"" _str(const char *s, std::size_t) {
return objc_msgSend("NSString"_cls, "stringWithUTF8String:"_sel, s);
return ((id(*)(id, SEL, const char *))objc_msgSend)(
"NSString"_cls, "stringWithUTF8String:"_sel, s);
}

class cocoa_wkwebview_engine {
public:
cocoa_wkwebview_engine(bool debug, void *window) {
// Application
id app = objc_msgSend("NSApplication"_cls, "sharedApplication"_sel);
objc_msgSend(app, "setActivationPolicy:"_sel,
NSApplicationActivationPolicyRegular);
id app = ((id(*)(id, SEL))objc_msgSend)("NSApplication"_cls,
"sharedApplication"_sel);
((void (*)(id, SEL, long))objc_msgSend)(
app, "setActivationPolicy:"_sel, NSApplicationActivationPolicyRegular);

// Delegate
auto cls =
Expand All @@ -597,73 +598,109 @@ class cocoa_wkwebview_engine {
(cocoa_wkwebview_engine *)objc_getAssociatedObject(
self, "webview");
assert(w);
w->on_message((const char *)objc_msgSend(
objc_msgSend(msg, "body"_sel), "UTF8String"_sel));
w->on_message(((const char *(*)(id, SEL))objc_msgSend)(
((id(*)(id, SEL))objc_msgSend)(msg, "body"_sel),
"UTF8String"_sel));
}),
"v@:@@");
objc_registerClassPair(cls);

auto delegate = objc_msgSend((id)cls, "new"_sel);
auto delegate = ((id(*)(id, SEL))objc_msgSend)((id)cls, "new"_sel);
objc_setAssociatedObject(delegate, "webview", (id)this,
OBJC_ASSOCIATION_ASSIGN);
objc_msgSend(app, sel_registerName("setDelegate:"), delegate);
((void (*)(id, SEL, id))objc_msgSend)(app, sel_registerName("setDelegate:"),
delegate);

// Main window
if (window == nullptr) {
m_window = objc_msgSend("NSWindow"_cls, "alloc"_sel);
m_window = objc_msgSend(
m_window, "initWithContentRect:styleMask:backing:defer:"_sel,
CGRectMake(0, 0, 0, 0), 0, NSBackingStoreBuffered, 0);
m_window = ((id(*)(id, SEL))objc_msgSend)("NSWindow"_cls, "alloc"_sel);
m_window =
((id(*)(id, SEL, CGRect, int, unsigned long, int))objc_msgSend)(
m_window, "initWithContentRect:styleMask:backing:defer:"_sel,
CGRectMake(0, 0, 0, 0), 0, NSBackingStoreBuffered, 0);
} else {
m_window = (id)window;
}

// Webview
auto config = objc_msgSend("WKWebViewConfiguration"_cls, "new"_sel);
m_manager = objc_msgSend(config, "userContentController"_sel);
m_webview = objc_msgSend("WKWebView"_cls, "alloc"_sel);
auto config =
((id(*)(id, SEL))objc_msgSend)("WKWebViewConfiguration"_cls, "new"_sel);
m_manager =
((id(*)(id, SEL))objc_msgSend)(config, "userContentController"_sel);
m_webview = ((id(*)(id, SEL))objc_msgSend)("WKWebView"_cls, "alloc"_sel);

if (debug) {
objc_msgSend(objc_msgSend(config, "preferences"_sel),
"setValue:forKey:"_sel,
objc_msgSend("NSNumber"_cls, "numberWithBool:"_sel, 1),
"developerExtrasEnabled"_str);
// Equivalent Obj-C:
// [[config preferences] setValue:@YES forKey:@"developerExtrasEnabled"];
((id(*)(id, SEL, id, id))objc_msgSend)(
((id(*)(id, SEL))objc_msgSend)(config, "preferences"_sel),
"setValue:forKey:"_sel,
((id(*)(id, SEL, BOOL))objc_msgSend)("NSNumber"_cls,
"numberWithBool:"_sel, 1),
"developerExtrasEnabled"_str);
}
objc_msgSend(objc_msgSend(config, "preferences"_sel),
"setValue:forKey:"_sel,
objc_msgSend("NSNumber"_cls, "numberWithBool:"_sel, 1),
"fullScreenEnabled"_str);
objc_msgSend(objc_msgSend(config, "preferences"_sel),
"setValue:forKey:"_sel,
objc_msgSend("NSNumber"_cls, "numberWithBool:"_sel, 1),
"javaScriptCanAccessClipboard"_str);
objc_msgSend(objc_msgSend(config, "preferences"_sel),
"setValue:forKey:"_sel,
objc_msgSend("NSNumber"_cls, "numberWithBool:"_sel, 1),
"DOMPasteAllowed"_str);
objc_msgSend(m_webview, "initWithFrame:configuration:"_sel,
CGRectMake(0, 0, 0, 0), config);
objc_msgSend(m_manager, "addScriptMessageHandler:name:"_sel, delegate,
"external"_str);

// Equivalent Obj-C:
// [[config preferences] setValue:@YES forKey:@"fullScreenEnabled"];
((id(*)(id, SEL, id, id))objc_msgSend)(
((id(*)(id, SEL))objc_msgSend)(config, "preferences"_sel),
"setValue:forKey:"_sel,
((id(*)(id, SEL, BOOL))objc_msgSend)("NSNumber"_cls,
"numberWithBool:"_sel, 1),
"fullScreenEnabled"_str);

// Equivalent Obj-C:
// [[config preferences] setValue:@YES forKey:@"javaScriptCanAccessClipboard"];
((id(*)(id, SEL, id, id))objc_msgSend)(
((id(*)(id, SEL))objc_msgSend)(config, "preferences"_sel),
"setValue:forKey:"_sel,
((id(*)(id, SEL, BOOL))objc_msgSend)("NSNumber"_cls,
"numberWithBool:"_sel, 1),
"javaScriptCanAccessClipboard"_str);

// Equivalent Obj-C:
// [[config preferences] setValue:@YES forKey:@"DOMPasteAllowed"];
((id(*)(id, SEL, id, id))objc_msgSend)(
((id(*)(id, SEL))objc_msgSend)(config, "preferences"_sel),
"setValue:forKey:"_sel,
((id(*)(id, SEL, BOOL))objc_msgSend)("NSNumber"_cls,
"numberWithBool:"_sel, 1),
"DOMPasteAllowed"_str);

((void (*)(id, SEL, CGRect, id))objc_msgSend)(
m_webview, "initWithFrame:configuration:"_sel, CGRectMake(0, 0, 0, 0),
config);
((void (*)(id, SEL, id, id))objc_msgSend)(
m_manager, "addScriptMessageHandler:name:"_sel, delegate,
"external"_str);

init(R"script(
window.external = {
invoke: function(s) {
window.webkit.messageHandlers.external.postMessage(s);
},
};
)script");
objc_msgSend(m_window, "setContentView:"_sel, m_webview);
objc_msgSend(m_window, "makeKeyAndOrderFront:"_sel, nullptr);
((void (*)(id, SEL, id))objc_msgSend)(m_window, "setContentView:"_sel,
m_webview);
((void (*)(id, SEL, id))objc_msgSend)(m_window, "makeKeyAndOrderFront:"_sel,
nullptr);
}
~cocoa_wkwebview_engine() { close(); }
void *window() { return (void *)m_window; }
void terminate() {
close();
objc_msgSend("NSApp"_cls, "terminate:"_sel, nullptr);
((void (*)(id, SEL, id))objc_msgSend)("NSApp"_cls, "terminate:"_sel,
nullptr);
}
void run() {
id app = objc_msgSend("NSApplication"_cls, "sharedApplication"_sel);
dispatch([&]() { objc_msgSend(app, "activateIgnoringOtherApps:"_sel, 1); });
objc_msgSend(app, "run"_sel);
id app = ((id(*)(id, SEL))objc_msgSend)("NSApplication"_cls,
"sharedApplication"_sel);
dispatch([&]() {
((void (*)(id, SEL, BOOL))objc_msgSend)(
app, "activateIgnoringOtherApps:"_sel, 1);
});
((void (*)(id, SEL))objc_msgSend)(app, "run"_sel);
}
void dispatch(std::function<void()> f) {
dispatch_async_f(dispatch_get_main_queue(), new dispatch_fn_t(f),
Expand All @@ -674,56 +711,66 @@ class cocoa_wkwebview_engine {
}));
}
void set_title(const std::string title) {
objc_msgSend(m_window, "setTitle:"_sel,
objc_msgSend("NSString"_cls, "stringWithUTF8String:"_sel,
title.c_str()));
((void (*)(id, SEL, id))objc_msgSend)(
m_window, "setTitle:"_sel,
((id(*)(id, SEL, const char *))objc_msgSend)(
"NSString"_cls, "stringWithUTF8String:"_sel, title.c_str()));
}
void set_size(int width, int height, int hints) {
auto style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
NSWindowStyleMaskMiniaturizable;
if (hints != WEBVIEW_HINT_FIXED) {
style = style | NSWindowStyleMaskResizable;
}
objc_msgSend(m_window, "setStyleMask:"_sel, style);
((void (*)(id, SEL, unsigned long))objc_msgSend)(
m_window, "setStyleMask:"_sel, style);

if (hints == WEBVIEW_HINT_MIN) {
objc_msgSend(m_window, "setContentMinSize:"_sel,
CGSizeMake(width, height));
((void (*)(id, SEL, CGSize))objc_msgSend)(
m_window, "setContentMinSize:"_sel, CGSizeMake(width, height));
} else if (hints == WEBVIEW_HINT_MAX) {
objc_msgSend(m_window, "setContentMaxSize:"_sel,
CGSizeMake(width, height));
((void (*)(id, SEL, CGSize))objc_msgSend)(
m_window, "setContentMaxSize:"_sel, CGSizeMake(width, height));
} else {
objc_msgSend(m_window, "setFrame:display:animate:"_sel,
CGRectMake(0, 0, width, height), 1, 0);
((void (*)(id, SEL, CGRect, BOOL, BOOL))objc_msgSend)(
m_window, "setFrame:display:animate:"_sel,
CGRectMake(0, 0, width, height), 1, 0);
}
}
void navigate(const std::string url) {
auto nsurl = objc_msgSend(
auto nsurl = ((id(*)(id, SEL, id))objc_msgSend)(
"NSURL"_cls, "URLWithString:"_sel,
objc_msgSend("NSString"_cls, "stringWithUTF8String:"_sel, url.c_str()));
objc_msgSend(
((id(*)(id, SEL, const char *))objc_msgSend)(
"NSString"_cls, "stringWithUTF8String:"_sel, url.c_str()));

((void (*)(id, SEL, id))objc_msgSend)(
m_webview, "loadRequest:"_sel,
objc_msgSend("NSURLRequest"_cls, "requestWithURL:"_sel, nsurl));
((id(*)(id, SEL, id))objc_msgSend)("NSURLRequest"_cls,
"requestWithURL:"_sel, nsurl));
}
void init(const std::string js) {
objc_msgSend(
// Equivalent Obj-C:
// [m_manager addUserScript:[[WKUserScript alloc] initWithSource:[NSString stringWithUTF8String:js.c_str()] injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES]]
((void (*)(id, SEL, id))objc_msgSend)(
m_manager, "addUserScript:"_sel,
objc_msgSend(objc_msgSend("WKUserScript"_cls, "alloc"_sel),
"initWithSource:injectionTime:forMainFrameOnly:"_sel,
objc_msgSend("NSString"_cls, "stringWithUTF8String:"_sel,
js.c_str()),
WKUserScriptInjectionTimeAtDocumentStart, 1));
((id(*)(id, SEL, id, long, BOOL))objc_msgSend)(
((id(*)(id, SEL))objc_msgSend)("WKUserScript"_cls, "alloc"_sel),
"initWithSource:injectionTime:forMainFrameOnly:"_sel,
((id(*)(id, SEL, const char *))objc_msgSend)(
"NSString"_cls, "stringWithUTF8String:"_sel, js.c_str()),
WKUserScriptInjectionTimeAtDocumentStart, 1));
}
void eval(const std::string js) {
objc_msgSend(
((void (*)(id, SEL, id, id))objc_msgSend)(
m_webview, "evaluateJavaScript:completionHandler:"_sel,
objc_msgSend("NSString"_cls, "stringWithUTF8String:"_sel, js.c_str()),
((id(*)(id, SEL, const char *))objc_msgSend)(
"NSString"_cls, "stringWithUTF8String:"_sel, js.c_str()),
nullptr);
}

private:
virtual void on_message(const std::string msg) = 0;
void close() { objc_msgSend(m_window, "close"_sel); }
void close() { ((void (*)(id, SEL))objc_msgSend)(m_window, "close"_sel); }
id m_window;
id m_webview;
id m_manager;
Expand Down

0 comments on commit 7b1b723

Please sign in to comment.