diff --git a/common/widgets/webview_panel.cpp b/common/widgets/webview_panel.cpp index 9b48e49701..14dc20ba0d 100644 --- a/common/widgets/webview_panel.cpp +++ b/common/widgets/webview_panel.cpp @@ -77,39 +77,32 @@ WEBVIEW_PANEL::WEBVIEW_PANEL( wxWindow* aParent, wxWindowID aId, const wxPoint& m_backend = wxWebViewBackendDefault; #endif + wxWebView* browser = GetWebView(); + + if( !browser ) + return; + #ifdef __WXMAC__ - m_browser->RegisterHandler( wxSharedPtr( new wxWebViewArchiveHandler( "wxfs" ) ) ); - m_browser->RegisterHandler( wxSharedPtr( new wxWebViewFSHandler( "memory" ) ) ); + browser->RegisterHandler( wxSharedPtr( new wxWebViewArchiveHandler( "wxfs" ) ) ); + browser->RegisterHandler( wxSharedPtr( new wxWebViewFSHandler( "memory" ) ) ); #endif - m_browser->SetUserAgent( wxString::Format( "KiCad/%s WebView/%s", GetMajorMinorPatchVersion(), wxGetOsDescription() ) ); - m_browser->Create( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize ); - sizer->Add( m_browser, 1, wxEXPAND ); + browser->SetUserAgent( wxString::Format( "KiCad/%s WebView/%s", GetMajorMinorPatchVersion(), wxGetOsDescription() ) ); + browser->Create( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize ); + sizer->Add( browser, 1, wxEXPAND ); SetSizer( sizer ); #ifndef __WXMAC__ - m_browser->RegisterHandler( wxSharedPtr( new wxWebViewArchiveHandler( "wxfs" ) ) ); - m_browser->RegisterHandler( wxSharedPtr( new wxWebViewFSHandler( "memory" ) ) ); + browser->RegisterHandler( wxSharedPtr( new wxWebViewArchiveHandler( "wxfs" ) ) ); + browser->RegisterHandler( wxSharedPtr( new wxWebViewFSHandler( "memory" ) ) ); #endif - Bind( wxEVT_WEBVIEW_NAVIGATING, &WEBVIEW_PANEL::OnNavigationRequest, this, m_browser->GetId() ); - Bind( wxEVT_WEBVIEW_NEWWINDOW, &WEBVIEW_PANEL::OnNewWindow, this, m_browser->GetId() ); - Bind( wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &WEBVIEW_PANEL::OnScriptMessage, this, m_browser->GetId() ); - Bind( wxEVT_WEBVIEW_SCRIPT_RESULT, &WEBVIEW_PANEL::OnScriptResult, this, m_browser->GetId() ); - Bind( wxEVT_WEBVIEW_ERROR, &WEBVIEW_PANEL::OnError, this, m_browser->GetId() ); + Bind( wxEVT_WEBVIEW_NAVIGATING, &WEBVIEW_PANEL::OnNavigationRequest, this, browser->GetId() ); + Bind( wxEVT_WEBVIEW_NEWWINDOW, &WEBVIEW_PANEL::OnNewWindow, this, browser->GetId() ); + Bind( wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &WEBVIEW_PANEL::OnScriptMessage, this, browser->GetId() ); + Bind( wxEVT_WEBVIEW_SCRIPT_RESULT, &WEBVIEW_PANEL::OnScriptResult, this, browser->GetId() ); + Bind( wxEVT_WEBVIEW_ERROR, &WEBVIEW_PANEL::OnError, this, browser->GetId() ); m_initRetryTimer.Bind( wxEVT_TIMER, [this]( wxTimerEvent& ) { DoInitHandlers(); } ); - - m_browser->Bind( wxEVT_DESTROY, [this]( wxWindowDestroyEvent& evt ) - { - if( evt.GetEventObject() == m_browser ) - { - // During panel teardown, wxWindow destroys children after C++ member - // destruction, so m_initRetryTimer may already be gone here. - m_browser = nullptr; - } - - evt.Skip(); - } ); } WEBVIEW_PANEL::~WEBVIEW_PANEL() @@ -121,7 +114,12 @@ void WEBVIEW_PANEL::BindLoadedEvent() if( m_loadedEventBound ) return; - Bind( wxEVT_WEBVIEW_LOADED, &WEBVIEW_PANEL::OnWebViewLoaded, this, m_browser->GetId() ); + wxWebView* browser = GetWebView(); + + if( !browser ) + return; + + Bind( wxEVT_WEBVIEW_LOADED, &WEBVIEW_PANEL::OnWebViewLoaded, this, browser->GetId() ); m_loadedEventBound = true; } @@ -132,7 +130,10 @@ void WEBVIEW_PANEL::LoadURL( const wxString& aURL ) if( aURL.starts_with( "file:/" ) && !aURL.starts_with( "file:///" ) ) { wxString new_url = wxString( "file:///" ) + aURL.AfterFirst( '/' ); - m_browser->LoadURL( new_url ); + + if( wxWebView* browser = GetWebView() ) + browser->LoadURL( new_url ); + return; } @@ -142,13 +143,16 @@ void WEBVIEW_PANEL::LoadURL( const wxString& aURL ) return; } - m_browser->LoadURL( aURL ); + if( wxWebView* browser = GetWebView() ) + browser->LoadURL( aURL ); } void WEBVIEW_PANEL::SetPage( const wxString& aHtmlContent ) { wxLogTrace( "webview", "Setting page content" ); - m_browser->SetPage( aHtmlContent, "file://" ); + + if( wxWebView* browser = GetWebView() ) + browser->SetPage( aHtmlContent, "file://" ); } bool WEBVIEW_PANEL::AddMessageHandler( const wxString& aName, MESSAGE_HANDLER aHandler ) @@ -164,8 +168,13 @@ bool WEBVIEW_PANEL::AddMessageHandler( const wxString& aName, MESSAGE_HANDLER aH m_msgHandlers.emplace( aName, std::move( aHandler ) ); - if( m_initialized && m_browser ) + if( m_initialized ) { + wxWebView* browser = GetWebView(); + + if( !browser ) + return true; + wxEventLoopBase* activeLoop = wxEventLoopBase::GetActive(); if( activeLoop && ( !activeLoop->IsMain() || activeLoop->IsYielding() ) ) @@ -174,7 +183,7 @@ bool WEBVIEW_PANEL::AddMessageHandler( const wxString& aName, MESSAGE_HANDLER aH } else { - if( !m_browser->AddScriptMessageHandler( aName ) ) + if( !browser->AddScriptMessageHandler( aName ) ) wxLogTrace( "webview", "Could not add script message handler %s", aName ); } } @@ -186,10 +195,10 @@ void WEBVIEW_PANEL::ClearMessageHandlers() { wxLogTrace( "webview", "Clearing all message handlers" ); - if( m_browser ) + if( wxWebView* browser = GetWebView() ) { for( const auto& handler : m_msgHandlers ) - m_browser->RemoveScriptMessageHandler( handler.first ); + browser->RemoveScriptMessageHandler( handler.first ); } m_msgHandlers.clear(); @@ -212,7 +221,9 @@ void WEBVIEW_PANEL::OnNavigationRequest( wxWebViewEvent& aEvt ) void WEBVIEW_PANEL::DoInitHandlers() { - if( !m_browser ) + wxWebView* browser = GetWebView(); + + if( !browser ) return; // WebKit's AddScriptMessageHandler internally calls RunScript which yields the @@ -230,11 +241,11 @@ void WEBVIEW_PANEL::DoInitHandlers() for( const auto& handler : m_msgHandlers ) { - if( !m_browser->AddScriptMessageHandler( handler.first ) ) + if( !browser->AddScriptMessageHandler( handler.first ) ) wxLogTrace( "webview", "Could not add script message handler %s", handler.first ); } - m_browser->AddUserScript( R"( + browser->AddUserScript( R"( (function() { // Change window.open to navigate in the same window window.open = function(url) { if (url) window.location.href = url; return null; }; @@ -278,7 +289,9 @@ void WEBVIEW_PANEL::OnWebViewLoaded( wxWebViewEvent& aEvt ) void WEBVIEW_PANEL::OnNewWindow( wxWebViewEvent& aEvt ) { - m_browser->LoadURL( aEvt.GetURL() ); + if( wxWebView* browser = GetWebView() ) + browser->LoadURL( aEvt.GetURL() ); + aEvt.Veto(); // Prevent default behavior of opening a new window wxLogTrace( "webview", "New window requested for URL: %s", aEvt.GetURL() ); wxLogTrace( "webview", "Target: %s", aEvt.GetTarget() ); diff --git a/include/widgets/webview_panel.h b/include/widgets/webview_panel.h index c0dde21353..18d8fc2a1a 100644 --- a/include/widgets/webview_panel.h +++ b/include/widgets/webview_panel.h @@ -23,12 +23,27 @@ #include #include #include +#include #include #include class TOOL_MANAGER; class TOOL_BASE; +namespace WEBVIEW_PANEL_DETAIL +{ +template +T* GetLiveWindow( const wxWeakRef& aWindowRef ) +{ + T* window = aWindowRef.get(); + + if( window && !window->IsBeingDeleted() ) + return window; + + return nullptr; +} +} // namespace WEBVIEW_PANEL_DETAIL + class WEBVIEW_PANEL : public wxPanel { public: @@ -39,7 +54,7 @@ public: TOOL_MANAGER* aToolManager = nullptr, TOOL_BASE* aTool = nullptr ); ~WEBVIEW_PANEL() override; - wxWebView* GetWebView() const { return m_browser; } + wxWebView* GetWebView() const { return WEBVIEW_PANEL_DETAIL::GetLiveWindow( m_browser ); } const wxString& GetBackend() const { return m_backend; } void LoadURL( const wxString& url ); @@ -53,7 +68,8 @@ public: void RunScriptAsync( const wxString& aScript, void* aClientData = nullptr ) const { - m_browser->RunScriptAsync( aScript, aClientData ); + if( wxWebView* browser = GetWebView() ) + browser->RunScriptAsync( aScript, aClientData ); } bool HasLoadError() const { return m_loadError; } @@ -76,7 +92,7 @@ private: bool m_handleExternalLinks; bool m_loadError; bool m_loadedEventBound; - wxWebView* m_browser; + wxWeakRef m_browser; wxString m_backend; std::map m_msgHandlers; TOOL_MANAGER* m_toolManager;