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.

313 lines
9.8KB

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