From 26d25ab46900d84b44e451c2a0a986bfed94a3f4 Mon Sep 17 00:00:00 2001 From: Fabien Freling Date: Tue, 25 Jan 2011 15:23:34 +0100 Subject: Move the flushing to [view drawRect:rect] Instead of flushing by grabbing the Core Graphics context, we do it directly in the drawRect: method. This approach allows us to call flush() many times and only proceed to flush when the system is ready. Reviewed-by: Richard Moe Gustavsen --- src/gui/kernel/qcocoaview_mac.mm | 114 +++++++++++++++++++----- src/gui/kernel/qwidget.cpp | 1 + src/gui/kernel/qwidget_p.h | 5 +- src/gui/painting/qunifiedtoolbarsurface_mac.cpp | 71 +++------------ src/gui/painting/qunifiedtoolbarsurface_mac_p.h | 7 +- src/gui/painting/qwindowsurface_raster.cpp | 42 +++++---- src/gui/painting/qwindowsurface_raster_p.h | 11 +++ 7 files changed, 153 insertions(+), 98 deletions(-) diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm index 6059946..e50c401 100644 --- a/src/gui/kernel/qcocoaview_mac.mm +++ b/src/gui/kernel/qcocoaview_mac.mm @@ -52,6 +52,8 @@ #include #include #include +#include +#include #include #include @@ -530,8 +532,86 @@ static int qCocoaViewCount = 0; if (!qwidget) return; + // Getting context. + CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; + qt_mac_retain_graphics_context(context); + // We use a different graphics system. - if (QApplicationPrivate::graphicsSystem() != 0 && !qwidgetprivate->isInUnifiedToolbar) { + if (QApplicationPrivate::graphicsSystem() != 0) { + + // Raster engine. + if (QApplicationPrivate::graphics_system_name == QLatin1String("raster")) { + + if (!qwidgetprivate->isInUnifiedToolbar) { + + // Qt handles the painting occuring inside the window. + // Cocoa also keeps track of all widgets as NSView and therefore might + // ask for a repainting of a widget even if Qt is already taking care of it. + // + // The only valid reason for Cocoa to call drawRect: is for window manipulation + // (ie. resize, ...). + // + // Qt will then forward the update to the children. + if (!qwidget->isWindow()) { + qt_mac_release_graphics_context(context); + return; + } + + QRasterWindowSurface *winSurface = dynamic_cast(qwidget->windowSurface()); + if (!winSurface || !winSurface->needsFlush) { + qt_mac_release_graphics_context(context); + return; + } + + // Clip to region. + const QVector &rects = winSurface->regionToFlush.rects(); + for (int i = 0; i < rects.size(); ++i) { + const QRect &rect = rects.at(i); + CGContextAddRect(context, CGRectMake(rect.x(), rect.y(), rect.width(), rect.height())); + } + CGContextClip(context); + + QRect r = winSurface->regionToFlush.boundingRect(); + const CGRect area = CGRectMake(r.x(), r.y(), r.width(), r.height()); + + qt_mac_draw_image(context, winSurface->imageContext(), area, area); + + winSurface->needsFlush = false; + winSurface->regionToFlush = QRegion(); + + } else { + + QUnifiedToolbarSurface *unifiedSurface = dynamic_cast(qwidgetprivate->unifiedSurface); + if (!unifiedSurface || !qwidgetprivate->flushRequested) { + qt_mac_release_graphics_context(context); + return; + } + + // We render the content of the toolbar in the surface. + unifiedSurface->updateToolbarOffset(qwidget); + QRect beginPaintRect(qwidgetprivate->toolbar_offset.x(), qwidgetprivate->toolbar_offset.y(), qwidget->geometry().width(), qwidget->geometry().height()); + QRegion beginPaintRegion(beginPaintRect); + + unifiedSurface->beginPaint(beginPaintRegion); + qwidget->render(unifiedSurface->paintDevice(), qwidgetprivate->toolbar_offset, QRegion(), QWidget::DrawChildren); + + int areaX = qwidgetprivate->toolbar_offset.x(); + int areaY = qwidgetprivate->toolbar_offset.y(); + int areaWidth = qwidget->geometry().width(); + int areaHeight = qwidget->geometry().height(); + const CGRect area = CGRectMake(areaX, areaY, areaWidth, areaHeight); + const CGRect drawingArea = CGRectMake(0, 0, areaWidth, areaHeight); + + qt_mac_draw_image(context, unifiedSurface->imageContext(), area, drawingArea); + + qwidgetprivate->flushRequested = false; + + } + + CGContextFlush(context); + qt_mac_release_graphics_context(context); + return; + } // Qt handles the painting occuring inside the window. // Cocoa also keeps track of all widgets as NSView and therefore might @@ -553,19 +633,8 @@ static int qCocoaViewCount = 0; return; } - CGContextRef cg = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; - CGContextRetain(cg); - qwidgetprivate->hd = cg; - - // We steal the CGContext for flushing in the unified toolbar with the raster engine. - if (QApplicationPrivate::graphicsSystem() != 0 && qwidgetprivate->isInUnifiedToolbar) { - qwidgetprivate->cgContext = cg; - qwidgetprivate->hasOwnContext = true; - qwidgetprivate->unifiedSurface->flush(qwidget, qwidgetprivate->ut_rg, qwidgetprivate->ut_pt); - return; - } - - CGContextSaveGState(cg); + // Native engine. + qwidgetprivate->hd = context; if (qwidget->isVisible() && qwidget->updatesEnabled()) { //process the actual paint event. if (qwidget->testAttribute(Qt::WA_WState_InPaintEvent)) @@ -600,18 +669,18 @@ static int qCocoaViewCount = 0; engine->setSystemClip(qrgn); if (qwidgetprivate->extra && qwidgetprivate->extra->hasMask) { CGRect widgetRect = CGRectMake(0, 0, qwidget->width(), qwidget->height()); - CGContextTranslateCTM (cg, 0, widgetRect.size.height); - CGContextScaleCTM(cg, 1, -1); + CGContextTranslateCTM (context, 0, widgetRect.size.height); + CGContextScaleCTM(context, 1, -1); if (qwidget->isWindow()) - CGContextClearRect(cg, widgetRect); - CGContextClipToMask(cg, widgetRect, qwidgetprivate->extra->imageMask); - CGContextScaleCTM(cg, 1, -1); - CGContextTranslateCTM (cg, 0, -widgetRect.size.height); + CGContextClearRect(context, widgetRect); + CGContextClipToMask(context, widgetRect, qwidgetprivate->extra->imageMask); + CGContextScaleCTM(context, 1, -1); + CGContextTranslateCTM (context, 0, -widgetRect.size.height); } if (qwidget->isWindow() && !qwidgetprivate->isOpaque && !qwidget->testAttribute(Qt::WA_MacBrushedMetal)) { - CGContextClearRect(cg, NSRectToCGRect(aRect)); + CGContextClearRect(context, NSRectToCGRect(aRect)); } // Check for alien widgets, use qwidgetPrivate->drawWidget() to draw the widget if this @@ -653,8 +722,7 @@ static int qCocoaViewCount = 0; " widget outside of the PaintEvent"); } qwidgetprivate->hd = 0; - CGContextRestoreGState(cg); - CGContextRelease(cg); + qt_mac_release_graphics_context(context); } - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 16f64ff..056aea6 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -324,6 +324,7 @@ QWidgetPrivate::QWidgetPrivate(int version) hasOwnContext = false; isInUnifiedToolbar = false; unifiedSurface = 0; + askedForFlush = false; #endif // QT_MAC_USE_COCOA #ifdef QWIDGET_EXTRA_DEBUG static int count = 0; diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index 6b85391..f5a965c 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -852,13 +852,16 @@ public: // Do we need to change the methods? bool changeMethods; bool hasOwnContext; + + // Unified toolbar variables CGContextRef cgContext; QRegion ut_rg; QPoint ut_pt; bool isInUnifiedToolbar; QWindowSurface *unifiedSurface; QPoint toolbar_offset; -#endif + bool askedForFlush; +#endif // QT_MAC_USE_COCOA void determineWindowClass(); void transferChildren(); bool qt_mac_dnd_event(uint, DragRef); diff --git a/src/gui/painting/qunifiedtoolbarsurface_mac.cpp b/src/gui/painting/qunifiedtoolbarsurface_mac.cpp index 02ba8db..38dc632 100644 --- a/src/gui/painting/qunifiedtoolbarsurface_mac.cpp +++ b/src/gui/painting/qunifiedtoolbarsurface_mac.cpp @@ -92,6 +92,11 @@ void QUnifiedToolbarSurface::recursiveRedirect(QObject *object, const QPoint &of } } +void QUnifiedToolbarSurface::updateRedirection(QWidget *widget) +{ + recursiveRedirect(widget, widget->d_func()->toolbar_offset); +} + void QUnifiedToolbarSurface::insertToolbar(QWidget *toolbar, const QPoint &offset) { setGeometry(QRect(QPoint(0, 0), QSize(offset.x() + toolbar->width(), 100))); // FIXME @@ -130,67 +135,13 @@ void QUnifiedToolbarSurface::updateToolbarOffset(QWidget *widget) void QUnifiedToolbarSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &offset) { Q_D(QUnifiedToolbarSurface); - - QRegion flushingRegion(widget->rect()); - - if (!d->image || rgn.rectCount() == 0) { - return; - } - Q_UNUSED(offset); - // Get a context for the widget. - CGContextRef context; - if (!(widget->d_func()->hasOwnContext)) { - widget->d_func()->ut_rg = rgn; - widget->d_func()->ut_pt = offset; - qt_mac_display(widget); + if (!d->image || rgn.rectCount() == 0) return; - } else { - // We render the content of the toolbar in the surface. - updateToolbarOffset(widget); - QRect beginPaintRect(widget->d_func()->toolbar_offset.x(), widget->d_func()->toolbar_offset.y(), widget->geometry().width(), widget->geometry().height()); - QRegion beginPaintRegion(beginPaintRect); - - context = widget->d_func()->cgContext; - beginPaint(beginPaintRegion); - widget->render(widget->d_func()->unifiedSurface->paintDevice(), widget->d_func()->toolbar_offset, QRegion(), QWidget::DrawChildren); - } - - CGContextSaveGState(context); - - int areaX = widget->d_func()->toolbar_offset.x(); - int areaY = widget->d_func()->toolbar_offset.y(); - int areaWidth = widget->geometry().width(); - int areaHeight = widget->geometry().height(); - const CGRect area = CGRectMake(areaX, areaY, areaWidth, areaHeight); - // Clip to region. - const QVector &rects = flushingRegion.rects(); - for (int i = 0; i < rects.size(); ++i) { - const QRect &rect = rects.at(i); - CGContextAddRect(context, CGRectMake(rect.x(), rect.y(), rect.width(), rect.height())); - } - CGContextAddRect(context, area); - CGContextClip(context); - - - CGImageRef image = CGBitmapContextCreateImage(d->image->cg); - CGImageRef subImage = CGImageCreateWithImageInRect(image, area); - - const CGRect drawingArea = CGRectMake(0, 0, areaWidth, areaHeight); - qt_mac_drawCGImage(context, &drawingArea, subImage); - - CGImageRelease(subImage); - CGImageRelease(image); - - CGContextFlush(context); - - // Restore context. - CGContextRestoreGState(context); - CGContextRelease(context); - widget->d_func()->cgContext = 0; - widget->d_func()->hasOwnContext = false; + widget->d_func()->askedForFlush = true; + qt_mac_setneedsdisplay(widget); } void QUnifiedToolbarSurface::prepareBuffer(QImage::Format format, QWidget *widget) @@ -254,6 +205,12 @@ void QUnifiedToolbarSurface::prepareBuffer(QImage::Format format, QWidget *widge delete oldImage; } +CGContextRef QUnifiedToolbarSurface::imageContext() +{ + Q_D(QUnifiedToolbarSurface); + return d->image->cg; +} + QT_END_NAMESPACE #endif // QT_MAC_USE_COCOA diff --git a/src/gui/painting/qunifiedtoolbarsurface_mac_p.h b/src/gui/painting/qunifiedtoolbarsurface_mac_p.h index 3bc0404..6e40a17 100644 --- a/src/gui/painting/qunifiedtoolbarsurface_mac_p.h +++ b/src/gui/painting/qunifiedtoolbarsurface_mac_p.h @@ -82,10 +82,13 @@ public: void setGeometry(const QRect &rect); void beginPaint(const QRegion &rgn); void insertToolbar(QWidget *toolbar, const QPoint &offset); + void updateRedirection(QWidget *widget); + void updateToolbarOffset(QWidget *widget); -private: QPaintDevice *paintDevice(); - void updateToolbarOffset(QWidget *widget); + CGContextRef imageContext(); + +private: void prepareBuffer(QImage::Format format, QWidget *widget); void recursiveRedirect(QObject *widget, const QPoint &offset); diff --git a/src/gui/painting/qwindowsurface_raster.cpp b/src/gui/painting/qwindowsurface_raster.cpp index 2b4e125..92e9425 100644 --- a/src/gui/painting/qwindowsurface_raster.cpp +++ b/src/gui/painting/qwindowsurface_raster.cpp @@ -98,6 +98,11 @@ QRasterWindowSurface::QRasterWindowSurface(QWidget *window, bool setDefaultSurfa d_ptr->image = 0; d_ptr->inSetGeometry = false; setStaticContentsSupport(true); + +#ifdef QT_MAC_USE_COCOA + needsFlush = false; + regionToFlush = QRegion(); +#endif // QT_MAC_USE_COCOA } @@ -251,13 +256,23 @@ void QRasterWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoi #ifdef Q_WS_MAC + Q_UNUSED(offset); + // This is mainly done for native components like native "open file" dialog. if (widget->testAttribute(Qt::WA_DontShowOnScreen)) { return; } #ifdef QT_MAC_USE_COCOA + this->needsFlush = true; + this->regionToFlush += rgn; + + // The actual flushing will be processed in [view drawRect:rect] + qt_mac_setneedsdisplay(widget); + // Unified toolbar hack. + // We issue a flush call for each QToolBar so they get repainted right after + // the main window. QMainWindow* mWindow = qobject_cast(widget->window()); if (mWindow) { QMainWindowLayout *mLayout = qobject_cast(mWindow->layout()); @@ -267,24 +282,17 @@ void QRasterWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoi QToolBar* toolbar = toolbarList.at(i); if (mLayout->toolBarArea(toolbar) == Qt::TopToolBarArea) { QWidget* tbWidget = (QWidget*) toolbar; - if (tbWidget->d_func()->unifiedSurface) { + if (tbWidget->d_func()->unifiedSurface) tbWidget->d_func()->unifiedSurface->flush(tbWidget, rgn, offset); - } } } } -#endif // QT_MAC_USE_COCOA - - Q_UNUSED(offset); +#else // Get a context for the widget. -#ifndef QT_MAC_USE_COCOA CGContextRef context; CGrafPtr port = GetWindowPort(qt_mac_window_for(widget)); QDBeginCGContext(port, &context); -#else - extern CGContextRef qt_mac_graphicsContextFor(QWidget *); - CGContextRef context = qt_mac_graphicsContextFor(widget); -#endif + CGContextRetain(context); CGContextSaveGState(context); @@ -310,16 +318,12 @@ void QRasterWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoi CGImageRelease(subImage); CGImageRelease(image); -#ifndef QT_MAC_USE_COCOA QDEndCGContext(port, &context); -#else - CGContextFlush(context); -#endif // Restore context. CGContextRestoreGState(context); CGContextRelease(context); - +#endif // QT_MAC_USE_COCOA #endif // Q_WS_MAC @@ -461,4 +465,12 @@ void QRasterWindowSurface::prepareBuffer(QImage::Format format, QWidget *widget) delete oldImage; } +#ifdef QT_MAC_USE_COCOA +CGContextRef QRasterWindowSurface::imageContext() +{ + Q_D(QRasterWindowSurface); + return d->image->cg; +} +#endif // QT_MAC_USE_COCOA + QT_END_NAMESPACE diff --git a/src/gui/painting/qwindowsurface_raster_p.h b/src/gui/painting/qwindowsurface_raster_p.h index a7c3b9f..4674fa0 100644 --- a/src/gui/painting/qwindowsurface_raster_p.h +++ b/src/gui/painting/qwindowsurface_raster_p.h @@ -56,6 +56,10 @@ #include #include "private/qwindowsurface_p.h" +#ifdef QT_MAC_USE_COCOA +# include +#endif // QT_MAC_USE_COCOA + QT_BEGIN_NAMESPACE #ifdef Q_WS_WIN @@ -106,6 +110,13 @@ public: void setGeometry(const QRect &rect); bool scroll(const QRegion &area, int dx, int dy); +#ifdef QT_MAC_USE_COCOA + CGContextRef imageContext(); + + bool needsFlush; + QRegion regionToFlush; +#endif // QT_MAC_USE_COCOA + private: void prepareBuffer(QImage::Format format, QWidget *widget); Q_DECLARE_PRIVATE(QRasterWindowSurface) -- cgit v0.12