Cocoa: Add QCocoaWindowPointer

This patch extends 5b54c352ed
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>
This commit is contained in:
Gabriel de Dietrich 2016-04-19 13:45:12 -07:00 committed by Gabriel de Dietrich
parent e6c0373421
commit 6eb27afcdf
3 changed files with 53 additions and 19 deletions

View File

@ -38,6 +38,7 @@
#include <qpa/qplatformwindow.h> #include <qpa/qplatformwindow.h>
#include <QRect> #include <QRect>
#include <QPointer>
#ifndef QT_NO_OPENGL #ifndef QT_NO_OPENGL
#include "qcocoaglcontext.h" #include "qcocoaglcontext.h"
@ -47,6 +48,32 @@
QT_FORWARD_DECLARE_CLASS(QCocoaWindow) 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); @class QT_MANGLE_NAMESPACE(QNSWindowHelper);
@protocol QNSWindowProtocol @protocol QNSWindowProtocol
@ -63,14 +90,13 @@ typedef NSWindow<QNSWindowProtocol> QCocoaNSWindow;
@interface QT_MANGLE_NAMESPACE(QNSWindowHelper) : NSObject @interface QT_MANGLE_NAMESPACE(QNSWindowHelper) : NSObject
{ {
QCocoaNSWindow *_window; QCocoaNSWindow *_window;
QCocoaWindow *_platformWindow; QCocoaWindowPointer _platformWindow;
BOOL _grabbingMouse; BOOL _grabbingMouse;
BOOL _releaseOnMouseUp; BOOL _releaseOnMouseUp;
QPointer<QObject> _watcher;
} }
@property (nonatomic, readonly) QCocoaNSWindow *window; @property (nonatomic, readonly) QCocoaNSWindow *window;
@property (nonatomic, readonly) QCocoaWindow *platformWindow; @property (nonatomic, readonly) QCocoaWindowPointer platformWindow;
@property (nonatomic) BOOL grabbingMouse; @property (nonatomic) BOOL grabbingMouse;
@property (nonatomic) BOOL releaseOnMouseUp; @property (nonatomic) BOOL releaseOnMouseUp;
@ -254,7 +280,7 @@ public: // for QNSView
NSView *m_contentView; NSView *m_contentView;
QNSView *m_qtView; QNSView *m_qtView;
QCocoaNSWindow *m_nsWindow; QCocoaNSWindow *m_nsWindow;
QCocoaWindow *m_forwardWindow; QCocoaWindowPointer m_forwardWindow;
// TODO merge to one variable if possible // TODO merge to one variable if possible
bool m_contentViewIsEmbedded; // true if the m_contentView is actually embedded in a "foreign" NSView hiearchy 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, BorderRange> m_contentBorderAreas; // identifer -> uppper/lower
QHash<quintptr, bool> m_enabledContentBorderAreas; // identifer -> enabled state (true/false) QHash<quintptr, bool> m_enabledContentBorderAreas; // identifer -> enabled state (true/false)
// This object is tracked by a 'watcher' // This object is tracked by QCocoaWindowPointer,
// object in a window helper, preventing use of dangling // preventing the use of dangling pointers.
// pointers.
QObject sentinel; QObject sentinel;
}; };

View File

@ -85,7 +85,7 @@ static bool isMouseEvent(NSEvent *ev)
self = [super init]; self = [super init];
if (self) { if (self) {
_window = window; _window = window;
_platformWindow = platformWindow; _platformWindow.assign(platformWindow);
_window.delegate = [[QNSWindowDelegate alloc] initWithQCocoaWindow:_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 // make sure that m_nsWindow stays valid until the
// QCocoaWindow is deleted by Qt. // QCocoaWindow is deleted by Qt.
[_window setReleasedWhenClosed:NO]; [_window setReleasedWhenClosed:NO];
_watcher = &_platformWindow->sentinel;
} }
return self; return self;
@ -103,19 +102,19 @@ static bool isMouseEvent(NSEvent *ev)
- (void)handleWindowEvent:(NSEvent *)theEvent - (void)handleWindowEvent:(NSEvent *)theEvent
{ {
QCocoaWindow *pw = self.platformWindow; QCocoaWindow *pw = self.platformWindow;
if (_watcher && pw && pw->m_forwardWindow) { if (pw && pw->m_forwardWindow) {
if (theEvent.type == NSLeftMouseUp || theEvent.type == NSLeftMouseDragged) { if (theEvent.type == NSLeftMouseUp || theEvent.type == NSLeftMouseDragged) {
QNSView *forwardView = pw->m_qtView; QNSView *forwardView = pw->m_qtView;
if (theEvent.type == NSLeftMouseUp) { if (theEvent.type == NSLeftMouseUp) {
[forwardView mouseUp:theEvent]; [forwardView mouseUp:theEvent];
pw->m_forwardWindow = 0; pw->m_forwardWindow.clear();
} else { } else {
[forwardView mouseDragged:theEvent]; [forwardView mouseDragged:theEvent];
} }
} }
if (!pw->m_isNSWindowChild && theEvent.type == NSLeftMouseDown) { 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) if (!self.window.delegate)
return; // Already detached, pending NSAppKitDefined event return; // Already detached, pending NSAppKitDefined event
if (_watcher && pw && pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) { if (pw && pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) {
NSPoint loc = [theEvent locationInWindow]; NSPoint loc = [theEvent locationInWindow];
NSRect windowFrame = [self.window convertRectFromScreen:[self.window frame]]; NSRect windowFrame = [self.window convertRectFromScreen:[self.window frame]];
NSRect contentFrame = [[self.window contentView] frame]; NSRect contentFrame = [[self.window contentView] frame];
@ -157,8 +156,7 @@ static bool isMouseEvent(NSEvent *ev)
- (void)detachFromPlatformWindow - (void)detachFromPlatformWindow
{ {
_platformWindow = 0; self.platformWindow.clear();
_watcher.clear();
[self.window.delegate release]; [self.window.delegate release];
self.window.delegate = nil; self.window.delegate = nil;
} }
@ -179,7 +177,7 @@ static bool isMouseEvent(NSEvent *ev)
- (void)dealloc - (void)dealloc
{ {
_window = nil; _window = nil;
_platformWindow = 0; self.platformWindow.clear();
[super dealloc]; [super dealloc];
} }
@ -331,6 +329,18 @@ static bool isMouseEvent(NSEvent *ev)
@end @end
void QCocoaWindowPointer::assign(QCocoaWindow *w)
{
window = w;
watcher = &w->sentinel;
}
void QCocoaWindowPointer::clear()
{
window = Q_NULLPTR;
watcher.clear();
}
const int QCocoaWindow::NoAlertRequest = -1; const int QCocoaWindow::NoAlertRequest = -1;
QCocoaWindow::QCocoaWindow(QWindow *tlw) QCocoaWindow::QCocoaWindow(QWindow *tlw)
@ -338,7 +348,6 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
, m_contentView(nil) , m_contentView(nil)
, m_qtView(nil) , m_qtView(nil)
, m_nsWindow(0) , m_nsWindow(0)
, m_forwardWindow(0)
, m_contentViewIsEmbedded(false) , m_contentViewIsEmbedded(false)
, m_contentViewIsToBeEmbedded(false) , m_contentViewIsToBeEmbedded(false)
, m_parentCocoaWindow(0) , m_parentCocoaWindow(0)
@ -1320,7 +1329,7 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow)
if (oldParentCocoaWindow) { if (oldParentCocoaWindow) {
if (!m_isNSWindowChild || oldParentCocoaWindow != m_parentCocoaWindow) if (!m_isNSWindowChild || oldParentCocoaWindow != m_parentCocoaWindow)
oldParentCocoaWindow->removeChildWindow(this); oldParentCocoaWindow->removeChildWindow(this);
m_forwardWindow = oldParentCocoaWindow; m_forwardWindow.assign(oldParentCocoaWindow);
} }
setNSWindow(m_nsWindow); setNSWindow(m_nsWindow);

View File

@ -741,7 +741,7 @@ QT_WARNING_POP
if (theEvent.type == NSLeftMouseDragged || theEvent.type == NSLeftMouseUp) if (theEvent.type == NSLeftMouseDragged || theEvent.type == NSLeftMouseUp)
targetView = m_platformWindow->m_forwardWindow->m_qtView; targetView = m_platformWindow->m_forwardWindow->m_qtView;
else 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 // Popups implicitly grap mouse events; forward to the active popup if there is one