diff options
author | Oswald Buddenhagen <oswald.buddenhagen@digia.com> | 2014-02-19 10:06:25 +0100 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@digia.com> | 2014-02-19 10:06:25 +0100 |
commit | 30fd22b9574def54726e7b193127cc0c901c1b4c (patch) | |
tree | 96dfc923044db0515064ba39d052d9ed577e3e40 /src/widgets/kernel | |
parent | d7b0581c1c2ef60c08d238dae39298af6904918f (diff) | |
parent | 6aa09bbce59828d028f6d1e81d2bfc6ba537aae1 (diff) |
Merge remote-tracking branch 'origin/dev' into stable
Change-Id: Ice524edcc51373509f0023ae7f7c2963f4602f88
Diffstat (limited to 'src/widgets/kernel')
-rw-r--r-- | src/widgets/kernel/kernel.pri | 5 | ||||
-rw-r--r-- | src/widgets/kernel/qapplication.cpp | 124 | ||||
-rw-r--r-- | src/widgets/kernel/qapplication.h | 4 | ||||
-rw-r--r-- | src/widgets/kernel/qapplication_p.h | 7 | ||||
-rw-r--r-- | src/widgets/kernel/qapplication_qpa.cpp | 4 | ||||
-rw-r--r-- | src/widgets/kernel/qformlayout.h | 2 | ||||
-rw-r--r-- | src/widgets/kernel/qopenglwidget.cpp | 183 | ||||
-rw-r--r-- | src/widgets/kernel/qopenglwidget_p.h | 135 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget.cpp | 114 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget_p.h | 33 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget_qpa.cpp | 5 | ||||
-rw-r--r-- | src/widgets/kernel/qwidgetbackingstore.cpp | 138 | ||||
-rw-r--r-- | src/widgets/kernel/qwidgetbackingstore_p.h | 27 | ||||
-rw-r--r-- | src/widgets/kernel/qwidgetwindow.cpp | 59 | ||||
-rw-r--r-- | src/widgets/kernel/qwidgetwindow_qpa_p.h | 1 | ||||
-rw-r--r-- | src/widgets/kernel/win.pri | 2 |
16 files changed, 731 insertions, 112 deletions
diff --git a/src/widgets/kernel/kernel.pri b/src/widgets/kernel/kernel.pri index 444b9b687f..857fe4ac91 100644 --- a/src/widgets/kernel/kernel.pri +++ b/src/widgets/kernel/kernel.pri @@ -79,3 +79,8 @@ wince*: { SOURCES += \ kernel/qwidgetsfunctions_wince.cpp } + +contains(QT_CONFIG, opengl) { + HEADERS += kernel/qopenglwidget_p.h + SOURCES += kernel/qopenglwidget.cpp +} diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index c9d6593662..9bc1576dc6 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -377,7 +377,6 @@ QPalette *QApplicationPrivate::set_pal = 0; // default palette set by pro QFont *QApplicationPrivate::sys_font = 0; // default system font QFont *QApplicationPrivate::set_font = 0; // default font set by programmer -QIcon *QApplicationPrivate::app_icon = 0; QWidget *QApplicationPrivate::main_widget = 0; // main application widget QWidget *QApplicationPrivate::focus_widget = 0; // has keyboard input focus QWidget *QApplicationPrivate::hidden_focus_widget = 0; // will get keyboard input focus after show() @@ -446,7 +445,8 @@ void QApplicationPrivate::process_cmdline() continue; } QByteArray arg = argv[i]; - arg = arg; + if (arg.startsWith("--")) + arg.remove(0, 1); QString s; if (arg == "-qdevel" || arg == "-qdebug") { // obsolete argument @@ -729,8 +729,6 @@ QApplication::~QApplication() delete QApplicationPrivate::app_style; QApplicationPrivate::app_style = 0; - delete QApplicationPrivate::app_icon; - QApplicationPrivate::app_icon = 0; #ifndef QT_NO_DRAGANDDROP if (qt_is_gui_used) @@ -1560,6 +1558,7 @@ QString QApplicationPrivate::desktopStyleKey() return QString(); } +#if QT_VERSION < 0x060000 // remove these forwarders in Qt 6 /*! \property QApplication::windowIcon \brief the default window icon @@ -1568,23 +1567,32 @@ QString QApplicationPrivate::desktopStyleKey() */ QIcon QApplication::windowIcon() { - return QApplicationPrivate::app_icon ? *QApplicationPrivate::app_icon : QIcon(); + return QGuiApplication::windowIcon(); } void QApplication::setWindowIcon(const QIcon &icon) { - if (!QApplicationPrivate::app_icon) - QApplicationPrivate::app_icon = new QIcon(); - *QApplicationPrivate::app_icon = icon; - if (QApplicationPrivate::is_app_running && !QApplicationPrivate::is_app_closing) { - QEvent e(QEvent::ApplicationWindowIconChange); - QWidgetList all = QApplication::allWidgets(); - for (QWidgetList::ConstIterator it = all.constBegin(); it != all.constEnd(); ++it) { - QWidget *w = *it; - if (w->isWindow()) - sendEvent(w, &e); - } + QGuiApplication::setWindowIcon(icon); +} +#endif + +void QApplicationPrivate::notifyWindowIconChanged() +{ + QEvent ev(QEvent::ApplicationWindowIconChange); + const QWidgetList list = QApplication::topLevelWidgets(); + QWindowList windowList = QGuiApplication::topLevelWindows(); + + // send to all top-level QWidgets + for (int i = 0; i < list.size(); ++i) { + QWidget *w = list.at(i); + windowList.removeOne(w->windowHandle()); + QCoreApplication::sendEvent(w, &ev); } + + // in case there are any plain QWindows in this QApplication-using + // application, also send the notification to them + for (int i = 0; i < windowList.size(); ++i) + QCoreApplication::sendEvent(windowList.at(i), &ev); } /*! @@ -1725,6 +1733,41 @@ QFontMetrics QApplication::fontMetrics() return desktop()->fontMetrics(); } +bool QApplicationPrivate::tryCloseAllWidgetWindows(QWindowList *processedWindows) +{ + Q_ASSERT(processedWindows); + while (QWidget *w = QApplication::activeModalWidget()) { + if (!w->isVisible() || w->data->is_closing) + break; + QWindow *window = w->windowHandle(); + if (!w->close()) // Qt::WA_DeleteOnClose may cause deletion. + return false; + if (window) + processedWindows->append(window); + } + + QWidgetList list = QApplication::topLevelWidgets(); + for (int i = 0; i < list.size(); ++i) { + QWidget *w = list.at(i); + if (w->isVisible() && w->windowType() != Qt::Desktop && !w->data->is_closing) { + QWindow *window = w->windowHandle(); + if (!w->close()) // Qt::WA_DeleteOnClose may cause deletion. + return false; + if (window) + processedWindows->append(window); + list = QApplication::topLevelWidgets(); + i = -1; + } + } + return true; +} + +bool QApplicationPrivate::tryCloseAllWindows() +{ + QWindowList processedWindows; + return QApplicationPrivate::tryCloseAllWidgetWindows(&processedWindows) + && QGuiApplicationPrivate::tryCloseRemainingWindows(processedWindows); +} /*! Closes all top-level windows. @@ -1746,24 +1789,8 @@ QFontMetrics QApplication::fontMetrics() */ void QApplication::closeAllWindows() { - bool did_close = true; - QWidget *w; - while ((w = activeModalWidget()) && did_close) { - if (!w->isVisible() || w->data->is_closing) - break; - did_close = w->close(); - } - QWidgetList list = QApplication::topLevelWidgets(); - for (int i = 0; did_close && i < list.size(); ++i) { - w = list.at(i); - if (w->isVisible() - && w->windowType() != Qt::Desktop - && !w->data->is_closing) { - did_close = w->close(); - list = QApplication::topLevelWidgets(); - i = -1; - } - } + QWindowList processedWindows; + QApplicationPrivate::tryCloseAllWidgetWindows(&processedWindows); } /*! @@ -2611,7 +2638,7 @@ QDesktopWidget *QApplication::desktop() void QApplication::setStartDragTime(int ms) { - Q_UNUSED(ms) + QGuiApplication::styleHints()->setStartDragTime(ms); } /*! @@ -2644,7 +2671,7 @@ int QApplication::startDragTime() void QApplication::setStartDragDistance(int l) { - Q_UNUSED(l); + QGuiApplication::styleHints()->setStartDragDistance(l); } /*! @@ -2716,9 +2743,11 @@ bool QApplicationPrivate::shouldQuit() QWindowList processedWindows; for (int i = 0; i < list.size(); ++i) { QWidget *w = list.at(i); - processedWindows.push_back(w->windowHandle()); - if (w->isVisible() && !w->parentWidget() && w->testAttribute(Qt::WA_QuitOnClose)) - return false; + if (QWindow *window = w->windowHandle()) { // Menus, popup widgets may not have a QWindow + processedWindows.push_back(window); + if (w->isVisible() && !w->parentWidget() && w->testAttribute(Qt::WA_QuitOnClose)) + return false; + } } return QGuiApplicationPrivate::shouldQuitInternal(processedWindows); } @@ -2767,6 +2796,13 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QApplicationPrivate::mouse_buttons |= me->button(); break; } + case QEvent::MouseButtonDblClick: + { + QMouseEvent *me = static_cast<QMouseEvent*>(e); + QApplicationPrivate::modifier_buttons = me->modifiers(); + QApplicationPrivate::mouse_buttons |= me->button(); + break; + } case QEvent::MouseButtonRelease: { QMouseEvent *me = static_cast<QMouseEvent*>(e); @@ -2995,6 +3031,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) mouse->modifiers()); me.spont = mouse->spontaneous(); me.setTimestamp(mouse->timestamp()); + QGuiApplicationPrivate::setMouseEventFlags(&me, mouse->flags()); // throw away any mouse-tracking-only mouse events if (!w->hasMouseTracking() && mouse->type() == QEvent::MouseMove && mouse->buttons() == 0) { @@ -3611,7 +3648,7 @@ bool QApplication::keypadNavigationEnabled() */ void QApplication::setCursorFlashTime(int msecs) { - Q_UNUSED(msecs); + QGuiApplication::styleHints()->setCursorFlashTime(msecs); } int QApplication::cursorFlashTime() @@ -3626,12 +3663,10 @@ int QApplication::cursorFlashTime() The default value on X11 is 400 milliseconds. On Windows and Mac OS, the operating system's value is used. - - Setting the interval is not supported anymore in Qt 5. */ void QApplication::setDoubleClickInterval(int ms) { - Q_UNUSED(ms); + QGuiApplication::styleHints()->setMouseDoubleClickInterval(ms); } int QApplication::doubleClickInterval() @@ -3659,7 +3694,7 @@ int QApplication::doubleClickInterval() */ void QApplication::setKeyboardInputInterval(int ms) { - Q_UNUSED(ms); + QGuiApplication::styleHints()->setKeyboardInputInterval(ms); } int QApplication::keyboardInputInterval() @@ -3750,6 +3785,7 @@ void QApplicationPrivate::giveFocusAccordingToFocusPolicy(QWidget *widget, QEven switch (event->type()) { case QEvent::MouseButtonPress: + case QEvent::MouseButtonDblClick: case QEvent::TouchBegin: if (setFocusOnRelease) return; diff --git a/src/widgets/kernel/qapplication.h b/src/widgets/kernel/qapplication.h index 83673eef4e..9cd18d5cd9 100644 --- a/src/widgets/kernel/qapplication.h +++ b/src/widgets/kernel/qapplication.h @@ -126,10 +126,10 @@ public: static void setFont(const QFont &, const char* className = 0); static QFontMetrics fontMetrics(); +#if QT_VERSION < 0x060000 // remove these forwarders in Qt 6 static void setWindowIcon(const QIcon &icon); static QIcon windowIcon(); - - +#endif static QWidgetList allWidgets(); static QWidgetList topLevelWidgets(); diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h index 29c6902c78..93c9ffe002 100644 --- a/src/widgets/kernel/qapplication_p.h +++ b/src/widgets/kernel/qapplication_p.h @@ -120,6 +120,7 @@ public: virtual void notifyActiveWindowChange(QWindow *); virtual bool shouldQuit(); + bool tryCloseAllWindows() Q_DECL_OVERRIDE; #if defined(Q_WS_X11) #ifndef QT_NO_SETTINGS @@ -137,6 +138,8 @@ public: void createEventDispatcher(); static void dispatchEnterLeave(QWidget *enter, QWidget *leave, const QPointF &globalPosF); + void notifyWindowIconChanged() Q_DECL_OVERRIDE; + //modality bool isWindowBlocked(QWindow *window, QWindow **blockingWindow = 0) const Q_DECL_OVERRIDE; static bool isBlockedByModal(QWidget *widget); @@ -144,7 +147,7 @@ public: static bool tryModalHelper(QWidget *widget, QWidget **rettop = 0); #ifdef Q_WS_MAC static QWidget *tryModalHelper_sys(QWidget *top); - bool canQuit(); + bool canQuit(); #endif bool notify_helper(QObject *receiver, QEvent * e); @@ -198,7 +201,6 @@ public: static QWidget *focus_widget; static QWidget *hidden_focus_widget; static QWidget *active_window; - static QIcon *app_icon; #ifndef QT_NO_WHEELEVENT static int wheel_scroll_lines; #endif @@ -293,6 +295,7 @@ public: QPixmap applyQIconStyleHelper(QIcon::Mode mode, const QPixmap& base) const; private: static QApplicationPrivate *self; + static bool tryCloseAllWidgetWindows(QWindowList *processedWindows); static void giveFocusAccordingToFocusPolicy(QWidget *w, QEvent *event, QPoint localPos); static bool shouldSetFocus(QWidget *w, Qt::FocusPolicy policy); diff --git a/src/widgets/kernel/qapplication_qpa.cpp b/src/widgets/kernel/qapplication_qpa.cpp index 1f8e950d00..7977ae3528 100644 --- a/src/widgets/kernel/qapplication_qpa.cpp +++ b/src/widgets/kernel/qapplication_qpa.cpp @@ -451,7 +451,7 @@ void qt_init(QApplicationPrivate *priv, int type) QApplicationPrivate::initializeWidgetFontHash(); } -#ifdef Q_OS_WIN +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) // #fixme: Remove. static HDC displayDC = 0; // display device context @@ -470,7 +470,7 @@ void qt_cleanup() QColormap::cleanup(); QApplicationPrivate::active_window = 0; //### this should not be necessary -#ifdef Q_OS_WIN +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) if (displayDC) { ReleaseDC(0, displayDC); displayDC = 0; diff --git a/src/widgets/kernel/qformlayout.h b/src/widgets/kernel/qformlayout.h index a1356c734f..0b8fd65a3f 100644 --- a/src/widgets/kernel/qformlayout.h +++ b/src/widgets/kernel/qformlayout.h @@ -143,7 +143,7 @@ public: int rowCount() const; #if 0 - void dump() const; + void dump() const; #endif private: diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp new file mode 100644 index 0000000000..a5f81a9df8 --- /dev/null +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtWidgets module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopenglwidget_p.h" +#include <QOpenGLContext> +#include <QtWidgets/private/qwidget_p.h> + +#include <QOpenGLFramebufferObject> +#include <QWindow> +#include <qpa/qplatformwindow.h> +#include <QDebug> +#include <QtGui/QGuiApplication> +#include <QtGui/QScreen> + +QT_BEGIN_NAMESPACE + +class QOpenGLWidgetPrivate : public QWidgetPrivate +{ + Q_DECLARE_PUBLIC(QOpenGLWidget) +public: + QOpenGLWidgetPrivate() + : fbo(0), uninitialized(true) + { + setRenderToTexture(); + } + GLuint textureId() const { return fbo ? fbo->texture() : 0; } + + const QSurface *surface() const { return q_func()->window()->windowHandle(); } + QSurface *surface() { return q_func()->window()->windowHandle(); } + void initialize(); + + QOpenGLContext context; + QOpenGLFramebufferObject *fbo; + bool uninitialized; + + int w,h; +}; + +void QOpenGLWidgetPrivate::initialize() +{ + Q_Q(QOpenGLWidget); + if (!uninitialized) + return; + context.setShareContext(get(q->window())->shareContext()); + context.setFormat(surface()->format()); + context.create(); + context.makeCurrent(surface()); + q->initializeGL(); + uninitialized = false; +} + +QOpenGLWidget::QOpenGLWidget(QWidget *parent, Qt::WindowFlags f) + : QWidget(*(new QOpenGLWidgetPrivate), parent, f) +{ +} + +QOpenGLWidget::~QOpenGLWidget() +{ +} + +bool QOpenGLWidget::isValid() const +{ + Q_D(const QOpenGLWidget); + return d->context.isValid(); +} + +void QOpenGLWidget::makeCurrent() +{ + Q_D(QOpenGLWidget); + d->context.makeCurrent(d->surface()); + d->fbo->bind(); +} + +void QOpenGLWidget::doneCurrent() +{ + Q_D(QOpenGLWidget); + d->context.doneCurrent(); +} + +QSurfaceFormat QOpenGLWidget::format() const +{ + Q_D(const QOpenGLWidget); + return d->surface()->format(); +} + +GLuint QOpenGLWidget::defaultFramebufferObject() const +{ + Q_D(const QOpenGLWidget); + return d->fbo ? d->fbo->handle() : 0; +} + +void QOpenGLWidget::initializeGL() +{ + +} + +void QOpenGLWidget::resizeGL(int w, int h) +{ + Q_UNUSED(w); + Q_UNUSED(h); +} + +void QOpenGLWidget::paintGL() +{ +} + +void QOpenGLWidget::updateGL() +{ + makeCurrent(); + paintGL(); + glFlush(); + doneCurrent(); + update(); +} + + +void QOpenGLWidget::resizeEvent(QResizeEvent *) +{ + Q_D(QOpenGLWidget); + d->w = width(); + d->h = height(); + d->initialize(); + + d->context.makeCurrent(d->surface()); + delete d->fbo; // recreate when resized + d->fbo = new QOpenGLFramebufferObject(size()); + d->fbo->bind(); + glBindTexture(GL_TEXTURE_2D, d->fbo->texture()); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + resizeGL(width(), height()); + paintGL(); + glFlush(); +} + +void QOpenGLWidget::paintEvent(QPaintEvent *) +{ + qWarning("QOpenGLWidget does not support paintEvent() yet."); + return; +} + +QT_END_NAMESPACE diff --git a/src/widgets/kernel/qopenglwidget_p.h b/src/widgets/kernel/qopenglwidget_p.h new file mode 100644 index 0000000000..1c7f0bfeec --- /dev/null +++ b/src/widgets/kernel/qopenglwidget_p.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtWidgets module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It may change from version to version +// without notice, or even be removed. +// +// We mean it. +// +#ifndef QOPENGLWIDGET_H +#define QOPENGLWIDGET_H + +#include <QWidget> +#include <QSurfaceFormat> + +#include <QtGui/qopengl.h> + +QT_BEGIN_NAMESPACE + +class QOpenGLWidgetPrivate; + +class Q_WIDGETS_EXPORT QOpenGLWidget : public QWidget +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QOpenGLWidget) + +public: + explicit QOpenGLWidget(QWidget* parent=0, + Qt::WindowFlags f=0); + +// This API is not finalized yet. The commented-out functions below are +// QGLWidget functions that have not been implemented for QOpenGLWidget. +// Some of them may not end up in the final version (which is planned for a +// future release of Qt). + +// explicit QOpenGLWidget(const QSurfaceFormat& format, QWidget* parent=0, +// Qt::WindowFlags f=0); + ~QOpenGLWidget(); + +// void qglClearColor(const QColor& c) const; + + bool isValid() const; +// bool isSharing() const; + + void makeCurrent(); + void doneCurrent(); + +// void swapBuffers(); + + QSurfaceFormat format() const; + GLuint defaultFramebufferObject() const; + +// QPixmap renderPixmap(int w = 0, int h = 0, bool useContext = false); + QImage grabFrameBuffer(bool withAlpha = false); + +// static QImage convertToGLFormat(const QImage& img); + +// QPaintEngine *paintEngine() const; + +// void drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget = GL_TEXTURE_2D); +// void drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget = GL_TEXTURE_2D); + +public Q_SLOTS: + void updateGL(); + +protected: +// bool event(QEvent *); + virtual void initializeGL(); + virtual void resizeGL(int w, int h); + virtual void paintGL(); + +// void setAutoBufferSwap(bool on); +// bool autoBufferSwap() const; + + void paintEvent(QPaintEvent*); + void resizeEvent(QResizeEvent*); + +// virtual void glInit(); +// virtual void glDraw(); + +// QOpenGLWidget(QOpenGLWidgetPrivate &dd, +// const QGLFormat &format = QGLFormat(), +// QWidget *parent = 0, +// const QOpenGLWidget* shareWidget = 0, +// Qt::WindowFlags f = 0); +private: + Q_DISABLE_COPY(QOpenGLWidget) + + +}; + +QT_END_NAMESPACE + +#endif // QOPENGLWIDGET_H diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index ee7f779a3a..46aa93fe48 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -78,6 +78,7 @@ #include "private/qstyle_p.h" #include "qfileinfo.h" #include <QtGui/qinputmethod.h> +#include <QtGui/qopenglcontext.h> #include <private/qgraphicseffect_p.h> #include <qbackingstore.h> @@ -270,6 +271,8 @@ QWidgetPrivate::QWidgetPrivate(int version) , isMoved(0) , usesDoubleBufferedGLContext(0) , mustHaveWindowHandle(0) + , renderToTexture(0) + , textureChildSeen(0) #ifndef QT_NO_IM , inheritsInputMethodHints(0) #endif @@ -353,10 +356,10 @@ void QWidgetPrivate::scrollChildren(int dx, int dy) } } -void QWidgetPrivate::updateWidgetTransform() +void QWidgetPrivate::updateWidgetTransform(QEvent *event) { Q_Q(QWidget); - if (q == qGuiApp->focusObject()) { + if (q == qGuiApp->focusObject() || event->type() == QEvent::FocusIn) { QTransform t; QPoint p = q->mapTo(q->topLevelWidget(), QPoint(0,0)); t.translate(p.x(), p.y()); @@ -1188,7 +1191,7 @@ void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f) if (++QWidgetPrivate::instanceCounter > QWidgetPrivate::maxInstances) QWidgetPrivate::maxInstances = QWidgetPrivate::instanceCounter; - if (QApplicationPrivate::testAttribute(Qt::AA_ImmediateWidgetCreation)) + if (QApplicationPrivate::testAttribute(Qt::AA_ImmediateWidgetCreation)) // ### fixme: Qt 6: Remove AA_ImmediateWidgetCreation. q->create(); QEvent e(QEvent::Create); @@ -1558,6 +1561,7 @@ void QWidgetPrivate::createTLExtra() x->inRepaint = false; x->embedded = 0; x->window = 0; + x->shareContext = 0; x->screenIndex = 0; #ifdef Q_WS_MAC x->wasMaximized = false; @@ -4178,7 +4182,7 @@ const QPalette &QWidget::palette() const if (!isEnabled()) { data->pal.setCurrentColorGroup(QPalette::Disabled); } else if ((!isVisible() || isActiveWindow()) -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) && !QApplicationPrivate::isBlockedByModal(const_cast<QWidget *>(this)) #endif ) { @@ -5133,9 +5137,17 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP << "geometry ==" << QRect(q->mapTo(q->window(), QPoint(0, 0)), q->size()); #endif - //actually send the paint event - QPaintEvent e(toBePainted); - QCoreApplication::sendSpontaneousEvent(q, &e); + if (renderToTexture) { + // This widget renders into a texture which is composed later. We just need to + // punch a hole in the backingstore, so the texture will be visible. + QPainter p(q); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.fillRect(q->rect(), Qt::transparent); + } else { + //actually send the paint event + QPaintEvent e(toBePainted); + QCoreApplication::sendSpontaneousEvent(q, &e); + } // Native widgets need to be marked dirty on screen so painting will be done in correct context if (backingStore && !onScreen && !asRoot && (q->internalWinId() || !q->nativeParentWidget()->isWindow())) @@ -6747,12 +6759,25 @@ bool QWidget::restoreGeometry(const QByteArray &geometry) if (maximized || fullScreen) { // set geometry before setting the window state to make // sure the window is maximized to the right screen. - // Skip on windows: the window is restored into a broken - // half-maximized state. + Qt::WindowStates ws = windowState(); #ifndef Q_OS_WIN setGeometry(restoredNormalGeometry); -#endif - Qt::WindowStates ws = windowState(); +#else + if (ws & Qt::WindowFullScreen) { + // Full screen is not a real window state on Windows. + move(availableGeometry.topLeft()); + } else if (ws & Qt::WindowMaximized) { + // Setting a geometry on an already maximized window causes this to be + // restored into a broken, half-maximized state, non-resizable state (QTBUG-4397). + // Move the window in normal state if needed. + if (restoredScreenNumber != desktop->screenNumber(this)) { + setWindowState(Qt::WindowNoState); + setGeometry(restoredNormalGeometry); + } + } else { + setGeometry(restoredNormalGeometry); + } +#endif // Q_OS_WIN if (maximized) ws |= Qt::WindowMaximized; if (fullScreen) @@ -8058,7 +8083,7 @@ bool QWidget::event(QEvent *event) break; case QEvent::FocusIn: focusInEvent((QFocusEvent*)event); - d->updateWidgetTransform(); + d->updateWidgetTransform(event); break; case QEvent::FocusOut: @@ -8100,12 +8125,12 @@ bool QWidget::event(QEvent *event) case QEvent::Move: moveEvent((QMoveEvent*)event); - d->updateWidgetTransform(); + d->updateWidgetTransform(event); break; case QEvent::Resize: resizeEvent((QResizeEvent*)event); - d->updateWidgetTransform(); + d->updateWidgetTransform(event); break; case QEvent::Close: @@ -9479,27 +9504,36 @@ void QWidget::updateGeometry() */ void QWidget::setWindowFlags(Qt::WindowFlags flags) { - if (data->window_flags == flags) - return; - Q_D(QWidget); + d->setWindowFlags(flags); +} + +/*! \internal + + Implemented in QWidgetPrivate so that QMdiSubWindowPrivate can reimplement it. +*/ +void QWidgetPrivate::setWindowFlags(Qt::WindowFlags flags) +{ + Q_Q(QWidget); + if (q->data->window_flags == flags) + return; - if ((data->window_flags | flags) & Qt::Window) { + if ((q->data->window_flags | flags) & Qt::Window) { // the old type was a window and/or the new type is a window - QPoint oldPos = pos(); - bool visible = isVisible(); - setParent(parentWidget(), flags); + QPoint oldPos = q->pos(); + bool visible = q->isVisible(); + q->setParent(q->parentWidget(), flags); // if both types are windows or neither of them are, we restore // the old position - if (!((data->window_flags ^ flags) & Qt::Window) - && (visible || testAttribute(Qt::WA_Moved))) { - move(oldPos); + if (!((q->data->window_flags ^ flags) & Qt::Window) + && (visible || q->testAttribute(Qt::WA_Moved))) { + q->move(oldPos); } // for backward-compatibility we change Qt::WA_QuitOnClose attribute value only when the window was recreated. - d->adjustQuitOnCloseAttribute(); + adjustQuitOnCloseAttribute(); } else { - data->window_flags = flags; + q->data->window_flags = flags; } } @@ -9615,6 +9649,13 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) if (desktopWidget) parent = 0; +#ifndef QT_NO_OPENGL + if (d->textureChildSeen && parent) { + // set the textureChildSeen flag up the whole parent chain + QWidgetPrivate::get(parent)->setTextureChildSeen(); + } +#endif + if (QWidgetBackingStore *oldBs = oldtlw->d_func()->maybeBackingStore()) { if (newParent) oldBs->removeDirtyWidget(this); @@ -9623,6 +9664,7 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) oldBs->moveStaticWidgets(this); } + // ### fixme: Qt 6: Remove AA_ImmediateWidgetCreation. if (QApplicationPrivate::testAttribute(Qt::AA_ImmediateWidgetCreation) && !testAttribute(Qt::WA_WState_Created)) create(); @@ -11085,7 +11127,25 @@ void QWidgetPrivate::adjustQuitOnCloseAttribute() } } - +QOpenGLContext *QWidgetPrivate::shareContext() const +{ +#ifdef QT_NO_OPENGL + return 0; +#else + if (!extra || !extra->topextra || !extra->topextra->window) { + qWarning() << "Asking for share context for widget that does not have a window handle"; + return 0; + } + QWidgetPrivate *that = const_cast<QWidgetPrivate *>(this); + if (!extra->topextra->shareContext) { + QOpenGLContext *ctx = new QOpenGLContext(); + ctx->setFormat(extra->topextra->window->format()); + ctx->create(); + that->extra->topextra->shareContext = ctx; + } + return that->extra->topextra->shareContext; +#endif // QT_NO_OPENGL +} Q_WIDGETS_EXPORT QWidgetData *qt_qwidget_data(QWidget *widget) { diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index 943b7057b5..bdfc57f7c3 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -60,6 +60,7 @@ #include "QtCore/qset.h" #include "QtGui/qregion.h" #include "QtGui/qinputmethod.h" +#include "QtGui/qopengl.h" #include "QtWidgets/qsizepolicy.h" #include "QtWidgets/qstyle.h" #include "QtWidgets/qapplication.h" @@ -80,6 +81,7 @@ class QPixmap; class QWidgetBackingStore; class QGraphicsProxyWidget; class QWidgetItemV2; +class QOpenGLContext; class QStyle; @@ -216,6 +218,7 @@ struct QTLWExtra { bool wasMaximized; #endif QWidgetWindow *window; + QOpenGLContext *shareContext; quint32 screenIndex; // index in qplatformscreenlist }; @@ -324,6 +327,8 @@ public: explicit QWidgetPrivate(int version = QObjectPrivateVersion); ~QWidgetPrivate(); + static QWidgetPrivate *get(QWidget *w) { return w->d_func(); } + QWExtra *extraData() const; QTLWExtra *topData() const; QTLWExtra *maybeTopData() const; @@ -438,7 +443,7 @@ public: void syncBackingStore(const QRegion ®ion); // tells the input method about the widgets transform - void updateWidgetTransform(); + void updateWidgetTransform(QEvent *event); void reparentFocusWidgets(QWidget *oldtlw); @@ -489,6 +494,7 @@ public: void setWindowTitle_helper(const QString &cap); void setWindowFilePath_helper(const QString &filePath); void setWindowModified_helper(); + virtual void setWindowFlags(Qt::WindowFlags windowFlags); bool setMinimumSize_helper(int &minw, int &minh); bool setMaximumSize_helper(int &maxw, int &maxh); @@ -537,6 +543,8 @@ public: } } } +#else + Q_UNUSED(widget); #endif return screen; } @@ -615,6 +623,27 @@ public: inline QRect mapFromWS(const QRect &r) const { QRect rr(r); rr.translate(data.wrect.topLeft()); return rr; } + QOpenGLContext *shareContext() const; + +#ifndef QT_NO_OPENGL + virtual GLuint textureId() const { return 0; } + + void setRenderToTexture() { renderToTexture = true; textureChildSeen = true; } + void setTextureChildSeen() + { + Q_Q(QWidget); + if (textureChildSeen) + return; + textureChildSeen = 1; + + if (!q->isWindow()) { + QWidget *parent = q->parentWidget(); + if (parent) + get(parent)->setTextureChildSeen(); + } + } +#endif + // Variables. // Regular pointers (keep them together to avoid gaps on 64 bit architectures). QWExtra *extra; @@ -695,6 +724,8 @@ public: uint isMoved : 1; uint usesDoubleBufferedGLContext : 1; uint mustHaveWindowHandle : 1; + uint renderToTexture : 1; + uint textureChildSeen : 1; #ifndef QT_NO_IM uint inheritsInputMethodHints : 1; #endif diff --git a/src/widgets/kernel/qwidget_qpa.cpp b/src/widgets/kernel/qwidget_qpa.cpp index 0a4bc990e6..c2260b6e7d 100644 --- a/src/widgets/kernel/qwidget_qpa.cpp +++ b/src/widgets/kernel/qwidget_qpa.cpp @@ -49,6 +49,7 @@ #include "QtWidgets/qdesktopwidget.h" #include <qpa/qplatformwindow.h> #include "QtGui/qsurfaceformat.h" +#include <QtGui/qopenglcontext.h> #include <qpa/qplatformopenglcontext.h> #include <qpa/qplatformintegration.h> #include "QtGui/private/qwindow_p.h" @@ -953,6 +954,10 @@ void QWidgetPrivate::deleteTLSysExtra() delete extra->topextra->backingStore; extra->topextra->backingStore = 0; +#ifndef QT_NO_OPENGL + delete extra->topextra->shareContext; + extra->topextra->shareContext = 0; +#endif } } diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp index 4a94cd6cb8..dc918657b4 100644 --- a/src/widgets/kernel/qwidgetbackingstore.cpp +++ b/src/widgets/kernel/qwidgetbackingstore.cpp @@ -57,6 +57,8 @@ #include <private/qpaintengine_raster_p.h> #include <private/qgraphicseffect_p.h> +#include <qpa/qplatformbackingstore.h> + #if defined(Q_OS_WIN) && !defined(QT_NO_PAINT_DEBUG) # include <QtCore/qt_windows.h> # include <qpa/qplatformnativeinterface.h> @@ -72,10 +74,15 @@ extern QRegion qt_dirtyRegion(QWidget *); * \a region is the region to be updated in \a widget coordinates. */ static inline void qt_flush(QWidget *widget, const QRegion ®ion, QBackingStore *backingStore, - QWidget *tlw, const QPoint &tlwOffset) + QWidget *tlw, const QPoint &tlwOffset, QPlatformTextureList *widgetTextures = 0, + QOpenGLContext *context = 0) { +#ifdef QT_NO_OPENGL + Q_UNUSED(widgetTextures); + Q_UNUSED(context); +#endif Q_ASSERT(widget); - Q_ASSERT(!region.isEmpty()); + Q_ASSERT(!region.isEmpty() || (context && widgetTextures && widgetTextures->count())); Q_ASSERT(backingStore); Q_ASSERT(tlw); @@ -104,14 +111,20 @@ static inline void qt_flush(QWidget *widget, const QRegion ®ion, QBackingStor if (tlw->testAttribute(Qt::WA_DontShowOnScreen) || widget->testAttribute(Qt::WA_DontShowOnScreen)) return; + QPoint offset = tlwOffset; if (widget != tlw) - backingStore->flush(region, widget->windowHandle(), tlwOffset + widget->mapTo(tlw, QPoint())); + offset += widget->mapTo(tlw, QPoint()); + +#ifndef QT_NO_OPENGL + if (widgetTextures) + backingStore->handle()->composeAndFlush(widget->windowHandle(), region, offset, widgetTextures, context); else - backingStore->flush(region, widget->windowHandle(), tlwOffset); +#endif + backingStore->flush(region, widget->windowHandle(), offset); } #ifndef QT_NO_PAINT_DEBUG -#ifdef Q_OS_WIN +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) static void showYellowThing_win(QWidget *widget, const QRegion ®ion, int msec) { @@ -151,7 +164,7 @@ static void showYellowThing_win(QWidget *widget, const QRegion ®ion, int msec QGuiApplication::platformNativeInterface()->nativeResourceForWindow(QByteArrayLiteral("releaseDC"), nativeWindow); ::Sleep(msec); } -#endif // Q_OS_WIN +#endif // defined(Q_OS_WIN) && !defined(Q_OS_WINRT) void QWidgetBackingStore::showYellowThing(QWidget *widget, const QRegion &toBePainted, int msec, bool unclipped) { @@ -166,7 +179,7 @@ void QWidgetBackingStore::showYellowThing(QWidget *widget, const QRegion &toBePa widget = nativeParent; } -#ifdef Q_OS_WIN +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) Q_UNUSED(unclipped); showYellowThing_win(widget, paintRegion, msec); #else @@ -430,7 +443,7 @@ QRegion QWidgetBackingStore::staticContents(QWidget *parent, const QRect &within return region; } -static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately) +void QWidgetBackingStore::sendUpdateRequest(QWidget *widget, bool updateImmediately) { if (!widget) return; @@ -439,6 +452,7 @@ static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately) QEvent event(QEvent::UpdateRequest); QApplication::sendEvent(widget, &event); } else { + updateRequestSent = true; QApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority); } } @@ -488,6 +502,7 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up return; } + //### FIXME fullUpdatePending seems to be always false???? if (fullUpdatePending) { if (updateImmediately) sendUpdateRequest(tlw, updateImmediately); @@ -495,6 +510,13 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up } const QPoint offset = widget->mapTo(tlw, QPoint()); + + if (QWidgetPrivate::get(widget)->renderToTexture) { + if (!updateRequestSent || updateImmediately) + sendUpdateRequest(tlw, updateImmediately); + return; + } + const QRect widgetRect = widget->d_func()->effectiveRectFor(widget->rect()); if (qt_region_strictContains(dirty, widgetRect.translated(offset))) { if (updateImmediately) @@ -503,7 +525,7 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up } if (invalidateBuffer) { - const bool eventAlreadyPosted = !dirty.isEmpty(); + const bool eventAlreadyPosted = !dirty.isEmpty() || updateRequestSent; #ifndef QT_NO_GRAPHICSEFFECT if (widget->d_func()->graphicsEffect) dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()).translated(offset); @@ -583,6 +605,13 @@ void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool upd return; } + if (QWidgetPrivate::get(widget)->renderToTexture) { + if (!updateRequestSent || updateImmediately) + sendUpdateRequest(tlw, updateImmediately); + return; + } + + const QRect widgetRect = widget->d_func()->effectiveRectFor(rect); const QRect translatedRect(widgetRect.translated(widget->mapTo(tlw, QPoint()))); if (qt_region_strictContains(dirty, translatedRect)) { @@ -703,7 +732,12 @@ void QWidgetBackingStore::updateLists(QWidget *cur) } QWidgetBackingStore::QWidgetBackingStore(QWidget *topLevel) - : tlw(topLevel), dirtyOnScreenWidgets(0), fullUpdatePending(0) + : tlw(topLevel), + dirtyOnScreenWidgets(0), + widgetTextures(0), + fullUpdatePending(0), + updateRequestSent(0), + textureListWatcher(0) { store = tlw->backingStore(); Q_ASSERT(store); @@ -892,17 +926,17 @@ static inline bool discardSyncRequest(QWidget *tlw, QTLWExtra *tlwExtra) void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedRegion) { QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); - if (discardSyncRequest(tlw, tlwExtra) || tlwExtra->inTopLevelResize) + if (!tlw->isVisible() || !tlwExtra || tlwExtra->inTopLevelResize) return; - if (!exposedWidget || !exposedWidget->internalWinId() || !exposedWidget->isVisible() + if (!exposedWidget || !exposedWidget->internalWinId() || !exposedWidget->isVisible() || !exposedWidget->testAttribute(Qt::WA_Mapped) || !exposedWidget->updatesEnabled() || exposedRegion.isEmpty()) { return; } // Nothing to repaint. if (!isDirty()) { - qt_flush(exposedWidget, exposedRegion, store, tlw, tlwOffset); + qt_flush(exposedWidget, exposedRegion, store, tlw, tlwOffset, widgetTextures, tlw->d_func()->shareContext()); return; } @@ -910,7 +944,42 @@ void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedReg markDirtyOnScreen(exposedRegion, exposedWidget, exposedWidget->mapTo(tlw, QPoint())); else markDirtyOnScreen(exposedRegion, exposedWidget, QPoint()); - sync(); + + doSync(); +} + +#ifndef QT_NO_OPENGL +static void findTextureWidgetsRecursively(QWidget *tlw, QWidget *widget, QPlatformTextureList *widgetTextures) +{ + QWidgetPrivate *wd = QWidgetPrivate::get(widget); + if (wd->renderToTexture) + widgetTextures->appendTexture(wd->textureId(), QRect(widget->mapTo(tlw, QPoint()), widget->size())); + + for (int i = 0; i < wd->children.size(); ++i) { + QWidget *w = qobject_cast<QWidget *>(wd->children.at(i)); + if (w && !w->isWindow() && !w->isHidden() && QWidgetPrivate::get(w)->textureChildSeen) + findTextureWidgetsRecursively(tlw, w, widgetTextures); + } +} +#endif + +QPlatformTextureListWatcher::QPlatformTextureListWatcher(QWidgetBackingStore *backingStore) + : m_locked(false), + m_backingStore(backingStore) +{ +} + +void QPlatformTextureListWatcher::watch(QPlatformTextureList *textureList) +{ + connect(textureList, SIGNAL(locked(bool)), SLOT(onLockStatusChanged(bool))); + m_locked = textureList->isLocked(); +} + +void QPlatformTextureListWatcher::onLockStatusChanged(bool locked) +{ + m_locked = locked; + if (!locked) + m_backingStore->sync(); } /*! @@ -918,6 +987,7 @@ void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedReg */ void QWidgetBackingStore::sync() { + updateRequestSent = false; QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); if (discardSyncRequest(tlw, tlwExtra)) { // If the top-level is minimized, it's not visible on the screen so we can delay the @@ -935,10 +1005,26 @@ void QWidgetBackingStore::sync() return; } + if (textureListWatcher && !textureListWatcher->isLocked()) { + textureListWatcher->deleteLater(); + textureListWatcher = 0; + } else if (widgetTextures && widgetTextures->isLocked()) { + if (!textureListWatcher) + textureListWatcher = new QPlatformTextureListWatcher(this); + if (!textureListWatcher->isLocked()) + textureListWatcher->watch(widgetTextures); + return; + } + + doSync(); +} + +void QWidgetBackingStore::doSync() +{ const bool updatesDisabled = !tlw->updatesEnabled(); bool repaintAllWidgets = false; - const bool inTopLevelResize = tlwExtra->inTopLevelResize; + const bool inTopLevelResize = tlw->d_func()->maybeTopData()->inTopLevelResize; const QRect tlwRect(topLevelRect()); const QRect surfaceGeometry(tlwRect.topLeft(), store->size()); if ((fullUpdatePending || inTopLevelResize || surfaceGeometry.size() != tlwRect.size()) && !updatesDisabled) { @@ -1018,7 +1104,15 @@ void QWidgetBackingStore::sync() } dirtyWidgets.clear(); +#ifndef QT_NO_OPENGL + delete widgetTextures; + widgetTextures = 0; + if (tlw->d_func()->textureChildSeen) { + widgetTextures = new QPlatformTextureList; + findTextureWidgetsRecursively(tlw, tlw, widgetTextures); + } fullUpdatePending = false; +#endif if (toClean.isEmpty()) { // Nothing to repaint. However, we might have newly exposed areas on the @@ -1032,6 +1126,7 @@ void QWidgetBackingStore::sync() if (tlw->d_func()->extra->proxyWidget) { updateStaticContentsSize(); dirty = QRegion(); + updateRequestSent = false; const QVector<QRect> rects(toClean.rects()); for (int i = 0; i < rects.size(); ++i) tlw->d_func()->extra->proxyWidget->update(rects.at(i)); @@ -1045,6 +1140,7 @@ void QWidgetBackingStore::sync() for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) resetWidget(opaqueNonOverlappedWidgets[i]); dirty = QRegion(); + updateRequestSent = false; return; } @@ -1053,6 +1149,7 @@ void QWidgetBackingStore::sync() updateStaticContentsSize(); const QRegion dirtyCopy(dirty); dirty = QRegion(); + updateRequestSent = false; // Paint opaque non overlapped widgets. for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) { @@ -1093,12 +1190,19 @@ void QWidgetBackingStore::flush(QWidget *widget) { if (!dirtyOnScreen.isEmpty()) { QWidget *target = widget ? widget : tlw; - qt_flush(target, dirtyOnScreen, store, tlw, tlwOffset); + qt_flush(target, dirtyOnScreen, store, tlw, tlwOffset, widgetTextures, tlw->d_func()->shareContext()); dirtyOnScreen = QRegion(); } - if (!dirtyOnScreenWidgets || dirtyOnScreenWidgets->isEmpty()) + if (!dirtyOnScreenWidgets || dirtyOnScreenWidgets->isEmpty()) { +#ifndef QT_NO_OPENGL + if (widgetTextures && widgetTextures->count()) { + QWidget *target = widget ? widget : tlw; + qt_flush(target, QRegion(), store, tlw, tlwOffset, widgetTextures, tlw->d_func()->shareContext()); + } +#endif return; + } for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) { QWidget *w = dirtyOnScreenWidgets->at(i); diff --git a/src/widgets/kernel/qwidgetbackingstore_p.h b/src/widgets/kernel/qwidgetbackingstore_p.h index b6c3e13cb0..2fe58fa4a7 100644 --- a/src/widgets/kernel/qwidgetbackingstore_p.h +++ b/src/widgets/kernel/qwidgetbackingstore_p.h @@ -60,6 +60,9 @@ QT_BEGIN_NAMESPACE +class QPlatformTextureList; +class QWidgetBackingStore; + struct BeginPaintInfo { inline BeginPaintInfo() : wasFlushed(0), nothingToPaint(0), backingStoreRecreated(0) {} uint wasFlushed : 1; @@ -67,6 +70,23 @@ struct BeginPaintInfo { uint backingStoreRecreated : 1; }; +class QPlatformTextureListWatcher : public QObject +{ + Q_OBJECT + +public: + QPlatformTextureListWatcher(QWidgetBackingStore *backingStore); + void watch(QPlatformTextureList *textureList); + bool isLocked() const { return m_locked; } + +private slots: + void onLockStatusChanged(bool locked); + +private: + bool m_locked; + QWidgetBackingStore *m_backingStore; +}; + class Q_AUTOTEST_EXPORT QWidgetBackingStore { public: @@ -102,14 +122,21 @@ private: QVector<QWidget *> dirtyWidgets; QVector<QWidget *> *dirtyOnScreenWidgets; QList<QWidget *> staticWidgets; + QPlatformTextureList *widgetTextures; QBackingStore *store; uint fullUpdatePending : 1; + uint updateRequestSent : 1; QPoint tlwOffset; + QPlatformTextureListWatcher *textureListWatcher; + + void sendUpdateRequest(QWidget *widget, bool updateImmediately); + static bool flushPaint(QWidget *widget, const QRegion &rgn); static void unflushPaint(QWidget *widget, const QRegion &rgn); + void doSync(); bool bltRect(const QRect &rect, int dx, int dy, QWidget *widget); void releaseBuffer(); diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 167102c633..0e40dd866f 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -50,6 +50,7 @@ #include <private/qwidgetbackingstore_p.h> #include <qpa/qwindowsysteminterface_p.h> #include <qpa/qplatformtheme.h> +#include <qpa/qplatformwindow.h> #include <private/qgesturemanager_p.h> QT_BEGIN_NAMESPACE @@ -91,6 +92,12 @@ QWidgetWindow::QWidgetWindow(QWidget *widget) , m_widget(widget) { updateObjectName(); + // Enable QOpenGLWidget/QQuickWidget children if the platform plugin supports it, + // and the application developer has not explicitly disabled it. + if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RasterGLSurface) + && !QApplication::testAttribute(Qt::AA_ForceRasterWidgets)) { + setSurfaceType(QSurface::RasterGLSurface); + } connect(m_widget, &QObject::objectNameChanged, this, &QWidgetWindow::updateObjectName); } @@ -473,7 +480,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event) if (!widget) widget = m_widget; - if (event->type() == QEvent::MouseButtonPress) + if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick) qt_button_down = widget; QWidget *receiver = QApplicationPrivate::pickMouseReceiver(m_widget, event->windowPos().toPoint(), &mapped, event->type(), event->buttons(), @@ -484,12 +491,17 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event) QApplicationPrivate::mouse_buttons &= ~event->button(); return; } - - QMouseEvent translated(event->type(), mapped, event->windowPos(), event->screenPos(), event->button(), event->buttons(), event->modifiers()); - translated.setTimestamp(event->timestamp()); - QApplicationPrivate::sendMouseEvent(receiver, &translated, widget, m_widget, &qt_button_down, - qt_last_mouse_receiver); - + if ((event->type() != QEvent::MouseButtonPress) + || !(event->flags().testFlag(Qt::MouseEventCreatedDoubleClick))) { + + // The preceding statement excludes MouseButtonPress events which caused + // creation of a MouseButtonDblClick event. QTBUG-25831 + QMouseEvent translated(event->type(), mapped, event->windowPos(), event->screenPos(), + event->button(), event->buttons(), event->modifiers()); + translated.setTimestamp(event->timestamp()); + QApplicationPrivate::sendMouseEvent(receiver, &translated, widget, m_widget, + &qt_button_down, qt_last_mouse_receiver); + } #ifndef QT_NO_CONTEXTMENU if (event->type() == contextMenuTrigger && event->button() == Qt::RightButton) { QContextMenuEvent e(QContextMenuEvent::Mouse, mapped, event->globalPos(), event->modifiers()); @@ -542,6 +554,24 @@ void QWidgetWindow::updateGeometry() m_widget->data->fstrut_dirty = false; } +Qt::WindowState effectiveState(Qt::WindowStates state); + +// Store normal geometry used for saving application settings. +void QWidgetWindow::updateNormalGeometry() +{ + QTLWExtra *tle = m_widget->d_func()->maybeTopData(); + if (!tle) + return; + // Ask platform window, default to widget geometry. + QRect normalGeometry; + if (const QPlatformWindow *pw = handle()) + normalGeometry = pw->normalGeometry(); + if (!normalGeometry.isValid() && effectiveState(m_widget->windowState()) == Qt::WindowNoState) + normalGeometry = m_widget->geometry(); + if (normalGeometry.isValid()) + tle->normalGeometry = normalGeometry; +} + void QWidgetWindow::handleMoveEvent(QMoveEvent *event) { updateGeometry(); @@ -654,6 +684,11 @@ void QWidgetWindow::handleDragLeaveEvent(QDragLeaveEvent *event) void QWidgetWindow::handleDropEvent(QDropEvent *event) { + if (m_dragTarget.isNull()) { + qWarning() << Q_FUNC_INFO << m_widget << ": No drag target set."; + event->ignore(); + return; + } const QPoint mapped = m_dragTarget.data()->mapFromGlobal(m_widget->mapToGlobal(event->pos())); QDropEvent translated(mapped, event->possibleActions(), event->mimeData(), event->mouseButtons(), event->keyboardModifiers()); QGuiApplication::sendSpontaneousEvent(m_dragTarget.data(), &translated); @@ -682,8 +717,6 @@ void QWidgetWindow::handleExposeEvent(QExposeEvent *event) } } -Qt::WindowState effectiveState(Qt::WindowStates state); - void QWidgetWindow::handleWindowStateChangedEvent(QWindowStateChangeEvent *event) { // QWindow does currently not know 'active'. @@ -702,16 +735,12 @@ void QWidgetWindow::handleWindowStateChangedEvent(QWindowStateChangeEvent *event widgetState |= Qt::WindowMinimized; break; case Qt::WindowMaximized: - if (effectiveState(widgetState) == Qt::WindowNoState) - if (QTLWExtra *tle = m_widget->d_func()->maybeTopData()) - tle->normalGeometry = m_widget->geometry(); + updateNormalGeometry(); widgetState |= Qt::WindowMaximized; widgetState &= ~(Qt::WindowMinimized | Qt::WindowFullScreen); break; case Qt::WindowFullScreen: - if (effectiveState(widgetState) == Qt::WindowNoState) - if (QTLWExtra *tle = m_widget->d_func()->maybeTopData()) - tle->normalGeometry = m_widget->geometry(); + updateNormalGeometry(); widgetState |= Qt::WindowFullScreen; widgetState &= ~(Qt::WindowMinimized); break; diff --git a/src/widgets/kernel/qwidgetwindow_qpa_p.h b/src/widgets/kernel/qwidgetwindow_qpa_p.h index ffde44dd27..8d6f14a669 100644 --- a/src/widgets/kernel/qwidgetwindow_qpa_p.h +++ b/src/widgets/kernel/qwidgetwindow_qpa_p.h @@ -104,6 +104,7 @@ private slots: private: void updateGeometry(); + void updateNormalGeometry(); enum FocusWidgets { FirstFocusWidget, diff --git a/src/widgets/kernel/win.pri b/src/widgets/kernel/win.pri index d5cba740d1..76bb709e2b 100644 --- a/src/widgets/kernel/win.pri +++ b/src/widgets/kernel/win.pri @@ -2,6 +2,6 @@ # -------------------------------------------------------------------- INCLUDEPATH += ../3rdparty/wintab -!wince* { +!wince*:!winrt { LIBS_PRIVATE *= -lshell32 } |