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 <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;
};

View File

@ -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);

View File

@ -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