diff options
Diffstat (limited to 'src/quick/items/qquickwindow.cpp')
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 320 |
1 files changed, 261 insertions, 59 deletions
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 4789314e01..619c72afb8 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -72,6 +72,10 @@ QT_BEGIN_NAMESPACE +extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha); + +bool QQuickWindowPrivate::defaultAlphaBuffer(0); + void QQuickWindowPrivate::updateFocusItemTransform() { Q_Q(QQuickWindow); @@ -85,44 +89,49 @@ void QQuickWindowPrivate::updateFocusItemTransform() #endif } - class QQuickWindowIncubationController : public QObject, public QQmlIncubationController { Q_OBJECT public: - QQuickWindowIncubationController(const QQuickWindow *window) - : m_window(QQuickWindowPrivate::get(const_cast<QQuickWindow *>(window))) + QQuickWindowIncubationController(QSGRenderLoop *loop) + : m_renderLoop(loop), m_timer(0) { // Allow incubation for 1/3 of a frame. m_incubation_time = qMax(1, int(1000 / QGuiApplication::primaryScreen()->refreshRate()) / 3); - m_animation_driver = m_window->windowManager->animationDriver(); + m_animation_driver = m_renderLoop->animationDriver(); if (m_animation_driver) { connect(m_animation_driver, SIGNAL(stopped()), this, SLOT(animationStopped())); - connect(window, SIGNAL(frameSwapped()), this, SLOT(incubate())); + connect(m_renderLoop, SIGNAL(timeToIncubate()), this, SLOT(incubate())); } } protected: - virtual bool event(QEvent *e) + void timerEvent(QTimerEvent *) { - if (e->type() == QEvent::User) { - incubate(); - return true; + killTimer(m_timer); + m_timer = 0; + incubate(); + } + + void incubateAgain() { + if (m_timer == 0) { + // Wait for a while before processing the next batch. Using a + // timer to avoid starvation of system events. + m_timer = startTimer(m_incubation_time); } - return QObject::event(e); } public slots: void incubate() { if (incubatingObjectCount()) { - if (m_animation_driver && m_animation_driver->isRunning()) { + if (m_renderLoop->interleaveIncubation()) { incubateFor(m_incubation_time); } else { incubateFor(m_incubation_time * 2); if (incubatingObjectCount()) - QCoreApplication::postEvent(this, new QEvent(QEvent::User)); + incubateAgain(); } } } @@ -132,14 +141,15 @@ public slots: protected: virtual void incubatingObjectCountChanged(int count) { - if (count && (!m_animation_driver || !m_animation_driver->isRunning())) - QCoreApplication::postEvent(this, new QEvent(QEvent::User)); + if (count && !m_renderLoop->interleaveIncubation()) + incubateAgain(); } private: - QQuickWindowPrivate *m_window; + QSGRenderLoop *m_renderLoop; int m_incubation_time; QAnimationDriver *m_animation_driver; + int m_timer; }; #include "qquickwindow.moc" @@ -149,8 +159,6 @@ private: /*! Returns an accessibility interface for this window, or 0 if such an interface cannot be created. - - \warning The caller is responsible for deleting the returned interface. */ QAccessibleInterface *QQuickWindow::accessibleRoot() const { @@ -258,29 +266,6 @@ void QQuickWindowPrivate::polishItems() updateFocusItemTransform(); } -/** - * This parameter enables that this window can be rendered without - * being shown on screen. This feature is very limited in what it supports. - * - * For this feature to be useful one needs to hook into beforeRender() - * and set the render target. - * - */ -void QQuickWindowPrivate::setRenderWithoutShowing(bool render) -{ - if (render == renderWithoutShowing) - return; - - Q_Q(QQuickWindow); - renderWithoutShowing = render; - - if (render) - windowManager->show(q); - else - windowManager->hide(q); -} - - /*! * Schedules the window to render another frame. * @@ -361,7 +346,6 @@ QQuickWindowPrivate::QQuickWindowPrivate() #endif , touchMouseId(-1) , touchMousePressTimestamp(0) - , renderWithoutShowing(false) , dirtyItemList(0) , context(0) , renderer(0) @@ -371,6 +355,7 @@ QQuickWindowPrivate::QQuickWindowPrivate() , persistentGLContext(true) , persistentSceneGraph(true) , lastWheelEventAccepted(false) + , componentCompleted(true) , renderTarget(0) , renderTargetId(0) , incubationController(0) @@ -414,7 +399,10 @@ void QQuickWindowPrivate::init(QQuickWindow *c) QQmlListProperty<QObject> QQuickWindowPrivate::data() { initContentItem(); - return QQuickItemPrivate::get(contentItem)->data(); + return QQmlListProperty<QObject>(q_func(), 0, QQuickWindowPrivate::data_append, + QQuickWindowPrivate::data_count, + QQuickWindowPrivate::data_at, + QQuickWindowPrivate::data_clear); } void QQuickWindowPrivate::initContentItem() @@ -432,7 +420,7 @@ static QMouseEvent *touchToMouseEvent(QEvent::Type type, const QTouchEvent::Touc { // The touch point local position and velocity are not yet transformed. QMouseEvent *me = new QMouseEvent(type, transformNeeded ? item->mapFromScene(p.scenePos()) : p.pos(), p.scenePos(), p.screenPos(), - Qt::LeftButton, Qt::LeftButton, event->modifiers()); + Qt::LeftButton, (type == QEvent::MouseButtonRelease ? Qt::NoButton : Qt::LeftButton), event->modifiers()); me->setAccepted(true); me->setTimestamp(event->timestamp()); QVector2D transformedVelocity = p.velocity(); @@ -838,15 +826,34 @@ void QQuickWindowPrivate::cleanup(QSGNode *n) \ingroup qtquick-visual \brief Creates a new top-level window - The Window object creates a new top-level window for a QtQuick scene. It automatically sets up the - window for use with QtQuick 2.x graphical types. + The Window object creates a new top-level window for a Qt Quick scene. It automatically sets up the + window for use with \c {QtQuick 2.x} graphical types. To use this type, you will need to import the module with the following line: \code import QtQuick.Window 2.1 \endcode - Restricting this import will allow you to have a QML environment without access to window system features. + Omitting this import will allow you to have a QML environment without + access to window system features. + + A Window can be declared inside an Item or inside another Window; in that + case the inner Window will automatically become "transient for" the outer + Window: that is, most platforms will show it centered upon the outer window + by default, and there may be other platform-dependent behaviors, depending + also on the \l flags. If the nested window is intended to be a dialog in + your application, you should also set \l flags to Qt.Dialog, because some + window managers will not provide the centering behavior without that flag. + You can also declare multiple windows inside a top-level \l QtObject, in which + case the windows will have no transient relationship. + + Alternatively you can set or bind \l x and \l y to position the Window + explicitly on the screen. + + When the user attempts to close a window, the \a closing signal will be + emitted. You can force the window to stay open (for example to prompt the + user to save changes) by writing an onClosing handler and setting + close.accepted = false. */ /*! \class QQuickWindow @@ -1094,7 +1101,10 @@ QQuickItem *QQuickWindow::contentItem() const } /*! - Returns the item which currently has active focus. + \property QQuickWindow::activeFocusItem + + \brief The item which currently has active focus or \c null if there is + no item with active focus. */ QQuickItem *QQuickWindow::activeFocusItem() const { @@ -1178,6 +1188,14 @@ bool QQuickWindow::event(QEvent *e) case QEvent::WindowDeactivate: contentItem()->windowDeactivateEvent(); break; + case QEvent::Close: { + // TOOD Qt 6 (binary incompatible) + // closeEvent(static_cast<QCloseEvent *>(e)); + QQuickCloseEvent qev; + qev.setAccepted(e->isAccepted()); + emit closing(&qev); + e->setAccepted(qev.isAccepted()); + } break; case QEvent::FocusAboutToChange: #ifndef QT_NO_IM if (d->activeFocusItem) @@ -2037,16 +2055,68 @@ bool QQuickWindowPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent return overThreshold; } +/*! + \qmlproperty list<Object> QtQuick.Window2::Window::data + \default + + The data property allows you to freely mix visual children, resources + and other Windows in a Window. + + If you assign another Window to the data list, the nested window will + become "transient for" the outer Window. + + If you assign an \l Item to the data list, it becomes a child of the + Window's \l contentItem, so that it appears inside the window. The item's + parent will be the window's contentItem, which is the root of the Item + ownership tree within that Window. + + If you assign any other object type, it is added as a resource. + + It should not generally be necessary to refer to the \c data property, + as it is the default property for Window and thus all child items are + automatically assigned to this property. + + \sa QWindow::transientParent() + */ + +void QQuickWindowPrivate::data_append(QQmlListProperty<QObject> *property, QObject *o) +{ + if (!o) + return; + QQuickWindow *that = static_cast<QQuickWindow *>(property->object); + if (QQuickWindow *window = qmlobject_cast<QQuickWindow *>(o)) + window->setTransientParent(that); + QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(that->contentItem())->data(); + itemProperty.append(&itemProperty, o); +} + +int QQuickWindowPrivate::data_count(QQmlListProperty<QObject> *property) +{ + QQuickWindow *win = static_cast<QQuickWindow*>(property->object); + if (!win || !win->contentItem() || !QQuickItemPrivate::get(win->contentItem())->data().count) + return 0; + QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(win->contentItem())->data(); + return itemProperty.count(&itemProperty); +} + +QObject *QQuickWindowPrivate::data_at(QQmlListProperty<QObject> *property, int i) +{ + QQuickWindow *win = static_cast<QQuickWindow*>(property->object); + QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(win->contentItem())->data(); + return itemProperty.at(&itemProperty, i); +} + +void QQuickWindowPrivate::data_clear(QQmlListProperty<QObject> *property) +{ + QQuickWindow *win = static_cast<QQuickWindow*>(property->object); + QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(win->contentItem())->data(); + itemProperty.clear(&itemProperty); +} + bool QQuickWindowPrivate::isRenderable() const { - const QQuickWindow *q = q_func(); - QRect geom = q->geometry(); - if (geom.width() <= 0 || geom.height() <= 0) - return false; - // Change to be applied after the visibility property is integrated in qtbase: -// return visibility != QWindow::Hidden || (renderWithoutShowing && platformWindow); - // Temporary version which is implementation-agnostic but slightly less efficient: - return q->isVisible() || (renderWithoutShowing && platformWindow); + Q_Q(const QQuickWindow); + return q->isExposed() && q->isVisible() && q->geometry().isValid(); } /*! @@ -2456,6 +2526,13 @@ void QQuickWindow::cleanupSceneGraph() d->renderer = 0; } +void QQuickWindow::setTransientParent_helper(QQuickWindow *window) +{ + setTransientParent(window); + disconnect(sender(), SIGNAL(windowChanged(QQuickWindow*)), + this, SLOT(setTransientParent_helper(QQuickWindow*))); +} + /*! Returns the opengl context used for rendering. @@ -2503,6 +2580,57 @@ QOpenGLContext *QQuickWindow::openglContext() const This signal will be emitted from the scene graph rendering thread. */ +/*! + \class QQuickCloseEvent + \internal + \since QtQuick 2.1 + + \inmodule QtQuick.Window + + \brief Notification that a \l QQuickWindow is about to be closed +*/ +/*! + \qmltype CloseEvent + \instantiates QQuickCloseEvent + \inqmlmodule QtQuick.Window 2 + \ingroup qtquick-visual + \brief Notification that a \l Window is about to be closed + \since Qt 5.1 + + Notification that a window is about to be closed by the windowing system + (e.g. the user clicked the titlebar close button). The CloseEvent contains + an accepted property which can be set to false to abort closing the window. + + \sa Window.closing() +*/ + +/*! + \qmlproperty bool QtQuick.Window2::CloseEvent::accepted + + This property indicates whether the application will allow the user to + close the window. It is true by default. +*/ + +/*! + \fn void QQuickWindow::closing() + \since QtQuick 2.1 + + This signal is emitted when the window receives a QCloseEvent from the + windowing system. +*/ + +/*! + \qmlsignal QtQuick.Window2::closing(CloseEvent close) + \since Qt 5.1 + + This signal is emitted when the user tries to close the window. + + This signal includes a closeEvent parameter. The \a close \l accepted + property is true by default so that the window is allowed to close; but you + can implement an onClosing() handler and set close.accepted = false if + you need to do something else before the window can be closed. + */ + /*! Sets the render target for this window to be \a fbo. @@ -2600,7 +2728,10 @@ QOpenGLFramebufferObject *QQuickWindow::renderTarget() const /*! Grabs the contents of the window and returns it as an image. - This function might not work if the window is not visible. + It is possible to call the grabWindow() function when the window is not + visible. This requires that the window is \l{QWindow::create} {created} + and has a valid size and that no other QQuickWindow instances are rendering + in the same process. \warning Calling this function will cause performance problems. @@ -2609,6 +2740,36 @@ QOpenGLFramebufferObject *QQuickWindow::renderTarget() const QImage QQuickWindow::grabWindow() { Q_D(QQuickWindow); + if (!isVisible()) { + + if (d->context->isReady()) { + qWarning("QQuickWindow::grabWindow: scene graph already in use"); + return QImage(); + } + + if (!handle() || !size().isValid()) { + qWarning("QQuickWindow::grabWindow: window must be created and have a valid size"); + return QImage(); + } + + QOpenGLContext context; + context.setFormat(requestedFormat()); + context.create(); + context.makeCurrent(this); + d->context->initialize(&context); + + d->polishItems(); + d->syncSceneGraph(); + d->renderSceneGraph(size()); + + QImage image = qt_gl_read_framebuffer(size(), false, false); + d->cleanupNodesOnShutdown(); + d->context->invalidate(); + context.doneCurrent(); + + return image; + } + return d->windowManager->grab(this); } @@ -2625,7 +2786,7 @@ QQmlIncubationController *QQuickWindow::incubationController() const Q_D(const QQuickWindow); if (!d->incubationController) - d->incubationController = new QQuickWindowIncubationController(this); + d->incubationController = new QQuickWindowIncubationController(d->windowManager); return d->incubationController; } @@ -2817,7 +2978,7 @@ QSGTexture *QQuickWindow::createTextureFromId(uint id, const QSize &size, Create Setting the clear color has no effect when clearing is disabled. By default, the clear color is white. - \sa setClearBeforeRendering() + \sa setClearBeforeRendering(), setDefaultAlphaBuffer() */ void QQuickWindow::setColor(const QColor &color) @@ -2827,7 +2988,7 @@ void QQuickWindow::setColor(const QColor &color) return; if (color.alpha() != d->clearColor.alpha()) { - QSurfaceFormat fmt = format(); + QSurfaceFormat fmt = requestedFormat(); if (color.alpha() < 255) fmt.setAlphaBufferSize(8); else @@ -2845,6 +3006,31 @@ QColor QQuickWindow::color() const } /*! + \brief Returns whether to use alpha transparency on newly created windows. + + \since Qt 5.1 + \sa setDefaultAlphaBuffer() + */ +bool QQuickWindow::hasDefaultAlphaBuffer() +{ + return QQuickWindowPrivate::defaultAlphaBuffer; +} + +/*! + \brief \a useAlpha specifies whether to use alpha transparency on newly created windows. + \since Qt 5.1 + + In any application which expects to create translucent windows, it's + necessary to set this to true before creating the first QQuickWindow, + because all windows will share the same \l QOpenGLContext. The default + value is false. + */ +void QQuickWindow::setDefaultAlphaBuffer(bool useAlpha) +{ + QQuickWindowPrivate::defaultAlphaBuffer = useAlpha; +} + +/*! \qmlproperty string QtQuick.Window2::Window::title The window's title in the windowing system. @@ -2994,6 +3180,22 @@ QColor QQuickWindow::color() const no item with active focus. */ +/*! + \qmlproperty QtQuick.Window2::Window::active + \since Qt 5.1 + + The active status of the window. + + \sa requestActivate() + */ + +/*! + \qmlmethod QtQuick2::Window::requestActivate() + \since QtQuick 2.1 + + Requests the window to be activated, i.e. receive keyboard focus. + */ + #include "moc_qquickwindow.cpp" QT_END_NAMESPACE |