From 6eb27afcdfb6df2e620f1ec66196600f0f9ed022 Mon Sep 17 00:00:00 2001
From: Gabriel de Dietrich <gabriel.dedietrich@theqtcompany.com>
Date: Tue, 19 Apr 2016 13:45:12 -0700
Subject: [PATCH] Cocoa: Add QCocoaWindowPointer

This patch extends 5b54c352edbc597ec5283bc9cfdd77906350161f
by abstracting the watcher pattern. The class is specialized
for QCocoaWindow since it's aware of the QObject sentinel there.

We update the usage in QNSWindowHelper and extend it to the
forward window (this one is used for mouse coordinate conversion
when docking windows).

Change-Id: I628415527593daec835bbad1b6e83d13fe7b6703
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@theqtcompany.com>
---
 src/plugins/platforms/cocoa/qcocoawindow.h  | 39 +++++++++++++++++----
 src/plugins/platforms/cocoa/qcocoawindow.mm | 31 ++++++++++------
 src/plugins/platforms/cocoa/qnsview.mm      |  2 +-
 3 files changed, 53 insertions(+), 19 deletions(-)

diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h
index e60ca196acd..9fcb221d374 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.h
+++ b/src/plugins/platforms/cocoa/qcocoawindow.h
@@ -38,6 +38,7 @@
 
 #include <qpa/qplatformwindow.h>
 #include <QRect>
+#include <QPointer>
 
 #ifndef QT_NO_OPENGL
 #include "qcocoaglcontext.h"
@@ -47,6 +48,32 @@
 
 QT_FORWARD_DECLARE_CLASS(QCocoaWindow)
 
+QT_BEGIN_NAMESPACE
+
+class QCocoaWindowPointer
+{
+public:
+    void assign(QCocoaWindow *w);
+    void clear();
+
+    QCocoaWindow *data() const
+    { return watcher.isNull() ? Q_NULLPTR : window; }
+    bool isNull() const
+    { return watcher.isNull(); }
+    operator QCocoaWindow*() const
+    { return data(); }
+    QCocoaWindow *operator->() const
+    { return data(); }
+    QCocoaWindow &operator*() const
+    { return *data(); }
+
+private:
+    QPointer<QObject> watcher;
+    QCocoaWindow *window;
+};
+
+QT_END_NAMESPACE
+
 @class QT_MANGLE_NAMESPACE(QNSWindowHelper);
 
 @protocol QNSWindowProtocol
@@ -63,14 +90,13 @@ typedef NSWindow<QNSWindowProtocol> QCocoaNSWindow;
 @interface QT_MANGLE_NAMESPACE(QNSWindowHelper) : NSObject
 {
     QCocoaNSWindow *_window;
-    QCocoaWindow *_platformWindow;
+    QCocoaWindowPointer _platformWindow;
     BOOL _grabbingMouse;
     BOOL _releaseOnMouseUp;
-    QPointer<QObject> _watcher;
 }
 
 @property (nonatomic, readonly) QCocoaNSWindow *window;
-@property (nonatomic, readonly) QCocoaWindow *platformWindow;
+@property (nonatomic, readonly) QCocoaWindowPointer platformWindow;
 @property (nonatomic) BOOL grabbingMouse;
 @property (nonatomic) BOOL releaseOnMouseUp;
 
@@ -254,7 +280,7 @@ public: // for QNSView
     NSView *m_contentView;
     QNSView *m_qtView;
     QCocoaNSWindow *m_nsWindow;
-    QCocoaWindow *m_forwardWindow;
+    QCocoaWindowPointer m_forwardWindow;
 
     // TODO merge to one variable if possible
     bool m_contentViewIsEmbedded; // true if the m_contentView is actually embedded in a "foreign" NSView hiearchy
@@ -317,9 +343,8 @@ public: // for QNSView
     QHash<quintptr, BorderRange> m_contentBorderAreas; // identifer -> uppper/lower
     QHash<quintptr, bool> m_enabledContentBorderAreas; // identifer -> enabled state (true/false)
 
-    // This object is tracked by a 'watcher'
-    // object in a window helper, preventing use of dangling
-    // pointers.
+    // This object is tracked by QCocoaWindowPointer,
+    // preventing the use of dangling pointers.
     QObject sentinel;
 };
 
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 12e85c52054..dd67946a272 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -85,7 +85,7 @@ static bool isMouseEvent(NSEvent *ev)
     self = [super init];
     if (self) {
         _window = window;
-        _platformWindow = platformWindow;
+        _platformWindow.assign(platformWindow);
 
         _window.delegate = [[QNSWindowDelegate alloc] initWithQCocoaWindow:_platformWindow];
 
@@ -94,7 +94,6 @@ static bool isMouseEvent(NSEvent *ev)
         // make sure that m_nsWindow stays valid until the
         // QCocoaWindow is deleted by Qt.
         [_window setReleasedWhenClosed:NO];
-        _watcher = &_platformWindow->sentinel;
     }
 
     return self;
@@ -103,19 +102,19 @@ static bool isMouseEvent(NSEvent *ev)
 - (void)handleWindowEvent:(NSEvent *)theEvent
 {
     QCocoaWindow *pw = self.platformWindow;
-    if (_watcher && pw && pw->m_forwardWindow) {
+    if (pw && pw->m_forwardWindow) {
         if (theEvent.type == NSLeftMouseUp || theEvent.type == NSLeftMouseDragged) {
             QNSView *forwardView = pw->m_qtView;
             if (theEvent.type == NSLeftMouseUp) {
                 [forwardView mouseUp:theEvent];
-                pw->m_forwardWindow = 0;
+                pw->m_forwardWindow.clear();
             } else {
                 [forwardView mouseDragged:theEvent];
             }
         }
 
         if (!pw->m_isNSWindowChild && theEvent.type == NSLeftMouseDown) {
-            pw->m_forwardWindow = 0;
+            pw->m_forwardWindow.clear();
         }
     }
 
@@ -142,7 +141,7 @@ static bool isMouseEvent(NSEvent *ev)
     if (!self.window.delegate)
         return; // Already detached, pending NSAppKitDefined event
 
-    if (_watcher && pw && pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) {
+    if (pw && pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) {
         NSPoint loc = [theEvent locationInWindow];
         NSRect windowFrame = [self.window convertRectFromScreen:[self.window frame]];
         NSRect contentFrame = [[self.window contentView] frame];
@@ -157,8 +156,7 @@ static bool isMouseEvent(NSEvent *ev)
 
 - (void)detachFromPlatformWindow
 {
-    _platformWindow = 0;
-    _watcher.clear();
+    self.platformWindow.clear();
     [self.window.delegate release];
     self.window.delegate = nil;
 }
@@ -179,7 +177,7 @@ static bool isMouseEvent(NSEvent *ev)
 - (void)dealloc
 {
     _window = nil;
-    _platformWindow = 0;
+    self.platformWindow.clear();
     [super dealloc];
 }
 
@@ -331,6 +329,18 @@ static bool isMouseEvent(NSEvent *ev)
 
 @end
 
+void QCocoaWindowPointer::assign(QCocoaWindow *w)
+{
+    window = w;
+    watcher = &w->sentinel;
+}
+
+void QCocoaWindowPointer::clear()
+{
+    window = Q_NULLPTR;
+    watcher.clear();
+}
+
 const int QCocoaWindow::NoAlertRequest = -1;
 
 QCocoaWindow::QCocoaWindow(QWindow *tlw)
@@ -338,7 +348,6 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
     , m_contentView(nil)
     , m_qtView(nil)
     , m_nsWindow(0)
-    , m_forwardWindow(0)
     , m_contentViewIsEmbedded(false)
     , m_contentViewIsToBeEmbedded(false)
     , m_parentCocoaWindow(0)
@@ -1320,7 +1329,7 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow)
         if (oldParentCocoaWindow) {
             if (!m_isNSWindowChild || oldParentCocoaWindow != m_parentCocoaWindow)
                 oldParentCocoaWindow->removeChildWindow(this);
-            m_forwardWindow = oldParentCocoaWindow;
+            m_forwardWindow.assign(oldParentCocoaWindow);
         }
 
         setNSWindow(m_nsWindow);
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 34c37d8aed0..0d58faa5bf0 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -741,7 +741,7 @@ QT_WARNING_POP
         if (theEvent.type == NSLeftMouseDragged || theEvent.type == NSLeftMouseUp)
             targetView = m_platformWindow->m_forwardWindow->m_qtView;
         else
-            m_platformWindow->m_forwardWindow = 0;
+            m_platformWindow->m_forwardWindow.clear();
     }
 
     // Popups implicitly grap mouse events; forward to the active popup if there is one
-- 
GitLab