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.

361 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. } // (juce namespace)
  19. class WebBrowserComponentInternal;
  20. #if JUCE_MAC
  21. #define DownloadClickDetector MakeObjCClassName(DownloadClickDetector)
  22. @interface DownloadClickDetector : NSObject
  23. {
  24. juce::WebBrowserComponent* ownerComponent;
  25. }
  26. - (DownloadClickDetector*) initWithWebBrowserOwner: (juce::WebBrowserComponent*) ownerComponent;
  27. - (void) webView: (WebView*) webView decidePolicyForNavigationAction: (NSDictionary*) actionInformation
  28. request: (NSURLRequest*) request
  29. frame: (WebFrame*) frame
  30. decisionListener: (id <WebPolicyDecisionListener>) listener;
  31. - (void) webView: (WebView*) webView didFinishLoadForFrame: (WebFrame*) frame;
  32. @end
  33. @implementation DownloadClickDetector
  34. - (DownloadClickDetector*) initWithWebBrowserOwner: (juce::WebBrowserComponent*) ownerComponent_
  35. {
  36. [super init];
  37. ownerComponent = ownerComponent_;
  38. return self;
  39. }
  40. - (void) webView: (WebView*) sender decidePolicyForNavigationAction: (NSDictionary*) actionInformation
  41. request: (NSURLRequest*) request
  42. frame: (WebFrame*) frame
  43. decisionListener: (id <WebPolicyDecisionListener>) listener
  44. {
  45. (void) sender; (void) request; (void) frame;
  46. NSURL* url = [actionInformation valueForKey: nsStringLiteral ("WebActionOriginalURLKey")];
  47. if (ownerComponent->pageAboutToLoad (nsStringToJuce ([url absoluteString])))
  48. [listener use];
  49. else
  50. [listener ignore];
  51. }
  52. - (void) webView: (WebView*) sender didFinishLoadForFrame: (WebFrame*) frame
  53. {
  54. if ([frame isEqual: [sender mainFrame]])
  55. {
  56. NSURL* url = [[[frame dataSource] request] URL];
  57. ownerComponent->pageFinishedLoading (nsStringToJuce ([url absoluteString]));
  58. }
  59. }
  60. @end
  61. #else
  62. //==============================================================================
  63. @interface WebViewTapDetector : NSObject <UIGestureRecognizerDelegate>
  64. {
  65. }
  66. - (BOOL) gestureRecognizer: (UIGestureRecognizer*) gestureRecognizer
  67. shouldRecognizeSimultaneouslyWithGestureRecognizer: (UIGestureRecognizer*) otherGestureRecognizer;
  68. @end
  69. @implementation WebViewTapDetector
  70. - (BOOL) gestureRecognizer: (UIGestureRecognizer*) gestureRecognizer
  71. shouldRecognizeSimultaneouslyWithGestureRecognizer: (UIGestureRecognizer*) otherGestureRecognizer
  72. {
  73. return YES;
  74. }
  75. @end
  76. //==============================================================================
  77. @interface WebViewURLChangeDetector : NSObject <UIWebViewDelegate>
  78. {
  79. juce::WebBrowserComponent* ownerComponent;
  80. }
  81. - (WebViewURLChangeDetector*) initWithWebBrowserOwner: (juce::WebBrowserComponent*) ownerComponent;
  82. - (BOOL) webView: (UIWebView*) webView shouldStartLoadWithRequest: (NSURLRequest*) request navigationType: (UIWebViewNavigationType) navigationType;
  83. @end
  84. @implementation WebViewURLChangeDetector
  85. - (WebViewURLChangeDetector*) initWithWebBrowserOwner: (juce::WebBrowserComponent*) ownerComponent_
  86. {
  87. [super init];
  88. ownerComponent = ownerComponent_;
  89. return self;
  90. }
  91. - (BOOL) webView: (UIWebView*) webView shouldStartLoadWithRequest: (NSURLRequest*) request navigationType: (UIWebViewNavigationType) navigationType
  92. {
  93. return ownerComponent->pageAboutToLoad (nsStringToJuce (request.URL.absoluteString));
  94. }
  95. @end
  96. #endif
  97. namespace juce
  98. {
  99. //==============================================================================
  100. class WebBrowserComponentInternal
  101. #if JUCE_MAC
  102. : public NSViewComponent
  103. #else
  104. : public UIViewComponent
  105. #endif
  106. {
  107. public:
  108. WebBrowserComponentInternal (WebBrowserComponent* owner)
  109. {
  110. #if JUCE_MAC
  111. webView = [[WebView alloc] initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)
  112. frameName: nsEmptyString()
  113. groupName: nsEmptyString()];
  114. setView (webView);
  115. clickListener = [[DownloadClickDetector alloc] initWithWebBrowserOwner: owner];
  116. [webView setPolicyDelegate: clickListener];
  117. [webView setFrameLoadDelegate: clickListener];
  118. #else
  119. webView = [[UIWebView alloc] initWithFrame: CGRectMake (0, 0, 1.0f, 1.0f)];
  120. setView (webView);
  121. tapDetector = [[WebViewTapDetector alloc] init];
  122. urlDetector = [[WebViewURLChangeDetector alloc] initWithWebBrowserOwner: owner];
  123. gestureRecogniser = nil;
  124. webView.delegate = urlDetector;
  125. #endif
  126. }
  127. ~WebBrowserComponentInternal()
  128. {
  129. #if JUCE_MAC
  130. [webView setPolicyDelegate: nil];
  131. [webView setFrameLoadDelegate: nil];
  132. [clickListener release];
  133. #else
  134. webView.delegate = nil;
  135. [webView removeGestureRecognizer: gestureRecogniser];
  136. [gestureRecogniser release];
  137. [tapDetector release];
  138. [urlDetector release];
  139. #endif
  140. setView (nil);
  141. }
  142. void goToURL (const String& url,
  143. const StringArray* headers,
  144. const MemoryBlock* postData)
  145. {
  146. NSMutableURLRequest* r
  147. = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: juceStringToNS (url)]
  148. cachePolicy: NSURLRequestUseProtocolCachePolicy
  149. timeoutInterval: 30.0];
  150. if (postData != nullptr && postData->getSize() > 0)
  151. {
  152. [r setHTTPMethod: nsStringLiteral ("POST")];
  153. [r setHTTPBody: [NSData dataWithBytes: postData->getData()
  154. length: postData->getSize()]];
  155. }
  156. if (headers != nullptr)
  157. {
  158. for (int i = 0; i < headers->size(); ++i)
  159. {
  160. const String headerName ((*headers)[i].upToFirstOccurrenceOf (":", false, false).trim());
  161. const String headerValue ((*headers)[i].fromFirstOccurrenceOf (":", false, false).trim());
  162. [r setValue: juceStringToNS (headerValue)
  163. forHTTPHeaderField: juceStringToNS (headerName)];
  164. }
  165. }
  166. stop();
  167. #if JUCE_MAC
  168. [[webView mainFrame] loadRequest: r];
  169. #else
  170. [webView loadRequest: r];
  171. #endif
  172. }
  173. void goBack() { [webView goBack]; }
  174. void goForward() { [webView goForward]; }
  175. #if JUCE_MAC
  176. void stop() { [webView stopLoading: nil]; }
  177. void refresh() { [webView reload: nil]; }
  178. #else
  179. void stop() { [webView stopLoading]; }
  180. void refresh() { [webView reload]; }
  181. #endif
  182. void mouseMove (const MouseEvent&)
  183. {
  184. // WebKit doesn't capture mouse-moves itself, so it seems the only way to make
  185. // them work is to push them via this non-public method..
  186. if ([webView respondsToSelector: @selector (_updateMouseoverWithFakeEvent)])
  187. [webView performSelector: @selector (_updateMouseoverWithFakeEvent)];
  188. }
  189. private:
  190. #if JUCE_MAC
  191. WebView* webView;
  192. DownloadClickDetector* clickListener;
  193. #else
  194. UIWebView* webView;
  195. WebViewTapDetector* tapDetector;
  196. WebViewURLChangeDetector* urlDetector;
  197. UITapGestureRecognizer* gestureRecogniser;
  198. #endif
  199. };
  200. //==============================================================================
  201. WebBrowserComponent::WebBrowserComponent (const bool unloadPageWhenBrowserIsHidden_)
  202. : browser (nullptr),
  203. blankPageShown (false),
  204. unloadPageWhenBrowserIsHidden (unloadPageWhenBrowserIsHidden_)
  205. {
  206. setOpaque (true);
  207. addAndMakeVisible (browser = new WebBrowserComponentInternal (this));
  208. }
  209. WebBrowserComponent::~WebBrowserComponent()
  210. {
  211. deleteAndZero (browser);
  212. }
  213. //==============================================================================
  214. void WebBrowserComponent::goToURL (const String& url,
  215. const StringArray* headers,
  216. const MemoryBlock* postData)
  217. {
  218. lastURL = url;
  219. lastHeaders.clear();
  220. if (headers != nullptr)
  221. lastHeaders = *headers;
  222. lastPostData.setSize (0);
  223. if (postData != nullptr)
  224. lastPostData = *postData;
  225. blankPageShown = false;
  226. browser->goToURL (url, headers, postData);
  227. }
  228. void WebBrowserComponent::stop()
  229. {
  230. browser->stop();
  231. }
  232. void WebBrowserComponent::goBack()
  233. {
  234. lastURL = String::empty;
  235. blankPageShown = false;
  236. browser->goBack();
  237. }
  238. void WebBrowserComponent::goForward()
  239. {
  240. lastURL = String::empty;
  241. browser->goForward();
  242. }
  243. void WebBrowserComponent::refresh()
  244. {
  245. browser->refresh();
  246. }
  247. //==============================================================================
  248. void WebBrowserComponent::paint (Graphics&)
  249. {
  250. }
  251. void WebBrowserComponent::checkWindowAssociation()
  252. {
  253. if (isShowing())
  254. {
  255. if (blankPageShown)
  256. goBack();
  257. }
  258. else
  259. {
  260. if (unloadPageWhenBrowserIsHidden && ! blankPageShown)
  261. {
  262. // when the component becomes invisible, some stuff like flash
  263. // carries on playing audio, so we need to force it onto a blank
  264. // page to avoid this, (and send it back when it's made visible again).
  265. blankPageShown = true;
  266. browser->goToURL ("about:blank", 0, 0);
  267. }
  268. }
  269. }
  270. void WebBrowserComponent::reloadLastURL()
  271. {
  272. if (lastURL.isNotEmpty())
  273. {
  274. goToURL (lastURL, &lastHeaders, &lastPostData);
  275. lastURL = String::empty;
  276. }
  277. }
  278. void WebBrowserComponent::parentHierarchyChanged()
  279. {
  280. checkWindowAssociation();
  281. }
  282. void WebBrowserComponent::resized()
  283. {
  284. browser->setSize (getWidth(), getHeight());
  285. }
  286. void WebBrowserComponent::visibilityChanged()
  287. {
  288. checkWindowAssociation();
  289. }
  290. bool WebBrowserComponent::pageAboutToLoad (const String&) { return true; }
  291. void WebBrowserComponent::pageFinishedLoading (const String&) {}