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.
 
 
 
 
 
 
dexed/JuceLibraryCode/modules/juce_gui_extra/native/juce_win32_WebBrowserCompon...

317 lines
9.9 KiB

/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
class WebBrowserComponent::Pimpl : public ActiveXControlComponent
{
public:
Pimpl()
: browser (nullptr),
connectionPoint (nullptr),
adviseCookie (0)
{
}
~Pimpl()
{
if (connectionPoint != nullptr)
connectionPoint->Unadvise (adviseCookie);
if (browser != nullptr)
browser->Release();
}
void createBrowser()
{
createControl (&CLSID_WebBrowser);
browser = (IWebBrowser2*) queryInterface (&IID_IWebBrowser2);
if (IConnectionPointContainer* connectionPointContainer
= (IConnectionPointContainer*) queryInterface (&IID_IConnectionPointContainer))
{
connectionPointContainer->FindConnectionPoint (DIID_DWebBrowserEvents2, &connectionPoint);
if (connectionPoint != nullptr)
{
WebBrowserComponent* const owner = dynamic_cast <WebBrowserComponent*> (getParentComponent());
jassert (owner != nullptr);
EventHandler* handler = new EventHandler (*owner);
connectionPoint->Advise (handler, &adviseCookie);
handler->Release();
}
}
}
void goToURL (const String& url,
const StringArray* headers,
const MemoryBlock* postData)
{
if (browser != nullptr)
{
LPSAFEARRAY sa = nullptr;
VARIANT flags, frame, postDataVar, headersVar; // (_variant_t isn't available in all compilers)
VariantInit (&flags);
VariantInit (&frame);
VariantInit (&postDataVar);
VariantInit (&headersVar);
if (headers != nullptr)
{
V_VT (&headersVar) = VT_BSTR;
V_BSTR (&headersVar) = SysAllocString ((const OLECHAR*) headers->joinIntoString ("\r\n").toWideCharPointer());
}
if (postData != nullptr && postData->getSize() > 0)
{
sa = SafeArrayCreateVector (VT_UI1, 0, (ULONG) postData->getSize());
if (sa != nullptr)
{
void* data = nullptr;
SafeArrayAccessData (sa, &data);
jassert (data != nullptr);
if (data != nullptr)
{
postData->copyTo (data, 0, postData->getSize());
SafeArrayUnaccessData (sa);
VARIANT postDataVar2;
VariantInit (&postDataVar2);
V_VT (&postDataVar2) = VT_ARRAY | VT_UI1;
V_ARRAY (&postDataVar2) = sa;
postDataVar = postDataVar2;
}
}
}
browser->Navigate ((BSTR) (const OLECHAR*) url.toWideCharPointer(),
&flags, &frame, &postDataVar, &headersVar);
if (sa != nullptr)
SafeArrayDestroy (sa);
VariantClear (&flags);
VariantClear (&frame);
VariantClear (&postDataVar);
VariantClear (&headersVar);
}
}
//==============================================================================
IWebBrowser2* browser;
private:
IConnectionPoint* connectionPoint;
DWORD adviseCookie;
//==============================================================================
class EventHandler : public ComBaseClassHelper <IDispatch>,
public ComponentMovementWatcher
{
public:
EventHandler (WebBrowserComponent& owner_)
: ComponentMovementWatcher (&owner_),
owner (owner_)
{
}
JUCE_COMRESULT GetTypeInfoCount (UINT*) { return E_NOTIMPL; }
JUCE_COMRESULT GetTypeInfo (UINT, LCID, ITypeInfo**) { return E_NOTIMPL; }
JUCE_COMRESULT GetIDsOfNames (REFIID, LPOLESTR*, UINT, LCID, DISPID*) { return E_NOTIMPL; }
JUCE_COMRESULT Invoke (DISPID dispIdMember, REFIID /*riid*/, LCID /*lcid*/, WORD /*wFlags*/, DISPPARAMS* pDispParams,
VARIANT* /*pVarResult*/, EXCEPINFO* /*pExcepInfo*/, UINT* /*puArgErr*/)
{
if (dispIdMember == DISPID_BEFORENAVIGATE2)
{
*pDispParams->rgvarg->pboolVal
= owner.pageAboutToLoad (getStringFromVariant (pDispParams->rgvarg[5].pvarVal)) ? VARIANT_FALSE
: VARIANT_TRUE;
return S_OK;
}
else if (dispIdMember == DISPID_DOCUMENTCOMPLETE)
{
owner.pageFinishedLoading (getStringFromVariant (pDispParams->rgvarg[0].pvarVal));
return S_OK;
}
else if (dispIdMember == 263 /*DISPID_WINDOWCLOSING*/)
{
owner.windowCloseRequest();
// setting this bool tells the browser to ignore the event - we'll handle it.
if (pDispParams->cArgs > 0 && pDispParams->rgvarg[0].vt == (VT_BYREF | VT_BOOL))
*pDispParams->rgvarg[0].pboolVal = VARIANT_TRUE;
return S_OK;
}
return E_NOTIMPL;
}
void componentMovedOrResized (bool, bool) override {}
void componentPeerChanged() override {}
void componentVisibilityChanged() override { owner.visibilityChanged(); }
private:
WebBrowserComponent& owner;
static String getStringFromVariant (VARIANT* v)
{
return (v->vt & VT_BYREF) != 0 ? *v->pbstrVal
: v->bstrVal;
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EventHandler)
};
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
};
//==============================================================================
WebBrowserComponent::WebBrowserComponent (const bool unloadPageWhenBrowserIsHidden_)
: browser (nullptr),
blankPageShown (false),
unloadPageWhenBrowserIsHidden (unloadPageWhenBrowserIsHidden_)
{
setOpaque (true);
addAndMakeVisible (browser = new Pimpl());
}
WebBrowserComponent::~WebBrowserComponent()
{
delete browser;
}
//==============================================================================
void WebBrowserComponent::goToURL (const String& url,
const StringArray* headers,
const MemoryBlock* postData)
{
lastURL = url;
lastHeaders.clear();
if (headers != nullptr)
lastHeaders = *headers;
lastPostData.setSize (0);
if (postData != nullptr)
lastPostData = *postData;
blankPageShown = false;
browser->goToURL (url, headers, postData);
}
void WebBrowserComponent::stop()
{
if (browser->browser != nullptr)
browser->browser->Stop();
}
void WebBrowserComponent::goBack()
{
lastURL.clear();
blankPageShown = false;
if (browser->browser != nullptr)
browser->browser->GoBack();
}
void WebBrowserComponent::goForward()
{
lastURL.clear();
if (browser->browser != nullptr)
browser->browser->GoForward();
}
void WebBrowserComponent::refresh()
{
if (browser->browser != nullptr)
browser->browser->Refresh();
}
//==============================================================================
void WebBrowserComponent::paint (Graphics& g)
{
if (browser->browser == nullptr)
g.fillAll (Colours::white);
}
void WebBrowserComponent::checkWindowAssociation()
{
if (isShowing())
{
if (browser->browser == nullptr && getPeer() != nullptr)
{
browser->createBrowser();
reloadLastURL();
}
else
{
if (blankPageShown)
goBack();
}
}
else
{
if (browser != nullptr && unloadPageWhenBrowserIsHidden && ! blankPageShown)
{
// when the component becomes invisible, some stuff like flash
// carries on playing audio, so we need to force it onto a blank
// page to avoid this..
blankPageShown = true;
browser->goToURL ("about:blank", 0, 0);
}
}
}
void WebBrowserComponent::reloadLastURL()
{
if (lastURL.isNotEmpty())
{
goToURL (lastURL, &lastHeaders, &lastPostData);
lastURL.clear();
}
}
void WebBrowserComponent::parentHierarchyChanged()
{
checkWindowAssociation();
}
void WebBrowserComponent::resized()
{
browser->setSize (getWidth(), getHeight());
}
void WebBrowserComponent::visibilityChanged()
{
checkWindowAssociation();
}