From 92f6f164b3692b25874f993b4e3e82afbf99a0ef Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 5 Sep 2023 21:22:33 +0200 Subject: [PATCH] Add wxEVT_WEBVIEW_CREATED for wxWebViewChromium async creation wxWebViewChromium creation is asynchronous and the object can't be really used until OnAfterCreated() is called, so expose this in the public API via a new event sent when the object becomes actually usable. As a side effect, add a convenient wxWebViewEvent ctor taking wxWebView as argument and calling SetEventObject() itself, instead of forcing all code creating wxWebViewEvents to do it. --- include/wx/webview.h | 14 ++++++++++++++ interface/wx/webview.h | 21 +++++++++++++++++++++ samples/webview/webview.cpp | 6 +++--- src/common/webview.cpp | 8 ++++++++ src/common/webview_chromium.cpp | 2 ++ src/gtk/webview_webkit.cpp | 2 ++ src/gtk/webview_webkit2.cpp | 2 ++ src/msw/webview_edge.cpp | 2 ++ src/msw/webview_ie.cpp | 2 ++ src/osx/webview_webkit.mm | 2 ++ 10 files changed, 58 insertions(+), 3 deletions(-) diff --git a/include/wx/webview.h b/include/wx/webview.h index 723c1b279f..a1d639dddd 100644 --- a/include/wx/webview.h +++ b/include/wx/webview.h @@ -333,6 +333,9 @@ protected: void SendScriptResult(void* clientData, bool success, const wxString& output) const; + // Send wxEVT_WEBVIEW_CREATED event. This function is MT-safe. + void NotifyWebViewCreated(); + private: static void InitFactoryMap(); static wxStringWebViewFactoryMap::iterator FindFactory(const wxString &backend); @@ -377,6 +380,12 @@ class WXDLLIMPEXP_WEBVIEW wxWebViewEvent : public wxNotifyEvent public: wxWebViewEvent() = default; + wxWebViewEvent(wxWebView& webview, wxEventType type) + : wxNotifyEvent(type, webview.GetId()) + { + SetEventObject(&webview); + } + wxWebViewEvent(wxEventType type, int id, const wxString& url, const wxString target, wxWebViewNavigationActionFlags flags = wxWEBVIEW_NAV_ACTION_NONE, @@ -405,6 +414,7 @@ private: wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN_DEF_COPY(wxWebViewEvent); }; +wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_CREATED, wxWebViewEvent ); wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_NAVIGATING, wxWebViewEvent ); wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_NAVIGATED, wxWebViewEvent ); wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_LOADED, wxWebViewEvent ); @@ -423,6 +433,10 @@ typedef void (wxEvtHandler::*wxWebViewEventFunction) #define wxWebViewEventHandler(func) \ wxEVENT_HANDLER_CAST(wxWebViewEventFunction, func) +#define EVT_WEBVIEW_CREATED(id, fn) \ + wx__DECLARE_EVT1(wxEVT_WEBVIEW_CREATED, id, \ + wxWebViewEventHandler(fn)) + #define EVT_WEBVIEW_NAVIGATING(id, fn) \ wx__DECLARE_EVT1(wxEVT_WEBVIEW_NAVIGATING, id, \ wxWebViewEventHandler(fn)) diff --git a/interface/wx/webview.h b/interface/wx/webview.h index 7796c01106..330241fde1 100644 --- a/interface/wx/webview.h +++ b/interface/wx/webview.h @@ -904,6 +904,11 @@ public: @c scheme:///C:/example/docs.zip;protocol=zip/main.htm @beginEventEmissionTable{wxWebViewEvent} + @event{EVT_WEBVIEW_CREATED(id, func)} + Process a @c wxEVT_WEBVIEW_CREATED event, generated when the object is + fully initialized. For the backends using asynchronous initialization, + such as wxWebViewChromium, most of this class member functions can be + only used once this event is received. @event{EVT_WEBVIEW_NAVIGATING(id, func)} Process a @c wxEVT_WEBVIEW_NAVIGATING event, generated before trying to get a resource. This event may be vetoed to prevent navigating to this @@ -967,6 +972,12 @@ public: /** Creation function for two-step creation. + + Please note that the object creation may be asynchronous when using + some backends (currently this is the case only for wxWebViewChromium) + and the object is not really created until wxEVT_WEBVIEW_CREATED event + is received, so any non-trivial calls to its member functions should be + delayed until then. */ virtual bool Create(wxWindow* parent, wxWindowID id, @@ -999,6 +1010,10 @@ public: /** Factory function to create a new wxWebView using a wxWebViewFactory. + + Note that the returned object may not be immediately usable yet, see + Create() and wxEVT_WEBVIEW_CREATED. + @param parent Parent window for the control @param id ID of this control @param url Initial URL to load @@ -1785,6 +1800,11 @@ public: wxWebView objects. @beginEventEmissionTable{wxWebViewEvent} + @event{EVT_WEBVIEW_CREATED(id, func)} + Process a @c wxEVT_WEBVIEW_CREATED event, generated when the object is + fully initialized. For the backends using asynchronous initialization, + such as wxWebViewChromium, most of this class member functions can be + only used once this event is received. @event{EVT_WEBVIEW_NAVIGATING(id, func)} Process a @c wxEVT_WEBVIEW_NAVIGATING event, generated before trying to get a resource. This event may be vetoed to prevent navigating to this @@ -1911,6 +1931,7 @@ public: }; +wxEventType wxEVT_WEBVIEW_CREATED; wxEventType wxEVT_WEBVIEW_NAVIGATING; wxEventType wxEVT_WEBVIEW_NAVIGATED; wxEventType wxEVT_WEBVIEW_LOADED; diff --git a/samples/webview/webview.cpp b/samples/webview/webview.cpp index 4eb4e0553e..e27b41cf2a 100644 --- a/samples/webview/webview.cpp +++ b/samples/webview/webview.cpp @@ -475,8 +475,8 @@ WebFrame::WebFrame(const wxString& url, bool isMain, wxWebViewWindowFeatures* wi // Chromium backend can't be used immediately after creation, so wait // until the browser is created before calling GetUserAgent(). - m_browser->Bind(wxEVT_CREATE, [this](wxWindowCreateEvent& event) { - wxLogMessage("User Agent: %s", m_browser->GetUserAgent()); + m_browser->Bind(wxEVT_WEBVIEW_CREATED, [this](wxWebViewEvent& event) { + wxLogMessage("Web view created, user agent is \"%s\"", m_browser->GetUserAgent()); event.Skip(); }); @@ -1398,7 +1398,7 @@ void WebFrame::OnAddUserScript(wxCommandEvent & WXUNUSED(evt)) void WebFrame::OnSetCustomUserAgent(wxCommandEvent& WXUNUSED(evt)) { - wxString customUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_1_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.1 Mobile/15E148 Safari/604.1"; + wxString customUserAgent = m_browser->GetUserAgent(); wxTextEntryDialog dialog ( this, diff --git a/src/common/webview.cpp b/src/common/webview.cpp index 99a880ed66..b57d23f0fa 100644 --- a/src/common/webview.cpp +++ b/src/common/webview.cpp @@ -45,6 +45,7 @@ extern WXDLLIMPEXP_DATA_WEBVIEW(const char) wxWebViewBackendDefault[] = "wxWebVi wxIMPLEMENT_ABSTRACT_CLASS(wxWebView, wxControl); wxIMPLEMENT_DYNAMIC_CLASS(wxWebViewEvent, wxCommandEvent); +wxDEFINE_EVENT( wxEVT_WEBVIEW_CREATED, wxWebViewEvent ); wxDEFINE_EVENT( wxEVT_WEBVIEW_NAVIGATING, wxWebViewEvent ); wxDEFINE_EVENT( wxEVT_WEBVIEW_NAVIGATED, wxWebViewEvent ); wxDEFINE_EVENT( wxEVT_WEBVIEW_LOADED, wxWebViewEvent ); @@ -446,6 +447,13 @@ wxWebView* wxWebView::New(wxWindow* parent, wxWindowID id, const wxString& url, } +void wxWebView::NotifyWebViewCreated() +{ + GetEventHandler()->QueueEvent( + new wxWebViewEvent{*this, wxEVT_WEBVIEW_CREATED} + ); +} + // static void wxWebView::RegisterFactory(const wxString& backend, wxSharedPtr factory) diff --git a/src/common/webview_chromium.cpp b/src/common/webview_chromium.cpp index 9b5de15b1a..8660419f42 100644 --- a/src/common/webview_chromium.cpp +++ b/src/common/webview_chromium.cpp @@ -1012,6 +1012,8 @@ void ClientHandler::OnAfterCreated(CefRefPtr browser) m_browserId = browser->GetIdentifier(); m_webview.PostSizeEvent(); + + m_webview.NotifyWebViewCreated(); } } bool ClientHandler::DoClose(CefRefPtr WXUNUSED(browser)) diff --git a/src/gtk/webview_webkit.cpp b/src/gtk/webview_webkit.cpp index 574028d9fe..2651ef7aa3 100644 --- a/src/gtk/webview_webkit.cpp +++ b/src/gtk/webview_webkit.cpp @@ -508,6 +508,8 @@ bool wxWebViewWebKit::Create(wxWindow *parent, G_CALLBACK(wxgtk_webview_webkit_load_status), this); + NotifyWebViewCreated(); + return true; } diff --git a/src/gtk/webview_webkit2.cpp b/src/gtk/webview_webkit2.cpp index a50525dedd..a57019521b 100644 --- a/src/gtk/webview_webkit2.cpp +++ b/src/gtk/webview_webkit2.cpp @@ -907,6 +907,8 @@ bool wxWebViewWebKit::Create(wxWindow *parent, PostCreation(size); + NotifyWebViewCreated(); + /* Open a webpage */ if (!isChildWebView) webkit_web_view_load_uri(m_web_view, url.utf8_str()); diff --git a/src/msw/webview_edge.cpp b/src/msw/webview_edge.cpp index 1dae4dc9c8..1314f2cef9 100644 --- a/src/msw/webview_edge.cpp +++ b/src/msw/webview_edge.cpp @@ -1033,6 +1033,8 @@ bool wxWebViewEdge::Create(wxWindow* parent, if (topLevelParent) topLevelParent->Bind(wxEVT_ICONIZE, &wxWebViewEdge::OnTopLevelParentIconized, this); + NotifyWebViewCreated(); + LoadURL(url); return true; } diff --git a/src/msw/webview_ie.cpp b/src/msw/webview_ie.cpp index 4d863783f2..581b3c4f98 100644 --- a/src/msw/webview_ie.cpp +++ b/src/msw/webview_ie.cpp @@ -109,6 +109,8 @@ bool wxWebViewIE::Create(wxWindow* parent, // pages without any physical network connection. SetOfflineMode(false); + NotifyWebViewCreated(); + LoadURL(url); return true; } diff --git a/src/osx/webview_webkit.mm b/src/osx/webview_webkit.mm index a58da3ac5f..205dad9ded 100644 --- a/src/osx/webview_webkit.mm +++ b/src/osx/webview_webkit.mm @@ -321,6 +321,8 @@ bool wxWebViewWebKit::Create(wxWindow *parent, m_UIDelegate = uiDelegate; + NotifyWebViewCreated(); + if (m_request) [m_webView loadRequest:(NSURLRequest*)m_request]; else