From 36655e04996983db9b5a040f4b60b9d26bb002ee Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Tue, 13 Jan 2026 15:06:50 -0800 Subject: [PATCH] Properly bind event handlers to a sink Lambdas are stored as opaque functors, so wxWidgets cannot see what they capture. Since we don't know what the event sink is, we don't know to detach the handler when the sink is destroyed. Then, events can execute after the swatch is destroyed Changing the lambdas to a member function explicitly binds the event to a sink and wxWidgets can track it and detach the handler when the swatch hits a dtor Fixes https://gitlab.com/kicad/code/kicad/-/issues/22689 --- common/widgets/color_swatch.cpp | 30 ++++++++++-------------------- include/widgets/color_swatch.h | 6 ++++++ 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/common/widgets/color_swatch.cpp b/common/widgets/color_swatch.cpp index 479dfe23db..94976884aa 100644 --- a/common/widgets/color_swatch.cpp +++ b/common/widgets/color_swatch.cpp @@ -220,11 +220,7 @@ void COLOR_SWATCH::setupEvents( bool aTriggerWithSingleClick ) { if( dynamic_cast( wxGetTopLevelParent( this ) ) ) { - m_swatch->Bind( wxEVT_LEFT_DOWN, - [this] ( wxMouseEvent& aEvt ) - { - GetNewSwatchColor(); - } ); + m_swatch->Bind( wxEVT_LEFT_DOWN, &COLOR_SWATCH::onMouseEvent, this ); } else { @@ -232,27 +228,15 @@ void COLOR_SWATCH::setupEvents( bool aTriggerWithSingleClick ) m_swatch->Bind( wxEVT_LEFT_DOWN, &COLOR_SWATCH::rePostEvent, this ); // bind the events that trigger the dialog - m_swatch->Bind( wxEVT_LEFT_DCLICK, - [this] ( wxMouseEvent& aEvt ) - { - GetNewSwatchColor(); - } ); + m_swatch->Bind( wxEVT_LEFT_DCLICK, &COLOR_SWATCH::onMouseEvent, this ); if( aTriggerWithSingleClick ) { - m_swatch->Bind( wxEVT_LEFT_UP, - [this] ( wxMouseEvent& aEvt ) - { - GetNewSwatchColor(); - } ); + m_swatch->Bind( wxEVT_LEFT_UP, &COLOR_SWATCH::onMouseEvent, this ); } } - m_swatch->Bind( wxEVT_MIDDLE_DOWN, - [this] ( wxMouseEvent& aEvt ) - { - GetNewSwatchColor(); - } ); + m_swatch->Bind( wxEVT_MIDDLE_DOWN, &COLOR_SWATCH::onMouseEvent, this ); m_swatch->Bind( wxEVT_RIGHT_DOWN, &COLOR_SWATCH::rePostEvent, this ); } @@ -264,6 +248,12 @@ void COLOR_SWATCH::rePostEvent( wxEvent& aEvent ) } +void COLOR_SWATCH::onMouseEvent( wxEvent& ) +{ + GetNewSwatchColor(); +} + + static void sendSwatchChangeEvent( COLOR_SWATCH& aSender ) { wxCommandEvent changeEvt( COLOR_SWATCH_CHANGED, aSender.GetId() ); diff --git a/include/widgets/color_swatch.h b/include/widgets/color_swatch.h index 02590d81c3..fdcb0373bd 100644 --- a/include/widgets/color_swatch.h +++ b/include/widgets/color_swatch.h @@ -142,6 +142,12 @@ private: */ void rePostEvent( wxEvent& aEvent ); + /** + * Handle mouse events on the swatch, and trigger the color picker dialog if appropriate. + * Binds to the event sink so it is properly freed when the swatch is destroyed. + */ + void onMouseEvent( wxEvent& aEvent ); + KIGFX::COLOR4D m_color; KIGFX::COLOR4D m_background; KIGFX::COLOR4D m_default;