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 Change-Id: I56f2707bbf5aa14a9efd0ec29e37b157e97cfc3e Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> (cherry picked from commit fa9449bbe8fb20cbdfc5b1e81181a30e4a7c358a) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
ef8fc89355
commit
059cbd17ba
@ -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
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
@ -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
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // QCORE_MAC_P_H
|
#endif // QCORE_MAC_P_H
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
#include <qpa/qplatformdrag.h>
|
#include <qpa/qplatformdrag.h>
|
||||||
#include <private/qsimpledrag_p.h>
|
#include <private/qsimpledrag_p.h>
|
||||||
|
|
||||||
|
#include <QtCore/private/qcore_mac_p.h>
|
||||||
|
|
||||||
#include <QtGui/private/qdnd_p.h>
|
#include <QtGui/private/qdnd_p.h>
|
||||||
#include <QtGui/private/qinternalmimedata_p.h>
|
#include <QtGui/private/qinternalmimedata_p.h>
|
||||||
|
|
||||||
@ -36,14 +38,13 @@ public:
|
|||||||
* event and view when handling an event in QNSView
|
* event and view when handling an event in QNSView
|
||||||
*/
|
*/
|
||||||
void setLastInputEvent(NSEvent *event, NSView *view);
|
void setLastInputEvent(NSEvent *event, NSView *view);
|
||||||
void viewDestroyed(NSView *view);
|
|
||||||
|
|
||||||
void setAcceptedAction(Qt::DropAction act);
|
void setAcceptedAction(Qt::DropAction act);
|
||||||
void exitDragLoop();
|
void exitDragLoop();
|
||||||
private:
|
private:
|
||||||
QDrag *m_drag;
|
QDrag *m_drag;
|
||||||
NSEvent *m_lastEvent;
|
NSEvent *m_lastEvent;
|
||||||
NSView *m_lastView;
|
QObjCWeakPointer<NSView> m_lastView;
|
||||||
Qt::DropAction m_executed_drop_action;
|
Qt::DropAction m_executed_drop_action;
|
||||||
QEventLoop *m_internalDragLoop = nullptr;
|
QEventLoop *m_internalDragLoop = nullptr;
|
||||||
|
|
||||||
|
@ -38,17 +38,6 @@ void QCocoaDrag::setLastInputEvent(NSEvent *event, NSView *view)
|
|||||||
m_lastView = 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()
|
QMimeData *QCocoaDrag::dragMimeData()
|
||||||
{
|
{
|
||||||
if (m_drag)
|
if (m_drag)
|
||||||
@ -107,8 +96,11 @@ Qt::DropAction QCocoaDrag::defaultAction(Qt::DropActions possibleActions,
|
|||||||
Qt::DropAction QCocoaDrag::drag(QDrag *o)
|
Qt::DropAction QCocoaDrag::drag(QDrag *o)
|
||||||
{
|
{
|
||||||
m_executed_drop_action = Qt::IgnoreAction;
|
m_executed_drop_action = Qt::IgnoreAction;
|
||||||
if (!m_lastEvent)
|
if (!m_lastView) {
|
||||||
|
[m_lastEvent release];
|
||||||
|
m_lastEvent = nil;
|
||||||
return m_executed_drop_action;
|
return m_executed_drop_action;
|
||||||
|
}
|
||||||
|
|
||||||
m_drag = o;
|
m_drag = o;
|
||||||
QMacPasteboard dragBoard(CFStringRef(NSPasteboardNameDrag), QUtiMimeConverter::HandlerScopeFlag::DnD);
|
QMacPasteboard dragBoard(CFStringRef(NSPasteboardNameDrag), QUtiMimeConverter::HandlerScopeFlag::DnD);
|
||||||
@ -151,7 +143,7 @@ bool QCocoaDrag::maybeDragMultipleItems()
|
|||||||
|
|
||||||
const QMacAutoReleasePool pool;
|
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:)])
|
if (![view respondsToSelector:@selector(draggingSession:sourceOperationMaskForDraggingContext:)])
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -173,10 +173,6 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMenuHelper);
|
|||||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
[m_mouseMoveHelper release];
|
[m_mouseMoveHelper release];
|
||||||
|
|
||||||
// FIXME: Replace with __weak or someting equivalent
|
|
||||||
QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
|
|
||||||
nativeDrag->viewDestroyed(self);
|
|
||||||
|
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user