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; }