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.

319 lines
10KB

  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. //==============================================================================
  19. class WebBrowserComponentInternal : public ActiveXControlComponent
  20. {
  21. public:
  22. //==============================================================================
  23. WebBrowserComponentInternal()
  24. : browser (nullptr),
  25. connectionPoint (nullptr),
  26. adviseCookie (0)
  27. {
  28. }
  29. ~WebBrowserComponentInternal()
  30. {
  31. if (connectionPoint != nullptr)
  32. connectionPoint->Unadvise (adviseCookie);
  33. if (browser != nullptr)
  34. browser->Release();
  35. }
  36. void createBrowser()
  37. {
  38. createControl (&CLSID_WebBrowser);
  39. browser = (IWebBrowser2*) queryInterface (&IID_IWebBrowser2);
  40. IConnectionPointContainer* connectionPointContainer = (IConnectionPointContainer*) queryInterface (&IID_IConnectionPointContainer);
  41. if (connectionPointContainer != nullptr)
  42. {
  43. connectionPointContainer->FindConnectionPoint (DIID_DWebBrowserEvents2,
  44. &connectionPoint);
  45. if (connectionPoint != nullptr)
  46. {
  47. WebBrowserComponent* const owner = dynamic_cast <WebBrowserComponent*> (getParentComponent());
  48. jassert (owner != nullptr);
  49. EventHandler* handler = new EventHandler (*owner);
  50. connectionPoint->Advise (handler, &adviseCookie);
  51. handler->Release();
  52. }
  53. }
  54. }
  55. void goToURL (const String& url,
  56. const StringArray* headers,
  57. const MemoryBlock* postData)
  58. {
  59. if (browser != nullptr)
  60. {
  61. LPSAFEARRAY sa = nullptr;
  62. VARIANT flags, frame, postDataVar, headersVar; // (_variant_t isn't available in all compilers)
  63. VariantInit (&flags);
  64. VariantInit (&frame);
  65. VariantInit (&postDataVar);
  66. VariantInit (&headersVar);
  67. if (headers != nullptr)
  68. {
  69. V_VT (&headersVar) = VT_BSTR;
  70. V_BSTR (&headersVar) = SysAllocString ((const OLECHAR*) headers->joinIntoString ("\r\n").toWideCharPointer());
  71. }
  72. if (postData != nullptr && postData->getSize() > 0)
  73. {
  74. LPSAFEARRAY sa = SafeArrayCreateVector (VT_UI1, 0, (ULONG) postData->getSize());
  75. if (sa != 0)
  76. {
  77. void* data = nullptr;
  78. SafeArrayAccessData (sa, &data);
  79. jassert (data != nullptr);
  80. if (data != nullptr)
  81. {
  82. postData->copyTo (data, 0, postData->getSize());
  83. SafeArrayUnaccessData (sa);
  84. VARIANT postDataVar2;
  85. VariantInit (&postDataVar2);
  86. V_VT (&postDataVar2) = VT_ARRAY | VT_UI1;
  87. V_ARRAY (&postDataVar2) = sa;
  88. postDataVar = postDataVar2;
  89. }
  90. }
  91. }
  92. browser->Navigate ((BSTR) (const OLECHAR*) url.toWideCharPointer(),
  93. &flags, &frame,
  94. &postDataVar, &headersVar);
  95. if (sa != 0)
  96. SafeArrayDestroy (sa);
  97. VariantClear (&flags);
  98. VariantClear (&frame);
  99. VariantClear (&postDataVar);
  100. VariantClear (&headersVar);
  101. }
  102. }
  103. //==============================================================================
  104. IWebBrowser2* browser;
  105. private:
  106. IConnectionPoint* connectionPoint;
  107. DWORD adviseCookie;
  108. //==============================================================================
  109. class EventHandler : public ComBaseClassHelper <IDispatch>,
  110. public ComponentMovementWatcher
  111. {
  112. public:
  113. EventHandler (WebBrowserComponent& owner_)
  114. : ComponentMovementWatcher (&owner_),
  115. owner (owner_)
  116. {
  117. }
  118. //==============================================================================
  119. JUCE_COMRESULT GetTypeInfoCount (UINT*) { return E_NOTIMPL; }
  120. JUCE_COMRESULT GetTypeInfo (UINT, LCID, ITypeInfo**) { return E_NOTIMPL; }
  121. JUCE_COMRESULT GetIDsOfNames (REFIID, LPOLESTR*, UINT, LCID, DISPID*) { return E_NOTIMPL; }
  122. JUCE_COMRESULT Invoke (DISPID dispIdMember, REFIID /*riid*/, LCID /*lcid*/, WORD /*wFlags*/, DISPPARAMS* pDispParams,
  123. VARIANT* /*pVarResult*/, EXCEPINFO* /*pExcepInfo*/, UINT* /*puArgErr*/)
  124. {
  125. if (dispIdMember == DISPID_BEFORENAVIGATE2)
  126. {
  127. VARIANT* const vurl = pDispParams->rgvarg[5].pvarVal;
  128. String url;
  129. if ((vurl->vt & VT_BYREF) != 0)
  130. url = *vurl->pbstrVal;
  131. else
  132. url = vurl->bstrVal;
  133. *pDispParams->rgvarg->pboolVal
  134. = owner.pageAboutToLoad (url) ? VARIANT_FALSE
  135. : VARIANT_TRUE;
  136. return S_OK;
  137. }
  138. return E_NOTIMPL;
  139. }
  140. void componentMovedOrResized (bool, bool ) {}
  141. void componentPeerChanged() {}
  142. void componentVisibilityChanged() { owner.visibilityChanged(); }
  143. //==============================================================================
  144. private:
  145. WebBrowserComponent& owner;
  146. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EventHandler);
  147. };
  148. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebBrowserComponentInternal);
  149. };
  150. //==============================================================================
  151. WebBrowserComponent::WebBrowserComponent (const bool unloadPageWhenBrowserIsHidden_)
  152. : browser (nullptr),
  153. blankPageShown (false),
  154. unloadPageWhenBrowserIsHidden (unloadPageWhenBrowserIsHidden_)
  155. {
  156. setOpaque (true);
  157. addAndMakeVisible (browser = new WebBrowserComponentInternal());
  158. }
  159. WebBrowserComponent::~WebBrowserComponent()
  160. {
  161. delete browser;
  162. }
  163. //==============================================================================
  164. void WebBrowserComponent::goToURL (const String& url,
  165. const StringArray* headers,
  166. const MemoryBlock* postData)
  167. {
  168. lastURL = url;
  169. lastHeaders.clear();
  170. if (headers != nullptr)
  171. lastHeaders = *headers;
  172. lastPostData.setSize (0);
  173. if (postData != nullptr)
  174. lastPostData = *postData;
  175. blankPageShown = false;
  176. browser->goToURL (url, headers, postData);
  177. }
  178. void WebBrowserComponent::stop()
  179. {
  180. if (browser->browser != nullptr)
  181. browser->browser->Stop();
  182. }
  183. void WebBrowserComponent::goBack()
  184. {
  185. lastURL = String::empty;
  186. blankPageShown = false;
  187. if (browser->browser != nullptr)
  188. browser->browser->GoBack();
  189. }
  190. void WebBrowserComponent::goForward()
  191. {
  192. lastURL = String::empty;
  193. if (browser->browser != nullptr)
  194. browser->browser->GoForward();
  195. }
  196. void WebBrowserComponent::refresh()
  197. {
  198. if (browser->browser != nullptr)
  199. browser->browser->Refresh();
  200. }
  201. //==============================================================================
  202. void WebBrowserComponent::paint (Graphics& g)
  203. {
  204. if (browser->browser == nullptr)
  205. g.fillAll (Colours::white);
  206. }
  207. void WebBrowserComponent::checkWindowAssociation()
  208. {
  209. if (isShowing())
  210. {
  211. if (browser->browser == nullptr && getPeer() != nullptr)
  212. {
  213. browser->createBrowser();
  214. reloadLastURL();
  215. }
  216. else
  217. {
  218. if (blankPageShown)
  219. goBack();
  220. }
  221. }
  222. else
  223. {
  224. if (browser != nullptr && unloadPageWhenBrowserIsHidden && ! blankPageShown)
  225. {
  226. // when the component becomes invisible, some stuff like flash
  227. // carries on playing audio, so we need to force it onto a blank
  228. // page to avoid this..
  229. blankPageShown = true;
  230. browser->goToURL ("about:blank", 0, 0);
  231. }
  232. }
  233. }
  234. void WebBrowserComponent::reloadLastURL()
  235. {
  236. if (lastURL.isNotEmpty())
  237. {
  238. goToURL (lastURL, &lastHeaders, &lastPostData);
  239. lastURL = String::empty;
  240. }
  241. }
  242. void WebBrowserComponent::parentHierarchyChanged()
  243. {
  244. checkWindowAssociation();
  245. }
  246. void WebBrowserComponent::resized()
  247. {
  248. browser->setSize (getWidth(), getHeight());
  249. }
  250. void WebBrowserComponent::visibilityChanged()
  251. {
  252. checkWindowAssociation();
  253. }
  254. bool WebBrowserComponent::pageAboutToLoad (const String&)
  255. {
  256. return true;
  257. }