summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Arne Vestbø <[email protected]>2024-11-11 13:00:10 +0100
committerTor Arne Vestbø <[email protected]>2024-11-18 17:23:36 +0100
commitfa9449bbe8fb20cbdfc5b1e81181a30e4a7c358a (patch)
tree9eee4afb682a8066137f1612baf2bfa1ffbfd2c9
parentaa7d479be0df3e118580e87f30e061445dfb37e3 (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.mm14
-rw-r--r--src/corelib/kernel/qcore_mac_p.h83
-rw-r--r--src/plugins/platforms/cocoa/qcocoadrag.h5
-rw-r--r--src/plugins/platforms/cocoa/qcocoadrag.mm18
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm4
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];
}