mirror of https://github.com/dcoredump/dexed.git
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.
311 lines
9.6 KiB
311 lines
9.6 KiB
11 years ago
|
/*
|
||
|
==============================================================================
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
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 = String::empty;
|
||
|
blankPageShown = false;
|
||
|
|
||
|
if (browser->browser != nullptr)
|
||
|
browser->browser->GoBack();
|
||
|
}
|
||
|
|
||
|
void WebBrowserComponent::goForward()
|
||
|
{
|
||
|
lastURL = String::empty;
|
||
|
|
||
|
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 = String::empty;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void WebBrowserComponent::parentHierarchyChanged()
|
||
|
{
|
||
|
checkWindowAssociation();
|
||
|
}
|
||
|
|
||
|
void WebBrowserComponent::resized()
|
||
|
{
|
||
|
browser->setSize (getWidth(), getHeight());
|
||
|
}
|
||
|
|
||
|
void WebBrowserComponent::visibilityChanged()
|
||
|
{
|
||
|
checkWindowAssociation();
|
||
|
}
|
||
|
|
||
|
bool WebBrowserComponent::pageAboutToLoad (const String&) { return true; }
|
||
|
void WebBrowserComponent::pageFinishedLoading (const String&) {}
|