summaryrefslogtreecommitdiffstats
path: root/src/widgets/kernel
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@theqtcompany.com>2014-10-20 19:12:23 +0200
committerFrederik Gladhorn <frederik.gladhorn@theqtcompany.com>2014-10-20 19:12:25 +0200
commit3361fcbc28be96262d22fd2b024c85fbcbc61462 (patch)
tree48976f337b3885971dc1976b9a27cec5e7dfa2ec /src/widgets/kernel
parentdc612acdc6577594c8f61345cea2de549d7aae34 (diff)
parent5e342f6f041208d142d97202f61179d7163eb773 (diff)
Merge remote-tracking branch 'origin/5.4' into dev
Diffstat (limited to 'src/widgets/kernel')
-rw-r--r--src/widgets/kernel/qopenglwidget.cpp105
-rw-r--r--src/widgets/kernel/qsizepolicy.h4
-rw-r--r--src/widgets/kernel/qwidget.cpp27
-rw-r--r--src/widgets/kernel/qwidget_p.h2
-rw-r--r--src/widgets/kernel/qwidgetwindow.cpp6
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();
}
};