diff options
author | Frederik Gladhorn <frederik.gladhorn@theqtcompany.com> | 2014-10-20 19:12:23 +0200 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@theqtcompany.com> | 2014-10-20 19:12:25 +0200 |
commit | 3361fcbc28be96262d22fd2b024c85fbcbc61462 (patch) | |
tree | 48976f337b3885971dc1976b9a27cec5e7dfa2ec /src/widgets/kernel | |
parent | dc612acdc6577594c8f61345cea2de549d7aae34 (diff) | |
parent | 5e342f6f041208d142d97202f61179d7163eb773 (diff) |
Merge remote-tracking branch 'origin/5.4' into dev
Change-Id: If7e51514ed6832750e3ad967e4d322ccf920d2bb
Diffstat (limited to 'src/widgets/kernel')
-rw-r--r-- | src/widgets/kernel/qopenglwidget.cpp | 105 | ||||
-rw-r--r-- | src/widgets/kernel/qsizepolicy.h | 4 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget.cpp | 27 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget_p.h | 2 | ||||
-rw-r--r-- | src/widgets/kernel/qwidgetwindow.cpp | 6 |
5 files changed, 121 insertions, 23 deletions
diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp index 543f59d7d1..8a4e0c8ffd 100644 --- a/src/widgets/kernel/qopenglwidget.cpp +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -45,6 +45,7 @@ #include <QtGui/private/qguiapplication_p.h> #include <QtGui/private/qopenglextensions_p.h> #include <QtGui/private/qfont_p.h> +#include <QtGui/private/qopenglpaintdevice_p.h> #include <QtWidgets/private/qwidget_p.h> QT_BEGIN_NAMESPACE @@ -239,6 +240,28 @@ QT_BEGIN_NAMESPACE \note Avoid calling winId() on a QOpenGLWidget. This function triggers the creation of a native window, resulting in reduced performance and possibly rendering glitches. + \section1 Differences to QGLWidget + + Besides the main conceptual difference of being backed by a framebuffer object, there + are a number of smaller, internal differences between QOpenGLWidget and the older + QGLWidget: + + \list + + \li OpenGL state when invoking paintGL(). QOpenGLWidget sets up the viewport via + glViewport(). It does not perform any clearing. + + \li Clearing when starting to paint via QPainter. Unlike regular widgets, QGLWidget + defaulted to a value of \c true for + \l{QWidget::autoFillBackground()}{autoFillBackground}. It then performed clearing to the + palette's background color every time QPainter::begin() was used. QOpenGLWidget does not + follow this: \l{QWidget::autoFillBackground()}{autoFillBackground} defaults to false, + like for any other widget. The only exception is when being used as a viewport for other + widgets like QGraphicsView. In such a case autoFillBackground will be automatically set + to true to ensure compatibility with QGLWidget-based viewports. + + \endlist + \section1 Multisampling To enable multisampling, set the number of requested samples on the @@ -432,16 +455,26 @@ QT_BEGIN_NAMESPACE due to resizing the widget. */ -class QOpenGLWidgetPaintDevice : public QOpenGLPaintDevice +class QOpenGLWidgetPaintDevicePrivate : public QOpenGLPaintDevicePrivate { public: - QOpenGLWidgetPaintDevice(QOpenGLWidget *widget) : w(widget) { } - void ensureActiveTarget() Q_DECL_OVERRIDE; + QOpenGLWidgetPaintDevicePrivate(QOpenGLWidget *widget) + : QOpenGLPaintDevicePrivate(QSize()), + w(widget) { } + + void beginPaint() Q_DECL_OVERRIDE; -private: QOpenGLWidget *w; }; +class QOpenGLWidgetPaintDevice : public QOpenGLPaintDevice +{ +public: + QOpenGLWidgetPaintDevice(QOpenGLWidget *widget) + : QOpenGLPaintDevice(new QOpenGLWidgetPaintDevicePrivate(widget)) { } + void ensureActiveTarget() Q_DECL_OVERRIDE; +}; + class QOpenGLWidgetPrivate : public QWidgetPrivate { Q_DECLARE_PUBLIC(QOpenGLWidget) @@ -454,7 +487,8 @@ public: initialized(false), fakeHidden(false), paintDevice(0), - inBackingStorePaint(false) + inBackingStorePaint(false), + flushPending(false) { requestedFormat = QSurfaceFormat::defaultFormat(); } @@ -478,6 +512,7 @@ public: void endBackingStorePainting() Q_DECL_OVERRIDE { inBackingStorePaint = false; } void beginCompose() Q_DECL_OVERRIDE; void endCompose() Q_DECL_OVERRIDE; + void initializeViewportFramebuffer() Q_DECL_OVERRIDE; void resizeViewportFramebuffer() Q_DECL_OVERRIDE; void resolveSamples() Q_DECL_OVERRIDE; @@ -490,22 +525,54 @@ public: QOpenGLPaintDevice *paintDevice; bool inBackingStorePaint; QSurfaceFormat requestedFormat; + bool flushPending; }; +void QOpenGLWidgetPaintDevicePrivate::beginPaint() +{ + // NB! autoFillBackground is and must be false by default. Otherwise we would clear on + // every QPainter begin() which is not desirable. This is only for legacy use cases, + // like using QOpenGLWidget as the viewport of a graphics view, that expect clearing + // with the palette's background color. + if (w->autoFillBackground()) { + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + if (w->testAttribute(Qt::WA_TranslucentBackground)) { + f->glClearColor(0, 0, 0, 0); + } else { + QColor c = w->palette().brush(w->backgroundRole()).color(); + float alpha = c.alphaF(); + f->glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha); + } + f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + } +} + void QOpenGLWidgetPaintDevice::ensureActiveTarget() { - QOpenGLWidgetPrivate *d = static_cast<QOpenGLWidgetPrivate *>(QWidgetPrivate::get(w)); - if (!d->initialized) + QOpenGLWidgetPaintDevicePrivate *d = static_cast<QOpenGLWidgetPaintDevicePrivate *>(d_ptr.data()); + QOpenGLWidgetPrivate *wd = static_cast<QOpenGLWidgetPrivate *>(QWidgetPrivate::get(d->w)); + if (!wd->initialized) return; - if (QOpenGLContext::currentContext() != d->context) - w->makeCurrent(); + if (QOpenGLContext::currentContext() != wd->context) + d->w->makeCurrent(); else - d->fbo->bind(); + wd->fbo->bind(); + + // When used as a viewport, drawing is done via opening a QPainter on the widget + // without going through paintEvent(). We will have to make sure a glFlush() is done + // before the texture is accessed also in this case. + wd->flushPending = true; } GLuint QOpenGLWidgetPrivate::textureId() const { + Q_Q(const QOpenGLWidget); + if (!q->isWindow() && q->internalWinId()) { + qWarning() << "QOpenGLWidget cannot be used as a native child widget." + << "Consider setting Qt::AA_DontCreateNativeWidgetAncestors and Siblings."; + return 0; + } return resolvedFbo ? resolvedFbo->texture() : (fbo ? fbo->texture() : 0); } @@ -566,6 +633,11 @@ void QOpenGLWidgetPrivate::recreateFbo() void QOpenGLWidgetPrivate::beginCompose() { Q_Q(QOpenGLWidget); + if (flushPending) { + flushPending = false; + q->makeCurrent(); + context->functions()->glFlush(); + } emit q->aboutToCompose(); } @@ -647,9 +719,10 @@ void QOpenGLWidgetPrivate::invokeUserPaint() { Q_Q(QOpenGLWidget); QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); - f->glViewport(0, 0, q->width() * q->devicePixelRatio(), q->height() * q->devicePixelRatio()); + f->glViewport(0, 0, q->width() * q->devicePixelRatio(), q->height() * q->devicePixelRatio()); q->paintGL(); + f->glFlush(); } void QOpenGLWidgetPrivate::render() @@ -661,7 +734,6 @@ void QOpenGLWidgetPrivate::render() q->makeCurrent(); invokeUserPaint(); - context->functions()->glFlush(); } extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha); @@ -680,6 +752,14 @@ QImage QOpenGLWidgetPrivate::grabFramebuffer() return res; } +void QOpenGLWidgetPrivate::initializeViewportFramebuffer() +{ + Q_Q(QOpenGLWidget); + // Legacy behavior for compatibility with QGLWidget when used as a graphics view + // viewport: enable clearing on each painter begin. + q->setAutoFillBackground(true); +} + void QOpenGLWidgetPrivate::resizeViewportFramebuffer() { Q_Q(QOpenGLWidget); @@ -923,7 +1003,6 @@ void QOpenGLWidget::resizeEvent(QResizeEvent *e) d->recreateFbo(); resizeGL(width(), height()); d->invokeUserPaint(); - d->context->functions()->glFlush(); d->resolveSamples(); } diff --git a/src/widgets/kernel/qsizepolicy.h b/src/widgets/kernel/qsizepolicy.h index 9730ec1206..41adf5c58a 100644 --- a/src/widgets/kernel/qsizepolicy.h +++ b/src/widgets/kernel/qsizepolicy.h @@ -150,6 +150,10 @@ private: quint32 data; }; }; +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) +// Can't add in Qt 5, as QList<QSizePolicy> would be BiC: +Q_DECLARE_TYPEINFO(QSizePolicy, Q_PRIMITIVE_TYPE); +#endif Q_DECLARE_OPERATORS_FOR_FLAGS(QSizePolicy::ControlTypes) diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 00cf39bdbf..af1745d845 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -6543,10 +6543,15 @@ void QWidget::clearFocus() QWidget *w = this; while (w) { + // Just like setFocus(), we update (clear) the focus_child of our parents if (w->d_func()->focus_child == this) w->d_func()->focus_child = 0; w = w->parentWidget(); } + // Since focus_child is the basis for the top level QWidgetWindow's focusObject() + // we need to report this change to the rest of Qt, but we match setFocus() and + // do it at the end of the function. + #ifndef QT_NO_GRAPHICSVIEW QWExtra *topData = d_func()->extra; if (topData && topData->proxyWidget) @@ -6567,11 +6572,15 @@ void QWidget::clearFocus() QAccessible::updateAccessibility(&event); #endif } + } - if (QTLWExtra *extra = window()->d_func()->maybeTopData()) { - if (extra->window) - emit extra->window->focusObjectChanged(extra->window->focusObject()); - } + // Since we've unconditionally cleared the focus_child of our parents, we need + // to report this to the rest of Qt. Note that the focus_child is not the same + // thing as the application's focusWidget, which is why this piece of code is + // not inside the hasFocus() block above. + if (QTLWExtra *extra = window()->d_func()->maybeTopData()) { + if (extra->window) + emit extra->window->focusObjectChanged(extra->window->focusObject()); } } @@ -9686,7 +9695,8 @@ void QWidget::setInputMethodHints(Qt::InputMethodHints hints) if (d->imHints == hints) return; d->imHints = hints; - qApp->inputMethod()->update(Qt::ImHints); + if (this == qApp->focusObject()) + qApp->inputMethod()->update(Qt::ImHints); #endif //QT_NO_IM } @@ -11029,7 +11039,7 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) d->createTLSysExtra(); #ifndef QT_NO_IM QWidget *focusWidget = d->effectiveFocusWidget(); - if (on && !internalWinId() && hasFocus() + if (on && !internalWinId() && this == qApp->focusObject() && focusWidget->testAttribute(Qt::WA_InputMethodEnabled)) { qApp->inputMethod()->commit(); qApp->inputMethod()->update(Qt::ImEnabled); @@ -11038,7 +11048,7 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) parentWidget()->d_func()->enforceNativeChildren(); if (on && !internalWinId() && testAttribute(Qt::WA_WState_Created)) d->createWinId(); - if (isEnabled() && focusWidget->isEnabled() + if (isEnabled() && focusWidget->isEnabled() && this == qApp->focusObject() && focusWidget->testAttribute(Qt::WA_InputMethodEnabled)) { qApp->inputMethod()->update(Qt::ImEnabled); } @@ -11564,7 +11574,8 @@ void QWidget::setShortcutAutoRepeat(int id, bool enable) void QWidget::updateMicroFocus() { // updating everything since this is currently called for any kind of state change - qApp->inputMethod()->update(Qt::ImQueryAll); + if (this == qApp->focusObject()) + qApp->inputMethod()->update(Qt::ImQueryAll); } /*! diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index 75a60fe3c4..d5a91f18d6 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -641,6 +641,8 @@ public: } } static void sendComposeStatus(QWidget *w, bool end); + // Called on setViewport(). + virtual void initializeViewportFramebuffer() { } // When using a QOpenGLWidget as viewport with QAbstractScrollArea, resize events are // filtered away from the widget. This is fine for QGLWidget but bad for QOpenGLWidget // since the fbo must be resized. We need an alternative way to notify. diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index cd57c1611e..d40fc84d77 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -73,8 +73,10 @@ public: void clearFocusObject() { - if (QApplicationPrivate::focus_widget) - QApplicationPrivate::focus_widget->clearFocus(); + Q_Q(QWidgetWindow); + QWidget *widget = q->widget(); + if (widget && widget->focusWidget()) + widget->focusWidget()->clearFocus(); } }; |