Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion modules/juce_gui_extra/misc/juce_WebBrowserComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,12 +259,35 @@ class JUCE_API WebBrowserComponent : public Component
return withMember (*this, &AppleWkWebView::acceptsFirstMouse, false);
}

/** Sets the background colour that the WKWebView paints underneath all web content.

By default WKWebView's NSView paints an opaque white background until the page
actually renders, which causes a one-frame flash whenever the surface is shown
or resized into real bounds. Setting a colour here turns that off so the JUCE
layer beneath composites through (transparent / clear colour), or the chosen
colour shows in the overscroll area (macOS 12+ / iOS 15+).

This mirrors the equivalent option on WinWebView2 so cross-platform host code
can configure both backends from one place.

The colour must be either fully opaque or fully transparent.
*/
[[nodiscard]] AppleWkWebView withBackgroundColour (const Colour& colour) const
{
// the background colour must be either fully opaque or transparent!
jassert (colour.isOpaque() || colour.isTransparent());

return withMember (*this, &AppleWkWebView::backgroundColour, colour);
}

auto getAllowAccessToEnclosingDirectory() const { return allowAccessToEnclosingDirectory; }
auto getAcceptsFirstMouse() const { return acceptsFirstMouse; }
auto getAcceptsFirstMouse() const { return acceptsFirstMouse; }
auto getBackgroundColour() const { return backgroundColour; }

private:
bool allowAccessToEnclosingDirectory = false;
bool acceptsFirstMouse = true;
std::optional<Colour> backgroundColour;
};

/** Specifies options that apply to the Windows implementation when the WebView2 feature is
Expand Down
68 changes: 66 additions & 2 deletions modules/juce_gui_extra/native/juce_WebBrowserComponent_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -878,9 +878,11 @@ void evaluateJavascript (const String&, WebBrowserComponent::EvaluationCallback)
[config.get() setURLSchemeHandler:webViewDelegate.get() forURLScheme:@"juce"];
}

#if JUCE_DEBUG
// Enable the Safari Web Inspector in all build configurations.
// Plugins running inside a DAW are inherently a release-build target,
// so gating this on JUCE_DEBUG made the inspector unreachable in the
// only environment where developers actually run them.
[preferences setValue: @(true) forKey: @"developerExtrasEnabled"];
#endif

#if JUCE_MAC
auto& webviewClass = [&]() -> auto&
Expand Down Expand Up @@ -912,6 +914,68 @@ void evaluateJavascript (const String&, WebBrowserComponent::EvaluationCallback)
[webView.get() setNavigationDelegate: webViewDelegate.get()];
[webView.get() setUIDelegate: webViewDelegate.get()];

// The `developerExtrasEnabled` preference above is the legacy path
// and remains sufficient on older macOS. From 13.3 / iOS 16.4 onward
// Apple requires the public `inspectable` property to be set as well
// before Safari's Develop menu will list this WebView.
if (@available (macOS 13.3, iOS 16.4, *))
[webView.get() setInspectable: YES];

// Mirrors WinWebView2::withBackgroundColour. Stops WKWebView from
// flashing its default opaque background colour before the page has
// painted: drawsBackground = NO makes the OS surface transparent so
// the JUCE layer beneath composites through, and (on macOS 12+ /
// iOS 15+) the public setUnderPageBackgroundColor handles the
// overscroll bounce area.
//
// The KVC trick must target the WKWebView itself, not the
// WKWebViewConfiguration — WKWebView copies config values at init
// time, so setValue on config after webview creation is a no-op.
// `drawsBackground` is undocumented but stable since macOS 10.14
// and is what Safari, Xcode and Tauri/wry use.
if (const auto bg = browserOptions.getAppleWkWebViewOptions().getBackgroundColour())
{
@try
{
[webView.get() setValue: @(NO) forKey: @"drawsBackground"];
}
@catch (NSException* exception)
{
// KVC compliance is private API; if a future OS rejects it,
// fall back silently rather than crashing the host.
(void) exception;
}

#if JUCE_MAC
// Belt-and-braces: also tell the underlying NSView's CALayer
// not to paint its own opaque background. Some WebKit builds
// still flash on the very first frame because the host NSView
// composites independently of the WKWebView's drawsBackground.
// Setting wantsLayer + a transparent layer background is a
// public-API safety net.
[webView.get() setWantsLayer: YES];
if (auto* layer = [webView.get() layer])
layer.backgroundColor = CGColorGetConstantColor (kCGColorClear);
#endif

if (@available (macOS 12.0, iOS 15.0, *))
{
const auto c = *bg;
#if JUCE_MAC
auto* colour = [NSColor colorWithSRGBRed: c.getFloatRed()
green: c.getFloatGreen()
blue: c.getFloatBlue()
alpha: c.getFloatAlpha()];
#else
auto* colour = [UIColor colorWithRed: c.getFloatRed()
green: c.getFloatGreen()
blue: c.getFloatBlue()
alpha: c.getFloatAlpha()];
#endif
[webView.get() setUnderPageBackgroundColor: colour];
}
}

setView (webView.get());
owner.owner.addAndMakeVisible (this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1019,9 +1019,11 @@ class WebBrowserComponent::Impl::Platform::WebView2 final : public WebBrowserCom

if (settings != nullptr)
{
#if ! JUCE_DEBUG
settings->put_AreDevToolsEnabled (false);
#endif
// Leave WebView2 DevTools enabled in all build configurations.
// Plugins running inside a DAW are inherently a release-build
// target, so disabling DevTools in release made the inspector
// unreachable in the only environment where developers
// actually run them.

settings->put_IsStatusBarEnabled (! preferences.getWinWebView2BackendOptions().getIsStatusBarDisabled());
settings->put_IsBuiltInErrorPageEnabled (! preferences.getWinWebView2BackendOptions().getIsBuiltInErrorPageDisabled());
Expand Down
Loading