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.

316 lines
10.0KB

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