Move webview pointer to wxweakref

Uses wx reference counting infrastructure to ensure we have a valid
pointer and adds proper null checking for the webview not being
instantiated yet
This commit is contained in:
Seth Hillbrand
2026-03-18 18:00:57 -07:00
parent 60a9e2ff72
commit 9fbb0378c5
2 changed files with 68 additions and 39 deletions
+49 -36
View File
@@ -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<wxWebViewHandler>( new wxWebViewArchiveHandler( "wxfs" ) ) );
m_browser->RegisterHandler( wxSharedPtr<wxWebViewHandler>( new wxWebViewFSHandler( "memory" ) ) );
browser->RegisterHandler( wxSharedPtr<wxWebViewHandler>( new wxWebViewArchiveHandler( "wxfs" ) ) );
browser->RegisterHandler( wxSharedPtr<wxWebViewHandler>( 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<wxWebViewHandler>( new wxWebViewArchiveHandler( "wxfs" ) ) );
m_browser->RegisterHandler( wxSharedPtr<wxWebViewHandler>( new wxWebViewFSHandler( "memory" ) ) );
browser->RegisterHandler( wxSharedPtr<wxWebViewHandler>( new wxWebViewArchiveHandler( "wxfs" ) ) );
browser->RegisterHandler( wxSharedPtr<wxWebViewHandler>( 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() );
+19 -3
View File
@@ -23,12 +23,27 @@
#include <wx/panel.h>
#include <wx/timer.h>
#include <wx/webview.h>
#include <wx/weakref.h>
#include <functional>
#include <map>
class TOOL_MANAGER;
class TOOL_BASE;
namespace WEBVIEW_PANEL_DETAIL
{
template<typename T>
T* GetLiveWindow( const wxWeakRef<T>& 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<wxWebView> m_browser;
wxString m_backend;
std::map<wxString, MESSAGE_HANDLER> m_msgHandlers;
TOOL_MANAGER* m_toolManager;