Audio plugin host https://kx.studio/carla
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.

juce_win32_WebBrowserComponent.cpp 11KB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. class WebBrowserComponent::Pimpl : public ActiveXControlComponent
  18. {
  19. public:
  20. Pimpl()
  21. : browser (nullptr),
  22. connectionPoint (nullptr),
  23. adviseCookie (0)
  24. {
  25. }
  26. ~Pimpl()
  27. {
  28. if (connectionPoint != nullptr)
  29. connectionPoint->Unadvise (adviseCookie);
  30. if (browser != nullptr)
  31. browser->Release();
  32. }
  33. void createBrowser()
  34. {
  35. createControl (&CLSID_WebBrowser);
  36. browser = (IWebBrowser2*) queryInterface (&IID_IWebBrowser2);
  37. if (IConnectionPointContainer* connectionPointContainer
  38. = (IConnectionPointContainer*) queryInterface (&IID_IConnectionPointContainer))
  39. {
  40. connectionPointContainer->FindConnectionPoint (DIID_DWebBrowserEvents2, &connectionPoint);
  41. if (connectionPoint != nullptr)
  42. {
  43. WebBrowserComponent* const owner = dynamic_cast<WebBrowserComponent*> (getParentComponent());
  44. jassert (owner != nullptr);
  45. EventHandler* handler = new EventHandler (*owner);
  46. connectionPoint->Advise (handler, &adviseCookie);
  47. handler->Release();
  48. }
  49. }
  50. }
  51. void goToURL (const String& url,
  52. const StringArray* headers,
  53. const MemoryBlock* postData)
  54. {
  55. if (browser != nullptr)
  56. {
  57. LPSAFEARRAY sa = nullptr;
  58. VARIANT headerFlags, frame, postDataVar, headersVar; // (_variant_t isn't available in all compilers)
  59. VariantInit (&headerFlags);
  60. VariantInit (&frame);
  61. VariantInit (&postDataVar);
  62. VariantInit (&headersVar);
  63. if (headers != nullptr)
  64. {
  65. V_VT (&headersVar) = VT_BSTR;
  66. V_BSTR (&headersVar) = SysAllocString ((const OLECHAR*) headers->joinIntoString ("\r\n").toWideCharPointer());
  67. }
  68. if (postData != nullptr && postData->getSize() > 0)
  69. {
  70. sa = SafeArrayCreateVector (VT_UI1, 0, (ULONG) postData->getSize());
  71. if (sa != nullptr)
  72. {
  73. void* data = nullptr;
  74. SafeArrayAccessData (sa, &data);
  75. jassert (data != nullptr);
  76. if (data != nullptr)
  77. {
  78. postData->copyTo (data, 0, postData->getSize());
  79. SafeArrayUnaccessData (sa);
  80. VARIANT postDataVar2;
  81. VariantInit (&postDataVar2);
  82. V_VT (&postDataVar2) = VT_ARRAY | VT_UI1;
  83. V_ARRAY (&postDataVar2) = sa;
  84. postDataVar = postDataVar2;
  85. }
  86. }
  87. }
  88. browser->Navigate ((BSTR) (const OLECHAR*) url.toWideCharPointer(),
  89. &headerFlags, &frame, &postDataVar, &headersVar);
  90. if (sa != nullptr)
  91. SafeArrayDestroy (sa);
  92. VariantClear (&headerFlags);
  93. VariantClear (&frame);
  94. VariantClear (&postDataVar);
  95. VariantClear (&headersVar);
  96. }
  97. }
  98. //==============================================================================
  99. IWebBrowser2* browser;
  100. private:
  101. IConnectionPoint* connectionPoint;
  102. DWORD adviseCookie;
  103. //==============================================================================
  104. struct EventHandler : public ComBaseClassHelper<IDispatch>,
  105. public ComponentMovementWatcher
  106. {
  107. EventHandler (WebBrowserComponent& w) : ComponentMovementWatcher (&w), owner (w) {}
  108. JUCE_COMRESULT GetTypeInfoCount (UINT*) { return E_NOTIMPL; }
  109. JUCE_COMRESULT GetTypeInfo (UINT, LCID, ITypeInfo**) { return E_NOTIMPL; }
  110. JUCE_COMRESULT GetIDsOfNames (REFIID, LPOLESTR*, UINT, LCID, DISPID*) { return E_NOTIMPL; }
  111. JUCE_COMRESULT Invoke (DISPID dispIdMember, REFIID /*riid*/, LCID /*lcid*/, WORD /*wFlags*/, DISPPARAMS* pDispParams,
  112. VARIANT* /*pVarResult*/, EXCEPINFO* /*pExcepInfo*/, UINT* /*puArgErr*/)
  113. {
  114. if (dispIdMember == DISPID_BEFORENAVIGATE2)
  115. {
  116. *pDispParams->rgvarg->pboolVal
  117. = owner.pageAboutToLoad (getStringFromVariant (pDispParams->rgvarg[5].pvarVal)) ? VARIANT_FALSE
  118. : VARIANT_TRUE;
  119. return S_OK;
  120. }
  121. if (dispIdMember == 273 /*DISPID_NEWWINDOW3*/)
  122. {
  123. owner.newWindowAttemptingToLoad (pDispParams->rgvarg[0].bstrVal);
  124. *pDispParams->rgvarg[3].pboolVal = VARIANT_TRUE;
  125. return S_OK;
  126. }
  127. if (dispIdMember == DISPID_DOCUMENTCOMPLETE)
  128. {
  129. owner.pageFinishedLoading (getStringFromVariant (pDispParams->rgvarg[0].pvarVal));
  130. return S_OK;
  131. }
  132. if (dispIdMember == 263 /*DISPID_WINDOWCLOSING*/)
  133. {
  134. owner.windowCloseRequest();
  135. // setting this bool tells the browser to ignore the event - we'll handle it.
  136. if (pDispParams->cArgs > 0 && pDispParams->rgvarg[0].vt == (VT_BYREF | VT_BOOL))
  137. *pDispParams->rgvarg[0].pboolVal = VARIANT_TRUE;
  138. return S_OK;
  139. }
  140. return E_NOTIMPL;
  141. }
  142. void componentMovedOrResized (bool, bool) override {}
  143. void componentPeerChanged() override {}
  144. void componentVisibilityChanged() override { owner.visibilityChanged(); }
  145. private:
  146. WebBrowserComponent& owner;
  147. static String getStringFromVariant (VARIANT* v)
  148. {
  149. return (v->vt & VT_BYREF) != 0 ? *v->pbstrVal
  150. : v->bstrVal;
  151. }
  152. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EventHandler)
  153. };
  154. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
  155. };
  156. //==============================================================================
  157. WebBrowserComponent::WebBrowserComponent (const bool unloadPageWhenBrowserIsHidden_)
  158. : browser (nullptr),
  159. blankPageShown (false),
  160. unloadPageWhenBrowserIsHidden (unloadPageWhenBrowserIsHidden_)
  161. {
  162. setOpaque (true);
  163. addAndMakeVisible (browser = new Pimpl());
  164. }
  165. WebBrowserComponent::~WebBrowserComponent()
  166. {
  167. delete browser;
  168. }
  169. //==============================================================================
  170. void WebBrowserComponent::goToURL (const String& url,
  171. const StringArray* headers,
  172. const MemoryBlock* postData)
  173. {
  174. lastURL = url;
  175. if (headers != nullptr)
  176. lastHeaders = *headers;
  177. else
  178. lastHeaders.clear();
  179. if (postData != nullptr)
  180. lastPostData = *postData;
  181. else
  182. lastPostData.reset();
  183. blankPageShown = false;
  184. if (browser->browser == nullptr)
  185. checkWindowAssociation();
  186. browser->goToURL (url, headers, postData);
  187. }
  188. void WebBrowserComponent::stop()
  189. {
  190. if (browser->browser != nullptr)
  191. browser->browser->Stop();
  192. }
  193. void WebBrowserComponent::goBack()
  194. {
  195. lastURL.clear();
  196. blankPageShown = false;
  197. if (browser->browser != nullptr)
  198. browser->browser->GoBack();
  199. }
  200. void WebBrowserComponent::goForward()
  201. {
  202. lastURL.clear();
  203. if (browser->browser != nullptr)
  204. browser->browser->GoForward();
  205. }
  206. void WebBrowserComponent::refresh()
  207. {
  208. if (browser->browser != nullptr)
  209. browser->browser->Refresh();
  210. }
  211. //==============================================================================
  212. void WebBrowserComponent::paint (Graphics& g)
  213. {
  214. if (browser->browser == nullptr)
  215. {
  216. g.fillAll (Colours::white);
  217. checkWindowAssociation();
  218. }
  219. }
  220. void WebBrowserComponent::checkWindowAssociation()
  221. {
  222. if (isShowing())
  223. {
  224. if (browser->browser == nullptr && getPeer() != nullptr)
  225. {
  226. browser->createBrowser();
  227. reloadLastURL();
  228. }
  229. else
  230. {
  231. if (blankPageShown)
  232. goBack();
  233. }
  234. }
  235. else
  236. {
  237. if (browser != nullptr && unloadPageWhenBrowserIsHidden && ! blankPageShown)
  238. {
  239. // when the component becomes invisible, some stuff like flash
  240. // carries on playing audio, so we need to force it onto a blank
  241. // page to avoid this..
  242. blankPageShown = true;
  243. browser->goToURL ("about:blank", 0, 0);
  244. }
  245. }
  246. }
  247. void WebBrowserComponent::reloadLastURL()
  248. {
  249. if (lastURL.isNotEmpty())
  250. {
  251. goToURL (lastURL, &lastHeaders, &lastPostData);
  252. lastURL.clear();
  253. }
  254. }
  255. void WebBrowserComponent::parentHierarchyChanged()
  256. {
  257. checkWindowAssociation();
  258. }
  259. void WebBrowserComponent::resized()
  260. {
  261. browser->setSize (getWidth(), getHeight());
  262. }
  263. void WebBrowserComponent::visibilityChanged()
  264. {
  265. checkWindowAssociation();
  266. }
  267. void WebBrowserComponent::focusGained (FocusChangeType)
  268. {
  269. if (IOleObject* oleObject = (IOleObject*) browser->queryInterface (&IID_IOleObject))
  270. {
  271. if (IOleWindow* oleWindow = (IOleWindow*) browser->queryInterface (&IID_IOleWindow))
  272. {
  273. IOleClientSite* oleClientSite = nullptr;
  274. if (SUCCEEDED (oleObject->GetClientSite (&oleClientSite)))
  275. {
  276. HWND hwnd;
  277. oleWindow->GetWindow (&hwnd);
  278. oleObject->DoVerb (OLEIVERB_UIACTIVATE, nullptr, oleClientSite, 0, hwnd, nullptr);
  279. oleClientSite->Release();
  280. }
  281. oleWindow->Release();
  282. }
  283. oleObject->Release();
  284. }
  285. }