Cocoa: update OpenGL viewport when nsview moves
authorRichard Moe Gustavsen <richard.gustavsen@digia.com>
Mon, 26 Nov 2012 14:47:02 +0000 (15:47 +0100)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Wed, 28 Nov 2012 20:09:42 +0000 (21:09 +0100)
NSOpenGLContext expexts an -update call whenever the
physical position of the view it draws to changes
on screen. Since we don't get geometry callbacks for such
views when the parent view moves, we need to
register a special notification for that case, and
tell Qt that we need to repaint the QWindow that the
view is backing.

This case does not hit very often, but is evident in
MDI applications where the subwindows are OpenGL
backed QGraphicsView widgets. Dragging the subwindows
around produces garbage inside the windows.

Change-Id: I1b162470b03cca6ed722c6c54080459f2c5e91d9
Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@digia.com>
src/plugins/platforms/cocoa/qcocoaglcontext.mm
src/plugins/platforms/cocoa/qnsview.h
src/plugins/platforms/cocoa/qnsview.mm

index 4e11f55..d9bb9c6 100644 (file)
@@ -113,8 +113,7 @@ void QCocoaGLContext::setActiveWindow(QWindow *window)
     QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
     cocoaWindow->setCurrentContext(this);
 
-    NSView *view = cocoaWindow->contentView();
-    [m_context setView:view];
+    [(QNSView *) cocoaWindow->contentView() setQCocoaGLContext:this];
 }
 
 void QCocoaGLContext::doneCurrent()
index 1ee3697..f93fd86 100644 (file)
@@ -51,6 +51,7 @@
 QT_BEGIN_NAMESPACE
 class QCocoaWindow;
 class QCocoaBackingStore;
+class QCocoaGLContext;
 QT_END_NAMESPACE
 
 @interface QNSView : NSView <NSTextInputClient> {
@@ -66,11 +67,12 @@ QT_END_NAMESPACE
     bool m_sendKeyEvent;
     QStringList *currentCustomDragTypes;
     Qt::KeyboardModifiers currentWheelModifiers;
+    bool m_subscribesForGlobalFrameNotifications;
 }
 
 - (id)init;
 - (id)initWithQWindow:(QWindow *)window platformWindow:(QCocoaWindow *) platformWindow;
-
+- (void)setQCocoaGLContext:(QCocoaGLContext *)context;
 - (void)flushBackingStore:(QCocoaBackingStore *)backingStore region:(const QRegion &)region offset:(QPoint)offset;
 - (void)setMaskRegion:(const QRegion *)region;
 - (void)drawRect:(NSRect)dirtyRect;
index 6811782..d2a4685 100644 (file)
@@ -56,6 +56,7 @@
 #include <QtCore/QDebug>
 #include <private/qguiapplication_p.h>
 #include "qcocoabackingstore.h"
+#include "qcocoaglcontext.h"
 
 #ifdef QT_COCOA_ENABLE_ACCESSIBILITY_INSPECTOR
 #include <accessibilityinspector.h>
@@ -81,7 +82,9 @@ static QTouchDevice *touchDevice = 0;
         m_window = 0;
         m_buttons = Qt::NoButton;
         m_sendKeyEvent = false;
+        m_subscribesForGlobalFrameNotifications = false;
         currentCustomDragTypes = 0;
+
         if (!touchDevice) {
             touchDevice = new QTouchDevice;
             touchDevice->setType(QTouchDevice::TouchPad);
@@ -99,6 +102,12 @@ static QTouchDevice *touchDevice = 0;
     delete[] m_maskData;
     m_maskData = 0;
     m_window = 0;
+    if (m_subscribesForGlobalFrameNotifications) {
+        m_subscribesForGlobalFrameNotifications = false;
+        [[NSNotificationCenter defaultCenter] removeObserver:self
+             name:NSViewGlobalFrameDidChangeNotification
+             object:self];
+}
     [super dealloc];
 }
 
@@ -140,6 +149,28 @@ static QTouchDevice *touchDevice = 0;
     return self;
 }
 
+- (void) setQCocoaGLContext:(QCocoaGLContext *)context
+{
+    [context->nsOpenGLContext() setView:self];
+    if (!m_subscribesForGlobalFrameNotifications) {
+        // NSOpenGLContext expects us to repaint (or update) the view when
+        // it changes position on screen. Since this happens unnoticed for
+        // the view when the parent view moves, we need to register a special
+        // notification that lets us handle this case:
+        m_subscribesForGlobalFrameNotifications = true;
+        [[NSNotificationCenter defaultCenter] addObserver:self
+            selector:@selector(globalFrameChanged:)
+            name:NSViewGlobalFrameDidChangeNotification
+            object:self];
+    }
+}
+
+- (void) globalFrameChanged:(NSNotification*)notification
+{
+    Q_UNUSED(notification);
+    QWindowSystemInterface::handleExposeEvent(m_window, m_window->geometry());
+}
+
 - (void)updateGeometry
 {
     QRect geometry;