diff options
author | Tor Arne Vestbø <[email protected]> | 2024-11-11 13:00:10 +0100 |
---|---|---|
committer | Tor Arne Vestbø <[email protected]> | 2024-11-18 17:23:36 +0100 |
commit | fa9449bbe8fb20cbdfc5b1e81181a30e4a7c358a (patch) | |
tree | 9eee4afb682a8066137f1612baf2bfa1ffbfd2c9 | |
parent | aa7d479be0df3e118580e87f30e061445dfb37e3 (diff) |
Add private QObjCWeakPointer for tracking Objective-C object lifetime
Uses __weak if possible, and otherwise falls back to associated objects.
Replaces manual tracking of QNSView lifetime for QCocoaDrag.
Task-number: QTBUG-116554
Pick-to: 6.8
Change-Id: I56f2707bbf5aa14a9efd0ec29e37b157e97cfc3e
Reviewed-by: Volker Hilsheimer <[email protected]>
-rw-r--r-- | src/corelib/kernel/qcore_mac.mm | 14 | ||||
-rw-r--r-- | src/corelib/kernel/qcore_mac_p.h | 83 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoadrag.h | 5 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoadrag.mm | 18 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qnsview.mm | 4 |
5 files changed, 105 insertions, 19 deletions
diff --git a/src/corelib/kernel/qcore_mac.mm b/src/corelib/kernel/qcore_mac.mm index 00b0d078d7d..5af84019787 100644 --- a/src/corelib/kernel/qcore_mac.mm +++ b/src/corelib/kernel/qcore_mac.mm @@ -774,5 +774,19 @@ QMacVersion::VersionTuple QMacVersion::libraryVersion() // ------------------------------------------------------------------------- +#if !(__has_feature(objc_arc_weak) && __has_feature(objc_arc_fields)) +QT_END_NAMESPACE +@implementation QT_MANGLE_NAMESPACE(WeakPointerLifetimeTracker) +- (void)dealloc +{ + *self.pointer = {}; + [super dealloc]; +} +@end +QT_BEGIN_NAMESPACE +#endif + +// ------------------------------------------------------------------------- + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h index f5ab2327732..30590ef2303 100644 --- a/src/corelib/kernel/qcore_mac_p.h +++ b/src/corelib/kernel/qcore_mac_p.h @@ -462,6 +462,89 @@ qt_objc_cast(id object) // ------------------------------------------------------------------------- +#if defined( __OBJC__) + +template <typename T = NSObject> +class QObjCWeakPointer; + +#if __has_feature(objc_arc_weak) && __has_feature(objc_arc_fields) +# define USE_OBJC_WEAK 1 +#endif + +#if !USE_OBJC_WEAK +QT_END_NAMESPACE +#include <objc/runtime.h> +Q_CORE_EXPORT +QT_DECLARE_NAMESPACED_OBJC_INTERFACE(WeakPointerLifetimeTracker, NSObject +@property (atomic, assign) QT_PREPEND_NAMESPACE(QObjCWeakPointer)<NSObject> *pointer; +) +QT_BEGIN_NAMESPACE +#endif + +template <typename T> +class QObjCWeakPointer +{ +public: + QObjCWeakPointer(T *object = nil) : m_object(object) + { +#if !USE_OBJC_WEAK + trackObjectLifetime(); +#endif + } + + QObjCWeakPointer(const QObjCWeakPointer &other) + { + QMacAutoReleasePool pool; + m_object = other.m_object; +#if !USE_OBJC_WEAK + trackObjectLifetime(); +#endif + } + + QObjCWeakPointer &operator=(const QObjCWeakPointer &other) + { + QMacAutoReleasePool pool; + m_object = other.m_object; +#if !USE_OBJC_WEAK + trackObjectLifetime(); +#endif + return *this; + } + + ~QObjCWeakPointer() + { +#if !USE_OBJC_WEAK + if (m_object) + objc_setAssociatedObject(m_object, this, nil, OBJC_ASSOCIATION_RETAIN); +#endif + } + + operator T*() const { return static_cast<T*>([[m_object retain] autorelease]); } + +private: +#if USE_OBJC_WEAK + __weak +#else + void trackObjectLifetime() + { + if (!m_object) + return; + + auto *lifetimeTracker = [WeakPointerLifetimeTracker new]; + lifetimeTracker.pointer = reinterpret_cast<QObjCWeakPointer<NSObject>*>(this); + objc_setAssociatedObject(m_object, this, lifetimeTracker, OBJC_ASSOCIATION_RETAIN); + [lifetimeTracker release]; + } +#endif + NSObject *m_object = nil; +}; + +#undef USE_OBJC_WEAK + +#endif // __OBJC__ + +// ------------------------------------------------------------------------- + QT_END_NAMESPACE #endif // QCORE_MAC_P_H diff --git a/src/plugins/platforms/cocoa/qcocoadrag.h b/src/plugins/platforms/cocoa/qcocoadrag.h index 30456a91bba..c5c126ecf3e 100644 --- a/src/plugins/platforms/cocoa/qcocoadrag.h +++ b/src/plugins/platforms/cocoa/qcocoadrag.h @@ -8,6 +8,8 @@ #include <qpa/qplatformdrag.h> #include <private/qsimpledrag_p.h> +#include <QtCore/private/qcore_mac_p.h> + #include <QtGui/private/qdnd_p.h> #include <QtGui/private/qinternalmimedata_p.h> @@ -36,14 +38,13 @@ public: * event and view when handling an event in QNSView */ void setLastInputEvent(NSEvent *event, NSView *view); - void viewDestroyed(NSView *view); void setAcceptedAction(Qt::DropAction act); void exitDragLoop(); private: QDrag *m_drag; NSEvent *m_lastEvent; - NSView *m_lastView; + QObjCWeakPointer<NSView> m_lastView; Qt::DropAction m_executed_drop_action; QEventLoop *m_internalDragLoop = nullptr; diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm index bbc75bf6dbe..8e9fd053bda 100644 --- a/src/plugins/platforms/cocoa/qcocoadrag.mm +++ b/src/plugins/platforms/cocoa/qcocoadrag.mm @@ -38,17 +38,6 @@ void QCocoaDrag::setLastInputEvent(NSEvent *event, NSView *view) m_lastView = view; } -void QCocoaDrag::viewDestroyed(NSView *view) -{ - if (view == m_lastView) { - if (m_lastEvent.window.contentView == view) { - [m_lastEvent release]; - m_lastEvent = nil; - } - m_lastView = nil; - } -} - QMimeData *QCocoaDrag::dragMimeData() { if (m_drag) @@ -107,8 +96,11 @@ Qt::DropAction QCocoaDrag::defaultAction(Qt::DropActions possibleActions, Qt::DropAction QCocoaDrag::drag(QDrag *o) { m_executed_drop_action = Qt::IgnoreAction; - if (!m_lastEvent) + if (!m_lastView) { + [m_lastEvent release]; + m_lastEvent = nil; return m_executed_drop_action; + } m_drag = o; QMacPasteboard dragBoard(CFStringRef(NSPasteboardNameDrag), QUtiMimeConverter::HandlerScopeFlag::DnD); @@ -151,7 +143,7 @@ bool QCocoaDrag::maybeDragMultipleItems() const QMacAutoReleasePool pool; - NSView *view = m_lastView ? m_lastView : m_lastEvent.window.contentView; + NSView *view = m_lastView ? static_cast<NSView*>(m_lastView) : m_lastEvent.window.contentView; if (![view respondsToSelector:@selector(draggingSession:sourceOperationMaskForDraggingContext:)]) return false; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index e961021d240..560cada5fb4 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -173,10 +173,6 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMenuHelper); [[NSNotificationCenter defaultCenter] removeObserver:self]; [m_mouseMoveHelper release]; - // FIXME: Replace with __weak or someting equivalent - QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); - nativeDrag->viewDestroyed(self); - [super dealloc]; } |