The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

706 lines
24KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. #if JUCE_IOS || (defined (MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10)
  21. #define JUCE_USE_WKWEBVIEW 1
  22. #if (defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12)
  23. #define WKWEBVIEW_OPENPANEL_SUPPORTED 1
  24. #endif
  25. #endif
  26. static NSMutableURLRequest* getRequestForURL (const String& url, const StringArray* headers, const MemoryBlock* postData)
  27. {
  28. NSString* urlString = juceStringToNS (url);
  29. #if JUCE_IOS || (defined (MAC_OS_X_VERSION_10_9) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9)
  30. urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
  31. #else
  32. urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
  33. #endif
  34. if (NSURL* nsURL = [NSURL URLWithString: urlString])
  35. {
  36. NSMutableURLRequest* r
  37. = [NSMutableURLRequest requestWithURL: nsURL
  38. cachePolicy: NSURLRequestUseProtocolCachePolicy
  39. timeoutInterval: 30.0];
  40. if (postData != nullptr && postData->getSize() > 0)
  41. {
  42. [r setHTTPMethod: nsStringLiteral ("POST")];
  43. [r setHTTPBody: [NSData dataWithBytes: postData->getData()
  44. length: postData->getSize()]];
  45. }
  46. if (headers != nullptr)
  47. {
  48. for (int i = 0; i < headers->size(); ++i)
  49. {
  50. auto headerName = (*headers)[i].upToFirstOccurrenceOf (":", false, false).trim();
  51. auto headerValue = (*headers)[i].fromFirstOccurrenceOf (":", false, false).trim();
  52. [r setValue: juceStringToNS (headerValue)
  53. forHTTPHeaderField: juceStringToNS (headerName)];
  54. }
  55. }
  56. return r;
  57. }
  58. return nullptr;
  59. }
  60. #if JUCE_MAC
  61. #if JUCE_USE_WKWEBVIEW
  62. using WebViewBase = ObjCClass<WKWebView>;
  63. #else
  64. using WebViewBase = ObjCClass<WebView>;
  65. #endif
  66. struct WebViewKeyEquivalentResponder : public WebViewBase
  67. {
  68. WebViewKeyEquivalentResponder()
  69. : WebViewBase ("WebViewKeyEquivalentResponder_")
  70. {
  71. addIvar<WebViewKeyEquivalentResponder*> ("owner");
  72. addMethod (@selector (performKeyEquivalent:), performKeyEquivalent, @encode (BOOL), "@:@");
  73. registerClass();
  74. }
  75. private:
  76. static WebViewKeyEquivalentResponder* getOwner (id self)
  77. {
  78. return getIvar<WebViewKeyEquivalentResponder*> (self, "owner");
  79. }
  80. static BOOL performKeyEquivalent (id self, SEL selector, NSEvent* event)
  81. {
  82. NSResponder* first = [[self window] firstResponder];
  83. if (([event modifierFlags] & NSDeviceIndependentModifierFlagsMask) == NSCommandKeyMask)
  84. {
  85. auto sendAction = [&] (SEL actionSelector) -> BOOL
  86. {
  87. return [NSApp sendAction: actionSelector
  88. to: first
  89. from: self];
  90. };
  91. if ([[event charactersIgnoringModifiers] isEqualToString: @"x"]) return sendAction (@selector (cut:));
  92. if ([[event charactersIgnoringModifiers] isEqualToString: @"c"]) return sendAction (@selector (copy:));
  93. if ([[event charactersIgnoringModifiers] isEqualToString: @"v"]) return sendAction (@selector (paste:));
  94. if ([[event charactersIgnoringModifiers] isEqualToString: @"a"]) return sendAction (@selector (selectAll:));
  95. }
  96. return sendSuperclassMessage<BOOL> (self, selector, event);
  97. }
  98. };
  99. #endif
  100. #if JUCE_USE_WKWEBVIEW
  101. struct WebViewDelegateClass : public ObjCClass<NSObject>
  102. {
  103. WebViewDelegateClass() : ObjCClass<NSObject> ("JUCEWebViewDelegate_")
  104. {
  105. addIvar<WebBrowserComponent*> ("owner");
  106. addMethod (@selector (webView:decidePolicyForNavigationAction:decisionHandler:), decidePolicyForNavigationAction, "v@:@@@");
  107. addMethod (@selector (webView:didFinishNavigation:), didFinishNavigation, "v@:@@");
  108. addMethod (@selector (webView:didFailNavigation:withError:), didFailNavigation, "v@:@@@");
  109. addMethod (@selector (webView:didFailProvisionalNavigation:withError:), didFailProvisionalNavigation, "v@:@@@");
  110. addMethod (@selector (webView:webViewDidClose:), webViewDidClose, "v@:@");
  111. addMethod (@selector (webView:createWebViewWithConfiguration:forNavigationAction:
  112. windowFeatures:), createWebView, "@@:@@@@");
  113. #if WKWEBVIEW_OPENPANEL_SUPPORTED
  114. addMethod (@selector (webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:), runOpenPanel, "v@:@@@@");
  115. #endif
  116. registerClass();
  117. }
  118. static void setOwner (id self, WebBrowserComponent* owner) { object_setInstanceVariable (self, "owner", owner); }
  119. static WebBrowserComponent* getOwner (id self) { return getIvar<WebBrowserComponent*> (self, "owner"); }
  120. private:
  121. static void decidePolicyForNavigationAction (id self, SEL, WKWebView*, WKNavigationAction* navigationAction,
  122. void (^decisionHandler)(WKNavigationActionPolicy))
  123. {
  124. if (getOwner (self)->pageAboutToLoad (nsStringToJuce ([[[navigationAction request] URL] absoluteString])))
  125. decisionHandler (WKNavigationActionPolicyAllow);
  126. else
  127. decisionHandler (WKNavigationActionPolicyCancel);
  128. }
  129. static void didFinishNavigation (id self, SEL, WKWebView* webview, WKNavigation*)
  130. {
  131. getOwner (self)->pageFinishedLoading (nsStringToJuce ([[webview URL] absoluteString]));
  132. }
  133. static void displayError (WebBrowserComponent* owner, NSError* error)
  134. {
  135. if ([error code] != NSURLErrorCancelled)
  136. {
  137. auto errorString = nsStringToJuce ([error localizedDescription]);
  138. bool proceedToErrorPage = owner->pageLoadHadNetworkError (errorString);
  139. // WKWebView doesn't have an internal error page, so make a really simple one ourselves
  140. if (proceedToErrorPage)
  141. owner->goToURL ("data:text/plain;charset=UTF-8," + errorString);
  142. }
  143. }
  144. static void didFailNavigation (id self, SEL, WKWebView*, WKNavigation*, NSError* error)
  145. {
  146. displayError (getOwner (self), error);
  147. }
  148. static void didFailProvisionalNavigation (id self, SEL, WKWebView*, WKNavigation*, NSError* error)
  149. {
  150. displayError (getOwner (self), error);
  151. }
  152. static void webViewDidClose (id self, SEL, WKWebView*)
  153. {
  154. getOwner (self)->windowCloseRequest();
  155. }
  156. static WKWebView* createWebView (id self, SEL, WKWebView*, WKWebViewConfiguration*,
  157. WKNavigationAction* navigationAction, WKWindowFeatures*)
  158. {
  159. getOwner (self)->newWindowAttemptingToLoad (nsStringToJuce ([[[navigationAction request] URL] absoluteString]));
  160. return nil;
  161. }
  162. #if WKWEBVIEW_OPENPANEL_SUPPORTED
  163. static void runOpenPanel (id, SEL, WKWebView*, WKOpenPanelParameters* parameters, WKFrameInfo*,
  164. void (^completionHandler)(NSArray<NSURL*>*))
  165. {
  166. #if JUCE_MODAL_LOOPS_PERMITTED
  167. FileChooser chooser (TRANS("Select the file you want to upload..."),
  168. File::getSpecialLocation (File::userHomeDirectory), "*");
  169. auto flags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles
  170. | ([parameters allowsMultipleSelection] ? FileBrowserComponent::canSelectMultipleItems : 0);
  171. #if (defined (MAC_OS_X_VERSION_10_14) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14)
  172. if ([parameters allowsDirectories])
  173. flags |= FileBrowserComponent::canSelectDirectories;
  174. #endif
  175. if (chooser.showDialog (flags, nullptr))
  176. {
  177. auto results = chooser.getResults();
  178. auto urls = [NSMutableArray arrayWithCapacity: (NSUInteger) results.size()];
  179. for (auto& f : results)
  180. [urls addObject: [NSURL fileURLWithPath: juceStringToNS (f.getFullPathName())]];
  181. completionHandler (urls);
  182. }
  183. else
  184. {
  185. completionHandler (nil);
  186. }
  187. #else
  188. ignoreUnused (parameters, completionHandler);
  189. jassertfalse; // Can't use this without modal loops being enabled!
  190. #endif
  191. }
  192. #endif
  193. };
  194. //==============================================================================
  195. class WebBrowserComponent::Pimpl
  196. #if JUCE_MAC
  197. : public NSViewComponent
  198. #else
  199. : public UIViewComponent
  200. #endif
  201. {
  202. public:
  203. Pimpl (WebBrowserComponent* owner)
  204. {
  205. ignoreUnused (owner);
  206. WKWebViewConfiguration* config = [[WKWebViewConfiguration alloc] init];
  207. #if JUCE_MAC
  208. auto frame = NSMakeRect (0, 0, 100.0f, 100.0f);
  209. static WebViewKeyEquivalentResponder webviewClass;
  210. webView = (WKWebView*) webviewClass.createInstance();
  211. webView = [webView initWithFrame: frame
  212. configuration: config];
  213. #else
  214. auto frame = CGRectMake (0, 0, 100.0f, 100.0f);
  215. webView = [[WKWebView alloc] initWithFrame: frame
  216. configuration: config];
  217. #endif
  218. static WebViewDelegateClass cls;
  219. webViewDelegate = [cls.createInstance() init];
  220. WebViewDelegateClass::setOwner (webViewDelegate, owner);
  221. [webView setNavigationDelegate: webViewDelegate];
  222. [webView setUIDelegate: webViewDelegate];
  223. setView (webView);
  224. }
  225. ~Pimpl()
  226. {
  227. [webView setNavigationDelegate: nil];
  228. [webView setUIDelegate: nil];
  229. [webViewDelegate release];
  230. setView (nil);
  231. }
  232. void goToURL (const String& url,
  233. const StringArray* headers,
  234. const MemoryBlock* postData)
  235. {
  236. stop();
  237. if (url.trimStart().startsWithIgnoreCase ("javascript:"))
  238. {
  239. [webView evaluateJavaScript: juceStringToNS (url.fromFirstOccurrenceOf (":", false, false))
  240. completionHandler: nil];
  241. }
  242. else if (NSMutableURLRequest* request = getRequestForURL (url, headers, postData))
  243. {
  244. [webView loadRequest: request];
  245. }
  246. }
  247. void goBack() { [webView goBack]; }
  248. void goForward() { [webView goForward]; }
  249. void stop() { [webView stopLoading]; }
  250. void refresh() { [webView reload]; }
  251. private:
  252. WKWebView* webView = nil;
  253. id webViewDelegate;
  254. };
  255. #else
  256. #if JUCE_MAC
  257. struct DownloadClickDetectorClass : public ObjCClass<NSObject>
  258. {
  259. DownloadClickDetectorClass() : ObjCClass<NSObject> ("JUCEWebClickDetector_")
  260. {
  261. addIvar<WebBrowserComponent*> ("owner");
  262. addMethod (@selector (webView:decidePolicyForNavigationAction:request:frame:decisionListener:),
  263. decidePolicyForNavigationAction, "v@:@@@@@");
  264. addMethod (@selector (webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener:),
  265. decidePolicyForNewWindowAction, "v@:@@@@@");
  266. addMethod (@selector (webView:didFinishLoadForFrame:), didFinishLoadForFrame, "v@:@@");
  267. addMethod (@selector (webView:didFailLoadWithError:forFrame:), didFailLoadWithError, "v@:@@@");
  268. addMethod (@selector (webView:didFailProvisionalLoadWithError:forFrame:), didFailLoadWithError, "v@:@@@");
  269. addMethod (@selector (webView:willCloseFrame:), willCloseFrame, "v@:@@");
  270. addMethod (@selector (webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:), runOpenPanel, "v@:@@", @encode (BOOL));
  271. registerClass();
  272. }
  273. static void setOwner (id self, WebBrowserComponent* owner) { object_setInstanceVariable (self, "owner", owner); }
  274. static WebBrowserComponent* getOwner (id self) { return getIvar<WebBrowserComponent*> (self, "owner"); }
  275. private:
  276. static String getOriginalURL (NSDictionary* actionInformation)
  277. {
  278. if (NSURL* url = [actionInformation valueForKey: nsStringLiteral ("WebActionOriginalURLKey")])
  279. return nsStringToJuce ([url absoluteString]);
  280. return {};
  281. }
  282. static void decidePolicyForNavigationAction (id self, SEL, WebView*, NSDictionary* actionInformation,
  283. NSURLRequest*, WebFrame*, id<WebPolicyDecisionListener> listener)
  284. {
  285. if (getOwner (self)->pageAboutToLoad (getOriginalURL (actionInformation)))
  286. [listener use];
  287. else
  288. [listener ignore];
  289. }
  290. static void decidePolicyForNewWindowAction (id self, SEL, WebView*, NSDictionary* actionInformation,
  291. NSURLRequest*, NSString*, id<WebPolicyDecisionListener> listener)
  292. {
  293. getOwner (self)->newWindowAttemptingToLoad (getOriginalURL (actionInformation));
  294. [listener ignore];
  295. }
  296. static void didFinishLoadForFrame (id self, SEL, WebView* sender, WebFrame* frame)
  297. {
  298. if ([frame isEqual: [sender mainFrame]])
  299. {
  300. NSURL* url = [[[frame dataSource] request] URL];
  301. getOwner (self)->pageFinishedLoading (nsStringToJuce ([url absoluteString]));
  302. }
  303. }
  304. static void didFailLoadWithError (id self, SEL, WebView* sender, NSError* error, WebFrame* frame)
  305. {
  306. if ([frame isEqual: [sender mainFrame]] && error != nullptr && [error code] != NSURLErrorCancelled)
  307. {
  308. auto errorString = nsStringToJuce ([error localizedDescription]);
  309. bool proceedToErrorPage = getOwner (self)->pageLoadHadNetworkError (errorString);
  310. // WebKit doesn't have an internal error page, so make a really simple one ourselves
  311. if (proceedToErrorPage)
  312. getOwner (self)->goToURL ("data:text/plain;charset=UTF-8," + errorString);
  313. }
  314. }
  315. static void willCloseFrame (id self, SEL, WebView*, WebFrame*)
  316. {
  317. getOwner (self)->windowCloseRequest();
  318. }
  319. static void runOpenPanel (id, SEL, WebView*, id<WebOpenPanelResultListener> resultListener, BOOL allowMultipleFiles)
  320. {
  321. #if JUCE_MODAL_LOOPS_PERMITTED
  322. FileChooser chooser (TRANS("Select the file you want to upload..."),
  323. File::getSpecialLocation (File::userHomeDirectory), "*");
  324. if (allowMultipleFiles ? chooser.browseForMultipleFilesToOpen()
  325. : chooser.browseForFileToOpen())
  326. {
  327. for (auto& f : chooser.getResults())
  328. [resultListener chooseFilename: juceStringToNS (f.getFullPathName())];
  329. }
  330. #else
  331. ignoreUnused (resultListener, allowMultipleFiles);
  332. jassertfalse; // Can't use this without modal loops being enabled!
  333. #endif
  334. }
  335. };
  336. #else
  337. struct WebViewDelegateClass : public ObjCClass<NSObject>
  338. {
  339. WebViewDelegateClass() : ObjCClass<NSObject> ("JUCEWebViewDelegate_")
  340. {
  341. addIvar<WebBrowserComponent*> ("owner");
  342. addMethod (@selector (gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:),
  343. shouldRecognizeSimultaneouslyWithGestureRecognizer, "c@:@@");
  344. addMethod (@selector (webView:shouldStartLoadWithRequest:navigationType:), shouldStartLoadWithRequest, "c@:@@@");
  345. addMethod (@selector (webViewDidFinishLoad:), webViewDidFinishLoad, "v@:@");
  346. registerClass();
  347. }
  348. static void setOwner (id self, WebBrowserComponent* owner) { object_setInstanceVariable (self, "owner", owner); }
  349. static WebBrowserComponent* getOwner (id self) { return getIvar<WebBrowserComponent*> (self, "owner"); }
  350. private:
  351. static BOOL shouldRecognizeSimultaneouslyWithGestureRecognizer (id, SEL, UIGestureRecognizer*, UIGestureRecognizer*)
  352. {
  353. return YES;
  354. }
  355. static BOOL shouldStartLoadWithRequest (id self, SEL, UIWebView*, NSURLRequest* request, UIWebViewNavigationType)
  356. {
  357. return getOwner (self)->pageAboutToLoad (nsStringToJuce ([[request URL] absoluteString]));
  358. }
  359. static void webViewDidFinishLoad (id self, SEL, UIWebView* webView)
  360. {
  361. getOwner (self)->pageFinishedLoading (nsStringToJuce ([[[webView request] URL] absoluteString]));
  362. }
  363. };
  364. #endif
  365. //==============================================================================
  366. class WebBrowserComponent::Pimpl
  367. #if JUCE_MAC
  368. : public NSViewComponent
  369. #else
  370. : public UIViewComponent
  371. #endif
  372. {
  373. public:
  374. Pimpl (WebBrowserComponent* owner)
  375. {
  376. #if JUCE_MAC
  377. static WebViewKeyEquivalentResponder webviewClass;
  378. webView = (WebView*) webviewClass.createInstance();
  379. webView = [webView initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)
  380. frameName: nsEmptyString()
  381. groupName: nsEmptyString()];
  382. static DownloadClickDetectorClass cls;
  383. clickListener = [cls.createInstance() init];
  384. DownloadClickDetectorClass::setOwner (clickListener, owner);
  385. [webView setPolicyDelegate: clickListener];
  386. [webView setFrameLoadDelegate: clickListener];
  387. [webView setUIDelegate: clickListener];
  388. #else
  389. webView = [[UIWebView alloc] initWithFrame: CGRectMake (0, 0, 1.0f, 1.0f)];
  390. static WebViewDelegateClass cls;
  391. webViewDelegate = [cls.createInstance() init];
  392. WebViewDelegateClass::setOwner (webViewDelegate, owner);
  393. [webView setDelegate: webViewDelegate];
  394. #endif
  395. setView (webView);
  396. }
  397. ~Pimpl()
  398. {
  399. #if JUCE_MAC
  400. [webView setPolicyDelegate: nil];
  401. [webView setFrameLoadDelegate: nil];
  402. [webView setUIDelegate: nil];
  403. [clickListener release];
  404. #else
  405. [webView setDelegate: nil];
  406. [webViewDelegate release];
  407. #endif
  408. setView (nil);
  409. }
  410. void goToURL (const String& url,
  411. const StringArray* headers,
  412. const MemoryBlock* postData)
  413. {
  414. stop();
  415. if (url.trimStart().startsWithIgnoreCase ("javascript:"))
  416. {
  417. [webView stringByEvaluatingJavaScriptFromString:
  418. juceStringToNS (url.fromFirstOccurrenceOf (":", false, false))];
  419. }
  420. else if (NSMutableURLRequest* request = getRequestForURL (url, headers, postData))
  421. {
  422. #if JUCE_MAC
  423. [[webView mainFrame] loadRequest: request];
  424. #else
  425. [webView loadRequest: request];
  426. #endif
  427. #if JUCE_IOS
  428. [webView setScalesPageToFit: YES];
  429. #endif
  430. }
  431. }
  432. void goBack() { [webView goBack]; }
  433. void goForward() { [webView goForward]; }
  434. #if JUCE_MAC
  435. void stop() { [webView stopLoading: nil]; }
  436. void refresh() { [webView reload: nil]; }
  437. #else
  438. void stop() { [webView stopLoading]; }
  439. void refresh() { [webView reload]; }
  440. #endif
  441. void mouseMove (const MouseEvent&)
  442. {
  443. // WebKit doesn't capture mouse-moves itself, so it seems the only way to make
  444. // them work is to push them via this non-public method..
  445. if ([webView respondsToSelector: @selector (_updateMouseoverWithFakeEvent)])
  446. [webView performSelector: @selector (_updateMouseoverWithFakeEvent)];
  447. }
  448. private:
  449. #if JUCE_MAC
  450. WebView* webView = nil;
  451. id clickListener;
  452. #else
  453. UIWebView* webView = nil;
  454. id webViewDelegate;
  455. #endif
  456. };
  457. #endif
  458. //==============================================================================
  459. WebBrowserComponent::WebBrowserComponent (bool unloadWhenHidden)
  460. : unloadPageWhenBrowserIsHidden (unloadWhenHidden)
  461. {
  462. setOpaque (true);
  463. browser.reset (new Pimpl (this));
  464. addAndMakeVisible (browser.get());
  465. }
  466. WebBrowserComponent::WebBrowserComponent (bool unloadWhenHidden,
  467. const File&,
  468. const File&)
  469. : WebBrowserComponent (unloadWhenHidden)
  470. {
  471. }
  472. WebBrowserComponent::~WebBrowserComponent()
  473. {
  474. }
  475. //==============================================================================
  476. void WebBrowserComponent::goToURL (const String& url,
  477. const StringArray* headers,
  478. const MemoryBlock* postData)
  479. {
  480. lastURL = url;
  481. if (headers != nullptr)
  482. lastHeaders = *headers;
  483. else
  484. lastHeaders.clear();
  485. if (postData != nullptr)
  486. lastPostData = *postData;
  487. else
  488. lastPostData.reset();
  489. blankPageShown = false;
  490. browser->goToURL (url, headers, postData);
  491. }
  492. void WebBrowserComponent::stop()
  493. {
  494. browser->stop();
  495. }
  496. void WebBrowserComponent::goBack()
  497. {
  498. lastURL.clear();
  499. blankPageShown = false;
  500. browser->goBack();
  501. }
  502. void WebBrowserComponent::goForward()
  503. {
  504. lastURL.clear();
  505. browser->goForward();
  506. }
  507. void WebBrowserComponent::refresh()
  508. {
  509. browser->refresh();
  510. }
  511. //==============================================================================
  512. void WebBrowserComponent::paint (Graphics&)
  513. {
  514. }
  515. void WebBrowserComponent::checkWindowAssociation()
  516. {
  517. if (isShowing())
  518. {
  519. reloadLastURL();
  520. if (blankPageShown)
  521. goBack();
  522. }
  523. else
  524. {
  525. if (unloadPageWhenBrowserIsHidden && ! blankPageShown)
  526. {
  527. // when the component becomes invisible, some stuff like flash
  528. // carries on playing audio, so we need to force it onto a blank
  529. // page to avoid this, (and send it back when it's made visible again).
  530. blankPageShown = true;
  531. browser->goToURL ("about:blank", nullptr, nullptr);
  532. }
  533. }
  534. }
  535. void WebBrowserComponent::reloadLastURL()
  536. {
  537. if (lastURL.isNotEmpty())
  538. {
  539. goToURL (lastURL, &lastHeaders, &lastPostData);
  540. lastURL.clear();
  541. }
  542. }
  543. void WebBrowserComponent::parentHierarchyChanged()
  544. {
  545. checkWindowAssociation();
  546. }
  547. void WebBrowserComponent::resized()
  548. {
  549. browser->setSize (getWidth(), getHeight());
  550. }
  551. void WebBrowserComponent::visibilityChanged()
  552. {
  553. checkWindowAssociation();
  554. }
  555. void WebBrowserComponent::focusGained (FocusChangeType)
  556. {
  557. }
  558. void WebBrowserComponent::clearCookies()
  559. {
  560. NSHTTPCookieStorage* storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
  561. if (NSArray* cookies = [storage cookies])
  562. {
  563. const NSUInteger n = [cookies count];
  564. for (NSUInteger i = 0; i < n; ++i)
  565. [storage deleteCookie: [cookies objectAtIndex: i]];
  566. }
  567. [[NSUserDefaults standardUserDefaults] synchronize];
  568. }
  569. } // namespace juce