diff options
Diffstat (limited to 'src/widgets/kernel')
-rw-r--r-- | src/widgets/kernel/kernel.pri | 5 | ||||
-rw-r--r-- | src/widgets/kernel/qapplication.cpp | 222 | ||||
-rw-r--r-- | src/widgets/kernel/qapplication.h | 6 | ||||
-rw-r--r-- | src/widgets/kernel/qapplication_p.h | 8 | ||||
-rw-r--r-- | src/widgets/kernel/qapplication_qpa.cpp | 4 | ||||
-rw-r--r-- | src/widgets/kernel/qformlayout.cpp | 2 | ||||
-rw-r--r-- | src/widgets/kernel/qformlayout.h | 2 | ||||
-rw-r--r-- | src/widgets/kernel/qopenglwidget.cpp | 186 | ||||
-rw-r--r-- | src/widgets/kernel/qopenglwidget_p.h | 135 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget.cpp | 144 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget_p.h | 33 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget_qpa.cpp | 61 | ||||
-rw-r--r-- | src/widgets/kernel/qwidgetbackingstore.cpp | 242 | ||||
-rw-r--r-- | src/widgets/kernel/qwidgetbackingstore_p.h | 51 | ||||
-rw-r--r-- | src/widgets/kernel/qwidgetwindow.cpp | 86 | ||||
-rw-r--r-- | src/widgets/kernel/qwidgetwindow_qpa_p.h | 2 | ||||
-rw-r--r-- | src/widgets/kernel/qwindowcontainer.cpp | 2 | ||||
-rw-r--r-- | src/widgets/kernel/win.pri | 2 |
18 files changed, 907 insertions, 286 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..cb6f4aeecd 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,42 @@ 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->testAttribute(Qt::WA_DontShowOnScreen) && !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 +1790,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 +2639,7 @@ QDesktopWidget *QApplication::desktop() void QApplication::setStartDragTime(int ms) { - Q_UNUSED(ms) + QGuiApplication::styleHints()->setStartDragTime(ms); } /*! @@ -2644,7 +2672,7 @@ int QApplication::startDragTime() void QApplication::setStartDragDistance(int l) { - Q_UNUSED(l); + QGuiApplication::styleHints()->setStartDragDistance(l); } /*! @@ -2663,7 +2691,8 @@ void QApplication::setStartDragDistance(int l) Qt uses this value internally, e.g. in QFileDialog. - The default value is 4 pixels. + The default value (if the platform doesn't provide a different default) + is 10 pixels. \sa startDragTime(), QPoint::manhattanLength(), {Drag and Drop} */ @@ -2716,9 +2745,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 +2798,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 +3033,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) { @@ -3239,30 +3278,6 @@ bool QApplication::notify(QObject *receiver, QEvent *e) } break; #endif - - case QEvent::TouchUpdate: - case QEvent::TouchEnd: - { - QWidget *widget = static_cast<QWidget *>(receiver); - QTouchEvent *touchEvent = static_cast<QTouchEvent *>(e); - const bool acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents); - - if (e->type() != QEvent::TouchUpdate && acceptTouchEvents && e->spontaneous()) { - const QPoint localPos = touchEvent->touchPoints()[0].pos().toPoint(); - QApplicationPrivate::giveFocusAccordingToFocusPolicy(widget, e, localPos); - } - - touchEvent->setTarget(widget); - touchEvent->setAccepted(acceptTouchEvents); - - res = acceptTouchEvents && d->notify_helper(widget, touchEvent); - - // If the touch event wasn't accepted, synthesize a mouse event and see if the widget wants it. - if (!touchEvent->isAccepted() && QGuiApplicationPrivate::synthesizeMouseFromTouchEventsEnabled()) - res = d->translateTouchToMouse(widget, touchEvent); - break; - } - case QEvent::TouchBegin: // Note: TouchUpdate and TouchEnd events are never propagated { @@ -3283,15 +3298,6 @@ bool QApplication::notify(QObject *receiver, QEvent *e) touchEvent->setAccepted(acceptTouchEvents); QPointer<QWidget> p = widget; res = acceptTouchEvents && d->notify_helper(widget, touchEvent); - - // If the touch event wasn't accepted, synthesize a mouse event and see if the widget wants it. - if (!touchEvent->isAccepted() && QGuiApplicationPrivate::synthesizeMouseFromTouchEventsEnabled()) { - res = d->translateTouchToMouse(widget, touchEvent); - eventAccepted = touchEvent->isAccepted(); - if (eventAccepted) - break; - } - eventAccepted = touchEvent->isAccepted(); if (p.isNull()) { // widget was deleted @@ -3611,7 +3617,7 @@ bool QApplication::keypadNavigationEnabled() */ void QApplication::setCursorFlashTime(int msecs) { - Q_UNUSED(msecs); + QGuiApplication::styleHints()->setCursorFlashTime(msecs); } int QApplication::cursorFlashTime() @@ -3626,12 +3632,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 +3663,7 @@ int QApplication::doubleClickInterval() */ void QApplication::setKeyboardInputInterval(int ms) { - Q_UNUSED(ms); + QGuiApplication::styleHints()->setKeyboardInputInterval(ms); } int QApplication::keyboardInputInterval() @@ -3750,6 +3754,7 @@ void QApplicationPrivate::giveFocusAccordingToFocusPolicy(QWidget *widget, QEven switch (event->type()) { case QEvent::MouseButtonPress: + case QEvent::MouseButtonDblClick: case QEvent::TouchBegin: if (setFocusOnRelease) return; @@ -3855,67 +3860,6 @@ QWidget *QApplicationPrivate::findClosestTouchPointTarget(QTouchDevice *device, return static_cast<QWidget *>(closestTarget); } -class WidgetAttributeSaver -{ -public: - explicit WidgetAttributeSaver(QWidget *widget, Qt::WidgetAttribute attribute, bool forcedValue) - : m_widget(widget), - m_attribute(attribute), - m_savedValue(widget->testAttribute(attribute)) - { - widget->setAttribute(attribute, forcedValue); - } - - ~WidgetAttributeSaver() - { - m_widget->setAttribute(m_attribute, m_savedValue); - } - -private: - QWidget * const m_widget; - const Qt::WidgetAttribute m_attribute; - const bool m_savedValue; -}; - -bool QApplicationPrivate::translateTouchToMouse(QWidget *widget, QTouchEvent *event) -{ - Q_FOREACH (const QTouchEvent::TouchPoint &p, event->touchPoints()) { - const QEvent::Type eventType = (p.state() & Qt::TouchPointPressed) ? QEvent::MouseButtonPress - : (p.state() & Qt::TouchPointReleased) ? QEvent::MouseButtonRelease - : (p.state() & Qt::TouchPointMoved) ? QEvent::MouseMove - : QEvent::None; - - if (eventType == QEvent::None) - continue; - - const QPoint pos = widget->mapFromGlobal(p.screenPos().toPoint()); - - QMouseEvent mouseEvent(eventType, pos, p.screenPos().toPoint(), - Qt::LeftButton, - (eventType == QEvent::MouseButtonRelease) ? Qt::NoButton : Qt::LeftButton, - event->modifiers()); - mouseEvent.setAccepted(true); - mouseEvent.setTimestamp(event->timestamp()); - - // Make sure our synthesized mouse event doesn't propagate - // we want to control the propagation ourself to get a chance to - // deliver a proper touch event higher up in the hierarchy if that - // widget doesn't pick up the mouse event either. - WidgetAttributeSaver saver(widget, Qt::WA_NoMousePropagation, true); - - // Note it has to be a spontaneous event if we want the focus management - // and input method support to behave properly. Quite some of the code - // related to those aspect check for the spontaneous flag. - const bool res = QCoreApplication::sendSpontaneousEvent(widget, &mouseEvent); - event->setAccepted(mouseEvent.isAccepted()); - - if (mouseEvent.isAccepted()) - return res; - } - - return false; -} - bool QApplicationPrivate::translateRawTouchEvent(QWidget *window, QTouchDevice *device, const QList<QTouchEvent::TouchPoint> &touchPoints, diff --git a/src/widgets/kernel/qapplication.h b/src/widgets/kernel/qapplication.h index 83673eef4e..e72fe29bdb 100644 --- a/src/widgets/kernel/qapplication.h +++ b/src/widgets/kernel/qapplication.h @@ -112,7 +112,7 @@ public: QT_DEPRECATED static inline void setGraphicsSystem(const QString &) {} #endif -#ifdef Q_NO_USING_KEYWORD +#if defined(Q_NO_USING_KEYWORD) && !defined(Q_QDOC) static QPalette palette() { return QGuiApplication::palette(); } #else using QGuiApplication::palette; @@ -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..0284a613d4 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 @@ -283,7 +285,6 @@ public: QWidget *findClosestTouchPointTarget(QTouchDevice *device, const QPointF &screenPos); void appendTouchPoint(const QTouchEvent::TouchPoint &touchPoint); void removeTouchPoint(int touchPointId); - bool translateTouchToMouse(QWidget *widget, QTouchEvent *event); static bool translateRawTouchEvent(QWidget *widget, QTouchDevice *device, const QList<QTouchEvent::TouchPoint> &touchPoints, @@ -293,6 +294,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.cpp b/src/widgets/kernel/qformlayout.cpp index c1d3e95e7a..239e1ce1e2 100644 --- a/src/widgets/kernel/qformlayout.cpp +++ b/src/widgets/kernel/qformlayout.cpp @@ -1683,7 +1683,7 @@ QWidget *QFormLayout::labelForField(QWidget *field) const Q_D(const QFormLayout); int row; - ItemRole role; + ItemRole role = LabelRole; getWidgetPosition(field, &row, &role); 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..e05c03d952 --- /dev/null +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** 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 <QOpenGLFunctions> +#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() +{ + Q_D(QOpenGLWidget); + makeCurrent(); + paintGL(); + d->context.functions()->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(); + QOpenGLFunctions *funcs = d->context.functions(); + funcs->glBindTexture(GL_TEXTURE_2D, d->fbo->texture()); + funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + resizeGL(width(), height()); + paintGL(); + funcs->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..102e659fbf 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; @@ -2400,7 +2404,8 @@ void QWidget::setStyleSheet(const QString& styleSheet) } if (proxy) { // style sheet update - proxy->repolish(this); + if (d->polished) + proxy->repolish(this); return; } @@ -4178,7 +4183,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 +5138,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 +6760,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 +8084,7 @@ bool QWidget::event(QEvent *event) break; case QEvent::FocusIn: focusInEvent((QFocusEvent*)event); - d->updateWidgetTransform(); + d->updateWidgetTransform(event); break; case QEvent::FocusOut: @@ -8100,12 +8126,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 +9505,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; } } @@ -9561,6 +9596,23 @@ void QWidget::setParent(QWidget *parent) setParent((QWidget*)parent, windowFlags() & ~Qt::WindowType_Mask); } +#ifndef QT_NO_OPENGL +static void sendWindowChangeToTextureChildrenRecursively(QWidget *widget) +{ + QWidgetPrivate *d = QWidgetPrivate::get(widget); + if (d->renderToTexture) { + QEvent e(QEvent::WindowChangeInternal); + QApplication::sendEvent(widget, &e); + } + + for (int i = 0; i < d->children.size(); ++i) { + QWidget *w = qobject_cast<QWidget *>(d->children.at(i)); + if (w && !w->isWindow() && !w->isHidden() && QWidgetPrivate::get(w)->textureChildSeen) + sendWindowChangeToTextureChildrenRecursively(w); + } +} +#endif + /*! \overload @@ -9615,6 +9667,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 +9682,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(); @@ -9677,6 +9737,12 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) QEvent e(QEvent::ParentChange); QApplication::sendEvent(this, &e); } +#ifndef QT_NO_OPENGL + //renderToTexture widgets also need to know when their top-level window changes + if (d->textureChildSeen && oldtlw != window()) { + sendWindowChangeToTextureChildrenRecursively(this); + } +#endif if (!wasCreated) { if (isWindow() || parentWidget()->isVisible()) @@ -9845,7 +9911,7 @@ void QWidget::repaint(const QRect &rect) QTLWExtra *tlwExtra = window()->d_func()->maybeTopData(); if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) { tlwExtra->inRepaint = true; - tlwExtra->backingStoreTracker->markDirty(rect, this, true); + tlwExtra->backingStoreTracker->markDirty(rect, this, QWidgetBackingStore::UpdateNow); tlwExtra->inRepaint = false; } } else { @@ -9874,7 +9940,7 @@ void QWidget::repaint(const QRegion &rgn) QTLWExtra *tlwExtra = window()->d_func()->maybeTopData(); if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) { tlwExtra->inRepaint = true; - tlwExtra->backingStoreTracker->markDirty(rgn, this, true); + tlwExtra->backingStoreTracker->markDirty(rgn, this, QWidgetBackingStore::UpdateNow); tlwExtra->inRepaint = false; } } else { @@ -11085,7 +11151,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..88a08060c1 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" @@ -523,7 +524,10 @@ void QWidgetPrivate::show_sys() return; } - QApplication::postEvent(q, new QUpdateLaterEvent(q->rect())); + if (renderToTexture && !q->isWindow()) + QApplication::postEvent(q->parentWidget(), new QUpdateLaterEvent(q->geometry())); + else + QApplication::postEvent(q, new QUpdateLaterEvent(q->rect())); if (!q->isWindow() && !q->testAttribute(Qt::WA_NativeWindow)) return; @@ -545,12 +549,6 @@ void QWidgetPrivate::show_sys() window->resize(geomRect.size()); } - if (QBackingStore *store = q->backingStore()) { - if (store->size() != geomRect.size()) { - store->resize(geomRect.size()); - } - } - #ifndef QT_NO_CURSOR qt_qpa_set_cursor(q, false); // Needed in case cursor was set before show #endif @@ -587,7 +585,10 @@ void QWidgetPrivate::hide_sys() if (!q->isWindow()) { QWidget *p = q->parentWidget(); if (p &&p->isVisible()) { - invalidateBuffer(q->rect()); + if (renderToTexture) + p->d_func()->invalidateBuffer(q->geometry()); + else + invalidateBuffer(q->rect()); } } else { invalidateBuffer(q->rect()); @@ -662,6 +663,11 @@ void QWidgetPrivate::raise_sys() Q_Q(QWidget); if (q->isWindow() || q->testAttribute(Qt::WA_NativeWindow)) { q->windowHandle()->raise(); + } else if (renderToTexture) { + if (QWidget *p = q->parentWidget()) { + setDirtyOpaqueRegion(); + p->d_func()->invalidateBuffer(effectiveRectFor(q->geometry())); + } } } @@ -750,21 +756,21 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) QPoint posInNativeParent = q->mapTo(q->nativeParentWidget(),QPoint()); q->windowHandle()->setGeometry(QRect(posInNativeParent,r.size())); } - const QWidgetBackingStore *bs = maybeBackingStore(); - if (bs && bs->store) { - if (isResize) - bs->store->resize(r.size()); - } if (needsShow) show_sys(); } if (!q->isWindow()) { - if (isMove && !isResize) + if (renderToTexture) { + QRegion updateRegion(q->geometry()); + updateRegion += QRect(oldPos, olds); + q->parentWidget()->d_func()->invalidateBuffer(updateRegion); + } else if (isMove && !isResize) { moveRect(QRect(oldPos, olds), x - oldPos.x(), y - oldPos.y()); - else + } else { invalidateBuffer_resizeHelper(oldPos, olds); + } } } @@ -938,6 +944,23 @@ void QWidgetPrivate::createTLSysExtra() void QWidgetPrivate::deleteTLSysExtra() { if (extra && extra->topextra) { + //the qplatformbackingstore may hold a reference to the window, so the backingstore + //needs to be deleted first. If the backingstore holds GL resources, we need to + // make the context current here, since the platform bs does not have a reference + // to the widget. + +#ifndef QT_NO_OPENGL + if (textureChildSeen && extra->topextra->shareContext) + extra->topextra->shareContext->makeCurrent(extra->topextra->window); +#endif + extra->topextra->backingStoreTracker.destroy(); + delete extra->topextra->backingStore; + extra->topextra->backingStore = 0; +#ifndef QT_NO_OPENGL + if (textureChildSeen && extra->topextra->shareContext) + extra->topextra->shareContext->doneCurrent(); +#endif + //the toplevel might have a context with a "qglcontext associated with it. We need to //delete the qglcontext before we delete the qplatformopenglcontext. //One unfortunate thing about this is that we potentially create a glContext just to @@ -949,10 +972,10 @@ void QWidgetPrivate::deleteTLSysExtra() delete extra->topextra->window; extra->topextra->window = 0; - extra->topextra->backingStoreTracker.destroy(); - 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..221e6825ed 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> @@ -71,11 +73,16 @@ extern QRegion qt_dirtyRegion(QWidget *); * \a tlwOffset is the position of the top level widget relative to the window surface. * \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) +void QWidgetBackingStore::qt_flush(QWidget *widget, const QRegion ®ion, QBackingStore *backingStore, + QWidget *tlw, const QPoint &tlwOffset, QPlatformTextureList *widgetTextures) { - Q_ASSERT(widget); +#ifdef QT_NO_OPENGL + Q_UNUSED(widgetTextures); Q_ASSERT(!region.isEmpty()); +#else + Q_ASSERT(!region.isEmpty() || (widgetTextures && widgetTextures->count())); +#endif + Q_ASSERT(widget); 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, tlw->d_func()->shareContext()); 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,16 +443,21 @@ QRegion QWidgetBackingStore::staticContents(QWidget *parent, const QRect &within return region; } -static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately) +void QWidgetBackingStore::sendUpdateRequest(QWidget *widget, UpdateTime updateTime) { if (!widget) return; - if (updateImmediately) { + switch (updateTime) { + case UpdateLater: + updateRequestSent = true; + QApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority); + break; + case UpdateNow: { QEvent event(QEvent::UpdateRequest); QApplication::sendEvent(widget, &event); - } else { - QApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority); + break; + } } } @@ -447,17 +465,17 @@ static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately) Marks the region of the widget as dirty (if not already marked as dirty) and posts an UpdateRequest event to the top-level widget (if not already posted). - If updateImmediately is true, the event is sent immediately instead of posted. + If updateTime is UpdateNow, the event is sent immediately instead of posted. - If invalidateBuffer is true, all widgets intersecting with the region will be dirty. + If bufferState is BufferInvalid, all widgets intersecting with the region will be dirty. If the widget paints directly on screen, the event is sent to the widget - instead of the top-level widget, and invalidateBuffer is completely ignored. + instead of the top-level widget, and bufferState is completely ignored. ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). */ -void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool updateImmediately, - bool invalidateBuffer) +void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, + UpdateTime updateTime, BufferState bufferState) { Q_ASSERT(tlw->d_func()->extra); Q_ASSERT(tlw->d_func()->extra->topextra); @@ -473,51 +491,59 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up if (widget->d_func()->paintOnScreen()) { if (widget->d_func()->dirty.isEmpty()) { widget->d_func()->dirty = rgn; - sendUpdateRequest(widget, updateImmediately); + sendUpdateRequest(widget, updateTime); return; } else if (qt_region_strictContains(widget->d_func()->dirty, widget->rect())) { - if (updateImmediately) - sendUpdateRequest(widget, updateImmediately); + if (updateTime == UpdateNow) + sendUpdateRequest(widget, updateTime); return; // Already dirty. } const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty(); widget->d_func()->dirty += rgn; - if (!eventAlreadyPosted || updateImmediately) - sendUpdateRequest(widget, updateImmediately); + if (!eventAlreadyPosted || updateTime == UpdateNow) + sendUpdateRequest(widget, updateTime); return; } + //### FIXME fullUpdatePending seems to be always false???? if (fullUpdatePending) { - if (updateImmediately) - sendUpdateRequest(tlw, updateImmediately); + if (updateTime == UpdateNow) + sendUpdateRequest(tlw, updateTime); return; } const QPoint offset = widget->mapTo(tlw, QPoint()); + + if (QWidgetPrivate::get(widget)->renderToTexture) { + if (!updateRequestSent || updateTime == UpdateNow) + sendUpdateRequest(tlw, updateTime); + return; + } + const QRect widgetRect = widget->d_func()->effectiveRectFor(widget->rect()); if (qt_region_strictContains(dirty, widgetRect.translated(offset))) { - if (updateImmediately) - sendUpdateRequest(tlw, updateImmediately); + if (updateTime == UpdateNow) + sendUpdateRequest(tlw, updateTime); return; // Already dirty. } - if (invalidateBuffer) { - const bool eventAlreadyPosted = !dirty.isEmpty(); + if (bufferState == BufferInvalid) { + const bool eventAlreadyPosted = !dirty.isEmpty() || updateRequestSent; #ifndef QT_NO_GRAPHICSEFFECT if (widget->d_func()->graphicsEffect) dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()).translated(offset); else #endif //QT_NO_GRAPHICSEFFECT dirty += rgn.translated(offset); - if (!eventAlreadyPosted || updateImmediately) - sendUpdateRequest(tlw, updateImmediately); + if (!eventAlreadyPosted || updateTime == UpdateNow) + sendUpdateRequest(tlw, updateTime); return; } if (dirtyWidgets.isEmpty()) { addDirtyWidget(widget, rgn); - sendUpdateRequest(tlw, updateImmediately); + sendUpdateRequest(tlw, updateTime); return; } @@ -534,8 +560,8 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up addDirtyWidget(widget, rgn); } - if (updateImmediately) - sendUpdateRequest(tlw, updateImmediately); + if (updateTime == UpdateNow) + sendUpdateRequest(tlw, updateTime); } /*! @@ -545,8 +571,8 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). */ -void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool updateImmediately, - bool invalidateBuffer) +void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, + UpdateTime updateTime, BufferState bufferState) { Q_ASSERT(tlw->d_func()->extra); Q_ASSERT(tlw->d_func()->extra->topextra); @@ -562,46 +588,53 @@ void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool upd if (widget->d_func()->paintOnScreen()) { if (widget->d_func()->dirty.isEmpty()) { widget->d_func()->dirty = QRegion(rect); - sendUpdateRequest(widget, updateImmediately); + sendUpdateRequest(widget, updateTime); return; } else if (qt_region_strictContains(widget->d_func()->dirty, rect)) { - if (updateImmediately) - sendUpdateRequest(widget, updateImmediately); + if (updateTime == UpdateNow) + sendUpdateRequest(widget, updateTime); return; // Already dirty. } const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty(); widget->d_func()->dirty += rect; - if (!eventAlreadyPosted || updateImmediately) - sendUpdateRequest(widget, updateImmediately); + if (!eventAlreadyPosted || updateTime == UpdateNow) + sendUpdateRequest(widget, updateTime); return; } if (fullUpdatePending) { - if (updateImmediately) - sendUpdateRequest(tlw, updateImmediately); + if (updateTime == UpdateNow) + sendUpdateRequest(tlw, updateTime); + return; + } + + if (QWidgetPrivate::get(widget)->renderToTexture) { + if (!updateRequestSent || updateTime == UpdateNow) + sendUpdateRequest(tlw, updateTime); return; } + const QRect widgetRect = widget->d_func()->effectiveRectFor(rect); const QRect translatedRect(widgetRect.translated(widget->mapTo(tlw, QPoint()))); if (qt_region_strictContains(dirty, translatedRect)) { - if (updateImmediately) - sendUpdateRequest(tlw, updateImmediately); + if (updateTime == UpdateNow) + sendUpdateRequest(tlw, updateTime); return; // Already dirty } - if (invalidateBuffer) { + if (bufferState == BufferInvalid) { const bool eventAlreadyPosted = !dirty.isEmpty(); dirty += translatedRect; - if (!eventAlreadyPosted || updateImmediately) - sendUpdateRequest(tlw, updateImmediately); + if (!eventAlreadyPosted || updateTime == UpdateNow) + sendUpdateRequest(tlw, updateTime); return; } if (dirtyWidgets.isEmpty()) { addDirtyWidget(widget, rect); - sendUpdateRequest(tlw, updateImmediately); + sendUpdateRequest(tlw, updateTime); return; } @@ -612,8 +645,8 @@ void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool upd addDirtyWidget(widget, rect); } - if (updateImmediately) - sendUpdateRequest(tlw, updateImmediately); + if (updateTime == UpdateNow) + sendUpdateRequest(tlw, updateTime); } /*! @@ -703,7 +736,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); @@ -717,8 +755,9 @@ QWidgetBackingStore::~QWidgetBackingStore() for (int c = 0; c < dirtyWidgets.size(); ++c) { resetWidget(dirtyWidgets.at(c)); } - +#ifndef QT_NO_OPENGL delete dirtyOnScreenWidgets; +#endif dirtyOnScreenWidgets = 0; } @@ -892,17 +931,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); + if (!isDirty() && store->size().isValid()) { + qt_flush(exposedWidget, exposedRegion, store, tlw, tlwOffset, widgetTextures); return; } @@ -910,14 +949,50 @@ 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); + } +} + +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(); +} +#endif // QT_NO_OPENGL + /*! Synchronizes the backing store, i.e. dirty areas are repainted and flushed. */ 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,14 +1010,32 @@ void QWidgetBackingStore::sync() return; } +#ifndef QT_NO_OPENGL + 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; + } +#endif + + 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) { - if (hasStaticContents()) { + if (hasStaticContents() && !store->size().isEmpty() ) { // Repaint existing dirty area and newly visible area. const QRect clipRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height()); const QRegion staticRegion(staticContents(0, clipRect)); @@ -1018,7 +1111,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 +1133,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 +1147,7 @@ void QWidgetBackingStore::sync() for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) resetWidget(opaqueNonOverlappedWidgets[i]); dirty = QRegion(); + updateRequestSent = false; return; } @@ -1053,6 +1156,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 +1197,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); 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); + } +#endif return; + } for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) { QWidget *w = dirtyOnScreenWidgets->at(i); @@ -1239,7 +1350,8 @@ void QWidgetPrivate::invalidateBuffer(const QRegion &rgn) if (wrgn.isEmpty()) return; - tlwExtra->backingStoreTracker->markDirty(wrgn, q, false, true); + tlwExtra->backingStoreTracker->markDirty(wrgn, q, + QWidgetBackingStore::UpdateLater, QWidgetBackingStore::BufferInvalid); } /*! @@ -1263,7 +1375,8 @@ void QWidgetPrivate::invalidateBuffer(const QRect &rect) return; if (graphicsEffect || !extra || !extra->hasMask) { - tlwExtra->backingStoreTracker->markDirty(wRect, q, false, true); + tlwExtra->backingStoreTracker->markDirty(wRect, q, + QWidgetBackingStore::UpdateLater, QWidgetBackingStore::BufferInvalid); return; } @@ -1272,7 +1385,8 @@ void QWidgetPrivate::invalidateBuffer(const QRect &rect) if (wRgn.isEmpty()) return; - tlwExtra->backingStoreTracker->markDirty(wRgn, q, false, true); + tlwExtra->backingStoreTracker->markDirty(wRgn, q, + QWidgetBackingStore::UpdateLater, QWidgetBackingStore::BufferInvalid); } void QWidgetPrivate::repaint_sys(const QRegion &rgn) diff --git a/src/widgets/kernel/qwidgetbackingstore_p.h b/src/widgets/kernel/qwidgetbackingstore_p.h index b6c3e13cb0..473e9deef4 100644 --- a/src/widgets/kernel/qwidgetbackingstore_p.h +++ b/src/widgets/kernel/qwidgetbackingstore_p.h @@ -60,6 +60,10 @@ QT_BEGIN_NAMESPACE +class QPlatformTextureList; +class QPlatformTextureListWatcher; +class QWidgetBackingStore; + struct BeginPaintInfo { inline BeginPaintInfo() : wasFlushed(0), nothingToPaint(0), backingStoreRecreated(0) {} uint wasFlushed : 1; @@ -67,9 +71,38 @@ struct BeginPaintInfo { uint backingStoreRecreated : 1; }; +#ifndef QT_NO_OPENGL +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; +}; +#endif + class Q_AUTOTEST_EXPORT QWidgetBackingStore { public: + enum UpdateTime { + UpdateNow, + UpdateLater + }; + + enum BufferState{ + BufferValid, + BufferInvalid + }; + QWidgetBackingStore(QWidget *t); ~QWidgetBackingStore(); @@ -89,10 +122,10 @@ public: } // ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). - void markDirty(const QRegion &rgn, QWidget *widget, bool updateImmediately = false, - bool invalidateBuffer = false); - void markDirty(const QRect &rect, QWidget *widget, bool updateImmediately = false, - bool invalidateBuffer = false); + void markDirty(const QRegion &rgn, QWidget *widget, UpdateTime updateTime = UpdateLater, + BufferState bufferState = BufferValid); + void markDirty(const QRect &rect, QWidget *widget, UpdateTime updateTime = UpdateLater, + BufferState bufferState = BufferValid); private: QWidget *tlw; @@ -102,14 +135,24 @@ 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, UpdateTime updateTime); + static bool flushPaint(QWidget *widget, const QRegion &rgn); static void unflushPaint(QWidget *widget, const QRegion &rgn); + static void qt_flush(QWidget *widget, const QRegion ®ion, QBackingStore *backingStore, + QWidget *tlw, const QPoint &tlwOffset, + QPlatformTextureList *widgetTextures = 0); + 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..ef138267bb 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 @@ -58,6 +59,7 @@ Q_WIDGETS_EXPORT extern bool qt_tab_all_widgets(); QWidget *qt_button_down = 0; // widget got last button-down static QWidget *qt_tablet_target = 0; +static QWidget *qt_tablet_target_window = 0; // popup control QWidget *qt_popup_down = 0; // popup that contains the pressed widget @@ -91,13 +93,22 @@ 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); + connect(this, SIGNAL(screenChanged(QScreen*)), this, SLOT(repaintWindow())); } QWidgetWindow::~QWidgetWindow() { - if (m_widget == qt_tablet_target) + if (m_widget == qt_tablet_target_window) { qt_tablet_target = 0; + qt_tablet_target_window = 0; + } } #ifndef QT_NO_ACCESSIBILITY @@ -400,6 +411,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event) widgetPos = receiver->mapFromGlobal(event->globalPos()); QWidget *alien = m_widget->childAt(m_widget->mapFromGlobal(event->globalPos())); QMouseEvent e(event->type(), widgetPos, event->windowPos(), event->screenPos(), event->button(), event->buttons(), event->modifiers()); + QGuiApplicationPrivate::setMouseEventSource(&e, QGuiApplicationPrivate::mouseEventSource(event)); e.setTimestamp(event->timestamp()); QApplicationPrivate::sendMouseEvent(receiver, &e, alien, m_widget, &qt_button_down, qt_last_mouse_receiver); } else { @@ -435,6 +447,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event) if (win && win->geometry().contains(event->globalPos())) { const QPoint localPos = win->mapFromGlobal(event->globalPos()); QMouseEvent e(QEvent::MouseButtonPress, localPos, localPos, event->globalPos(), event->button(), event->buttons(), event->modifiers()); + QGuiApplicationPrivate::setMouseEventSource(&e, QGuiApplicationPrivate::mouseEventSource(event)); e.setTimestamp(event->timestamp()); QApplication::sendSpontaneousEvent(win, &e); } @@ -473,7 +486,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 +497,18 @@ 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()); + QGuiApplicationPrivate::setMouseEventSource(&translated, QGuiApplicationPrivate::mouseEventSource(event)); + 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 +561,37 @@ void QWidgetWindow::updateGeometry() m_widget->data->fstrut_dirty = false; } +// Invalidates the backing store buffer and repaints immediately. +// ### Qt 5.4: replace with QUpdateWindowRequestEvent. +void QWidgetWindow::repaintWindow() +{ + if (!m_widget->isVisible() || !m_widget->updatesEnabled()) + return; + + QTLWExtra *tlwExtra = m_widget->window()->d_func()->maybeTopData(); + if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) + tlwExtra->backingStoreTracker->markDirty(m_widget->rect(), m_widget, + QWidgetBackingStore::UpdateNow, QWidgetBackingStore::BufferInvalid); +} + +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 +704,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 +737,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 +755,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; @@ -742,6 +791,7 @@ void QWidgetWindow::handleTabletEvent(QTabletEvent *event) widget = m_widget; qt_tablet_target = widget; + qt_tablet_target_window = m_widget; } if (qt_tablet_target) { @@ -754,8 +804,10 @@ void QWidgetWindow::handleTabletEvent(QTabletEvent *event) QGuiApplication::sendSpontaneousEvent(qt_tablet_target, &ev); } - if (event->type() == QEvent::TabletRelease) + if (event->type() == QEvent::TabletRelease) { qt_tablet_target = 0; + qt_tablet_target_window = 0; + } } #endif // QT_NO_TABLETEVENT diff --git a/src/widgets/kernel/qwidgetwindow_qpa_p.h b/src/widgets/kernel/qwidgetwindow_qpa_p.h index ffde44dd27..06ba8ea646 100644 --- a/src/widgets/kernel/qwidgetwindow_qpa_p.h +++ b/src/widgets/kernel/qwidgetwindow_qpa_p.h @@ -101,9 +101,11 @@ protected: private slots: void updateObjectName(); + void repaintWindow(); private: void updateGeometry(); + void updateNormalGeometry(); enum FocusWidgets { FirstFocusWidget, diff --git a/src/widgets/kernel/qwindowcontainer.cpp b/src/widgets/kernel/qwindowcontainer.cpp index a4b3caf78d..4618e1c91d 100644 --- a/src/widgets/kernel/qwindowcontainer.cpp +++ b/src/widgets/kernel/qwindowcontainer.cpp @@ -197,7 +197,7 @@ QWindowContainer::QWindowContainer(QWindow *embeddedWindow, QWidget *parent, Qt: d->window = embeddedWindow; d->window->setParent(&d->fakeParent); - connect(QGuiApplication::instance(), SIGNAL(focusWindowChanged(QWindow *)), this, SLOT(focusWindowChanged(QWindow *))); + connect(QGuiApplication::instance(), SIGNAL(focusWindowChanged(QWindow*)), this, SLOT(focusWindowChanged(QWindow*))); } QWindow *QWindowContainer::containedWindow() const 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 } |