From e15a1ac18ebeebf16a554f5f8df5fa54332c5e06 Mon Sep 17 00:00:00 2001 From: Tobias Taschner Date: Thu, 23 Mar 2023 15:28:24 +0100 Subject: [PATCH] Add wxWebViewWindowFeatures and event This replaces the previously implemented wxWebViewWindowInfo. It explicitly breaks the previous API to enable WebKitGTK integration and to make the usage in application code less error prone. A new event wxEVT_WEBVIEW_NEWWINDOW_FEATURES is added to allow access to the window features and the child web view. --- include/wx/gtk/webview_webkit.h | 1 + include/wx/msw/private/webview_edge.h | 8 +- include/wx/osx/webview_webkit.h | 5 +- include/wx/webview.h | 16 ++-- interface/wx/webview.h | 112 ++++++++++++++---------- samples/webview/webview.cpp | 73 ++++++++++------ src/common/webview.cpp | 19 ++++ src/gtk/webview_webkit2.cpp | 121 ++++++++++++++++++++++++-- src/msw/webview_edge.cpp | 70 ++++++--------- src/osx/webview_webkit.mm | 58 ++++++------ 10 files changed, 323 insertions(+), 160 deletions(-) diff --git a/include/wx/gtk/webview_webkit.h b/include/wx/gtk/webview_webkit.h index d8022f2a5f..824e55dd1d 100644 --- a/include/wx/gtk/webview_webkit.h +++ b/include/wx/gtk/webview_webkit.h @@ -35,6 +35,7 @@ public: wxWebViewWebKit(); #if wxUSE_WEBVIEW_WEBKIT2 + wxWebViewWebKit(WebKitWebView* parentWebView, wxWebViewWebKit* parentWebViewCtrl); wxWebViewWebKit(const wxWebViewConfiguration& config); #endif diff --git a/include/wx/msw/private/webview_edge.h b/include/wx/msw/private/webview_edge.h index b840a550a4..c3e5fe0fb6 100644 --- a/include/wx/msw/private/webview_edge.h +++ b/include/wx/msw/private/webview_edge.h @@ -46,7 +46,7 @@ __CRT_UUID_DECL(ICoreWebView2WindowCloseRequestedEventHandler, 0x5c19e9e0,0x092f WX_DECLARE_STRING_HASH_MAP(wxSharedPtr, wxStringToWebHandlerMap); -class wxWebViewEdgeParentWindowInfo; +class wxWebViewWindowFeaturesEdge; class wxWebViewEdgeImpl { @@ -57,15 +57,15 @@ public: bool Create(); - wxWebViewEdge* CreateChildWebView(std::shared_ptr parentWindowInfo); - wxWebViewEdge* m_ctrl; wxWebViewConfiguration m_config; wxCOMPtr m_webViewEnvironment; wxCOMPtr m_webView; wxCOMPtr m_webViewController; - std::shared_ptr m_parentWindowInfo; + + wxCOMPtr m_newWindowArgs; + wxCOMPtr m_newWindowDeferral; bool m_initialized; bool m_isBusy; diff --git a/include/wx/osx/webview_webkit.h b/include/wx/osx/webview_webkit.h index b4dcc15e38..e6a7c84dc2 100644 --- a/include/wx/osx/webview_webkit.h +++ b/include/wx/osx/webview_webkit.h @@ -27,13 +27,12 @@ WX_DECLARE_STRING_HASH_MAP(wxSharedPtr, wxStringToWebHandlerMap); -class wxWebViewWindowInfoWebKit; class wxWebViewConfigurationImplWebKit; class WXDLLIMPEXP_WEBVIEW wxWebViewWebKit : public wxWebView { public: - explicit wxWebViewWebKit(const wxWebViewConfiguration& config, wxWebViewWindowInfoWebKit* parentWindowInfo = nullptr); + explicit wxWebViewWebKit(const wxWebViewConfiguration& config, WX_NSObject request = nullptr); bool Create(wxWindow *parent, wxWindowID winID = wxID_ANY, @@ -109,7 +108,7 @@ private: OSXWebViewPtr m_webView; wxStringToWebHandlerMap m_handlers; wxString m_customUserAgent; - wxWebViewWindowInfoWebKit* m_parentWindowInfo = nullptr; + WX_NSObject m_request; WX_NSObject m_navigationDelegate; WX_NSObject m_UIDelegate; diff --git a/include/wx/webview.h b/include/wx/webview.h index 9652d2427e..82ccf984f4 100644 --- a/include/wx/webview.h +++ b/include/wx/webview.h @@ -344,10 +344,14 @@ private: wxDECLARE_ABSTRACT_CLASS(wxWebView); }; -class WXDLLIMPEXP_WEBVIEW wxWebViewWindowInfo +class WXDLLIMPEXP_WEBVIEW wxWebViewWindowFeatures { public: - virtual ~wxWebViewWindowInfo() = default; + wxWebViewWindowFeatures(wxWebView* childWebView); + + virtual ~wxWebViewWindowFeatures(); + + wxWebView* GetChildWebView() const; virtual wxPoint GetPosition() const = 0; @@ -361,10 +365,11 @@ public: virtual bool ShouldDisplayScrollBars() const = 0; - virtual wxWebView* CreateChildWebView() = 0; +protected: + mutable bool m_childWebViewWasUsed; + std::unique_ptr m_childWebView; }; - class WXDLLIMPEXP_WEBVIEW wxWebViewEvent : public wxNotifyEvent { public: @@ -385,7 +390,7 @@ public: wxWebViewNavigationActionFlags GetNavigationAction() const { return m_actionFlags; } const wxString& GetMessageHandler() const { return m_messageHandler; } - wxWebViewWindowInfo* GetTargetWindowInfo() const { return (wxWebViewWindowInfo*)m_clientData; } + wxWebViewWindowFeatures* GetTargetWindowFeatures() const { return (wxWebViewWindowFeatures*)m_clientData; } virtual wxEvent* Clone() const override { return new wxWebViewEvent(*this); } private: @@ -402,6 +407,7 @@ wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_NAVIGATED, wxWebVie wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_LOADED, wxWebViewEvent ); wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_ERROR, wxWebViewEvent ); wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_NEWWINDOW, wxWebViewEvent ); +wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_NEWWINDOW_FEATURES, wxWebViewEvent ); wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_WINDOW_CLOSE_REQUESTED, wxWebViewEvent); wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_TITLE_CHANGED, wxWebViewEvent ); wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_FULLSCREEN_CHANGED, wxWebViewEvent); diff --git a/interface/wx/webview.h b/interface/wx/webview.h index 42f936382e..30c4370fa5 100644 --- a/interface/wx/webview.h +++ b/interface/wx/webview.h @@ -163,19 +163,63 @@ enum wxWebViewIE_EmulationLevel /** A class describing the window information for a new child window. - This class is available via wxWebViewEvent::GetTargetWindowInfo() - while handling @c wxEVT_WEBVIEW_NEWWINDOW. - If the new window should be created use CreateChildWebView() while - processing the event. This will ensure that the new web view is - accessible from JavaScript within the originating wxWebView. + An object of this class can be obtained using wxWebViewEvent::GetTargetWindowFeatures() + while handling @c wxEVT_WEBVIEW_NEWWINDOW_FEATURES. + If a @c wxEVT_WEBVIEW_NEWWINDOW is not vetoed, a @c wxEVT_WEBVIEW_NEWWINDOW_FEATURES + event will be sent to the application. The application can then create a new + window and call wxWebViewEvent::GetTargetWindowInfo() to get this class providing + information about the new window. A new child web view will be available + via GetChildWebView(). The application can then place the child web view into + the new window by calling wxWebView::Create() on the child web view. + + Sample JavaScript opening a new window: + @code + window.open("http://www.wxwidgets.org", "newWindow", "width=400,height=400"); + @endcode + + Sample C++ code handling a new window request: + @code + // Bind new window handler + m_webView->Bind(wxEVT_WEBVIEW_NEWWINDOW, [](wxWebViewEvent& evt) { + if (evt.GetURL() == "http://badwebsite.com") + evt.Veto(); // Disallow new window for badwebsite.com + else + evt.Skip(); // Allow new window for all other websites + }); + + // Bind new window features handler + m_webView->Bind(wxEVT_WEBVIEW_NEWWINDOW_FEATURES, [](wxWebViewEvent& evt) { + // Get target window features + wxWebViewWindowFeatures* features = evt.GetTargetWindowFeatures(); + // Create a top level window for the child web view + wxWindow* win = new wxWindow(this, wxID_ANY, features->GetPosition(), features->GetSize()); + wxSizer* sizer = new wxBoxSizer(wxVERTICAL); + win->SetSizer(sizer); + // Get the child web view + wxWebView* childWebView = features->GetChildWebView(); + // Place the child web view into the window + childWebView->Create(win, wxID_ANY); + sizer->Add(childWebView, 1, wxEXPAND); + } + @endcode @since 3.3.0 */ -class WXDLLIMPEXP_WEBVIEW wxWebViewWindowInfo +class WXDLLIMPEXP_WEBVIEW wxWebViewWindowFeatures { public: + /** + Get the child web view for the target window. + + This is available in the event handler for @c wxEVT_WEBVIEW_NEWWINDOW_FEATURES + and wxWebView::Create() @b must be called on the child web view directly. + + The requested URL will be loaded automatically in the child web view. + */ + wxWebView* GetChildWebView(); + /** Returns the position of the new window if specified by a @c window.open() call. @@ -211,39 +255,6 @@ public: scroll bars as specified by a @c window.open() call. */ virtual bool ShouldDisplayScrollBars() const = 0; - - /** - Create a new child web view for the target window. - - This @b must be created in the event handler for @c wxEVT_WEBVIEW_NEWWINDOW - and wxWebView::Create() @b must be called directly. - - The requested URL will be loaded automatically in the new child web view. - - Sample C++ code handling the event: - @code - // Bind handler - m_webView->Bind(wxEVT_WEBVIEW_NEWWINDOW, [](wxWebViewEvent& evt) { - // Get target window info - wxWebViewWindowInfo* info = evt.GetTargetWindowInfo(); - // Create a top level window for the child web view - wxWindow* win = new wxWindow(this, wxID_ANY, info->GetPosition(), info->GetSize()); - wxSizer* sizer = new wxBoxSizer(wxVERTICAL); - // Create the child web view - wxWebView* childWebView = info->CreateChildWebView(); - // Place the child web view into the window - childWebView->Create(win, wxID_ANY); - sizer->Add(childWebView, 1, wxEXPAND); - }); - @endcode - - Sample JavaScript opening a new window: - @code - window.open("http://www.wxwidgets.org", "newWindow", "width=400,height=400"); - @endcode - - */ - virtual wxWebView* CreateChildWebView() = 0; }; /** @@ -912,7 +923,12 @@ public: Process a @c wxEVT_WEBVIEW_NEWWINDOW event, generated when a new window is created. You must handle this event if you want anything to happen, for example to load the page in a new window or tab. For usage - details see wxWebViewWindowInfo::CreateChildWebView(). + details see wxWebViewWindowFeatures. + @event{EVT_WEBVIEW_NEWWINDOW_FEATURES(id, func)} + Process a @c wxEVT_WEBVIEW_NEWWINDOW_FEATURES event, generated when + window features are available for the new window. For usage + details see wxWebViewWindowFeatures. + only available in wxWidgets 3.3.0 or later. @event{wxEVT_WEBVIEW_WINDOW_CLOSE_REQUESTED(id, func)} Process a @c wxEVT_WEBVIEW_WINDOW_CLOSE_REQUESTED event, generated when a window is requested to be closed. @@ -1784,7 +1800,12 @@ public: Process a @c wxEVT_WEBVIEW_NEWWINDOW event, generated when a new window is created. You must handle this event if you want anything to happen, for example to load the page in a new window or tab. For usage - details see wxWebViewWindowInfo::CreateChildWebView(). + details see wxWebViewWindowFeatures. + @event{EVT_WEBVIEW_NEWWINDOW_FEATURES(id, func)} + Process a @c wxEVT_WEBVIEW_NEWWINDOW_FEATURES event, generated when + window features are available for the new window. For usage + details see wxWebViewWindowFeatures. + only available in wxWidgets 3.3.0 or later. @event{wxEVT_WEBVIEW_WINDOW_CLOSE_REQUESTED(id, func)} Process a @c wxEVT_WEBVIEW_WINDOW_CLOSE_REQUESTED event, generated when a window is requested to be closed. @@ -1852,14 +1873,14 @@ public: /** Get information about the target window. Only valid for events of type - @c wxEVT_WEBVIEW_NEWWINDOW + @c wxEVT_WEBVIEW_NEWWINDOW_FEATURES - @note This is only available with the macOS and the Edge backend. + @note This function is not implemented and always returns @NULL when using WebKit1 or Internet Explorer backend. - @see wxWebViewWindowInfo + @see wxWebViewWindowFeatures @since 3.3.0 */ - wxWebViewWindowInfo* GetTargetWindowInfo() const; + wxWebViewWindowFeatures* GetTargetWindowFeatures() const; /** Returns true the script execution failed. Only valid for events of type @@ -1886,6 +1907,7 @@ wxEventType wxEVT_WEBVIEW_NAVIGATED; wxEventType wxEVT_WEBVIEW_LOADED; wxEventType wxEVT_WEBVIEW_ERROR; wxEventType wxEVT_WEBVIEW_NEWWINDOW; +wxEventType wxEVT_WEBVIEW_NEWWINDOW_FEATURES; wxEventType wxEVT_WEBVIEW_TITLE_CHANGED; wxEventType wxEVT_WEBVIEW_FULLSCREEN_CHANGED; wxEventType wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED; diff --git a/samples/webview/webview.cpp b/samples/webview/webview.cpp index d1605b5c7c..1156fa3542 100644 --- a/samples/webview/webview.cpp +++ b/samples/webview/webview.cpp @@ -98,7 +98,7 @@ private: class WebFrame : public wxFrame { public: - WebFrame(const wxString& url, bool isMain = true, wxWebViewWindowInfo* newWindowInfo = nullptr); + WebFrame(const wxString& url, bool isMain = true, wxWebViewWindowFeatures* windowFeatures = nullptr); virtual ~WebFrame(); void UpdateState(); @@ -114,6 +114,7 @@ public: void OnNavigationComplete(wxWebViewEvent& evt); void OnDocumentLoaded(wxWebViewEvent& evt); void OnNewWindow(wxWebViewEvent& evt); + void OnNewWindowFeatures(wxWebViewEvent& evt); void OnTitleChanged(wxWebViewEvent& evt); void OnFullScreenChanged(wxWebViewEvent& evt); void OnScriptMessage(wxWebViewEvent& evt); @@ -334,7 +335,7 @@ bool WebApp::OnInit() return true; } -WebFrame::WebFrame(const wxString& url, bool isMain, wxWebViewWindowInfo* newWindowInfo) : +WebFrame::WebFrame(const wxString& url, bool isMain, wxWebViewWindowFeatures* windowFeatures): wxFrame(nullptr, wxID_ANY, "wxWebView Sample") { m_isMainFrame = isMain; @@ -420,7 +421,7 @@ WebFrame::WebFrame(const wxString& url, bool isMain, wxWebViewWindowInfo* newWin } #endif // Create the webview - m_browser = (newWindowInfo) ? newWindowInfo->CreateChildWebView() : wxWebView::New(); + m_browser = (windowFeatures) ? windowFeatures->GetChildWebView() : wxWebView::New(); #ifdef __WXMAC__ if (m_isMainFrame) { @@ -433,18 +434,6 @@ WebFrame::WebFrame(const wxString& url, bool isMain, wxWebViewWindowInfo* newWin m_browser->Create(this, wxID_ANY, url, wxDefaultPosition, wxDefaultSize); topsizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1)); - if (newWindowInfo) - { - if (newWindowInfo->GetSize().IsFullySpecified()) - SetSize(FromDIP(newWindowInfo->GetSize())); - if (newWindowInfo->GetPosition().IsFullySpecified()) - Move(FromDIP(newWindowInfo->GetPosition())); - if (!newWindowInfo->ShouldDisplayToolBar()) - m_toolbar->Hide(); - if (!newWindowInfo->ShouldDisplayMenuBar()) - SetMenuBar(nullptr); - } - if (m_isMainFrame) { // Log backend information @@ -470,6 +459,18 @@ WebFrame::WebFrame(const wxString& url, bool isMain, wxWebViewWindowInfo* newWin //Set a more sensible size for web browsing SetSize(FromDIP(wxSize(800, 600))); + if (windowFeatures) + { + if (windowFeatures->GetSize().IsFullySpecified()) + SetSize(FromDIP(windowFeatures->GetSize())); + if (windowFeatures->GetPosition().IsFullySpecified()) + Move(FromDIP(windowFeatures->GetPosition())); + if (!windowFeatures->ShouldDisplayToolBar()) + m_toolbar->Hide(); + if (!windowFeatures->ShouldDisplayMenuBar()) + SetMenuBar(nullptr); + } + // Create the Tools menu m_tools_menu = new wxMenu(); wxMenuItem* print = m_tools_menu->Append(wxID_ANY , _("Print")); @@ -602,6 +603,7 @@ WebFrame::WebFrame(const wxString& url, bool isMain, wxWebViewWindowInfo* newWin Bind(wxEVT_WEBVIEW_LOADED, &WebFrame::OnDocumentLoaded, this, m_browser->GetId()); Bind(wxEVT_WEBVIEW_ERROR, &WebFrame::OnError, this, m_browser->GetId()); Bind(wxEVT_WEBVIEW_NEWWINDOW, &WebFrame::OnNewWindow, this, m_browser->GetId()); + Bind(wxEVT_WEBVIEW_NEWWINDOW_FEATURES, &WebFrame::OnNewWindowFeatures, this, m_browser->GetId()); Bind(wxEVT_WEBVIEW_TITLE_CHANGED, &WebFrame::OnTitleChanged, this, m_browser->GetId()); Bind(wxEVT_WEBVIEW_FULLSCREEN_CHANGED, &WebFrame::OnFullScreenChanged, this, m_browser->GetId()); Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &WebFrame::OnScriptMessage, this, m_browser->GetId()); @@ -973,24 +975,41 @@ void WebFrame::OnNewWindow(wxWebViewEvent& evt) } wxLogMessage("%s", "New window; url='" + evt.GetURL() + "'" + flag); - wxWebViewWindowInfo* info = evt.GetTargetWindowInfo(); - if (info) - { - wxLogMessage(" New window info: Position=%d,%d Size=%d,%d", - info->GetPosition().x, info->GetPosition().y, - info->GetSize().GetWidth(), info->GetSize().GetHeight()); - } //If we handle new window events then create a new frame - if (m_tools_handle_new_window->IsChecked()) - { - WebFrame* newFrame = new WebFrame(evt.GetURL(), false, info); - newFrame->Show(); - } + if (!m_tools_handle_new_window->IsChecked()) + evt.Veto(); UpdateState(); } +void WebFrame::OnNewWindowFeatures(wxWebViewEvent &evt) +{ + wxWebViewWindowFeatures* features = evt.GetTargetWindowFeatures(); + if (!features) + return; + + wxString featureDescription; + if (features->GetPosition().IsFullySpecified()) + featureDescription += wxString::Format(" Position: %d, %d; ", features->GetPosition().x, features->GetPosition().y); + if (features->GetSize().IsFullySpecified()) + featureDescription += wxString::Format(" Size: %d, %d; ", features->GetSize().x, features->GetSize().y); + if (features->ShouldDisplayMenuBar()) + featureDescription += " MenuBar; "; + if (features->ShouldDisplayStatusBar()) + featureDescription += " StatusBar; "; + if (features->ShouldDisplayToolBar()) + featureDescription += " ToolBar; "; + if (features->ShouldDisplayScrollBars()) + featureDescription += " ScrollBars; "; + + wxLogMessage("Window features of child webview are available." + featureDescription); + + // Create child frame with the features specified by window.open() call + WebFrame* newFrame = new WebFrame(evt.GetURL(), false, features); + newFrame->Show(); +} + void WebFrame::OnTitleChanged(wxWebViewEvent& evt) { SetTitle(evt.GetString()); diff --git a/src/common/webview.cpp b/src/common/webview.cpp index 59537b9ba9..33fb2b8de0 100644 --- a/src/common/webview.cpp +++ b/src/common/webview.cpp @@ -50,6 +50,7 @@ wxDEFINE_EVENT( wxEVT_WEBVIEW_NAVIGATED, wxWebViewEvent ); wxDEFINE_EVENT( wxEVT_WEBVIEW_LOADED, wxWebViewEvent ); wxDEFINE_EVENT( wxEVT_WEBVIEW_ERROR, wxWebViewEvent ); wxDEFINE_EVENT( wxEVT_WEBVIEW_NEWWINDOW, wxWebViewEvent ); +wxDEFINE_EVENT( wxEVT_WEBVIEW_NEWWINDOW_FEATURES, wxWebViewEvent ); wxDEFINE_EVENT( wxEVT_WEBVIEW_WINDOW_CLOSE_REQUESTED, wxWebViewEvent ); wxDEFINE_EVENT( wxEVT_WEBVIEW_TITLE_CHANGED, wxWebViewEvent ); wxDEFINE_EVENT( wxEVT_WEBVIEW_FULLSCREEN_CHANGED, wxWebViewEvent); @@ -86,6 +87,24 @@ wxString wxWebViewConfiguration::GetDataPath() const return m_impl->GetDataPath(); } +// wxWebViewWindowFeatures +wxWebViewWindowFeatures::wxWebViewWindowFeatures(wxWebView * childWebView): + m_childWebViewWasUsed(false), + m_childWebView(childWebView) +{ } + +wxWebViewWindowFeatures::~wxWebViewWindowFeatures() +{ + if (m_childWebViewWasUsed) + m_childWebView.release(); +} + +wxWebView *wxWebViewWindowFeatures::GetChildWebView() const +{ + m_childWebViewWasUsed = true; + return m_childWebView.get(); +} + // wxWebViewHandlerRequest wxString wxWebViewHandlerRequest::GetDataString(const wxMBConv& conv) const { diff --git a/src/gtk/webview_webkit2.cpp b/src/gtk/webview_webkit2.cpp index f0344941d2..9d18227b5e 100644 --- a/src/gtk/webview_webkit2.cpp +++ b/src/gtk/webview_webkit2.cpp @@ -88,6 +88,62 @@ bool wxGetStringFromJSResult(WebKitJavascriptResult* js_result, wxString* output return true; } +//----------------------------------------------------------------------------- +// wxWebViewWindowFeaturesWebKit +//----------------------------------------------------------------------------- +class wxWebViewWindowFeaturesWebKit : public wxWebViewWindowFeatures +{ +public: + wxWebViewWindowFeaturesWebKit(wxWebView* webViewCtrl, WebKitWebView *web_view): + wxWebViewWindowFeatures(webViewCtrl) + { + m_properties = webkit_web_view_get_window_properties(web_view); + webkit_window_properties_get_geometry(m_properties, &m_geometry); + // Treat 0 as -1 to indicate that the value is not set + if (m_geometry.width == 0) + m_geometry.width = -1; + if (m_geometry.height == 0) + m_geometry.height = -1; + if (m_geometry.x == 0) + m_geometry.x = -1; + if (m_geometry.y == 0) + m_geometry.y = -1; + } + + virtual wxPoint GetPosition() const override + { + return wxPoint(m_geometry.x, m_geometry.y); + } + + virtual wxSize GetSize() const override + { + return wxSize(m_geometry.width, m_geometry.height); + } + + virtual bool ShouldDisplayMenuBar() const override + { + return webkit_window_properties_get_toolbar_visible(m_properties); + } + + virtual bool ShouldDisplayStatusBar() const override + { + return webkit_window_properties_get_statusbar_visible(m_properties); + } + + virtual bool ShouldDisplayToolBar() const override + { + return webkit_window_properties_get_toolbar_visible(m_properties); + } + + virtual bool ShouldDisplayScrollBars() const override + { + return webkit_window_properties_get_scrollbars_visible(m_properties); + } + + GdkRectangle m_geometry; + WebKitWindowProperties *m_properties; +}; + // ---------------------------------------------------------------------------- // GTK callbacks // ---------------------------------------------------------------------------- @@ -378,6 +434,27 @@ static void wxgtk_webview_webkit_close (WebKitWebView *WXUNUSED(web_view), webKitCtrl->HandleWindowEvent(event); } +class wxReadyToShowParams +{ +public: + wxWebViewWebKit* childWebView; + wxWebViewWebKit* parentWebView; +}; + +static void wxgtk_webview_webkit_ready_to_show (WebKitWebView *web_view, + wxReadyToShowParams *params) +{ + wxWebViewWindowFeaturesWebKit features(params->childWebView, web_view); + wxWebViewEvent event(wxEVT_WEBVIEW_NEWWINDOW_FEATURES, + params->parentWebView->GetId(), + params->childWebView->GetCurrentURL(), + ""); + event.SetEventObject(params->parentWebView); + event.SetClientData(&features); + params->parentWebView->HandleWindowEvent(event); + delete params; +} + static gboolean wxgtk_webview_webkit_decide_policy(WebKitWebView *web_view, WebKitPolicyDecision *decision, @@ -478,13 +555,25 @@ wxgtk_webview_webkit_context_menu(WebKitWebView *, static WebKitWebView* wxgtk_webview_webkit_create_webview(WebKitWebView *web_view, - WebKitNavigationAction *, + WebKitNavigationAction *navigation_action, wxWebViewWebKit *webKitCtrl) { - //As we do not know the uri being loaded at this point allow the load to - //continue and catch it in navigation-policy-decision-requested - webKitCtrl->m_creating = true; - return web_view; + auto request = webkit_navigation_action_get_request(navigation_action); + wxString url = wxString::FromUTF8(webkit_uri_request_get_uri(request)); + wxWebViewEvent event(wxEVT_WEBVIEW_NEWWINDOW, + webKitCtrl->GetId(), + url, + ""); + event.SetEventObject(webKitCtrl); + webKitCtrl->HandleWindowEvent(event); + + if ( event.IsAllowed() ) + { + wxWebView* childWebView = new wxWebViewWebKit(web_view, webKitCtrl); + return (WebKitWebView*)childWebView->GetNativeBackend(); + } + else + return nullptr; } static void @@ -738,6 +827,21 @@ wxWebViewWebKit::wxWebViewWebKit(): m_extension = nullptr; } +wxWebViewWebKit::wxWebViewWebKit(WebKitWebView* parentWebView, wxWebViewWebKit* parentWebViewCtrl): + m_config(parentWebViewCtrl->m_config) +{ + m_web_view = (WebKitWebView*) webkit_web_view_new_with_related_view(parentWebView); + m_dbusServer = nullptr; + m_extension = nullptr; + + wxReadyToShowParams* params = new wxReadyToShowParams(); + params->childWebView = this; + params->parentWebView = parentWebViewCtrl; + + g_signal_connect(m_web_view, "ready-to-show", + G_CALLBACK(wxgtk_webview_webkit_ready_to_show), params); +} + wxWebViewWebKit::wxWebViewWebKit(const wxWebViewConfiguration &config): m_config(config) { @@ -754,7 +858,6 @@ bool wxWebViewWebKit::Create(wxWindow *parent, long style, const wxString& name) { - m_web_view = nullptr; m_dbusServer = nullptr; m_extension = nullptr; m_busy = false; @@ -762,6 +865,8 @@ bool wxWebViewWebKit::Create(wxWindow *parent, m_creating = false; FindClear(); + bool isChildWebView = m_web_view != nullptr; + // We currently unconditionally impose scrolling in both directions as it's // necessary to show arbitrary pages. style |= wxHSCROLL | wxVSCROLL; @@ -779,6 +884,7 @@ bool wxWebViewWebKit::Create(wxWindow *parent, G_CALLBACK(wxgtk_initialize_web_extensions), m_dbusServer); + if (!isChildWebView) #ifdef wxHAVE_WEBKIT_WEBSITE_DATA_MANAGER m_web_view = WEBKIT_WEB_VIEW(webkit_web_view_new_with_context(WEBKIT_WEB_CONTEXT(m_config.GetNativeConfiguration()))); #else @@ -825,7 +931,8 @@ bool wxWebViewWebKit::Create(wxWindow *parent, PostCreation(size); /* Open a webpage */ - webkit_web_view_load_uri(m_web_view, url.utf8_str()); + if (!isChildWebView) + webkit_web_view_load_uri(m_web_view, url.utf8_str()); // last to avoid getting signal too early g_signal_connect(m_web_view, "load-changed", diff --git a/src/msw/webview_edge.cpp b/src/msw/webview_edge.cpp index ca82e27fd9..1bca4e3bea 100644 --- a/src/msw/webview_edge.cpp +++ b/src/msw/webview_edge.cpp @@ -320,13 +320,13 @@ public: wxString wxWebViewConfigurationImplEdge::ms_browserExecutableDir; -// wxWebViewNewWindowInfoEdge +// wxWebViewWindowFeaturesEdge -class wxWebViewNewWindowInfoEdge : public wxWebViewWindowInfo +class wxWebViewWindowFeaturesEdge : public wxWebViewWindowFeatures { public: - wxWebViewNewWindowInfoEdge(wxWebViewEdgeImpl* impl, ICoreWebView2NewWindowRequestedEventArgs* args): - m_impl(impl), + wxWebViewWindowFeaturesEdge(wxWebView* childWebView, ICoreWebView2NewWindowRequestedEventArgs* args): + wxWebViewWindowFeatures(childWebView), m_args(args) { m_args->get_WindowFeatures(&m_windowFeatures); @@ -395,36 +395,11 @@ public: return true; } - virtual wxWebView* CreateChildWebView() override - { - return m_impl->CreateChildWebView( - std::make_shared(m_args)); - } - private: - wxWebViewEdgeImpl* m_impl; wxCOMPtr m_args; wxCOMPtr m_windowFeatures; }; -class wxWebViewEdgeParentWindowInfo -{ -public: - wxWebViewEdgeParentWindowInfo(ICoreWebView2NewWindowRequestedEventArgs* args): - m_args(args) - { - HRESULT hr = m_args->GetDeferral(&m_deferral); - if (FAILED(hr)) - wxLogApiError("GetDeferral", hr); - } - - virtual ~wxWebViewEdgeParentWindowInfo() = default; - - wxCOMPtr m_args; - wxCOMPtr m_deferral; -}; - - #define wxWEBVIEW_EDGE_EVENT_HANDLER_METHOD \ m_inEventCallback = true; \ wxON_BLOCK_EXIT_SET(m_inEventCallback, false); @@ -476,13 +451,6 @@ bool wxWebViewEdgeImpl::Create() CreateOrGetEnvironment(this); } -wxWebViewEdge* wxWebViewEdgeImpl::CreateChildWebView(std::shared_ptr parentWindowInfo) -{ - wxWebViewEdge* childWebView = new wxWebViewEdge(m_config); - childWebView->m_impl->m_parentWindowInfo = parentWindowInfo; - return childWebView; -} - void wxWebViewEdgeImpl::EnvironmentAvailable(ICoreWebView2Environment* environment) { environment->QueryInterface(IID_PPV_ARGS(&m_webViewEnvironment)); @@ -684,11 +652,24 @@ HRESULT wxWebViewEdgeImpl::OnNewWindowRequested(ICoreWebView2* WXUNUSED(sender), if (SUCCEEDED(args->get_IsUserInitiated(&isUserInitiated)) && isUserInitiated) navFlags = wxWEBVIEW_NAV_ACTION_USER; - wxWebViewNewWindowInfoEdge windowInfo(this, args); - wxWebViewEvent evt(wxEVT_WEBVIEW_NEWWINDOW, m_ctrl->GetId(), evtURL, wxString(), navFlags, ""); - evt.SetClientData(&windowInfo); - m_ctrl->HandleWindowEvent(evt); + wxWebViewEvent newWindowEvent(wxEVT_WEBVIEW_NEWWINDOW, m_ctrl->GetId(), evtURL, wxString(), navFlags, ""); + m_ctrl->HandleWindowEvent(newWindowEvent); args->put_Handled(true); + + if (newWindowEvent.IsAllowed()) + { + wxWebViewEdge* childWebView = new wxWebViewEdge(m_config); + childWebView->m_impl->m_newWindowArgs = args; + HRESULT hr = args->GetDeferral(&childWebView->m_impl->m_newWindowDeferral); + if (FAILED(hr)) + wxLogApiError("GetDeferral", hr); + + wxWebViewWindowFeaturesEdge windowFeatures(childWebView, args); + wxWebViewEvent featuresEvent(wxEVT_WEBVIEW_NEWWINDOW_FEATURES, m_ctrl->GetId(), evtURL, wxString(), navFlags, ""); + featuresEvent.SetClientData(&windowFeatures); + m_ctrl->HandleWindowEvent(featuresEvent); + } + return S_OK; } @@ -916,13 +897,14 @@ HRESULT wxWebViewEdgeImpl::OnWebViewCreated(HRESULT result, ICoreWebView2Control m_pendingUserScripts.clear(); } - if (m_parentWindowInfo) + if (m_newWindowArgs) { - if (FAILED(m_parentWindowInfo->m_args->put_NewWindow(baseWebView))) + if (FAILED(m_newWindowArgs->put_NewWindow(baseWebView))) SendErrorEventForAPI("WebView2::WebViewCreated (put_NewWindow)", hr); - if (FAILED(m_parentWindowInfo->m_deferral->Complete())) + if (FAILED(m_newWindowDeferral->Complete())) SendErrorEventForAPI("WebView2::WebViewCreated (Complete)", hr); - m_parentWindowInfo.reset(); + m_newWindowArgs.reset(); + m_newWindowDeferral.reset(); return S_OK; } diff --git a/src/osx/webview_webkit.mm b/src/osx/webview_webkit.mm index 5605768400..d98b66bffd 100644 --- a/src/osx/webview_webkit.mm +++ b/src/osx/webview_webkit.mm @@ -140,15 +140,17 @@ wxWebViewConfiguration wxWebViewFactoryWebKit::CreateConfiguration() } //----------------------------------------------------------------------------- -// wxWebViewWindowInfoWebKit +// wxWebViewWindowFeaturesWebKit //----------------------------------------------------------------------------- -class wxWebViewWindowInfoWebKit: public wxWebViewWindowInfo +class wxWebViewWindowFeaturesWebKit: public wxWebViewWindowFeatures { public: - wxWebViewWindowInfoWebKit(WKWebViewConfiguration* configuration, - WKNavigationAction* navigationAction, - WKWindowFeatures* windowFeatures): + wxWebViewWindowFeaturesWebKit(wxWebView* childWebView, + WKWebViewConfiguration* configuration, + WKNavigationAction* navigationAction, + WKWindowFeatures* windowFeatures): + wxWebViewWindowFeatures(childWebView), m_configuration(configuration), m_navigationAction(navigationAction), m_windowFeatures(windowFeatures) @@ -206,14 +208,6 @@ public: return true; } - virtual wxWebView* CreateChildWebView() override - { - m_childWebView = new wxWebViewWebKit(wxWebViewConfiguration(wxWebViewBackendWebKit, - new wxWebViewConfigurationImplWebKit(m_configuration)), this); - return m_childWebView; - } - - wxWebView* m_childWebView = nullptr; WKWebViewConfiguration* m_configuration; WKNavigationAction* m_navigationAction; WKWindowFeatures* m_windowFeatures; @@ -224,9 +218,9 @@ public: // creation/destruction // ---------------------------------------------------------------------------- -wxWebViewWebKit::wxWebViewWebKit(const wxWebViewConfiguration& config, wxWebViewWindowInfoWebKit* parentWindowInfo): +wxWebViewWebKit::wxWebViewWebKit(const wxWebViewConfiguration& config, WX_NSObject request): m_configuration(config), - m_parentWindowInfo(parentWindowInfo) + m_request(request) { } @@ -240,10 +234,12 @@ bool wxWebViewWebKit::Create(wxWindow *parent, DontCreatePeer(); wxControl::Create(parent, winID, pos, size, style, wxDefaultValidator, name); + bool isChildWebView = m_request != nil; + NSRect r = wxOSXGetFrameForControl( this, pos , size ) ; WKWebViewConfiguration* webViewConfig = (WKWebViewConfiguration*) m_configuration.GetNativeConfiguration(); - if (!m_handlers.empty() && !m_parentWindowInfo) + if (!m_handlers.empty() && !isChildWebView) { #if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13 if ( WX_IS_MACOS_AVAILABLE(10, 13) ) @@ -285,7 +281,7 @@ bool wxWebViewWebKit::Create(wxWindow *parent, [m_webView setUIDelegate:uiDelegate]; - if (!m_parentWindowInfo) + if (!isChildWebView) { // Implement javascript fullscreen interface with user script and message handler AddUserScript("\ @@ -326,8 +322,8 @@ bool wxWebViewWebKit::Create(wxWindow *parent, m_UIDelegate = uiDelegate; - if (m_parentWindowInfo) - [m_webView loadRequest:m_parentWindowInfo->m_navigationAction.request]; + if (m_request) + [m_webView loadRequest:(NSURLRequest*)m_request]; else LoadURL(strURL); return true; @@ -1126,19 +1122,31 @@ WX_API_AVAILABLE_MACOS(10, 13) wxWEBVIEW_NAV_ACTION_USER : wxWEBVIEW_NAV_ACTION_OTHER; - wxWebViewWindowInfoWebKit windowInfo(configuration, navigationAction, windowFeatures); - wxWebViewEvent event(wxEVT_WEBVIEW_NEWWINDOW, + wxWebViewEvent newWinEvent(wxEVT_WEBVIEW_NEWWINDOW, webKitWindow->GetId(), wxCFStringRef::AsString( navigationAction.request.URL.absoluteString ), "", navFlags); - event.SetClientData(&windowInfo); if (webKitWindow && webKitWindow->GetEventHandler()) - webKitWindow->GetEventHandler()->ProcessEvent(event); + webKitWindow->GetEventHandler()->ProcessEvent(newWinEvent); - if (windowInfo.m_childWebView) - return (WKWebView*) windowInfo.m_childWebView->GetNativeBackend(); + if (newWinEvent.IsAllowed()) + { + wxWebView* childWebView = new wxWebViewWebKit(wxWebViewConfiguration(wxWebViewBackendWebKit, + new wxWebViewConfigurationImplWebKit(configuration)), navigationAction.request); + wxWebViewWindowFeaturesWebKit childWindowFeatures(childWebView, configuration, navigationAction, windowFeatures); + + wxWebViewEvent featuresEvent(wxEVT_WEBVIEW_NEWWINDOW_FEATURES, + webKitWindow->GetId(), + wxCFStringRef::AsString( navigationAction.request.URL.absoluteString ), + "", navFlags); + featuresEvent.SetClientData(&childWindowFeatures); + if (webKitWindow && webKitWindow->GetEventHandler()) + webKitWindow->GetEventHandler()->ProcessEvent(featuresEvent); + + return (WKWebView*) childWebView->GetNativeBackend(); + } else return nil; }