1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-22 01:34:21 +00:00

WebBrowserComponent: Tidy up macOS implementation

This commit is contained in:
reuk 2022-07-28 11:22:26 +01:00
parent 41ef5b7fd5
commit 97971cd4b4
No known key found for this signature in database
GPG key ID: FCB43929F012EE5C

View file

@ -113,58 +113,119 @@ struct WebViewKeyEquivalentResponder : public ObjCClass<WebViewClass>
WebViewKeyEquivalentResponder()
: ObjCClass<WebViewClass> ("WebViewKeyEquivalentResponder_")
{
ObjCClass<WebViewClass>::addMethod (@selector (performKeyEquivalent:), performKeyEquivalent);
ObjCClass<WebViewClass>::registerClass();
}
this->addMethod (@selector (performKeyEquivalent:),
[] (id self, SEL selector, NSEvent* event)
{
const auto isCommandDown = [event]
{
const auto modifierFlags = [event modifierFlags];
private:
static BOOL performKeyEquivalent (id self, SEL selector, NSEvent* event)
{
const auto isCommandDown = [event]
{
const auto modifierFlags = [event modifierFlags];
if (@available (macOS 10.12, *))
return (modifierFlags & NSEventModifierFlagDeviceIndependentFlagsMask) == NSEventModifierFlagCommand;
if (@available (macOS 10.12, *))
return (modifierFlags & NSEventModifierFlagDeviceIndependentFlagsMask) == NSEventModifierFlagCommand;
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
return (modifierFlags & NSDeviceIndependentModifierFlagsMask) == NSCommandKeyMask;
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
}();
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
return (modifierFlags & NSDeviceIndependentModifierFlagsMask) == NSCommandKeyMask;
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
}();
if (isCommandDown)
{
auto sendAction = [&] (SEL actionSelector) -> BOOL
{
return [NSApp sendAction:actionSelector
to:[[self window] firstResponder]
from:self];
};
if (isCommandDown)
{
auto sendAction = [&] (SEL actionSelector) -> BOOL
{
return [NSApp sendAction: actionSelector
to: [[self window] firstResponder]
from: self];
};
if ([[event charactersIgnoringModifiers] isEqualToString:@"x"])
return sendAction (@selector (cut:));
if ([[event charactersIgnoringModifiers] isEqualToString:@"c"])
return sendAction (@selector (copy:));
if ([[event charactersIgnoringModifiers] isEqualToString:@"v"])
return sendAction (@selector (paste:));
if ([[event charactersIgnoringModifiers] isEqualToString:@"a"])
return sendAction (@selector (selectAll:));
}
if ([[event charactersIgnoringModifiers] isEqualToString: @"x"]) return sendAction (@selector (cut:));
if ([[event charactersIgnoringModifiers] isEqualToString: @"c"]) return sendAction (@selector (copy:));
if ([[event charactersIgnoringModifiers] isEqualToString: @"v"]) return sendAction (@selector (paste:));
if ([[event charactersIgnoringModifiers] isEqualToString: @"a"]) return sendAction (@selector (selectAll:));
}
return ObjCClass<WebViewClass>::template sendSuperclassMessage<BOOL> (self, selector, event);
return ObjCClass<WebViewClass>::template sendSuperclassMessage<BOOL> (self, selector, event);
});
this->registerClass();
}
};
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
struct DownloadClickDetectorClass : public ObjCClass<NSObject>
{
DownloadClickDetectorClass() : ObjCClass<NSObject> ("JUCEWebClickDetector_")
DownloadClickDetectorClass() : ObjCClass ("JUCEWebClickDetector_")
{
addIvar<WebBrowserComponent*> ("owner");
addMethod (@selector (webView:decidePolicyForNavigationAction:request:frame:decisionListener:), decidePolicyForNavigationAction);
addMethod (@selector (webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener:), decidePolicyForNewWindowAction);
addMethod (@selector (webView:didFinishLoadForFrame:), didFinishLoadForFrame);
addMethod (@selector (webView:didFailLoadWithError:forFrame:), didFailLoadWithError);
addMethod (@selector (webView:didFailProvisionalLoadWithError:forFrame:), didFailLoadWithError);
addMethod (@selector (webView:willCloseFrame:), willCloseFrame);
addMethod (@selector (webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:), runOpenPanel);
addMethod (@selector (webView:didFailLoadWithError:forFrame:), didFailLoadWithError);
addMethod (@selector (webView:didFailProvisionalLoadWithError:forFrame:), didFailLoadWithError);
addMethod (@selector (webView:decidePolicyForNavigationAction:request:frame:decisionListener:),
[] (id self, SEL, WebView*, NSDictionary* actionInformation, NSURLRequest*, WebFrame*, id<WebPolicyDecisionListener> listener)
{
if (getOwner (self)->pageAboutToLoad (getOriginalURL (actionInformation)))
[listener use];
else
[listener ignore];
});
addMethod (@selector (webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener:),
[] (id self, SEL, WebView*, NSDictionary* actionInformation, NSURLRequest*, NSString*, id<WebPolicyDecisionListener> listener)
{
getOwner (self)->newWindowAttemptingToLoad (getOriginalURL (actionInformation));
[listener ignore];
});
addMethod (@selector (webView:didFinishLoadForFrame:),
[] (id self, SEL, WebView* sender, WebFrame* frame)
{
if ([frame isEqual:[sender mainFrame]])
{
NSURL* url = [[[frame dataSource] request] URL];
getOwner (self)->pageFinishedLoading (nsStringToJuce ([url absoluteString]));
}
});
addMethod (@selector (webView:willCloseFrame:),
[] (id self, SEL, WebView*, WebFrame*)
{
getOwner (self)->windowCloseRequest();
});
addMethod (@selector (webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:),
[] (id, SEL, WebView*, id<WebOpenPanelResultListener> resultListener, BOOL allowMultipleFiles)
{
struct DeletedFileChooserWrapper : private DeletedAtShutdown
{
DeletedFileChooserWrapper (std::unique_ptr<FileChooser> fc, id<WebOpenPanelResultListener> rl)
: chooser (std::move (fc)), listener (rl)
{
[listener.get() retain];
}
std::unique_ptr<FileChooser> chooser;
ObjCObjectHandle<id<WebOpenPanelResultListener>> listener;
};
auto chooser = std::make_unique<FileChooser> (TRANS ("Select the file you want to upload..."),
File::getSpecialLocation (File::userHomeDirectory),
"*");
auto* wrapper = new DeletedFileChooserWrapper (std::move (chooser), resultListener);
auto flags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles
| (allowMultipleFiles ? FileBrowserComponent::canSelectMultipleItems : 0);
wrapper->chooser->launchAsync (flags, [wrapper] (const FileChooser&)
{
for (auto& f : wrapper->chooser->getResults())
[wrapper->listener.get() chooseFilename: juceStringToNS (f.getFullPathName())];
delete wrapper;
});
});
registerClass();
}
@ -181,31 +242,6 @@ private:
return {};
}
static void decidePolicyForNavigationAction (id self, SEL, WebView*, NSDictionary* actionInformation,
NSURLRequest*, WebFrame*, id<WebPolicyDecisionListener> listener)
{
if (getOwner (self)->pageAboutToLoad (getOriginalURL (actionInformation)))
[listener use];
else
[listener ignore];
}
static void decidePolicyForNewWindowAction (id self, SEL, WebView*, NSDictionary* actionInformation,
NSURLRequest*, NSString*, id<WebPolicyDecisionListener> listener)
{
getOwner (self)->newWindowAttemptingToLoad (getOriginalURL (actionInformation));
[listener ignore];
}
static void didFinishLoadForFrame (id self, SEL, WebView* sender, WebFrame* frame)
{
if ([frame isEqual: [sender mainFrame]])
{
NSURL* url = [[[frame dataSource] request] URL];
getOwner (self)->pageFinishedLoading (nsStringToJuce ([url absoluteString]));
}
}
static void didFailLoadWithError (id self, SEL, WebView* sender, NSError* error, WebFrame* frame)
{
if ([frame isEqual: [sender mainFrame]] && error != nullptr && [error code] != NSURLErrorCancelled)
@ -218,62 +254,122 @@ private:
getOwner (self)->goToURL ("data:text/plain;charset=UTF-8," + errorString);
}
}
static void willCloseFrame (id self, SEL, WebView*, WebFrame*)
{
getOwner (self)->windowCloseRequest();
}
static void runOpenPanel (id, SEL, WebView*, id<WebOpenPanelResultListener> resultListener, BOOL allowMultipleFiles)
{
struct DeletedFileChooserWrapper : private DeletedAtShutdown
{
DeletedFileChooserWrapper (std::unique_ptr<FileChooser> fc, id<WebOpenPanelResultListener> rl)
: chooser (std::move (fc)), listener (rl)
{
[listener.get() retain];
}
std::unique_ptr<FileChooser> chooser;
ObjCObjectHandle<id<WebOpenPanelResultListener>> listener;
};
auto chooser = std::make_unique<FileChooser> (TRANS("Select the file you want to upload..."),
File::getSpecialLocation (File::userHomeDirectory), "*");
auto* wrapper = new DeletedFileChooserWrapper (std::move (chooser), resultListener);
auto flags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles
| (allowMultipleFiles ? FileBrowserComponent::canSelectMultipleItems : 0);
wrapper->chooser->launchAsync (flags, [wrapper] (const FileChooser&)
{
for (auto& f : wrapper->chooser->getResults())
[wrapper->listener.get() chooseFilename: juceStringToNS (f.getFullPathName())];
delete wrapper;
});
}
};
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
#endif
struct API_AVAILABLE (macos (10.10)) WebViewDelegateClass : public ObjCClass<NSObject>
{
WebViewDelegateClass() : ObjCClass<NSObject> ("JUCEWebViewDelegate_")
WebViewDelegateClass() : ObjCClass ("JUCEWebViewDelegate_")
{
addIvar<WebBrowserComponent*> ("owner");
addMethod (@selector (webView:decidePolicyForNavigationAction:decisionHandler:), decidePolicyForNavigationAction);
addMethod (@selector (webView:didFinishNavigation:), didFinishNavigation);
addMethod (@selector (webView:didFailNavigation:withError:), didFailNavigation);
addMethod (@selector (webView:didFailProvisionalNavigation:withError:), didFailProvisionalNavigation);
addMethod (@selector (webViewDidClose:), webViewDidClose);
addMethod (@selector (webView:createWebViewWithConfiguration:forNavigationAction:
windowFeatures:), createWebView);
addMethod (@selector (webView:decidePolicyForNavigationAction:decisionHandler:),
[] (id self, SEL, WKWebView*, WKNavigationAction* navigationAction, void (^decisionHandler) (WKNavigationActionPolicy))
{
if (getOwner (self)->pageAboutToLoad (nsStringToJuce ([[[navigationAction request] URL] absoluteString])))
decisionHandler (WKNavigationActionPolicyAllow);
else
decisionHandler (WKNavigationActionPolicyCancel);
});
addMethod (@selector (webView:didFinishNavigation:),
[] (id self, SEL, WKWebView* webview, WKNavigation*)
{
getOwner (self)->pageFinishedLoading (nsStringToJuce ([[webview URL] absoluteString]));
});
addMethod (@selector (webView:didFailNavigation:withError:),
[] (id self, SEL, WKWebView*, WKNavigation*, NSError* error)
{
displayError (getOwner (self), error);
});
addMethod (@selector (webView:didFailProvisionalNavigation:withError:),
[] (id self, SEL, WKWebView*, WKNavigation*, NSError* error)
{
displayError (getOwner (self), error);
});
addMethod (@selector (webViewDidClose:),
[] (id self, SEL, WKWebView*)
{
getOwner (self)->windowCloseRequest();
});
addMethod (@selector (webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:),
[] (id self, SEL, WKWebView*, WKWebViewConfiguration*, WKNavigationAction* navigationAction, WKWindowFeatures*)
{
getOwner (self)->newWindowAttemptingToLoad (nsStringToJuce ([[[navigationAction request] URL] absoluteString]));
return nil;
});
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
if (@available (macOS 10.12, *))
addMethod (@selector (webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:), runOpenPanel);
{
addMethod (@selector (webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:),
[] (id, SEL, WKWebView*, WKOpenPanelParameters* parameters, WKFrameInfo*, void (^completionHandler)(NSArray<NSURL*>*))
{
using CompletionHandlerType = decltype (completionHandler);
class DeletedFileChooserWrapper : private DeletedAtShutdown
{
public:
DeletedFileChooserWrapper (std::unique_ptr<FileChooser> fc, CompletionHandlerType h)
: chooser (std::move (fc)), handler (h)
{
[handler.get() retain];
}
~DeletedFileChooserWrapper()
{
callHandler (nullptr);
}
void callHandler (NSArray<NSURL*>* urls)
{
if (handlerCalled)
return;
handler.get() (urls);
handlerCalled = true;
}
std::unique_ptr<FileChooser> chooser;
private:
ObjCObjectHandle<CompletionHandlerType> handler;
bool handlerCalled = false;
};
auto chooser = std::make_unique<FileChooser> (TRANS("Select the file you want to upload..."),
File::getSpecialLocation (File::userHomeDirectory), "*");
auto* wrapper = new DeletedFileChooserWrapper (std::move (chooser), completionHandler);
auto flags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles
| ([parameters allowsMultipleSelection] ? FileBrowserComponent::canSelectMultipleItems : 0);
#if JUCE_MAC
if (@available (macOS 10.14, *))
{
if ([parameters allowsDirectories])
flags |= FileBrowserComponent::canSelectDirectories;
}
#endif
wrapper->chooser->launchAsync (flags, [wrapper] (const FileChooser&)
{
auto results = wrapper->chooser->getResults();
auto urls = [NSMutableArray arrayWithCapacity: (NSUInteger) results.size()];
for (auto& f : results)
[urls addObject: [NSURL fileURLWithPath: juceStringToNS (f.getFullPathName())]];
wrapper->callHandler (urls);
delete wrapper;
});
});
}
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
registerClass();
@ -283,20 +379,6 @@ struct API_AVAILABLE (macos (10.10)) WebViewDelegateClass : public ObjCClass<NS
static WebBrowserComponent* getOwner (id self) { return getIvar<WebBrowserComponent*> (self, "owner"); }
private:
static void decidePolicyForNavigationAction (id self, SEL, WKWebView*, WKNavigationAction* navigationAction,
void (^decisionHandler)(WKNavigationActionPolicy))
{
if (getOwner (self)->pageAboutToLoad (nsStringToJuce ([[[navigationAction request] URL] absoluteString])))
decisionHandler (WKNavigationActionPolicyAllow);
else
decisionHandler (WKNavigationActionPolicyCancel);
}
static void didFinishNavigation (id self, SEL, WKWebView* webview, WKNavigation*)
{
getOwner (self)->pageFinishedLoading (nsStringToJuce ([[webview URL] absoluteString]));
}
static void displayError (WebBrowserComponent* owner, NSError* error)
{
if ([error code] != NSURLErrorCancelled)
@ -309,92 +391,6 @@ private:
owner->goToURL ("data:text/plain;charset=UTF-8," + errorString);
}
}
static void didFailNavigation (id self, SEL, WKWebView*, WKNavigation*, NSError* error)
{
displayError (getOwner (self), error);
}
static void didFailProvisionalNavigation (id self, SEL, WKWebView*, WKNavigation*, NSError* error)
{
displayError (getOwner (self), error);
}
static void webViewDidClose (id self, SEL, WKWebView*)
{
getOwner (self)->windowCloseRequest();
}
static WKWebView* createWebView (id self, SEL, WKWebView*, WKWebViewConfiguration*,
WKNavigationAction* navigationAction, WKWindowFeatures*)
{
getOwner (self)->newWindowAttemptingToLoad (nsStringToJuce ([[[navigationAction request] URL] absoluteString]));
return nil;
}
API_AVAILABLE (macos (10.12))
static void runOpenPanel (id, SEL, WKWebView*, WKOpenPanelParameters* parameters, WKFrameInfo*,
void (^completionHandler)(NSArray<NSURL*>*))
{
using CompletionHandlerType = decltype (completionHandler);
class DeletedFileChooserWrapper : private DeletedAtShutdown
{
public:
DeletedFileChooserWrapper (std::unique_ptr<FileChooser> fc, CompletionHandlerType h)
: chooser (std::move (fc)), handler (h)
{
[handler.get() retain];
}
~DeletedFileChooserWrapper()
{
callHandler (nullptr);
}
void callHandler (NSArray<NSURL*>* urls)
{
if (handlerCalled)
return;
handler.get() (urls);
handlerCalled = true;
}
std::unique_ptr<FileChooser> chooser;
private:
ObjCObjectHandle<CompletionHandlerType> handler;
bool handlerCalled = false;
};
auto chooser = std::make_unique<FileChooser> (TRANS("Select the file you want to upload..."),
File::getSpecialLocation (File::userHomeDirectory), "*");
auto* wrapper = new DeletedFileChooserWrapper (std::move (chooser), completionHandler);
auto flags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles
| ([parameters allowsMultipleSelection] ? FileBrowserComponent::canSelectMultipleItems : 0);
#if JUCE_MAC
if (@available (macOS 10.14, *))
{
if ([parameters allowsDirectories])
flags |= FileBrowserComponent::canSelectDirectories;
}
#endif
wrapper->chooser->launchAsync (flags, [wrapper] (const FileChooser&)
{
auto results = wrapper->chooser->getResults();
auto urls = [NSMutableArray arrayWithCapacity: (NSUInteger) results.size()];
for (auto& f : results)
[urls addObject: [NSURL fileURLWithPath: juceStringToNS (f.getFullPathName())]];
wrapper->callHandler (urls);
delete wrapper;
});
}
};
//==============================================================================