mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
WebBrowserComponent: Added a user agent option to change the browser's user agent
This commit is contained in:
parent
57b07997d3
commit
542312296f
9 changed files with 425 additions and 258 deletions
|
|
@ -4,6 +4,43 @@ JUCE breaking changes
|
|||
develop
|
||||
=======
|
||||
|
||||
Change
|
||||
------
|
||||
The constructor of WebBrowserComponent now requires passing in an instance of
|
||||
a new Options class instead of a single option boolean. The
|
||||
WindowsWebView2WebBrowserComponent class was removed.
|
||||
|
||||
Possible Issues
|
||||
---------------
|
||||
Code using the WebBrowserComponent's boolean parameter to indicate if a
|
||||
webpage should be unloaded when the component is hidden, will now fail to
|
||||
compile. Additionally, any code using the WindowsWebView2WebBrowserComponent
|
||||
class will fail to compile. Code relying on the default value of the
|
||||
WebBrowserComponent's constructor are not affected.
|
||||
|
||||
Workaround
|
||||
----------
|
||||
Instead of passing in a single boolean to the WebBrowserComponent's
|
||||
constructor you should now set this option via tha
|
||||
WebBrowserComponent::Options::withKeepPageLoadedWhenBrowserIsHidden method.
|
||||
|
||||
If you were previously using WindowsWebView2WebBrowserComponent to indicate to
|
||||
JUCE that you prefer JUCE to use Windows' Webview2 browser backend, you now do
|
||||
this by setting the WebBrowserComponent::Options::withBackend method. The
|
||||
WebView2Preferences can now be modified with the methods in
|
||||
WebBrowserComponent::Options::WinWebView2.
|
||||
|
||||
Rationale
|
||||
---------
|
||||
The old API made adding further options to the WebBrowserComponent cumbersome
|
||||
especially as the WindowsWebView2WebBrowserComponent already had a parameter
|
||||
very similar to the above Options class, whereas the base class did not use
|
||||
such a parameter. Furthermore, using an option to specify the preferred
|
||||
browser backend is more intuitive then requiring the user to derive from a
|
||||
special class, especially if additional browser backends are added in the
|
||||
future.
|
||||
|
||||
|
||||
Change
|
||||
------
|
||||
The function AudioIODeviceCallback::audioDeviceIOCallback() was removed.
|
||||
|
|
|
|||
|
|
@ -107,6 +107,11 @@ public:
|
|||
*/
|
||||
bool areMouseEventsAllowed() const noexcept { return mouseEventsAllowed; }
|
||||
|
||||
//==============================================================================
|
||||
/** Set an instance of IDispatch where dispatch events should be delivered to
|
||||
*/
|
||||
void setEventHandler (void* eventHandler);
|
||||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
void paint (Graphics&) override;
|
||||
|
|
|
|||
|
|
@ -185,11 +185,3 @@
|
|||
#include "native/juce_android_WebBrowserComponent.cpp"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#if ! JUCE_WINDOWS && JUCE_WEB_BROWSER
|
||||
juce::WebBrowserComponent::WebBrowserComponent (ConstructWithoutPimpl) {}
|
||||
juce::WindowsWebView2WebBrowserComponent::WindowsWebView2WebBrowserComponent (bool unloadWhenHidden,
|
||||
const WebView2Preferences&)
|
||||
: WebBrowserComponent (unloadWhenHidden) {}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -46,6 +46,136 @@ class JUCE_API WebBrowserComponent : public Component
|
|||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
class JUCE_API Options
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
enum class Backend
|
||||
{
|
||||
/**
|
||||
Default web browser backend. WebKit will be used on macOS, gtk-webkit2 on Linux and internet
|
||||
explorer on Windows. On Windows, the default may change to webview2 in the fututre.
|
||||
*/
|
||||
defaultBackend,
|
||||
|
||||
/**
|
||||
Use Internet Explorer as the backend on Windows. By default, IE will use an ancient version
|
||||
of IE. To change this behaviour, you either need to add the following html element into your page's
|
||||
head section:
|
||||
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
|
||||
or you need to change windows registry values for your application. More infromation on the latter
|
||||
can be found here:
|
||||
|
||||
https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/general-info/ee330730(v=vs.85)?redirectedfrom=MSDN#browser-emulation
|
||||
*/
|
||||
ie,
|
||||
|
||||
/**
|
||||
Use the chromium based WebView2 engine on Windows
|
||||
*/
|
||||
webview2
|
||||
};
|
||||
|
||||
/**
|
||||
Use a particular backend to create the WebViewBrowserComponent. JUCE will silently
|
||||
fallback to the default backend if the selected backend is not supported. To check
|
||||
if a specific backend is supported on your platform or not, use
|
||||
WebBrowserComponent::areOptionsSupported.
|
||||
*/
|
||||
[[nodiscard]] Options withBackend (Backend backend) const { return withMember (*this, &Options::browserBackend, backend); }
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Tell JUCE to keep the web page alive when the WebBrowserComponent is not visible.
|
||||
By default, JUCE will replace the current page with a blank page - this can be
|
||||
handy to stop the browser using resources in the background when it's not
|
||||
actually being used.
|
||||
*/
|
||||
[[nodiscard]] Options withKeepPageLoadedWhenBrowserIsHidden () const { return withMember (*this, &Options::keepPageLoadedWhenBrowserIsHidden, true); }
|
||||
|
||||
/**
|
||||
Use a specific user agent string when requesting web pages.
|
||||
*/
|
||||
[[nodiscard]] Options withUserAgent (String ua) const { return withMember (*this, &Options::userAgent, std::move (ua)); }
|
||||
|
||||
//==============================================================================
|
||||
/** Options specific to the WebView2 backend. These options will be ignored
|
||||
if another backend is used.
|
||||
*/
|
||||
class WinWebView2
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Sets a custom location for the WebView2Loader.dll that is not a part of the
|
||||
standard system DLL search paths.
|
||||
*/
|
||||
[[nodiscard]] WinWebView2 withDLLLocation (const File& location) const { return withMember (*this, &WinWebView2::dllLocation, location); }
|
||||
|
||||
/** Sets a non-default location for storing user data for the browser instance. */
|
||||
[[nodiscard]] WinWebView2 withUserDataFolder (const File& folder) const { return withMember (*this, &WinWebView2::userDataFolder, folder); }
|
||||
|
||||
/** If this is set, the status bar usually displayed in the lower-left of the webview
|
||||
will be disabled.
|
||||
*/
|
||||
[[nodiscard]] WinWebView2 withStatusBarDisabled() const { return withMember (*this, &WinWebView2::disableStatusBar, true); }
|
||||
|
||||
/** If this is set, a blank page will be displayed on error instead of the default
|
||||
built-in error page.
|
||||
*/
|
||||
[[nodiscard]] WinWebView2 withBuiltInErrorPageDisabled() const { return withMember (*this, &WinWebView2::disableBuiltInErrorPage, true); }
|
||||
|
||||
/** Sets the background colour that WebView2 renders underneath all web content.
|
||||
|
||||
This colour must either be fully opaque or transparent. On Windows 7 this
|
||||
colour must be opaque.
|
||||
*/
|
||||
[[nodiscard]] WinWebView2 withBackgroundColour (const Colour& colour) const
|
||||
{
|
||||
// the background colour must be either fully opaque or transparent!
|
||||
jassert (colour.isOpaque() || colour.isTransparent());
|
||||
|
||||
return withMember (*this, &WinWebView2::backgroundColour, colour);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
File getDLLLocation() const { return dllLocation; }
|
||||
File getUserDataFolder() const { return userDataFolder; }
|
||||
bool getIsStatusBarDisabled() const noexcept { return disableStatusBar; }
|
||||
bool getIsBuiltInErrorPageDisabled() const noexcept { return disableBuiltInErrorPage; }
|
||||
Colour getBackgroundColour() const { return backgroundColour; }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
File dllLocation, userDataFolder;
|
||||
bool disableStatusBar = false, disableBuiltInErrorPage = false;
|
||||
Colour backgroundColour;
|
||||
};
|
||||
|
||||
[[nodiscard]] Options withWinWebView2Options (const WinWebView2& winWebView2Options) const
|
||||
{
|
||||
return withMember (*this, &Options::winWebView2, winWebView2Options);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Backend getBackend() const noexcept { return browserBackend; }
|
||||
bool keepsPageLoadedWhenBrowserIsHidden() const noexcept { return keepPageLoadedWhenBrowserIsHidden; }
|
||||
String getUserAgent() const { return userAgent; }
|
||||
WinWebView2 getWinWebView2BackendOptions() const { return winWebView2; }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
Backend browserBackend = Backend::defaultBackend;
|
||||
bool keepPageLoadedWhenBrowserIsHidden = false;
|
||||
String userAgent;
|
||||
WinWebView2 winWebView2;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a WebBrowserComponent with default options*/
|
||||
WebBrowserComponent() : WebBrowserComponent (Options {}) {}
|
||||
|
||||
/** Creates a WebBrowserComponent.
|
||||
|
||||
Once it's created and visible, send the browser to a URL using goToURL().
|
||||
|
|
@ -56,11 +186,15 @@ public:
|
|||
the browser using resources in the background when it's not
|
||||
actually being used.
|
||||
*/
|
||||
explicit WebBrowserComponent (bool unloadPageWhenBrowserIsHidden = true);
|
||||
explicit WebBrowserComponent (const Options& options);
|
||||
|
||||
/** Destructor. */
|
||||
~WebBrowserComponent() override;
|
||||
|
||||
//==============================================================================
|
||||
/** Check if the specified options are supported on this platform. */
|
||||
static bool areOptionsSupported (const Options& options);
|
||||
|
||||
//==============================================================================
|
||||
/** Sends the browser to a particular URL.
|
||||
|
||||
|
|
@ -141,17 +275,6 @@ public:
|
|||
/** @internal */
|
||||
class Pimpl;
|
||||
|
||||
protected:
|
||||
friend class WindowsWebView2WebBrowserComponent;
|
||||
|
||||
/** @internal */
|
||||
struct ConstructWithoutPimpl
|
||||
{
|
||||
explicit ConstructWithoutPimpl (bool unloadOnHide) : unloadWhenHidden (unloadOnHide) {}
|
||||
const bool unloadWhenHidden;
|
||||
};
|
||||
explicit WebBrowserComponent (ConstructWithoutPimpl);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
std::unique_ptr<Pimpl> browser;
|
||||
|
|
@ -165,123 +288,6 @@ private:
|
|||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebBrowserComponent)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Class used to create a set of preferences to pass to the WindowsWebView2WebBrowserComponent
|
||||
wrapper constructor to modify aspects of its behaviour and settings.
|
||||
|
||||
You can chain together a series of calls to this class's methods to create a set of whatever
|
||||
preferences you want to specify.
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API WebView2Preferences
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Sets a custom location for the WebView2Loader.dll that is not a part of the
|
||||
standard system DLL search paths.
|
||||
*/
|
||||
[[nodiscard]] WebView2Preferences withDLLLocation (const File& location) const { return with (&WebView2Preferences::dllLocation, location); }
|
||||
|
||||
/** Sets a non-default location for storing user data for the browser instance. */
|
||||
WebView2Preferences withUserDataFolder (const File& folder) const { return with (&WebView2Preferences::userDataFolder, folder); }
|
||||
|
||||
/** If this is set, the status bar usually displayed in the lower-left of the webview
|
||||
will be disabled.
|
||||
*/
|
||||
[[nodiscard]] WebView2Preferences withStatusBarDisabled() const { return with (&WebView2Preferences::disableStatusBar, true); }
|
||||
|
||||
/** If this is set, a blank page will be displayed on error instead of the default
|
||||
built-in error page.
|
||||
*/
|
||||
[[nodiscard]] WebView2Preferences withBuiltInErrorPageDisabled() const { return with (&WebView2Preferences::disableBuiltInErrorPage, true); }
|
||||
|
||||
/** Sets the background colour that WebView2 renders underneath all web content.
|
||||
|
||||
This colour must either be fully opaque or transparent. On Windows 7 this
|
||||
colour must be opaque.
|
||||
*/
|
||||
[[nodiscard]] WebView2Preferences withBackgroundColour (const Colour& colour) const
|
||||
{
|
||||
// the background colour must be either fully opaque or transparent!
|
||||
jassert (colour.isOpaque() || colour.isTransparent());
|
||||
|
||||
return with (&WebView2Preferences::backgroundColour, colour);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
File getDLLLocation() const { return dllLocation; }
|
||||
File getUserDataFolder() const { return userDataFolder; }
|
||||
bool getIsStatusBarDisabled() const noexcept { return disableStatusBar; }
|
||||
bool getIsBuiltInErrorPageDisabled() const noexcept { return disableBuiltInErrorPage; }
|
||||
Colour getBackgroundColour() const { return backgroundColour; }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
template <typename Member, typename Item>
|
||||
WebView2Preferences with (Member&& member, Item&& item) const
|
||||
{
|
||||
auto options = *this;
|
||||
options.*member = std::forward<Item> (item);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
File dllLocation, userDataFolder;
|
||||
bool disableStatusBar = false, disableBuiltInErrorPage = false;
|
||||
Colour backgroundColour = Colours::white;
|
||||
};
|
||||
|
||||
/**
|
||||
If you have enabled the JUCE_USE_WIN_WEBVIEW2 flag then this wrapper will attempt to
|
||||
use the Microsoft Edge (Chromium) WebView2 control instead of IE on Windows. It will
|
||||
behave the same as WebBrowserComponent on all other platforms and will fall back to
|
||||
IE on Windows if the WebView2 requirements are not met.
|
||||
|
||||
This requires Microsoft Edge (minimum version 82.0.488.0) to be installed at runtime.
|
||||
|
||||
Currently this also requires that WebView2Loader.dll, which can be found in the
|
||||
Microsoft.Web.WebView package, is installed at runtime. As this is not a standard
|
||||
system DLL, we can't rely on it being found via the normal system DLL search paths.
|
||||
Therefore in order to use WebView2 you need to ensure that WebView2Loader.dll is
|
||||
installed either to a location covered by the Windows DLL system search paths or
|
||||
to the folder specified in the WebView2Preferences.
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class WindowsWebView2WebBrowserComponent : public WebBrowserComponent
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a WebBrowserComponent that is compatible with the WebView2 control
|
||||
on Windows.
|
||||
|
||||
@param unloadPageWhenBrowserIsHidden if this is true, then when the browser
|
||||
component is taken offscreen, it'll clear the current page
|
||||
and replace it with a blank page - this can be handy to stop
|
||||
the browser using resources in the background when it's not
|
||||
actually being used.
|
||||
@param preferences a set of preferences used to control aspects of the webview's
|
||||
behaviour.
|
||||
|
||||
@see WebView2Preferences
|
||||
*/
|
||||
WindowsWebView2WebBrowserComponent (bool unloadPageWhenBrowserIsHidden = true,
|
||||
const WebView2Preferences& preferences = {});
|
||||
|
||||
// This constructor has been deprecated. Use the new constructor that takes a
|
||||
// WebView2Preferences instead.
|
||||
explicit WindowsWebView2WebBrowserComponent (bool unloadPageWhenBrowserIsHidden = true,
|
||||
const File& dllLocation = {},
|
||||
const File& userDataFolder = {})
|
||||
: WindowsWebView2WebBrowserComponent (unloadPageWhenBrowserIsHidden,
|
||||
WebView2Preferences().withDLLLocation (dllLocation)
|
||||
.withUserDataFolder (userDataFolder))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -175,7 +175,8 @@ DECLARE_JNI_CLASS (AndroidCookieManager, "android/webkit/CookieManager")
|
|||
METHOD (setBuiltInZoomControls, "setBuiltInZoomControls", "(Z)V") \
|
||||
METHOD (setDisplayZoomControls, "setDisplayZoomControls", "(Z)V") \
|
||||
METHOD (setJavaScriptEnabled, "setJavaScriptEnabled", "(Z)V") \
|
||||
METHOD (setSupportMultipleWindows, "setSupportMultipleWindows", "(Z)V")
|
||||
METHOD (setSupportMultipleWindows, "setSupportMultipleWindows", "(Z)V") \
|
||||
METHOD (setUserAgentString, "setUserAgentString", "(Ljava/lang/String;)V")
|
||||
|
||||
DECLARE_JNI_CLASS (WebSettings, "android/webkit/WebSettings")
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
|
@ -197,7 +198,7 @@ class WebBrowserComponent::Pimpl : public AndroidViewComponent,
|
|||
public AsyncUpdater
|
||||
{
|
||||
public:
|
||||
Pimpl (WebBrowserComponent& o)
|
||||
Pimpl (WebBrowserComponent& o, const String& userAgent)
|
||||
: owner (o)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
|
@ -210,6 +211,9 @@ public:
|
|||
env->CallVoidMethod (settings, WebSettings.setDisplayZoomControls, false);
|
||||
env->CallVoidMethod (settings, WebSettings.setSupportMultipleWindows, true);
|
||||
|
||||
if (userAgent.isNotEmpty())
|
||||
env->CallVoidMethod (settings, WebSettings.setUserAgentString, javaString (userAgent).get());
|
||||
|
||||
juceWebChromeClient = GlobalRef (LocalRef<jobject> (env->NewObject (JuceWebChromeClient, JuceWebChromeClient.constructor,
|
||||
reinterpret_cast<jlong> (this))));
|
||||
env->CallVoidMethod ((jobject) getView(), AndroidWebView.setWebChromeClient, juceWebChromeClient.get());
|
||||
|
|
@ -582,13 +586,13 @@ private:
|
|||
};
|
||||
|
||||
//==============================================================================
|
||||
WebBrowserComponent::WebBrowserComponent (const bool unloadWhenHidden)
|
||||
WebBrowserComponent::WebBrowserComponent (const Options& options)
|
||||
: blankPageShown (false),
|
||||
unloadPageWhenHidden (unloadWhenHidden)
|
||||
unloadPageWhenHidden (! options.keepsPageLoadedWhenBrowserIsHidden())
|
||||
{
|
||||
setOpaque (true);
|
||||
|
||||
browser.reset (new Pimpl (*this));
|
||||
browser.reset (new Pimpl (*this, options.getUserAgent()));
|
||||
addAndMakeVisible (browser.get());
|
||||
}
|
||||
|
||||
|
|
@ -719,6 +723,11 @@ void WebBrowserComponent::clearCookies()
|
|||
}
|
||||
}
|
||||
|
||||
bool WebBrowserComponent::areOptionsSupported (const Options& options)
|
||||
{
|
||||
return (options.getBackend() == Options::Backend::defaultBackend);
|
||||
}
|
||||
|
||||
WebBrowserComponent::Pimpl::JuceWebViewClient16_Class WebBrowserComponent::Pimpl::JuceWebViewClient16;
|
||||
WebBrowserComponent::Pimpl::JuceWebViewClient21_Class WebBrowserComponent::Pimpl::JuceWebViewClient21;
|
||||
WebBrowserComponent::Pimpl::JuceWebChromeClient_Class WebBrowserComponent::Pimpl::JuceWebChromeClient;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@ public:
|
|||
JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_settings_set_hardware_acceleration_policy, juce_webkit_settings_set_hardware_acceleration_policy,
|
||||
(WebKitSettings*, int), void)
|
||||
|
||||
JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_settings_set_user_agent, juce_webkit_settings_set_user_agent,
|
||||
(WebKitSettings*, const gchar*), void)
|
||||
|
||||
JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_web_view_new_with_settings, juce_webkit_web_view_new_with_settings,
|
||||
(WebKitSettings*), GtkWidget*)
|
||||
|
||||
|
|
@ -168,6 +171,7 @@ private:
|
|||
return loadSymbols (webkitLib,
|
||||
makeSymbolBinding (juce_webkit_settings_new, "webkit_settings_new"),
|
||||
makeSymbolBinding (juce_webkit_settings_set_hardware_acceleration_policy, "webkit_settings_set_hardware_acceleration_policy"),
|
||||
makeSymbolBinding (juce_webkit_settings_set_user_agent, "webkit_settings_set_user_agent"),
|
||||
makeSymbolBinding (juce_webkit_web_view_new_with_settings, "webkit_web_view_new_with_settings"),
|
||||
makeSymbolBinding (juce_webkit_policy_decision_use, "webkit_policy_decision_use"),
|
||||
makeSymbolBinding (juce_webkit_policy_decision_ignore, "webkit_policy_decision_ignore"),
|
||||
|
|
@ -344,9 +348,10 @@ class GtkChildProcess : private CommandReceiver::Responder
|
|||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
GtkChildProcess (int inChannel, int outChannelToUse)
|
||||
GtkChildProcess (int inChannel, int outChannelToUse, const String& userAgentToUse)
|
||||
: outChannel (outChannelToUse),
|
||||
receiver (this, inChannel)
|
||||
receiver (this, inChannel),
|
||||
userAgent (userAgentToUse)
|
||||
{}
|
||||
|
||||
int entry()
|
||||
|
|
@ -361,6 +366,8 @@ public:
|
|||
auto* settings = WebKitSymbols::getInstance()->juce_webkit_settings_new();
|
||||
WebKitSymbols::getInstance()->juce_webkit_settings_set_hardware_acceleration_policy (settings,
|
||||
/* WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER */ 2);
|
||||
if (userAgent.isNotEmpty())
|
||||
WebKitSymbols::getInstance()->juce_webkit_settings_set_user_agent (settings, userAgent.toRawUTF8());
|
||||
|
||||
auto* plug = WebKitSymbols::getInstance()->juce_gtk_plug_new (0);
|
||||
auto* container = WebKitSymbols::getInstance()->juce_gtk_scrolled_window_new (nullptr, nullptr);
|
||||
|
|
@ -606,6 +613,7 @@ private:
|
|||
|
||||
int outChannel = 0;
|
||||
CommandReceiver receiver;
|
||||
String userAgent;
|
||||
WebKitWebView* webview = nullptr;
|
||||
Array<WebKitPolicyDecision*> decisions;
|
||||
};
|
||||
|
|
@ -615,8 +623,8 @@ class WebBrowserComponent::Pimpl : private Thread,
|
|||
private CommandReceiver::Responder
|
||||
{
|
||||
public:
|
||||
Pimpl (WebBrowserComponent& parent)
|
||||
: Thread ("Webview"), owner (parent)
|
||||
Pimpl (WebBrowserComponent& parent, const String& userAgentToUse)
|
||||
: Thread ("Webview"), owner (parent), userAgent (userAgentToUse)
|
||||
{
|
||||
webKitIsAvailable = WebKitSymbols::getInstance()->isWebKitAvailable();
|
||||
}
|
||||
|
|
@ -776,7 +784,6 @@ private:
|
|||
close (inPipe[0]);
|
||||
close (outPipe[1]);
|
||||
|
||||
HeapBlock<const char*> argv (5);
|
||||
StringArray arguments;
|
||||
|
||||
arguments.add (File::getSpecialLocation (File::currentExecutableFile).getFullPathName());
|
||||
|
|
@ -784,15 +791,21 @@ private:
|
|||
arguments.add (String (outPipe[0]));
|
||||
arguments.add (String (inPipe [1]));
|
||||
|
||||
for (int i = 0; i < arguments.size(); ++i)
|
||||
argv[i] = arguments[i].toRawUTF8();
|
||||
if (userAgent.isNotEmpty())
|
||||
arguments.add (userAgent);
|
||||
|
||||
argv[4] = nullptr;
|
||||
std::vector<const char*> argv;
|
||||
argv.reserve (static_cast<std::size_t> (arguments.size() + 1));
|
||||
|
||||
for (const auto& arg : arguments)
|
||||
argv.push_back (arg.toRawUTF8());
|
||||
|
||||
argv.push_back (nullptr);
|
||||
|
||||
if (JUCEApplicationBase::isStandaloneApp())
|
||||
execv (arguments[0].toRawUTF8(), (char**) argv.getData());
|
||||
execv (arguments[0].toRawUTF8(), (char**) argv.data());
|
||||
else
|
||||
juce_gtkWebkitMain (4, (const char**) argv.getData());
|
||||
juce_gtkWebkitMain (arguments.size(), (const char**) argv.data());
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
|
@ -904,6 +917,7 @@ private:
|
|||
bool webKitIsAvailable = false;
|
||||
|
||||
WebBrowserComponent& owner;
|
||||
String userAgent;
|
||||
std::unique_ptr<CommandReceiver> receiver;
|
||||
int childProcess = 0, inChannel = 0, outChannel = 0;
|
||||
int threadControl[2];
|
||||
|
|
@ -913,9 +927,8 @@ private:
|
|||
};
|
||||
|
||||
//==============================================================================
|
||||
WebBrowserComponent::WebBrowserComponent (const bool unloadWhenHidden)
|
||||
: browser (new Pimpl (*this)),
|
||||
unloadPageWhenHidden (unloadWhenHidden)
|
||||
WebBrowserComponent::WebBrowserComponent (const Options& options)
|
||||
: browser (new Pimpl (*this, options.getUserAgent()))
|
||||
{
|
||||
ignoreUnused (blankPageShown);
|
||||
ignoreUnused (unloadPageWhenHidden);
|
||||
|
|
@ -1018,13 +1031,19 @@ void WebBrowserComponent::clearCookies()
|
|||
jassertfalse;
|
||||
}
|
||||
|
||||
bool WebBrowserComponent::areOptionsSupported (const Options& options)
|
||||
{
|
||||
return (options.getBackend() == Options::Backend::defaultBackend);
|
||||
}
|
||||
|
||||
int juce_gtkWebkitMain (int argc, const char* argv[])
|
||||
{
|
||||
if (argc != 4)
|
||||
if (argc < 4)
|
||||
return -1;
|
||||
|
||||
GtkChildProcess child (String (argv[2]).getIntValue(),
|
||||
String (argv[3]).getIntValue());
|
||||
String (argv[3]).getIntValue(),
|
||||
argc >= 5 ? String (argv[4]) : String());
|
||||
|
||||
return child.entry();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -412,7 +412,7 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
|
|||
class WebViewImpl : public WebViewBase
|
||||
{
|
||||
public:
|
||||
WebViewImpl (WebBrowserComponent* owner)
|
||||
WebViewImpl (WebBrowserComponent* owner, const String& userAgent)
|
||||
{
|
||||
static WebViewKeyEquivalentResponder<WebView> webviewClass;
|
||||
|
||||
|
|
@ -420,6 +420,8 @@ public:
|
|||
frameName: nsEmptyString()
|
||||
groupName: nsEmptyString()]);
|
||||
|
||||
webView.get().customUserAgent = juceStringToNS (userAgent);
|
||||
|
||||
static DownloadClickDetectorClass cls;
|
||||
clickListener.reset ([cls.createInstance() init]);
|
||||
DownloadClickDetectorClass::setOwner (clickListener.get(), owner);
|
||||
|
|
@ -497,7 +499,7 @@ JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
|||
class API_AVAILABLE (macos (10.11)) WKWebViewImpl : public WebViewBase
|
||||
{
|
||||
public:
|
||||
WKWebViewImpl (WebBrowserComponent* owner)
|
||||
WKWebViewImpl (WebBrowserComponent* owner, const String& userAgent)
|
||||
{
|
||||
#if JUCE_MAC
|
||||
static WebViewKeyEquivalentResponder<WKWebView> webviewClass;
|
||||
|
|
@ -507,6 +509,9 @@ public:
|
|||
webView.reset ([[WKWebView alloc] initWithFrame: CGRectMake (0, 0, 100.0f, 100.0f)]);
|
||||
#endif
|
||||
|
||||
if (userAgent.isNotEmpty())
|
||||
webView.get().customUserAgent = juceStringToNS (userAgent);
|
||||
|
||||
static WebViewDelegateClass cls;
|
||||
webViewDelegate.reset ([cls.createInstance() init]);
|
||||
WebViewDelegateClass::setOwner (webViewDelegate.get(), owner);
|
||||
|
|
@ -576,13 +581,13 @@ class WebBrowserComponent::Pimpl
|
|||
#endif
|
||||
{
|
||||
public:
|
||||
Pimpl (WebBrowserComponent* owner)
|
||||
Pimpl (WebBrowserComponent* owner, const String& userAgent)
|
||||
{
|
||||
if (@available (macOS 10.11, *))
|
||||
webView = std::make_unique<WKWebViewImpl> (owner);
|
||||
webView = std::make_unique<WKWebViewImpl> (owner, userAgent);
|
||||
#if JUCE_MAC
|
||||
else
|
||||
webView = std::make_unique<WebViewImpl> (owner);
|
||||
webView = std::make_unique<WebViewImpl> (owner, userAgent);
|
||||
#endif
|
||||
|
||||
setView (webView->getWebView());
|
||||
|
|
@ -612,11 +617,11 @@ private:
|
|||
};
|
||||
|
||||
//==============================================================================
|
||||
WebBrowserComponent::WebBrowserComponent (bool unloadWhenHidden)
|
||||
: unloadPageWhenHidden (unloadWhenHidden)
|
||||
WebBrowserComponent::WebBrowserComponent (const Options& options)
|
||||
: unloadPageWhenHidden (! options.keepsPageLoadedWhenBrowserIsHidden())
|
||||
{
|
||||
setOpaque (true);
|
||||
browser.reset (new Pimpl (this));
|
||||
browser.reset (new Pimpl (this, options.getUserAgent()));
|
||||
addAndMakeVisible (browser.get());
|
||||
}
|
||||
|
||||
|
|
@ -738,4 +743,10 @@ void WebBrowserComponent::clearCookies()
|
|||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool WebBrowserComponent::areOptionsSupported (const Options& options)
|
||||
{
|
||||
return (options.getBackend() == Options::Backend::defaultBackend);
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -147,6 +147,12 @@ namespace ActiveXHelpers
|
|||
~JuceIOleClientSite()
|
||||
{
|
||||
inplaceSite->Release();
|
||||
|
||||
if (dispatchEventHandler != nullptr)
|
||||
{
|
||||
dispatchEventHandler->Release();
|
||||
dispatchEventHandler = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
JUCE_COMRESULT QueryInterface (REFIID type, void** result)
|
||||
|
|
@ -159,6 +165,12 @@ namespace ActiveXHelpers
|
|||
*result = static_cast<IOleInPlaceSite*> (inplaceSite);
|
||||
return S_OK;
|
||||
}
|
||||
else if (type == __uuidof(IDispatch) && dispatchEventHandler != nullptr)
|
||||
{
|
||||
dispatchEventHandler->AddRef();
|
||||
*result = dispatchEventHandler;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return ComBaseClassHelper <IOleClientSite>::QueryInterface (type, result);
|
||||
|
||||
|
|
@ -180,7 +192,31 @@ namespace ActiveXHelpers
|
|||
return S_FALSE;
|
||||
}
|
||||
|
||||
void setEventHandler (void* eventHandler)
|
||||
{
|
||||
IDispatch* newEventHandler = nullptr;
|
||||
|
||||
if (eventHandler != nullptr)
|
||||
{
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
|
||||
|
||||
auto iidIDispatch = __uuidof (IDispatch);
|
||||
|
||||
if (static_cast<IUnknown*>(eventHandler)->QueryInterface (iidIDispatch, (void**) &newEventHandler) != S_OK
|
||||
|| newEventHandler == nullptr)
|
||||
return;
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
}
|
||||
|
||||
if (dispatchEventHandler != nullptr)
|
||||
dispatchEventHandler->Release();
|
||||
|
||||
dispatchEventHandler = newEventHandler;
|
||||
}
|
||||
|
||||
JuceIOleInPlaceSite* inplaceSite;
|
||||
IDispatch* dispatchEventHandler = nullptr;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -490,6 +526,12 @@ intptr_t ActiveXControlComponent::offerEventToActiveXControlStatic (void* ptr)
|
|||
return S_FALSE;
|
||||
}
|
||||
|
||||
void ActiveXControlComponent::setEventHandler (void* eventHandler)
|
||||
{
|
||||
if (control->clientSite != nullptr)
|
||||
control->clientSite->setEventHandler (eventHandler);
|
||||
}
|
||||
|
||||
LRESULT juce_offerEventToActiveXControl (::MSG& msg);
|
||||
LRESULT juce_offerEventToActiveXControl (::MSG& msg)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -52,7 +52,9 @@ class Win32WebView : public InternalWebViewType,
|
|||
public ActiveXControlComponent
|
||||
{
|
||||
public:
|
||||
Win32WebView (WebBrowserComponent& owner)
|
||||
Win32WebView (WebBrowserComponent& parent, const String& userAgentToUse)
|
||||
: owner (parent),
|
||||
userAgent (userAgentToUse)
|
||||
{
|
||||
owner.addAndMakeVisible (this);
|
||||
}
|
||||
|
|
@ -78,6 +80,7 @@ public:
|
|||
|
||||
auto iidWebBrowser2 = __uuidof (IWebBrowser2);
|
||||
auto iidConnectionPointContainer = __uuidof (IConnectionPointContainer);
|
||||
auto iidOleControl = __uuidof (IOleControl);
|
||||
|
||||
browser = (IWebBrowser2*) queryInterface (&iidWebBrowser2);
|
||||
|
||||
|
|
@ -87,17 +90,21 @@ public:
|
|||
|
||||
if (connectionPoint != nullptr)
|
||||
{
|
||||
if (auto* owner = dynamic_cast<WebBrowserComponent*> (Component::getParentComponent()))
|
||||
{
|
||||
auto handler = new EventHandler (*owner);
|
||||
connectionPoint->Advise (handler, &adviseCookie);
|
||||
handler->Release();
|
||||
}
|
||||
auto handler = new EventHandler (*this);
|
||||
connectionPoint->Advise (handler, &adviseCookie);
|
||||
setEventHandler (handler);
|
||||
handler->Release();
|
||||
}
|
||||
|
||||
connectionPointContainer->Release();
|
||||
}
|
||||
|
||||
if (auto oleControl = (IOleControl*) queryInterface (&iidOleControl))
|
||||
{
|
||||
oleControl->OnAmbientPropertyChange (/*DISPID_AMBIENT_USERAGENT*/-5513);
|
||||
oleControl->Release();
|
||||
}
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
}
|
||||
|
||||
|
|
@ -106,7 +113,7 @@ public:
|
|||
return browser != nullptr;
|
||||
}
|
||||
|
||||
void goToURL (const String& url, const StringArray* headers, const MemoryBlock* postData) override
|
||||
void goToURL (const String& url, const StringArray* requestedHeaders, const MemoryBlock* postData) override
|
||||
{
|
||||
if (browser != nullptr)
|
||||
{
|
||||
|
|
@ -116,10 +123,18 @@ public:
|
|||
VariantInit (&postDataVar);
|
||||
VariantInit (&headersVar);
|
||||
|
||||
if (headers != nullptr)
|
||||
StringArray headers;
|
||||
|
||||
if (userAgent.isNotEmpty())
|
||||
headers.add("User-Agent: " + userAgent);
|
||||
|
||||
if (requestedHeaders != nullptr)
|
||||
headers.addArray (*requestedHeaders);
|
||||
|
||||
if (headers.size() > 0)
|
||||
{
|
||||
V_VT (&headersVar) = VT_BSTR;
|
||||
V_BSTR (&headersVar) = SysAllocString ((const OLECHAR*) headers->joinIntoString ("\r\n").toWideCharPointer());
|
||||
V_BSTR (&headersVar) = SysAllocString ((const OLECHAR*) headers.joinIntoString ("\r\n").toWideCharPointer());
|
||||
}
|
||||
|
||||
if (postData != nullptr && postData->getSize() > 0)
|
||||
|
|
@ -225,41 +240,51 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
WebBrowserComponent& owner;
|
||||
IWebBrowser2* browser = nullptr;
|
||||
IConnectionPoint* connectionPoint = nullptr;
|
||||
DWORD adviseCookie = 0;
|
||||
String userAgent;
|
||||
|
||||
//==============================================================================
|
||||
struct EventHandler : public ComBaseClassHelper<IDispatch>,
|
||||
public ComponentMovementWatcher
|
||||
{
|
||||
EventHandler (WebBrowserComponent& w) : ComponentMovementWatcher (&w), owner (w) {}
|
||||
EventHandler (Win32WebView& w) : ComponentMovementWatcher (&w.owner), owner (w) {}
|
||||
|
||||
JUCE_COMRESULT GetTypeInfoCount (UINT*) override { return E_NOTIMPL; }
|
||||
JUCE_COMRESULT GetTypeInfo (UINT, LCID, ITypeInfo**) override { return E_NOTIMPL; }
|
||||
JUCE_COMRESULT GetIDsOfNames (REFIID, LPOLESTR*, UINT, LCID, DISPID*) override { return E_NOTIMPL; }
|
||||
|
||||
JUCE_COMRESULT Invoke (DISPID dispIdMember, REFIID /*riid*/, LCID /*lcid*/, WORD /*wFlags*/, DISPPARAMS* pDispParams,
|
||||
VARIANT* /*pVarResult*/, EXCEPINFO* /*pExcepInfo*/, UINT* /*puArgErr*/) override
|
||||
VARIANT* pVarResult, EXCEPINFO* /*pExcepInfo*/, UINT* /*puArgErr*/) override
|
||||
{
|
||||
|
||||
if (dispIdMember == /*DISPID_AMBIENT_USERAGENT*/-5513)
|
||||
{
|
||||
V_VT( pVarResult ) = VT_BSTR;
|
||||
V_BSTR( pVarResult ) = SysAllocString ((const OLECHAR*) String(owner.userAgent).toWideCharPointer());;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (dispIdMember == DISPID_BEFORENAVIGATE2)
|
||||
{
|
||||
*pDispParams->rgvarg->pboolVal
|
||||
= owner.pageAboutToLoad (getStringFromVariant (pDispParams->rgvarg[5].pvarVal)) ? VARIANT_FALSE
|
||||
= owner.owner.pageAboutToLoad (getStringFromVariant (pDispParams->rgvarg[5].pvarVal)) ? VARIANT_FALSE
|
||||
: VARIANT_TRUE;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (dispIdMember == 273 /*DISPID_NEWWINDOW3*/)
|
||||
{
|
||||
owner.newWindowAttemptingToLoad (pDispParams->rgvarg[0].bstrVal);
|
||||
owner.owner.newWindowAttemptingToLoad (pDispParams->rgvarg[0].bstrVal);
|
||||
*pDispParams->rgvarg[3].pboolVal = VARIANT_TRUE;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (dispIdMember == DISPID_DOCUMENTCOMPLETE)
|
||||
{
|
||||
owner.pageFinishedLoading (getStringFromVariant (pDispParams->rgvarg[0].pvarVal));
|
||||
owner.owner.pageFinishedLoading (getStringFromVariant (pDispParams->rgvarg[0].pvarVal));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
@ -280,7 +305,7 @@ private:
|
|||
String message (messageBuffer, size);
|
||||
LocalFree (messageBuffer);
|
||||
|
||||
if (! owner.pageLoadHadNetworkError (message))
|
||||
if (! owner.owner.pageLoadHadNetworkError (message))
|
||||
*pDispParams->rgvarg[0].pboolVal = VARIANT_TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -289,7 +314,7 @@ private:
|
|||
|
||||
if (dispIdMember == 263 /*DISPID_WINDOWCLOSING*/)
|
||||
{
|
||||
owner.windowCloseRequest();
|
||||
owner.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))
|
||||
|
|
@ -309,7 +334,7 @@ private:
|
|||
using ComponentMovementWatcher::componentMovedOrResized;
|
||||
|
||||
private:
|
||||
WebBrowserComponent& owner;
|
||||
Win32WebView& owner;
|
||||
|
||||
static String getStringFromVariant (VARIANT* v)
|
||||
{
|
||||
|
|
@ -333,12 +358,15 @@ class WebView2 : public InternalWebViewType,
|
|||
public ComponentMovementWatcher
|
||||
{
|
||||
public:
|
||||
WebView2 (WebBrowserComponent& o, const WebView2Preferences& prefs)
|
||||
WebView2 (WebBrowserComponent& o, const WebBrowserComponent::Options& prefs)
|
||||
: ComponentMovementWatcher (&o),
|
||||
owner (o),
|
||||
preferences (prefs)
|
||||
preferences (prefs.getWinWebView2BackendOptions()),
|
||||
userAgent (prefs.getUserAgent())
|
||||
{
|
||||
if (! createWebViewEnvironment())
|
||||
if (auto handle = createWebViewHandle (preferences))
|
||||
webViewHandle = std::move (*handle);
|
||||
else
|
||||
throw std::runtime_error ("Failed to create the CoreWebView2Environemnt");
|
||||
|
||||
owner.addAndMakeVisible (this);
|
||||
|
|
@ -348,16 +376,13 @@ public:
|
|||
{
|
||||
removeEventHandlers();
|
||||
closeWebView();
|
||||
|
||||
if (webView2LoaderHandle != nullptr)
|
||||
::FreeLibrary (webView2LoaderHandle);
|
||||
}
|
||||
|
||||
void createBrowser() override
|
||||
{
|
||||
if (webView == nullptr)
|
||||
{
|
||||
jassert (webViewEnvironment != nullptr);
|
||||
jassert (webViewHandle.environment != nullptr);
|
||||
createWebView();
|
||||
}
|
||||
}
|
||||
|
|
@ -437,6 +462,56 @@ public:
|
|||
owner.visibilityChanged();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct WebViewHandle
|
||||
{
|
||||
using LibraryRef = std::unique_ptr<typename std::pointer_traits<HMODULE>::element_type, decltype(&::FreeLibrary)>;
|
||||
LibraryRef loaderHandle {nullptr, &::FreeLibrary};
|
||||
ComSmartPtr<ICoreWebView2Environment> environment;
|
||||
};
|
||||
|
||||
static std::optional<WebViewHandle> createWebViewHandle(const WebBrowserComponent::Options::WinWebView2& options)
|
||||
{
|
||||
using CreateWebViewEnvironmentWithOptionsFunc = HRESULT (*) (PCWSTR, PCWSTR,
|
||||
ICoreWebView2EnvironmentOptions*,
|
||||
ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler*);
|
||||
|
||||
auto dllPath = options.getDLLLocation().getFullPathName();
|
||||
|
||||
if (dllPath.isEmpty())
|
||||
dllPath = "WebView2Loader.dll";
|
||||
|
||||
WebViewHandle result;
|
||||
|
||||
result.loaderHandle = WebViewHandle::LibraryRef (LoadLibraryA (dllPath.toUTF8()), &::FreeLibrary);
|
||||
|
||||
if (result.loaderHandle == nullptr)
|
||||
return {};
|
||||
|
||||
auto* createWebViewEnvironmentWithOptions = (CreateWebViewEnvironmentWithOptionsFunc) GetProcAddress (result.loaderHandle.get(),
|
||||
"CreateCoreWebView2EnvironmentWithOptions");
|
||||
if (createWebViewEnvironmentWithOptions == nullptr)
|
||||
return {};
|
||||
|
||||
auto webViewOptions = Microsoft::WRL::Make<CoreWebView2EnvironmentOptions>();
|
||||
const auto userDataFolder = options.getUserDataFolder().getFullPathName();
|
||||
|
||||
auto hr = createWebViewEnvironmentWithOptions (nullptr,
|
||||
userDataFolder.isNotEmpty() ? userDataFolder.toWideCharPointer() : nullptr,
|
||||
webViewOptions.Get(),
|
||||
Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>(
|
||||
[&result] (HRESULT, ICoreWebView2Environment* env) -> HRESULT
|
||||
{
|
||||
result.environment = env;
|
||||
return S_OK;
|
||||
}).Get());
|
||||
|
||||
if (! SUCCEEDED (hr))
|
||||
return {};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
template <class ArgType>
|
||||
|
|
@ -618,52 +693,19 @@ private:
|
|||
{
|
||||
settings->put_IsStatusBarEnabled (! preferences.getIsStatusBarDisabled());
|
||||
settings->put_IsBuiltInErrorPageEnabled (! preferences.getIsBuiltInErrorPageDisabled());
|
||||
|
||||
if (userAgent.isNotEmpty())
|
||||
{
|
||||
ComSmartPtr<ICoreWebView2Settings2> settings2;
|
||||
|
||||
settings.QueryInterface (settings2);
|
||||
|
||||
if (settings2 != nullptr)
|
||||
settings2->put_UserAgent (userAgent.toWideCharPointer());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool createWebViewEnvironment()
|
||||
{
|
||||
using CreateWebViewEnvironmentWithOptionsFunc = HRESULT (*) (PCWSTR, PCWSTR,
|
||||
ICoreWebView2EnvironmentOptions*,
|
||||
ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler*);
|
||||
|
||||
auto dllPath = preferences.getDLLLocation().getFullPathName();
|
||||
|
||||
if (dllPath.isEmpty())
|
||||
dllPath = "WebView2Loader.dll";
|
||||
|
||||
webView2LoaderHandle = LoadLibraryA (dllPath.toUTF8());
|
||||
|
||||
if (webView2LoaderHandle == nullptr)
|
||||
return false;
|
||||
|
||||
auto* createWebViewEnvironmentWithOptions = (CreateWebViewEnvironmentWithOptionsFunc) GetProcAddress (webView2LoaderHandle,
|
||||
"CreateCoreWebView2EnvironmentWithOptions");
|
||||
if (createWebViewEnvironmentWithOptions == nullptr)
|
||||
{
|
||||
// failed to load WebView2Loader.dll
|
||||
jassertfalse;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto options = Microsoft::WRL::Make<CoreWebView2EnvironmentOptions>();
|
||||
const auto userDataFolder = preferences.getUserDataFolder().getFullPathName();
|
||||
|
||||
auto hr = createWebViewEnvironmentWithOptions (nullptr,
|
||||
userDataFolder.isNotEmpty() ? userDataFolder.toWideCharPointer() : nullptr,
|
||||
options.Get(),
|
||||
Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>(
|
||||
[weakThis = WeakReference<WebView2> { this }] (HRESULT, ICoreWebView2Environment* env) -> HRESULT
|
||||
{
|
||||
if (weakThis != nullptr)
|
||||
weakThis->webViewEnvironment = env;
|
||||
|
||||
return S_OK;
|
||||
}).Get());
|
||||
|
||||
return SUCCEEDED (hr);
|
||||
}
|
||||
|
||||
void createWebView()
|
||||
{
|
||||
if (auto* peer = getPeer())
|
||||
|
|
@ -672,7 +714,7 @@ private:
|
|||
|
||||
WeakReference<WebView2> weakThis (this);
|
||||
|
||||
webViewEnvironment->CreateCoreWebView2Controller ((HWND) peer->getNativeHandle(),
|
||||
webViewHandle.environment->CreateCoreWebView2Controller ((HWND) peer->getNativeHandle(),
|
||||
Callback<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler> (
|
||||
[weakThis = WeakReference<WebView2> { this }] (HRESULT, ICoreWebView2Controller* controller) -> HRESULT
|
||||
{
|
||||
|
|
@ -711,7 +753,7 @@ private:
|
|||
webView = nullptr;
|
||||
}
|
||||
|
||||
webViewEnvironment = nullptr;
|
||||
webViewHandle.environment = nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -737,11 +779,10 @@ private:
|
|||
|
||||
//==============================================================================
|
||||
WebBrowserComponent& owner;
|
||||
WebView2Preferences preferences;
|
||||
WebBrowserComponent::Options::WinWebView2 preferences;
|
||||
String userAgent;
|
||||
|
||||
HMODULE webView2LoaderHandle = nullptr;
|
||||
|
||||
ComSmartPtr<ICoreWebView2Environment> webViewEnvironment;
|
||||
WebViewHandle webViewHandle;
|
||||
ComSmartPtr<ICoreWebView2Controller> webViewController;
|
||||
ComSmartPtr<ICoreWebView2> webView;
|
||||
|
||||
|
|
@ -774,8 +815,8 @@ class WebBrowserComponent::Pimpl
|
|||
{
|
||||
public:
|
||||
Pimpl (WebBrowserComponent& owner,
|
||||
const WebView2Preferences& preferences,
|
||||
bool useWebView2)
|
||||
const Options& preferences,
|
||||
bool useWebView2, const String& userAgent)
|
||||
{
|
||||
if (useWebView2)
|
||||
{
|
||||
|
|
@ -791,7 +832,7 @@ public:
|
|||
ignoreUnused (preferences);
|
||||
|
||||
if (internal == nullptr)
|
||||
internal.reset (new Win32WebView (owner));
|
||||
internal.reset (new Win32WebView (owner, userAgent));
|
||||
}
|
||||
|
||||
InternalWebViewType& getInternalWebView()
|
||||
|
|
@ -804,15 +845,10 @@ private:
|
|||
};
|
||||
|
||||
//==============================================================================
|
||||
WebBrowserComponent::WebBrowserComponent (bool unloadWhenHidden)
|
||||
: browser (new Pimpl (*this, {}, false)),
|
||||
unloadPageWhenHidden (unloadWhenHidden)
|
||||
{
|
||||
setOpaque (true);
|
||||
}
|
||||
|
||||
WebBrowserComponent::WebBrowserComponent (ConstructWithoutPimpl args)
|
||||
: unloadPageWhenHidden (args.unloadWhenHidden)
|
||||
WebBrowserComponent::WebBrowserComponent (const Options& options)
|
||||
: browser (new Pimpl (*this, options,
|
||||
options.getBackend() == Options::Backend::webview2, options.getUserAgent())),
|
||||
unloadPageWhenHidden (! options.keepsPageLoadedWhenBrowserIsHidden())
|
||||
{
|
||||
setOpaque (true);
|
||||
}
|
||||
|
|
@ -821,13 +857,6 @@ WebBrowserComponent::~WebBrowserComponent()
|
|||
{
|
||||
}
|
||||
|
||||
WindowsWebView2WebBrowserComponent::WindowsWebView2WebBrowserComponent (bool unloadWhenHidden,
|
||||
const WebView2Preferences& preferences)
|
||||
: WebBrowserComponent (ConstructWithoutPimpl { unloadWhenHidden })
|
||||
{
|
||||
browser = std::make_unique<Pimpl> (*this, preferences, true);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void WebBrowserComponent::goToURL (const String& url,
|
||||
const StringArray* headers,
|
||||
|
|
@ -982,4 +1011,21 @@ void WebBrowserComponent::clearCookies()
|
|||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool WebBrowserComponent::areOptionsSupported (const Options& options)
|
||||
{
|
||||
if (options.getBackend() == Options::Backend::defaultBackend || options.getBackend() == Options::Backend::ie)
|
||||
return true;
|
||||
|
||||
#if JUCE_USE_WIN_WEBVIEW2
|
||||
if (options.getBackend() != Options::Backend::webview2)
|
||||
return false;
|
||||
|
||||
if (auto webView = WebView2::createWebViewHandle (options.getWinWebView2BackendOptions()))
|
||||
return true;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue