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.

349 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. END_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. @end
  32. @implementation DownloadClickDetector
  33. - (DownloadClickDetector*) initWithWebBrowserOwner: (juce::WebBrowserComponent*) ownerComponent_
  34. {
  35. [super init];
  36. ownerComponent = ownerComponent_;
  37. return self;
  38. }
  39. - (void) webView: (WebView*) sender decidePolicyForNavigationAction: (NSDictionary*) actionInformation
  40. request: (NSURLRequest*) request
  41. frame: (WebFrame*) frame
  42. decisionListener: (id <WebPolicyDecisionListener>) listener
  43. {
  44. (void) sender; (void) request; (void) frame;
  45. NSURL* url = [actionInformation valueForKey: nsStringLiteral ("WebActionOriginalURLKey")];
  46. if (ownerComponent->pageAboutToLoad (nsStringToJuce ([url absoluteString])))
  47. [listener use];
  48. else
  49. [listener ignore];
  50. }
  51. @end
  52. #else
  53. //==============================================================================
  54. @interface WebViewTapDetector : NSObject <UIGestureRecognizerDelegate>
  55. {
  56. }
  57. - (BOOL) gestureRecognizer: (UIGestureRecognizer*) gestureRecognizer
  58. shouldRecognizeSimultaneouslyWithGestureRecognizer: (UIGestureRecognizer*) otherGestureRecognizer;
  59. @end
  60. @implementation WebViewTapDetector
  61. - (BOOL) gestureRecognizer: (UIGestureRecognizer*) gestureRecognizer
  62. shouldRecognizeSimultaneouslyWithGestureRecognizer: (UIGestureRecognizer*) otherGestureRecognizer
  63. {
  64. return YES;
  65. }
  66. @end
  67. //==============================================================================
  68. @interface WebViewURLChangeDetector : NSObject <UIWebViewDelegate>
  69. {
  70. juce::WebBrowserComponent* ownerComponent;
  71. }
  72. - (WebViewURLChangeDetector*) initWithWebBrowserOwner: (juce::WebBrowserComponent*) ownerComponent;
  73. - (BOOL) webView: (UIWebView*) webView shouldStartLoadWithRequest: (NSURLRequest*) request navigationType: (UIWebViewNavigationType) navigationType;
  74. @end
  75. @implementation WebViewURLChangeDetector
  76. - (WebViewURLChangeDetector*) initWithWebBrowserOwner: (juce::WebBrowserComponent*) ownerComponent_
  77. {
  78. [super init];
  79. ownerComponent = ownerComponent_;
  80. return self;
  81. }
  82. - (BOOL) webView: (UIWebView*) webView shouldStartLoadWithRequest: (NSURLRequest*) request navigationType: (UIWebViewNavigationType) navigationType
  83. {
  84. return ownerComponent->pageAboutToLoad (nsStringToJuce (request.URL.absoluteString));
  85. }
  86. @end
  87. #endif
  88. BEGIN_JUCE_NAMESPACE
  89. //==============================================================================
  90. class WebBrowserComponentInternal
  91. #if JUCE_MAC
  92. : public NSViewComponent
  93. #else
  94. : public UIViewComponent
  95. #endif
  96. {
  97. public:
  98. WebBrowserComponentInternal (WebBrowserComponent* owner)
  99. {
  100. #if JUCE_MAC
  101. webView = [[WebView alloc] initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)
  102. frameName: nsEmptyString()
  103. groupName: nsEmptyString()];
  104. setView (webView);
  105. clickListener = [[DownloadClickDetector alloc] initWithWebBrowserOwner: owner];
  106. [webView setPolicyDelegate: clickListener];
  107. #else
  108. webView = [[UIWebView alloc] initWithFrame: CGRectMake (0, 0, 1.0f, 1.0f)];
  109. setView (webView);
  110. tapDetector = [[WebViewTapDetector alloc] init];
  111. urlDetector = [[WebViewURLChangeDetector alloc] initWithWebBrowserOwner: owner];
  112. gestureRecogniser = nil;
  113. webView.delegate = urlDetector;
  114. #endif
  115. }
  116. ~WebBrowserComponentInternal()
  117. {
  118. #if JUCE_MAC
  119. [webView setPolicyDelegate: nil];
  120. [clickListener release];
  121. #else
  122. webView.delegate = nil;
  123. [webView removeGestureRecognizer: gestureRecogniser];
  124. [gestureRecogniser release];
  125. [tapDetector release];
  126. [urlDetector release];
  127. #endif
  128. setView (nil);
  129. }
  130. void goToURL (const String& url,
  131. const StringArray* headers,
  132. const MemoryBlock* postData)
  133. {
  134. NSMutableURLRequest* r
  135. = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: juceStringToNS (url)]
  136. cachePolicy: NSURLRequestUseProtocolCachePolicy
  137. timeoutInterval: 30.0];
  138. if (postData != nullptr && postData->getSize() > 0)
  139. {
  140. [r setHTTPMethod: nsStringLiteral ("POST")];
  141. [r setHTTPBody: [NSData dataWithBytes: postData->getData()
  142. length: postData->getSize()]];
  143. }
  144. if (headers != nullptr)
  145. {
  146. for (int i = 0; i < headers->size(); ++i)
  147. {
  148. const String headerName ((*headers)[i].upToFirstOccurrenceOf (":", false, false).trim());
  149. const String headerValue ((*headers)[i].fromFirstOccurrenceOf (":", false, false).trim());
  150. [r setValue: juceStringToNS (headerValue)
  151. forHTTPHeaderField: juceStringToNS (headerName)];
  152. }
  153. }
  154. stop();
  155. #if JUCE_MAC
  156. [[webView mainFrame] loadRequest: r];
  157. #else
  158. [webView loadRequest: r];
  159. #endif
  160. }
  161. void goBack() { [webView goBack]; }
  162. void goForward() { [webView goForward]; }
  163. #if JUCE_MAC
  164. void stop() { [webView stopLoading: nil]; }
  165. void refresh() { [webView reload: nil]; }
  166. #else
  167. void stop() { [webView stopLoading]; }
  168. void refresh() { [webView reload]; }
  169. #endif
  170. void mouseMove (const MouseEvent&)
  171. {
  172. // WebKit doesn't capture mouse-moves itself, so it seems the only way to make
  173. // them work is to push them via this non-public method..
  174. if ([webView respondsToSelector: @selector (_updateMouseoverWithFakeEvent)])
  175. [webView performSelector: @selector (_updateMouseoverWithFakeEvent)];
  176. }
  177. private:
  178. #if JUCE_MAC
  179. WebView* webView;
  180. DownloadClickDetector* clickListener;
  181. #else
  182. UIWebView* webView;
  183. WebViewTapDetector* tapDetector;
  184. WebViewURLChangeDetector* urlDetector;
  185. UITapGestureRecognizer* gestureRecogniser;
  186. #endif
  187. };
  188. //==============================================================================
  189. WebBrowserComponent::WebBrowserComponent (const bool unloadPageWhenBrowserIsHidden_)
  190. : browser (nullptr),
  191. blankPageShown (false),
  192. unloadPageWhenBrowserIsHidden (unloadPageWhenBrowserIsHidden_)
  193. {
  194. setOpaque (true);
  195. addAndMakeVisible (browser = new WebBrowserComponentInternal (this));
  196. }
  197. WebBrowserComponent::~WebBrowserComponent()
  198. {
  199. deleteAndZero (browser);
  200. }
  201. //==============================================================================
  202. void WebBrowserComponent::goToURL (const String& url,
  203. const StringArray* headers,
  204. const MemoryBlock* postData)
  205. {
  206. lastURL = url;
  207. lastHeaders.clear();
  208. if (headers != nullptr)
  209. lastHeaders = *headers;
  210. lastPostData.setSize (0);
  211. if (postData != nullptr)
  212. lastPostData = *postData;
  213. blankPageShown = false;
  214. browser->goToURL (url, headers, postData);
  215. }
  216. void WebBrowserComponent::stop()
  217. {
  218. browser->stop();
  219. }
  220. void WebBrowserComponent::goBack()
  221. {
  222. lastURL = String::empty;
  223. blankPageShown = false;
  224. browser->goBack();
  225. }
  226. void WebBrowserComponent::goForward()
  227. {
  228. lastURL = String::empty;
  229. browser->goForward();
  230. }
  231. void WebBrowserComponent::refresh()
  232. {
  233. browser->refresh();
  234. }
  235. //==============================================================================
  236. void WebBrowserComponent::paint (Graphics&)
  237. {
  238. }
  239. void WebBrowserComponent::checkWindowAssociation()
  240. {
  241. if (isShowing())
  242. {
  243. if (blankPageShown)
  244. goBack();
  245. }
  246. else
  247. {
  248. if (unloadPageWhenBrowserIsHidden && ! blankPageShown)
  249. {
  250. // when the component becomes invisible, some stuff like flash
  251. // carries on playing audio, so we need to force it onto a blank
  252. // page to avoid this, (and send it back when it's made visible again).
  253. blankPageShown = true;
  254. browser->goToURL ("about:blank", 0, 0);
  255. }
  256. }
  257. }
  258. void WebBrowserComponent::reloadLastURL()
  259. {
  260. if (lastURL.isNotEmpty())
  261. {
  262. goToURL (lastURL, &lastHeaders, &lastPostData);
  263. lastURL = String::empty;
  264. }
  265. }
  266. void WebBrowserComponent::parentHierarchyChanged()
  267. {
  268. checkWindowAssociation();
  269. }
  270. void WebBrowserComponent::resized()
  271. {
  272. browser->setSize (getWidth(), getHeight());
  273. }
  274. void WebBrowserComponent::visibilityChanged()
  275. {
  276. checkWindowAssociation();
  277. }
  278. bool WebBrowserComponent::pageAboutToLoad (const String&)
  279. {
  280. return true;
  281. }