From c2ba24b4d01255c9b00f80f71d0f225953563886 Mon Sep 17 00:00:00 2001 From: reuk Date: Wed, 28 Jan 2026 14:03:09 +0000 Subject: [PATCH] OpenGL: Fix listener deregistration when removing child components Previously, if parent.removeChildComponent (child) was called, passing a child component that was attached to an OpenGL context, the child component would fail to inform its old peer that it no longer wanted to receive scale notification callbacks. This in turn could result in the peer continuing to send callbacks to a dangling pointer. --- .../juce_opengl/native/juce_OpenGL_windows.h | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/modules/juce_opengl/native/juce_OpenGL_windows.h b/modules/juce_opengl/native/juce_OpenGL_windows.h index 177887232d..b5bbaef7f1 100644 --- a/modules/juce_opengl/native/juce_OpenGL_windows.h +++ b/modules/juce_opengl/native/juce_OpenGL_windows.h @@ -38,8 +38,7 @@ namespace juce extern ComponentPeer* createNonRepaintingEmbeddedWindowsPeer (Component&, Component* parent); //============================================================================== -class OpenGLContext::NativeContext : private ComponentPeer::ScaleFactorListener, - private AsyncUpdater +class OpenGLContext::NativeContext : private AsyncUpdater { public: NativeContext (Component& component, @@ -47,7 +46,8 @@ public: void* contextToShareWithIn, bool /*useMultisampling*/, OpenGLVersion version) - : sharedContext (contextToShareWithIn) + : safeComponent (&component), + sharedContext (contextToShareWithIn) { placeholderComponent.reset (new PlaceholderComponent (*this)); createNativeWindow (component); @@ -95,10 +95,6 @@ public: cancelPendingUpdate(); renderContext.reset(); dc.reset(); - - if (safeComponent != nullptr) - if (auto* peer = safeComponent->getTopLevelComponent()->getPeer()) - peer->removeScaleFactorListener (this); } InitResult initialiseOnRenderThread (OpenGLContext& c) @@ -315,7 +311,7 @@ private: }; //============================================================================== - void nativeScaleFactorChanged (double newScaleFactor) override + void nativeScaleFactorChanged (double newScaleFactor) { if (approximatelyEqual (newScaleFactor, nativeScaleFactor) || safeComponent == nullptr) @@ -330,6 +326,8 @@ private: void createNativeWindow (Component& component) { + safeComponent = &component; + auto* topComp = component.getTopLevelComponent(); { @@ -341,11 +339,8 @@ private: if (auto* peer = topComp->getPeer()) { - safeComponent = &component; - nativeScaleFactor = peer->getPlatformScaleFactor(); updateWindowPosition (peer->getAreaCoveredBy (component)); - peer->addScaleFactorListener (this); } dc = { GetDC ((HWND) nativeWindow->getNativeHandle()), @@ -440,6 +435,8 @@ private: void* sharedContext = nullptr; double nativeScaleFactor = 1.0; bool haveBuffersBeenSwapped = false; + NativeScaleFactorNotifier scaleFactorNotifier { safeComponent.getComponent(), + [this] (auto x) { nativeScaleFactorChanged (x); } }; //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)