Audio plugin host https://kx.studio/carla
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.

juce_mac_WebBrowserComponent.mm 24KB

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