forked from LeenkxTeam/LNXRNT
469 lines
18 KiB
Plaintext
469 lines
18 KiB
Plaintext
|
|
#ifdef WITH_WEBVIEW
|
||
|
|
|
||
|
|
#include <kinc/global.h>
|
||
|
|
|
||
|
|
#ifdef KINC_MACOS
|
||
|
|
|
||
|
|
#import <WebKit/WebKit.h>
|
||
|
|
#import <AppKit/AppKit.h>
|
||
|
|
#include "webview.h"
|
||
|
|
#include <kinc/log.h>
|
||
|
|
#include <kinc/window.h>
|
||
|
|
|
||
|
|
@interface LNXRNTWebViewDelegate : NSObject <WKNavigationDelegate, WKScriptMessageHandler, NSWindowDelegate, WKUIDelegate> {
|
||
|
|
@public int webviewId;
|
||
|
|
@public bool isDetached;
|
||
|
|
@public NSWindow* detachedWindow;
|
||
|
|
}
|
||
|
|
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;
|
||
|
|
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;
|
||
|
|
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error;
|
||
|
|
- (BOOL)windowShouldClose:(NSWindow *)sender;
|
||
|
|
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;
|
||
|
|
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;
|
||
|
|
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *result))completionHandler;
|
||
|
|
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures;
|
||
|
|
- (void)webView:(WKWebView *)webView runOpenPanelWithParameters:(WKOpenPanelParameters *)parameters initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSArray<NSURL *> *URLs))completionHandler;
|
||
|
|
@end
|
||
|
|
|
||
|
|
@implementation LNXRNTWebViewDelegate
|
||
|
|
|
||
|
|
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
|
||
|
|
NSString *msgBody = [[message body] isKindOfClass:[NSString class]] ? [message body] : [NSString stringWithFormat:@"%@", [message body]];
|
||
|
|
const char *cstr = [msgBody UTF8String];
|
||
|
|
WebViewManager::instance().dispatchMessage(webviewId, std::string(cstr));
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
|
||
|
|
WebViewManager::instance().dispatchLoad(webviewId);
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
|
||
|
|
NSString *desc = [error localizedDescription];
|
||
|
|
WebViewManager::instance().dispatchError(webviewId, std::string([desc UTF8String]));
|
||
|
|
}
|
||
|
|
|
||
|
|
- (BOOL)windowShouldClose:(NSWindow *)sender {
|
||
|
|
WebViewManager::instance().dispatchClose(webviewId);
|
||
|
|
[sender orderOut:nil];
|
||
|
|
return NO;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
|
||
|
|
NSAlert *alert = [[NSAlert alloc] init];
|
||
|
|
[alert setMessageText:message];
|
||
|
|
[alert addButtonWithTitle:@"OK"];
|
||
|
|
[alert runModal];
|
||
|
|
completionHandler();
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
|
||
|
|
NSAlert *alert = [[NSAlert alloc] init];
|
||
|
|
[alert setMessageText:message];
|
||
|
|
[alert addButtonWithTitle:@"OK"];
|
||
|
|
[alert addButtonWithTitle:@"Cancel"];
|
||
|
|
NSModalResponse result = [alert runModal];
|
||
|
|
completionHandler(result == NSAlertFirstButtonReturn);
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *result))completionHandler {
|
||
|
|
NSAlert *alert = [[NSAlert alloc] init];
|
||
|
|
[alert setMessageText:prompt];
|
||
|
|
[alert addButtonWithTitle:@"OK"];
|
||
|
|
[alert addButtonWithTitle:@"Cancel"];
|
||
|
|
NSTextField *input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 250, 24)];
|
||
|
|
[input setStringValue:defaultText ? defaultText : @""];
|
||
|
|
[alert setAccessoryView:input];
|
||
|
|
NSModalResponse result = [alert runModal];
|
||
|
|
if (result == NSAlertFirstButtonReturn) {
|
||
|
|
completionHandler([input stringValue]);
|
||
|
|
} else {
|
||
|
|
completionHandler(nil);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {
|
||
|
|
if (!navigationAction.targetFrame.isMainFrame) {
|
||
|
|
return nil;
|
||
|
|
}
|
||
|
|
NSRect frame = NSMakeRect(100, 100, 800, 600);
|
||
|
|
NSUInteger styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
|
||
|
|
NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable;
|
||
|
|
NSWindow *newWindow = [[NSWindow alloc]
|
||
|
|
initWithContentRect:frame
|
||
|
|
styleMask:styleMask
|
||
|
|
backing:NSBackingStoreBuffered
|
||
|
|
defer:YES];
|
||
|
|
WKWebView *newWebView = [[WKWebView alloc] initWithFrame:frame configuration:configuration];
|
||
|
|
newWebView.navigationDelegate = self;
|
||
|
|
newWebView.UIDelegate = self;
|
||
|
|
[newWindow setContentView:newWebView];
|
||
|
|
[newWindow makeKeyAndOrderFront:nil];
|
||
|
|
return newWebView;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)webView:(WKWebView *)webView runOpenPanelWithParameters:(WKOpenPanelParameters *)parameters initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSArray<NSURL *> *URLs))completionHandler {
|
||
|
|
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
|
||
|
|
openPanel.allowsMultipleSelection = parameters.allowsMultipleSelection;
|
||
|
|
openPanel.canChooseDirectories = parameters.allowsDirectories;
|
||
|
|
if ([openPanel runModal] == NSModalResponseOK) {
|
||
|
|
completionHandler(openPanel.URLs);
|
||
|
|
} else {
|
||
|
|
completionHandler(nil);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
@end
|
||
|
|
|
||
|
|
struct MacWebViewState {
|
||
|
|
WKWebView* webView;
|
||
|
|
LNXRNTWebViewDelegate* delegate;
|
||
|
|
NSWindow* detachedWindow;
|
||
|
|
bool isDetached;
|
||
|
|
};
|
||
|
|
|
||
|
|
extern "C" NSWindow* kinc_get_mac_window_handle(int window_index);
|
||
|
|
|
||
|
|
int platformCreate(WebViewInstance* wv) {
|
||
|
|
auto* state = new MacWebViewState();
|
||
|
|
state->webView = nullptr;
|
||
|
|
state->delegate = nullptr;
|
||
|
|
state->detachedWindow = nullptr;
|
||
|
|
state->isDetached = (wv->parentWindow < 0);
|
||
|
|
wv->platformHandle = state;
|
||
|
|
|
||
|
|
WKWebViewConfiguration* config = [[WKWebViewConfiguration alloc] init];
|
||
|
|
|
||
|
|
WKUserContentController* contentController = [[WKUserContentController alloc] init];
|
||
|
|
state->delegate = [[LNXRNTWebViewDelegate alloc] init];
|
||
|
|
state->delegate->webviewId = wv->id;
|
||
|
|
state->delegate->isDetached = state->isDetached;
|
||
|
|
[contentController addScriptMessageHandler:state->delegate name:@"lnxrnt"];
|
||
|
|
config.userContentController = contentController;
|
||
|
|
|
||
|
|
CGFloat scale = 1.0;
|
||
|
|
if (!state->isDetached) {
|
||
|
|
NSWindow* kincWindow = kinc_get_mac_window_handle(wv->parentWindow);
|
||
|
|
if (kincWindow) {
|
||
|
|
scale = [kincWindow backingScaleFactor];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
CGFloat ptWidth = wv->width / scale;
|
||
|
|
CGFloat ptHeight = wv->height / scale;
|
||
|
|
NSRect frame = NSMakeRect(wv->x, wv->y, ptWidth, ptHeight);
|
||
|
|
state->webView = [[WKWebView alloc] initWithFrame:frame configuration:config];
|
||
|
|
state->webView.navigationDelegate = state->delegate;
|
||
|
|
state->webView.UIDelegate = state->delegate;
|
||
|
|
|
||
|
|
if (wv->transparent) {
|
||
|
|
[state->webView setValue:@NO forKey:@"opaque"];
|
||
|
|
[state->webView setValue:@NO forKey:@"drawsBackground"];
|
||
|
|
}
|
||
|
|
|
||
|
|
if (state->isDetached) {
|
||
|
|
NSUInteger styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
|
||
|
|
NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable;
|
||
|
|
state->detachedWindow = [[NSWindow alloc]
|
||
|
|
initWithContentRect:frame
|
||
|
|
styleMask:styleMask
|
||
|
|
backing:NSBackingStoreBuffered
|
||
|
|
defer:YES];
|
||
|
|
[state->detachedWindow setTitle:[NSString stringWithUTF8String:wv->title.c_str()]];
|
||
|
|
[state->detachedWindow setContentView:state->webView];
|
||
|
|
[state->detachedWindow setDelegate:state->delegate];
|
||
|
|
state->delegate->detachedWindow = state->detachedWindow;
|
||
|
|
} else {
|
||
|
|
NSWindow* kincWindow = kinc_get_mac_window_handle(wv->parentWindow);
|
||
|
|
if (!kincWindow) {
|
||
|
|
kinc_log(KINC_LOG_LEVEL_ERROR, "Failed to get Kinc NSWindow for webview window %d", wv->parentWindow);
|
||
|
|
[state->webView release];
|
||
|
|
[contentController release];
|
||
|
|
[state->delegate release];
|
||
|
|
delete state;
|
||
|
|
wv->platformHandle = nullptr;
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
NSView* contentView = [kincWindow contentView];
|
||
|
|
CGFloat flippedY = [contentView frame].size.height - wv->y - ptHeight;
|
||
|
|
[state->webView setFrameOrigin:NSMakePoint(wv->x, flippedY)];
|
||
|
|
[contentView addSubview:state->webView positioned:NSWindowAbove relativeTo:nil];
|
||
|
|
}
|
||
|
|
|
||
|
|
return wv->id;
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformDestroy(WebViewInstance* wv) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state) return;
|
||
|
|
|
||
|
|
if (state->webView) {
|
||
|
|
[state->webView removeFromSuperview];
|
||
|
|
[state->webView release];
|
||
|
|
}
|
||
|
|
if (state->detachedWindow) {
|
||
|
|
[state->detachedWindow close];
|
||
|
|
}
|
||
|
|
if (state->delegate) {
|
||
|
|
[state->delegate release];
|
||
|
|
}
|
||
|
|
delete state;
|
||
|
|
wv->platformHandle = nullptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformLoadHTML(WebViewInstance* wv, const std::string& html) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->webView) return;
|
||
|
|
NSString* nsHtml = [NSString stringWithUTF8String:html.c_str()];
|
||
|
|
[state->webView loadHTMLString:nsHtml baseURL:nil];
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformLoadURL(WebViewInstance* wv, const std::string& url) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->webView) return;
|
||
|
|
NSString* nsUrl = [NSString stringWithUTF8String:url.c_str()];
|
||
|
|
NSURL* nsURL = [NSURL URLWithString:nsUrl];
|
||
|
|
[state->webView loadRequest:[NSURLRequest requestWithURL:nsURL]];
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformEvalJS(WebViewInstance* wv, const std::string& js) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->webView) return;
|
||
|
|
NSString* nsJs = [NSString stringWithUTF8String:js.c_str()];
|
||
|
|
[state->webView evaluateJavaScript:nsJs completionHandler:nil];
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformEvalJSAsync(WebViewInstance* wv, const std::string& js) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->webView) return;
|
||
|
|
NSString* nsJs = [NSString stringWithUTF8String:js.c_str()];
|
||
|
|
int webviewId = wv->id;
|
||
|
|
[state->webView evaluateJavaScript:nsJs completionHandler:^(id result, NSError* error) {
|
||
|
|
std::string resultStr;
|
||
|
|
if (error) {
|
||
|
|
resultStr = "null";
|
||
|
|
} else if (result == nil) {
|
||
|
|
resultStr = "null";
|
||
|
|
} else if ([result isKindOfClass:[NSString class]]) {
|
||
|
|
resultStr = std::string([[result description] UTF8String]);
|
||
|
|
} else if ([result isKindOfClass:[NSNumber class]]) {
|
||
|
|
resultStr = std::string([[result description] UTF8String]);
|
||
|
|
} else {
|
||
|
|
NSError* jsonErr = nil;
|
||
|
|
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:result options:0 error:&jsonErr];
|
||
|
|
if (jsonData && !jsonErr) {
|
||
|
|
NSString* jsonStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||
|
|
resultStr = std::string([jsonStr UTF8String]);
|
||
|
|
} else {
|
||
|
|
resultStr = std::string([[result description] UTF8String]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
WebViewManager::instance().dispatchEvalResult(webviewId, resultStr);
|
||
|
|
}];
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformShow(WebViewInstance* wv) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state) return;
|
||
|
|
if (state->isDetached && state->detachedWindow) {
|
||
|
|
[state->detachedWindow makeKeyAndOrderFront:nil];
|
||
|
|
} else if (state->webView) {
|
||
|
|
[state->webView setHidden:NO];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformHide(WebViewInstance* wv) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state) return;
|
||
|
|
if (state->isDetached && state->detachedWindow) {
|
||
|
|
[state->detachedWindow orderOut:nil];
|
||
|
|
} else if (state->webView) {
|
||
|
|
[state->webView setHidden:YES];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformResize(WebViewInstance* wv, int width, int height) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->webView) return;
|
||
|
|
|
||
|
|
if (state->isDetached && state->detachedWindow) {
|
||
|
|
NSRect frame = NSMakeRect(wv->x, wv->y, width, height);
|
||
|
|
[state->detachedWindow setFrame:frame display:YES];
|
||
|
|
} else {
|
||
|
|
NSView* superview = [state->webView superview];
|
||
|
|
CGFloat scale = [[superview window] backingScaleFactor];
|
||
|
|
if (scale == 0) scale = 1.0;
|
||
|
|
CGFloat ptW = width / scale;
|
||
|
|
CGFloat ptH = height / scale;
|
||
|
|
if (superview) {
|
||
|
|
CGFloat flippedY = [superview frame].size.height - wv->y - ptH;
|
||
|
|
[state->webView setFrame:NSMakeRect(wv->x, flippedY, ptW, ptH)];
|
||
|
|
} else {
|
||
|
|
[state->webView setFrameSize:NSMakeSize(ptW, ptH)];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformMove(WebViewInstance* wv, int x, int y) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->webView) return;
|
||
|
|
|
||
|
|
if (state->isDetached && state->detachedWindow) {
|
||
|
|
[state->detachedWindow setFrameOrigin:NSMakePoint(x, y)];
|
||
|
|
} else {
|
||
|
|
NSView* superview = [state->webView superview];
|
||
|
|
if (superview) {
|
||
|
|
CGFloat scale = [[superview window] backingScaleFactor];
|
||
|
|
if (scale == 0) scale = 1.0;
|
||
|
|
CGFloat ptH = wv->height / scale;
|
||
|
|
CGFloat flippedY = [superview frame].size.height - y - ptH;
|
||
|
|
[state->webView setFrameOrigin:NSMakePoint(x, flippedY)];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformSetTransparent(WebViewInstance* wv, bool transparent) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->webView) return;
|
||
|
|
[state->webView setValue:(transparent ? @NO : @YES) forKey:@"opaque"];
|
||
|
|
[state->webView setValue:(transparent ? @NO : @YES) forKey:@"drawsBackground"];
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformSetClickThrough(WebViewInstance* wv, bool enabled) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->webView) return;
|
||
|
|
if (enabled) {
|
||
|
|
[state->webView setAcceptsTouchEvents:NO];
|
||
|
|
[state->webView evaluateJavaScript:
|
||
|
|
@"document.body.style.pointerEvents = 'none';"
|
||
|
|
completionHandler:nil];
|
||
|
|
} else {
|
||
|
|
[state->webView setAcceptsTouchEvents:YES];
|
||
|
|
[state->webView evaluateJavaScript:
|
||
|
|
@"document.body.style.pointerEvents = 'auto';"
|
||
|
|
completionHandler:nil];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformSetTitle(WebViewInstance* wv, const std::string& title) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->isDetached || !state->detachedWindow) return;
|
||
|
|
[state->detachedWindow setTitle:[NSString stringWithUTF8String:title.c_str()]];
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformSend(WebViewInstance* wv, const std::string& message) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->webView) return;
|
||
|
|
NSString* escaped = [[NSString stringWithUTF8String:message.c_str()]
|
||
|
|
stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"];
|
||
|
|
escaped = [escaped stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"];
|
||
|
|
escaped = [escaped stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"];
|
||
|
|
escaped = [escaped stringByReplacingOccurrencesOfString:@"\r" withString:@"\\r"];
|
||
|
|
NSString* js = [NSString stringWithFormat:
|
||
|
|
@"if(window.__lnxrntOnMessage)window.__lnxrntOnMessage('%@');", escaped];
|
||
|
|
[state->webView evaluateJavaScript:js completionHandler:nil];
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformGoBack(WebViewInstance* wv) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->webView) return;
|
||
|
|
if ([state->webView canGoBack]) [state->webView goBack];
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformGoForward(WebViewInstance* wv) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->webView) return;
|
||
|
|
if ([state->webView canGoForward]) [state->webView goForward];
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformReload(WebViewInstance* wv) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->webView) return;
|
||
|
|
[state->webView reload];
|
||
|
|
}
|
||
|
|
|
||
|
|
bool platformCanGoBack(WebViewInstance* wv) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->webView) return false;
|
||
|
|
return [state->webView canGoBack];
|
||
|
|
}
|
||
|
|
|
||
|
|
bool platformCanGoForward(WebViewInstance* wv) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->webView) return false;
|
||
|
|
return [state->webView canGoForward];
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string platformGetURL(WebViewInstance* wv) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->webView) return "";
|
||
|
|
NSString* url = [state->webView.URL absoluteString];
|
||
|
|
return url ? std::string([url UTF8String]) : "";
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string platformGetTitle(WebViewInstance* wv) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->webView) return "";
|
||
|
|
NSString* title = [state->webView title];
|
||
|
|
return title ? std::string([title UTF8String]) : "";
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformMinimize(WebViewInstance* wv) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->isDetached || !state->detachedWindow) return;
|
||
|
|
[state->detachedWindow miniaturize:nil];
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformMaximize(WebViewInstance* wv) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->isDetached || !state->detachedWindow) return;
|
||
|
|
[state->detachedWindow zoom:nil];
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformRestore(WebViewInstance* wv) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->isDetached || !state->detachedWindow) return;
|
||
|
|
if ([state->detachedWindow isMiniaturized]) [state->detachedWindow deminiaturize:nil];
|
||
|
|
if ([state->detachedWindow isZoomed]) [state->detachedWindow zoom:nil];
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformSetFullscreen(WebViewInstance* wv, bool fullscreen) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->isDetached || !state->detachedWindow) return;
|
||
|
|
if (fullscreen) {
|
||
|
|
[state->detachedWindow toggleFullScreen:nil];
|
||
|
|
} else {
|
||
|
|
if (([state->detachedWindow styleMask] & NSWindowStyleMaskFullScreen) != 0) {
|
||
|
|
[state->detachedWindow toggleFullScreen:nil];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool platformIsFullscreen(WebViewInstance* wv) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->isDetached || !state->detachedWindow) return false;
|
||
|
|
return ([state->detachedWindow styleMask] & NSWindowStyleMaskFullScreen) != 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformEnableDevTools(WebViewInstance* wv, bool enabled) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->webView) return;
|
||
|
|
[state->webView.configuration.preferences setValue:@(enabled) forKey:@"developerExtrasEnabled"];
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformSetContextMenuEnabled(WebViewInstance* wv, bool enabled) {
|
||
|
|
auto* state = (MacWebViewState*)wv->platformHandle;
|
||
|
|
if (!state || !state->webView) return;
|
||
|
|
if (!enabled) {
|
||
|
|
NSString* js = @"document.addEventListener('contextmenu', function(e){e.preventDefault();}, true);";
|
||
|
|
[state->webView evaluateJavaScript:js completionHandler:nil];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void platformTick() {
|
||
|
|
// WKWebView callbacks are in NSRunLoop already integrated with Kinc loop.
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif
|
||
|
|
#endif
|