Cocoa integration - avoid using dangling pointers

While re-parenting a widget on a mouse down, it's possible that NSWindow
lives longer than QCocoaWindow (because self.grabbingMouse == YES),
on mouse release event self.platformWindow is not nil yet, but is not a valid
pointer already. Bail out early before touching it.

Change-Id: Iea1025a82386d4b9dc21b3cbd3a5b248b2dd3620
Task-number: QTBUG-42059
Reviewed-by: Morten Johan Sørvig <morten.sorvig@theqtcompany.com>
This commit is contained in:
Timur Pocheptsov 2016-02-24 13:45:30 +01:00
parent 9132d1516a
commit aeb169a488
2 changed files with 10 additions and 2 deletions

View File

@ -72,6 +72,7 @@ typedef NSWindow<QNSWindowProtocol> QCocoaNSWindow;
QCocoaWindow *_platformWindow; QCocoaWindow *_platformWindow;
BOOL _grabbingMouse; BOOL _grabbingMouse;
BOOL _releaseOnMouseUp; BOOL _releaseOnMouseUp;
QPointer<QObject> _watcher;
} }
@property (nonatomic, readonly) QCocoaNSWindow *window; @property (nonatomic, readonly) QCocoaNSWindow *window;
@ -321,6 +322,11 @@ 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'
// object in a window helper, preventing use of dangling
// pointers.
QObject sentinel;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -99,6 +99,7 @@ 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;
@ -107,7 +108,7 @@ static bool isMouseEvent(NSEvent *ev)
- (void)handleWindowEvent:(NSEvent *)theEvent - (void)handleWindowEvent:(NSEvent *)theEvent
{ {
QCocoaWindow *pw = self.platformWindow; QCocoaWindow *pw = self.platformWindow;
if (pw && pw->m_forwardWindow) { if (_watcher && 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) {
@ -146,7 +147,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 (pw && pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) { if (_watcher && 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];
@ -162,6 +163,7 @@ static bool isMouseEvent(NSEvent *ev)
- (void)detachFromPlatformWindow - (void)detachFromPlatformWindow
{ {
_platformWindow = 0; _platformWindow = 0;
_watcher.clear();
[self.window.delegate release]; [self.window.delegate release];
self.window.delegate = nil; self.window.delegate = nil;
} }