aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@theqtcompany.com>2014-10-29 10:48:54 +0100
committerFrederik Gladhorn <frederik.gladhorn@theqtcompany.com>2014-10-29 10:48:54 +0100
commit4e33b069c426c975319d91e11223114fd0d8ad40 (patch)
treed73e1251bc313b7303fdb000c0789cdfb4c7bb1f /src/quick
parentd9e70d1a49af347f79db7e64bdd8e2e8083a77b5 (diff)
parent05d8ffb4dff5e693967c8ee7cee6d6158eadccbd (diff)
Merge remote-tracking branch 'origin/5.4' into dev
Conflicts: src/quick/items/qquickaccessibleattached_p.h src/quick/items/qquickwindow.cpp src/quick/scenegraph/qsgthreadedrenderloop.cpp Change-Id: I8bf07487a75f9d1b0d6efa5914dd06875fc9654d
Diffstat (limited to 'src/quick')
-rw-r--r--src/quick/accessible/qaccessiblequickitem.cpp88
-rw-r--r--src/quick/accessible/qaccessiblequickitem_p.h3
-rw-r--r--src/quick/accessible/qaccessiblequickview.cpp86
-rw-r--r--src/quick/accessible/qaccessiblequickview_p.h2
-rw-r--r--src/quick/accessible/qqmlaccessible.cpp21
-rw-r--r--src/quick/accessible/qqmlaccessible_p.h2
-rw-r--r--src/quick/doc/qtquick.qdocconf3
-rw-r--r--src/quick/doc/src/concepts/input/focus.qdoc6
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp24
-rw-r--r--src/quick/items/qquickaccessibleattached.cpp97
-rw-r--r--src/quick/items/qquickaccessibleattached_p.h12
-rw-r--r--src/quick/items/qquickevents.cpp3
-rw-r--r--src/quick/items/qquickflickable.cpp18
-rw-r--r--src/quick/items/qquickframebufferobject.cpp23
-rw-r--r--src/quick/items/qquickimagebase.cpp2
-rw-r--r--src/quick/items/qquickitem.cpp40
-rw-r--r--src/quick/items/qquickitem_p.h4
-rw-r--r--src/quick/items/qquickpathview.cpp5
-rw-r--r--src/quick/items/qquickrendercontrol.cpp2
-rw-r--r--src/quick/items/qquickscreen.cpp18
-rw-r--r--src/quick/items/qquickscreen_p.h3
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp4
-rw-r--r--src/quick/items/qquickspriteengine.cpp4
-rw-r--r--src/quick/items/qquickspritesequence.cpp10
-rw-r--r--src/quick/items/qquicktext.cpp1
-rw-r--r--src/quick/items/qquicktextinput.cpp7
-rw-r--r--src/quick/items/qquickwindow.cpp27
-rw-r--r--src/quick/items/qquickwindow.h2
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp18
-rw-r--r--src/quick/scenegraph/qsgcontext.cpp36
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.cpp21
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp24
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp11
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp2
-rw-r--r--src/quick/scenegraph/shaders/styledtext.vert3
-rw-r--r--src/quick/scenegraph/shaders/styledtext_core.vert3
-rw-r--r--src/quick/scenegraph/shaders/textmask.vert3
-rw-r--r--src/quick/scenegraph/shaders/textmask_core.vert3
-rw-r--r--src/quick/util/qquickanimatorcontroller.cpp44
-rw-r--r--src/quick/util/qquickanimatorcontroller_p.h21
-rw-r--r--src/quick/util/qquickanimatorjob.cpp11
-rw-r--r--src/quick/util/qquickanimatorjob_p.h2
-rw-r--r--src/quick/util/qquickfontmetrics.cpp1
-rw-r--r--src/quick/util/qquicktextmetrics.cpp1
44 files changed, 474 insertions, 247 deletions
diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp
index c201076199..e13224f6fb 100644
--- a/src/quick/accessible/qaccessiblequickitem.cpp
+++ b/src/quick/accessible/qaccessiblequickitem.cpp
@@ -39,7 +39,6 @@
#include "QtQuick/private/qquicktext_p.h"
#include "QtQuick/private/qquickaccessibleattached_p.h"
#include "QtQuick/qquicktextdocument.h"
-
QT_BEGIN_NAMESPACE
#ifndef QT_NO_ACCESSIBILITY
@@ -82,19 +81,46 @@ bool QAccessibleQuickItem::clipsChildren() const
return static_cast<QQuickItem *>(item())->clip();
}
+QAccessibleInterface *QAccessibleQuickItem::childAt(int x, int y) const
+{
+ if (item()->clip()) {
+ if (!rect().contains(x, y))
+ return 0;
+ }
+
+ const QList<QQuickItem*> kids = accessibleUnignoredChildren(item(), true);
+ for (int i = kids.count() - 1; i >= 0; --i) {
+ QAccessibleInterface *childIface = QAccessible::queryAccessibleInterface(kids.at(i));
+ if (QAccessibleInterface *childChild = childIface->childAt(x, y))
+ return childChild;
+ if (childIface && !childIface->state().invisible) {
+ if (childIface->rect().contains(x, y))
+ return childIface;
+ }
+ }
+
+ return 0;
+}
+
QAccessibleInterface *QAccessibleQuickItem::parent() const
{
QQuickItem *parent = item()->parentItem();
+ QQuickWindow *window = item()->window();
+ QQuickItem *ci = window ? window->contentItem() : 0;
+ while (parent && !QQuickItemPrivate::get(parent)->isAccessible && parent != ci)
+ parent = parent->parentItem();
+
if (parent) {
- QQuickWindow *window = item()->window();
- // Jump out to the scene widget if the parent is the root item.
- // There are two root items, QQuickWindow::rootItem and
- // QQuickView::declarativeRoot. The former is the true root item,
- // but is not a part of the accessibility tree. Check if we hit
- // it here and return an interface for the scene instead.
- if (window && (parent == window->contentItem())) {
+ if (parent == ci) {
+ // Jump out to the scene widget if the parent is the root item.
+ // There are two root items, QQuickWindow::rootItem and
+ // QQuickView::declarativeRoot. The former is the true root item,
+ // but is not a part of the accessibility tree. Check if we hit
+ // it here and return an interface for the scene instead.
return QAccessible::queryAccessibleInterface(window);
} else {
+ while (parent && !parent->d_func()->isAccessible)
+ parent = parent->parentItem();
return QAccessible::queryAccessibleInterface(parent);
}
}
@@ -121,27 +147,31 @@ int QAccessibleQuickItem::indexOfChild(const QAccessibleInterface *iface) const
return kids.indexOf(static_cast<QQuickItem*>(iface->object()));
}
-QList<QQuickItem *> QAccessibleQuickItem::childItems() const
+static void unignoredChildren(QQuickItem *item, QList<QQuickItem *> *items, bool paintOrder)
{
- if ( role() == QAccessible::Button ||
- role() == QAccessible::CheckBox ||
- role() == QAccessible::RadioButton ||
- role() == QAccessible::SpinBox ||
- role() == QAccessible::EditableText ||
- role() == QAccessible::Slider ||
- role() == QAccessible::PageTab ||
- role() == QAccessible::ProgressBar)
- return QList<QQuickItem *>();
+ QList<QQuickItem*> childItems = paintOrder ? QQuickItemPrivate::get(item)->paintOrderChildItems()
+ : item->childItems();
+ Q_FOREACH (QQuickItem *child, childItems) {
+ if (QQuickItemPrivate::get(child)->isAccessible) {
+ items->append(child);
+ } else {
+ unignoredChildren(child, items, paintOrder);
+ }
+ }
+}
+QList<QQuickItem *> accessibleUnignoredChildren(QQuickItem *item, bool paintOrder)
+{
QList<QQuickItem *> items;
- Q_FOREACH (QQuickItem *child, item()->childItems()) {
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(child);
- if (itemPrivate->isAccessible)
- items.append(child);
- }
+ unignoredChildren(item, &items, paintOrder);
return items;
}
+QList<QQuickItem *> QAccessibleQuickItem::childItems() const
+{
+ return accessibleUnignoredChildren(item());
+}
+
QAccessible::State QAccessibleQuickItem::state() const
{
QQuickAccessibleAttached *attached = QQuickAccessibleAttached::attachedProperties(item());
@@ -186,16 +216,24 @@ QStringList QAccessibleQuickItem::actionNames() const
QStringList actions = QQmlAccessible::actionNames();
if (state().focusable)
actions.append(QAccessibleActionInterface::setFocusAction());
+
+ // ### The following can lead to duplicate action names. We'll fix that when we kill QQmlAccessible
+ if (QQuickAccessibleAttached *attached = QQuickAccessibleAttached::attachedProperties(item()))
+ attached->availableActions(&actions);
return actions;
}
void QAccessibleQuickItem::doAction(const QString &actionName)
{
+ bool accepted = false;
if (actionName == QAccessibleActionInterface::setFocusAction()) {
item()->forceActiveFocus();
- } else {
- QQmlAccessible::doAction(actionName);
+ accepted = true;
}
+ if (QQuickAccessibleAttached *attached = QQuickAccessibleAttached::attachedProperties(item()))
+ accepted = attached->doAction(actionName);
+ if (!accepted)
+ QQmlAccessible::doAction(actionName);
}
QStringList QAccessibleQuickItem::keyBindingsForAction(const QString &actionName) const
diff --git a/src/quick/accessible/qaccessiblequickitem_p.h b/src/quick/accessible/qaccessiblequickitem_p.h
index 5cf120a802..e8486721f3 100644
--- a/src/quick/accessible/qaccessiblequickitem_p.h
+++ b/src/quick/accessible/qaccessiblequickitem_p.h
@@ -53,6 +53,7 @@ public:
QRect viewRect() const;
bool clipsChildren() const;
+ QAccessibleInterface *childAt(int x, int y) const;
QAccessibleInterface *parent() const;
QAccessibleInterface *child(int index) const;
@@ -118,7 +119,7 @@ private:
};
QRect itemScreenRect(QQuickItem *item);
-
+QList<QQuickItem *> accessibleUnignoredChildren(QQuickItem *item, bool paintOrder = false);
#endif // QT_NO_ACCESSIBILITY
diff --git a/src/quick/accessible/qaccessiblequickview.cpp b/src/quick/accessible/qaccessiblequickview.cpp
index cfd62b877d..e3ee1d2722 100644
--- a/src/quick/accessible/qaccessiblequickview.cpp
+++ b/src/quick/accessible/qaccessiblequickview.cpp
@@ -50,19 +50,16 @@ QAccessibleQuickWindow::QAccessibleQuickWindow(QQuickWindow *object)
{
}
-QQuickItem *QAccessibleQuickWindow::rootItem() const
+QList<QQuickItem *> QAccessibleQuickWindow::rootItems() const
{
- if (QQuickItem *ci = window()->contentItem()) {
- const QList<QQuickItem *> &childItems = ci->childItems();
- if (!childItems.isEmpty())
- return childItems.first();
- }
- return 0;
+ if (QQuickItem *ci = window()->contentItem())
+ return accessibleUnignoredChildren(ci);
+ return QList<QQuickItem *>();
}
int QAccessibleQuickWindow::childCount() const
{
- return rootItem() ? 1 : 0;
+ return rootItems().count();
}
QAccessibleInterface *QAccessibleQuickWindow::parent() const
@@ -73,8 +70,9 @@ QAccessibleInterface *QAccessibleQuickWindow::parent() const
QAccessibleInterface *QAccessibleQuickWindow::child(int index) const
{
- if (index == 0)
- return QAccessible::queryAccessibleInterface(rootItem());
+ const QList<QQuickItem*> &kids = rootItems();
+ if (index >= 0 && index < kids.count())
+ return QAccessible::queryAccessibleInterface(kids.at(index));
return 0;
}
@@ -110,68 +108,34 @@ QString QAccessibleQuickWindow::text(QAccessible::Text text) const
return window()->title();
}
-
-/*!
- \internal
-
- Can also return \a item itself
- */
-static QQuickItem *childAt_helper(QQuickItem *item, int x, int y)
-{
- if (!item->isVisible() || !item->isEnabled())
- return 0;
-
- if (item->flags() & QQuickItem::ItemClipsChildrenToShape) {
- if (!itemScreenRect(item).contains(x, y))
- return 0;
- }
-
- QAccessibleInterface *accessibleInterface = QAccessible::queryAccessibleInterface(item);
- // this item has no Accessible attached property
- if (!accessibleInterface)
- return 0;
-
- if (accessibleInterface->childCount() == 0) {
- return (itemScreenRect(item).contains(x, y)) ? item : 0;
- }
-
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
-
- QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
- for (int i = children.count() - 1; i >= 0; --i) {
- QQuickItem *child = children.at(i);
- if (QQuickItem *childChild = childAt_helper(child, x, y))
- return childChild;
- }
-
- QRect screenRect = itemScreenRect(item);
-
- if (screenRect.contains(x, y))
- return item;
-
- return 0;
-}
-
QAccessibleInterface *QAccessibleQuickWindow::childAt(int x, int y) const
{
Q_ASSERT(window());
- QQuickItem *root = rootItem();
- if (root) {
- if (QQuickItem *item = childAt_helper(root, x, y))
- return QAccessible::queryAccessibleInterface(item);
- return QAccessible::queryAccessibleInterface(root);
+ for (int i = childCount() - 1; i >= 0; --i) {
+ QAccessibleInterface *childIface = child(i);
+ if (childIface && !childIface->state().invisible) {
+ if (QAccessibleInterface *iface = childIface->childAt(x, y))
+ return iface;
+ if (childIface->rect().contains(x, y))
+ return childIface;
+ }
}
return 0;
}
int QAccessibleQuickWindow::indexOfChild(const QAccessibleInterface *iface) const
{
+ int i = -1;
if (iface) {
- QQuickItem *declarativeRoot = rootItem();
- if (declarativeRoot == iface->object())
- return 0;
+ const QList<QQuickItem *> &roots = rootItems();
+ i = roots.count() - 1;
+ while (i >= 0) {
+ if (iface->object() == roots.at(i))
+ break;
+ --i;
+ }
}
- return -1;
+ return i;
}
QT_END_NAMESPACE
diff --git a/src/quick/accessible/qaccessiblequickview_p.h b/src/quick/accessible/qaccessiblequickview_p.h
index 44a3bc047b..f6da6ba25d 100644
--- a/src/quick/accessible/qaccessiblequickview_p.h
+++ b/src/quick/accessible/qaccessiblequickview_p.h
@@ -60,7 +60,7 @@ public:
private:
QQuickWindow *window() const { return static_cast<QQuickWindow*>(object()); }
- QQuickItem *rootItem() const;
+ QList<QQuickItem *> rootItems() const;
};
#endif // QT_NO_ACCESSIBILITY
diff --git a/src/quick/accessible/qqmlaccessible.cpp b/src/quick/accessible/qqmlaccessible.cpp
index 65d321d0a1..53eb6a7a0d 100644
--- a/src/quick/accessible/qqmlaccessible.cpp
+++ b/src/quick/accessible/qqmlaccessible.cpp
@@ -54,27 +54,6 @@ QQmlAccessible::~QQmlAccessible()
{
}
-QAccessibleInterface *QQmlAccessible::childAt(int x, int y) const
-{
- // Note that this function will disregard stacking order.
- // (QAccessibleQuickView::childAt() does this correctly and more efficient)
-
- // If the item clips its children, we can return early if the coordinate is outside its rect
- if (clipsChildren()) {
- if (!rect().contains(x, y))
- return 0;
- }
-
- for (int i = childCount() - 1; i >= 0; --i) {
- QAccessibleInterface *childIface = child(i);
- if (childIface && !childIface->state().invisible) {
- if (childIface->rect().contains(x, y))
- return childIface;
- }
- }
- return 0;
-}
-
QAccessible::State QQmlAccessible::state() const
{
QAccessible::State state;
diff --git a/src/quick/accessible/qqmlaccessible_p.h b/src/quick/accessible/qqmlaccessible_p.h
index 38e3dcff59..5948f06cb5 100644
--- a/src/quick/accessible/qqmlaccessible_p.h
+++ b/src/quick/accessible/qqmlaccessible_p.h
@@ -64,7 +64,6 @@ public:
void *interface_cast(QAccessible::InterfaceType t);
virtual QRect viewRect() const = 0;
- QAccessibleInterface *childAt(int, int) const;
QAccessible::State state() const;
QStringList actionNames() const;
@@ -72,7 +71,6 @@ public:
QStringList keyBindingsForAction(const QString &actionName) const;
protected:
- virtual bool clipsChildren() const = 0;
// For subclasses, use instantiateObject factory method outside the class.
QQmlAccessible(QObject *object);
};
diff --git a/src/quick/doc/qtquick.qdocconf b/src/quick/doc/qtquick.qdocconf
index d54e5feecb..41fe42777b 100644
--- a/src/quick/doc/qtquick.qdocconf
+++ b/src/quick/doc/qtquick.qdocconf
@@ -62,7 +62,8 @@ headerdirs += ../../plugins
sourcedirs += ../../plugins
#exclude certain directories
-excludedirs += ../../imports/models
+excludedirs += ../../imports/models \
+ ../../imports/statemachine
examples.fileextensions += "*.qm"
diff --git a/src/quick/doc/src/concepts/input/focus.qdoc b/src/quick/doc/src/concepts/input/focus.qdoc
index 748c8eb53c..f75f3d2bad 100644
--- a/src/quick/doc/src/concepts/input/focus.qdoc
+++ b/src/quick/doc/src/concepts/input/focus.qdoc
@@ -47,12 +47,12 @@ is delivered to it.
\li The key event is delivered by the scene to the \l Item with
\e {active focus}. If no item has active focus, the key event is ignored.
\li If the \l QQuickItem with active focus accepts the key event, propagation
-stops. Otherwise the event is send to the Item's parent until
+stops. Otherwise the event is sent to the Item's parent until
the event is accepted, or the root item is reached.
If the \c {Rectangle} type in the following example has active focus and the \c A key is pressed,
-the event will not be propagated further. Pressing the \c B key the event will propagate to the root
-item and thus subsequently be ignored.
+the event will not be propagated further. Upon pressing the \c B key, the event will propagate to the root
+item and thus be ignored.
\snippet qml/focus/rectangle.qml simple key event
\snippet qml/focus/rectangle.qml simple key event end
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index d9ac3abdc3..b1af6f10dd 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -2801,28 +2801,10 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_strokeText(QV4::CallContex
}
/*!
- \qmltype TextMetrics
- \inqmlmodule QtQuick
- \since 5.0
- \ingroup qtquick-canvas
- \brief Provides a Context2D TextMetrics interface
-
- The TextMetrics object can be created by QtQuick::Context2D::measureText method.
- See \l{http://www.w3.org/TR/2dcontext/#textmetrics}{W3C 2d context TextMetrics} for more details.
-
- \sa Context2D::measureText
- \sa width
- */
+ \qmlmethod object QtQuick::Context2D::measureText(text)
-/*!
- \qmlproperty int QtQuick::TextMetrics::width
- Holds the advance width of the text that was passed to the QtQuick::Context2D::measureText() method.
- This property is read only.
- */
-
-/*!
- \qmlmethod variant QtQuick::Context2D::measureText(text)
- Returns a TextMetrics object with the metrics of the given text in the current font.
+ Returns an object with a \c width property, whose value is equivalent to
+ calling \l {QFontMetrics::width()} with the given \a text in the current font.
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_measureText(QV4::CallContext *ctx)
{
diff --git a/src/quick/items/qquickaccessibleattached.cpp b/src/quick/items/qquickaccessibleattached.cpp
index 3f0ebab6f3..abb763c2eb 100644
--- a/src/quick/items/qquickaccessibleattached.cpp
+++ b/src/quick/items/qquickaccessibleattached.cpp
@@ -69,7 +69,7 @@ QT_BEGIN_NAMESPACE
Accessible.role: Accessible.Button
Accessible.name: label.text
Accessible.description: "shows the next page"
- function accessiblePressAction() {
+ Accessible.onPressAction: {
// do a button click
}
}
@@ -79,8 +79,8 @@ QT_BEGIN_NAMESPACE
The name is a short and consise description of the control and should reflect the visual label.
In this case it is not clear what the button does with the name only, so \l description contains
an explanation.
- There is also a function \c accessiblePressAction() which can be invoked by assistive tools to trigger
- the button. This function needs to have the same effect as tapping or clicking the button would have.
+ There is also a signal handler \l {Accessible::pressAction}{Accessible.pressAction} which can be invoked by assistive tools to trigger
+ the button. This signal handler needs to have the same effect as tapping or clicking the button would have.
\sa Accessibility
*/
@@ -117,7 +117,7 @@ QT_BEGIN_NAMESPACE
\table
\header
\li \b {Role}
- \li \b {Properties and functions}
+ \li \b {Properties and signals}
\li \b {Explanation}
\row
\li All interactive elements
@@ -128,13 +128,14 @@ QT_BEGIN_NAMESPACE
can be moved from item to item.
\row
\li Button, CheckBox, RadioButton
- \li \c accessiblePressAction()
- \li A button should have a function with the name \c accessiblePressAction.
- This function may be called by an assistive tool such as a screen-reader.
+ \li \l {Accessible::pressAction}{Accessible.pressAction}
+ \li A button should have a signal handler with the name \c onPressAction.
+ This signal may be emitted by an assistive tool such as a screen-reader.
The implementation needs to behave the same as a mouse click or tap on the button.
\row
\li CheckBox, RadioButton
- \li \l checkable, \l checked
+ \li \l checkable, \l checked, \l {Accessible::toggleAction}{Accessible.toggleAction}
+
\li The check state of the check box. Updated on Press, Check and Uncheck actions.
\row
\li Slider, SpinBox, Dial, ScrollBar
@@ -142,7 +143,7 @@ QT_BEGIN_NAMESPACE
\li These properties reflect the state and possible values for the elements.
\row
\li Slider, SpinBox, Dial, ScrollBar
- \li \c accessibleIncreaseAction(), \c accessibleDecreaseAction()
+ \li \l {Accessible::increaseAction}{Accessible.increaseAction}, \l {Accessible::decreaseAction}{Accessible.decreaseAction}
\li Actions to increase and decrease the value of the element.
\endtable
*/
@@ -179,6 +180,12 @@ QT_BEGIN_NAMESPACE
By default this property is \c false.
*/
+/*! \qmlproperty bool QtQuick::Accessible::searchEdit
+ \brief This property holds whether this item is input for a search query.
+ This property will only affect editable text.
+
+ By default this property is \c false.
+*/
/*! \qmlproperty bool QtQuick::Accessible::ignored
\brief This property holds whether this item should be ignored by the accessibility framework.
@@ -256,6 +263,40 @@ QT_BEGIN_NAMESPACE
By default this property is \c false.
*/
+/*!
+ \qmlsignal QtQuick::Accessible::pressAction()
+
+ This signal is emitted when a press action is received from an assistive tool such as a screen-reader.
+
+ The corresponding handler is \c onPressAction.
+*/
+/*!
+ \qmlsignal QtQuick::Accessible::toggleAction()
+
+ This signal is emitted when a toggle action is received from an assistive tool such as a screen-reader.
+
+ The corresponding handler is \c onToggleAction.
+*/
+/*!
+ \qmlsignal QtQuick::Accessible::increaseAction()
+
+ This signal is emitted when a increase action is received from an assistive tool such as a screen-reader.
+
+ The corresponding handler is \c onIncreaseAction.
+*/
+/*!
+ \qmlsignal QtQuick::Accessible::decreaseAction()
+
+ This signal is emitted when a decrease action is received from an assistive tool such as a screen-reader.
+
+ The corresponding handler is \c onDecreaseAction.
+*/
+
+QMetaMethod QQuickAccessibleAttached::sigPress;
+QMetaMethod QQuickAccessibleAttached::sigToggle;
+QMetaMethod QQuickAccessibleAttached::sigIncrease;
+QMetaMethod QQuickAccessibleAttached::sigDecrease;
+
QQuickAccessibleAttached::QQuickAccessibleAttached(QObject *parent)
: QObject(parent), m_role(QAccessible::NoRole)
{
@@ -266,7 +307,7 @@ QQuickAccessibleAttached::QQuickAccessibleAttached(QObject *parent)
// Enable accessibility for items with accessible content. This also
// enables accessibility for the ancestors of souch items.
- item->d_func()->setAccessibleFlagAndListener();
+ item->d_func()->setAccessible();
QAccessibleEvent ev(item, QAccessible::ObjectCreated);
QAccessible::updateAccessibility(&ev);
@@ -276,6 +317,13 @@ QQuickAccessibleAttached::QQuickAccessibleAttached(QObject *parent)
if (!parent->property("cursorPosition").isNull()) {
connect(parent, SIGNAL(cursorPositionChanged()), this, SLOT(cursorPositionChanged()));
}
+
+ if (!sigPress.isValid()) {
+ sigPress = QMetaMethod::fromSignal(&QQuickAccessibleAttached::pressAction);
+ sigToggle = QMetaMethod::fromSignal(&QQuickAccessibleAttached::toggleAction);
+ sigIncrease = QMetaMethod::fromSignal(&QQuickAccessibleAttached::increaseAction);
+ sigDecrease = QMetaMethod::fromSignal(&QQuickAccessibleAttached::decreaseAction);
+ }
}
QQuickAccessibleAttached::~QQuickAccessibleAttached()
@@ -300,6 +348,35 @@ void QQuickAccessibleAttached::setIgnored(bool ignored)
}
}
+bool QQuickAccessibleAttached::doAction(const QString &actionName)
+{
+ QMetaMethod *sig = 0;
+ if (actionName == QAccessibleActionInterface::pressAction())
+ sig = &sigPress;
+ else if (actionName == QAccessibleActionInterface::toggleAction())
+ sig = &sigToggle;
+ else if (actionName == QAccessibleActionInterface::increaseAction())
+ sig = &sigIncrease;
+ else if (actionName == QAccessibleActionInterface::decreaseAction())
+ sig = &sigDecrease;
+
+ if (sig && isSignalConnected(*sig))
+ return sig->invoke(this);
+ return false;
+}
+
+void QQuickAccessibleAttached::availableActions(QStringList *actions) const
+{
+ if (isSignalConnected(sigPress))
+ actions->append(QAccessibleActionInterface::pressAction());
+ if (isSignalConnected(sigToggle))
+ actions->append(QAccessibleActionInterface::toggleAction());
+ if (isSignalConnected(sigIncrease))
+ actions->append(QAccessibleActionInterface::increaseAction());
+ if (isSignalConnected(sigDecrease))
+ actions->append(QAccessibleActionInterface::decreaseAction());
+}
+
QT_END_NAMESPACE
#endif
diff --git a/src/quick/items/qquickaccessibleattached_p.h b/src/quick/items/qquickaccessibleattached_p.h
index 270360895d..ad6165f936 100644
--- a/src/quick/items/qquickaccessibleattached_p.h
+++ b/src/quick/items/qquickaccessibleattached_p.h
@@ -88,6 +88,7 @@ public:
STATE_PROPERTY(defaultButton)
STATE_PROPERTY(passwordEdit)
STATE_PROPERTY(selectableText)
+ STATE_PROPERTY(searchEdit)
QQuickAccessibleAttached(QObject *parent);
~QQuickAccessibleAttached();
@@ -187,6 +188,8 @@ public:
QAccessible::State state() { return m_state; }
bool ignored() const;
+ bool doAction(const QString &actionName);
+ void availableActions(QStringList *actions) const;
public Q_SLOTS:
void valueChanged() {
@@ -205,6 +208,10 @@ Q_SIGNALS:
void nameChanged();
void descriptionChanged();
void ignoredChanged();
+ void pressAction();
+ void toggleAction();
+ void increaseAction();
+ void decreaseAction();
private:
QQuickItem *item() const { return static_cast<QQuickItem*>(parent()); }
@@ -214,6 +221,11 @@ private:
QString m_name;
QString m_description;
+ static QMetaMethod sigPress;
+ static QMetaMethod sigToggle;
+ static QMetaMethod sigIncrease;
+ static QMetaMethod sigDecrease;
+
public:
using QObject::property;
};
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index 2ae846a750..e34df86a77 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -61,8 +61,7 @@ Item {
See \l {Qt::Key}{Qt.Key} for the list of keyboard codes. These codes are
independent of the underlying window system. Note that this
function does not distinguish between capital and non-capital
- letters, use the text() function (returning the Unicode text the
- key generated) for this purpose.
+ letters; use the \l {KeyEvent::}{text} property for this purpose.
A value of either 0 or \l {Qt::Key_unknown}{Qt.Key_Unknown} means that the event is not
the result of a known key; for example, it may be the result of
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index c3a56ba8d8..f851ef1bac 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -334,7 +334,7 @@ bool QQuickFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal maxExt
qreal dist = v2 / (accel * 2.0);
if (v > 0)
dist = -dist;
- qreal target = qRound(data.move.value() - dist);
+ qreal target = -qRound(-(data.move.value() - dist));
dist = -target + data.move.value();
accel = v2 / (2.0f * qAbs(dist));
@@ -436,18 +436,18 @@ void QQuickFlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal maxExt
} else if (data.move.value() < maxExtent) {
resetTimeline(data);
adjustContentPos(data, maxExtent);
- } else if (qRound(data.move.value()) != data.move.value()) {
+ } else if (-qRound(-data.move.value()) != data.move.value()) {
// We could animate, but since it is less than 0.5 pixel it's probably not worthwhile.
resetTimeline(data);
qreal val = data.move.value();
- if (qAbs(qRound(val) - val) < 0.25) // round small differences
- val = qRound(val);
+ if (qAbs(-qRound(-val) - val) < 0.25) // round small differences
+ val = -qRound(-val);
else if (data.smoothVelocity.value() > 0) // continue direction of motion for larger
- val = qFloor(val);
+ val = -qFloor(-val);
else if (data.smoothVelocity.value() < 0)
- val = qCeil(val);
+ val = -qCeil(-val);
else // otherwise round
- val = qRound(val);
+ val = -qRound(-val);
timeline.set(data.move, val);
}
data.inOvershoot = false;
@@ -1374,12 +1374,12 @@ void QQuickFlickablePrivate::replayDelayedPress()
//XXX pixelAligned ignores the global position of the Flickable, i.e. assumes Flickable itself is pixel aligned.
void QQuickFlickablePrivate::setViewportX(qreal x)
{
- contentItem->setX(pixelAligned ? qRound(x) : x);
+ contentItem->setX(pixelAligned ? -qRound(-x) : x);
}
void QQuickFlickablePrivate::setViewportY(qreal y)
{
- contentItem->setY(pixelAligned ? qRound(y) : y);
+ contentItem->setY(pixelAligned ? -qRound(-y) : y);
}
void QQuickFlickable::timerEvent(QTimerEvent *event)
diff --git a/src/quick/items/qquickframebufferobject.cpp b/src/quick/items/qquickframebufferobject.cpp
index dc4668be3f..09a25f4efa 100644
--- a/src/quick/items/qquickframebufferobject.cpp
+++ b/src/quick/items/qquickframebufferobject.cpp
@@ -161,6 +161,7 @@ public:
, renderer(0)
, renderPending(true)
, invalidatePending(false)
+ , devicePixelRatio(1)
{
qsgnode_set_description(this, QStringLiteral("fbonode"));
}
@@ -202,14 +203,25 @@ public Q_SLOTS:
}
}
+ void handleScreenChange()
+ {
+ if (window->effectiveDevicePixelRatio() != devicePixelRatio) {
+ renderer->invalidateFramebufferObject();
+ quickFbo->update();
+ }
+ }
+
public:
QQuickWindow *window;
QOpenGLFramebufferObject *fbo;
QOpenGLFramebufferObject *msDisplayFbo;
QQuickFramebufferObject::Renderer *renderer;
+ QQuickFramebufferObject *quickFbo;
bool renderPending;
bool invalidatePending;
+
+ int devicePixelRatio;
};
/*!
@@ -239,7 +251,9 @@ QSGNode *QQuickFramebufferObject::updatePaintNode(QSGNode *node, UpdatePaintNode
n->window = window();
n->renderer = createRenderer();
n->renderer->data = n;
+ n->quickFbo = this;
connect(window(), SIGNAL(beforeRendering()), n, SLOT(render()));
+ connect(window(), SIGNAL(screenChanged(QScreen*)), n, SLOT(handleScreenChange()));
}
n->renderer->synchronize(this);
@@ -248,6 +262,9 @@ QSGNode *QQuickFramebufferObject::updatePaintNode(QSGNode *node, UpdatePaintNode
QSize desiredFboSize(qMax<int>(minFboSize.width(), width()),
qMax<int>(minFboSize.height(), height()));
+ n->devicePixelRatio = window()->effectiveDevicePixelRatio();
+ desiredFboSize *= n->devicePixelRatio;
+
if (n->fbo && (d->followsItemSize || n->invalidatePending)) {
if (n->fbo->size() != desiredFboSize) {
delete n->fbo;
@@ -414,6 +431,12 @@ void QQuickFramebufferObject::Renderer::invalidateFramebufferObject()
* \note Some hardware has issues with small FBO sizes. \a size takes that into account, so
* be cautious when overriding the size with a fixed size. A minimal size of 64x64 should
* always work.
+ *
+ * \note \a size takes the device pixel ratio into account, meaning that it is
+ * already multiplied by the correct scale factor. When moving the window
+ * containing the QQuickFramebufferObject item to a screen with different
+ * settings, the FBO is automatically recreated and this function is invoked
+ * with the correct size.
*/
QOpenGLFramebufferObject *QQuickFramebufferObject::Renderer::createFramebufferObject(const QSize &size)
{
diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp
index 5ec3e81727..1a5d115a3c 100644
--- a/src/quick/items/qquickimagebase.cpp
+++ b/src/quick/items/qquickimagebase.cpp
@@ -206,7 +206,7 @@ void QQuickImageBase::load()
options |= QQuickPixmap::Cache;
d->pix.clear(this);
- const qreal targetDevicePixelRatio = (window() ? window()->devicePixelRatio() : qApp->devicePixelRatio());
+ const qreal targetDevicePixelRatio = (window() ? window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio());
d->devicePixelRatio = 1.0;
QUrl loadUrl = d->url;
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index b68a9b5455..b2ee5af6ff 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -452,7 +452,7 @@ QQuickItem *QQuickKeyNavigationAttached::left() const
void QQuickKeyNavigationAttached::setLeft(QQuickItem *i)
{
Q_D(QQuickKeyNavigationAttached);
- if (d->left == i)
+ if (d->leftSet && d->left == i)
return;
d->left = i;
d->leftSet = true;
@@ -474,7 +474,7 @@ QQuickItem *QQuickKeyNavigationAttached::right() const
void QQuickKeyNavigationAttached::setRight(QQuickItem *i)
{
Q_D(QQuickKeyNavigationAttached);
- if (d->right == i)
+ if (d->rightSet && d->right == i)
return;
d->right = i;
d->rightSet = true;
@@ -496,7 +496,7 @@ QQuickItem *QQuickKeyNavigationAttached::up() const
void QQuickKeyNavigationAttached::setUp(QQuickItem *i)
{
Q_D(QQuickKeyNavigationAttached);
- if (d->up == i)
+ if (d->upSet && d->up == i)
return;
d->up = i;
d->upSet = true;
@@ -518,7 +518,7 @@ QQuickItem *QQuickKeyNavigationAttached::down() const
void QQuickKeyNavigationAttached::setDown(QQuickItem *i)
{
Q_D(QQuickKeyNavigationAttached);
- if (d->down == i)
+ if (d->downSet && d->down == i)
return;
d->down = i;
d->downSet = true;
@@ -540,7 +540,7 @@ QQuickItem *QQuickKeyNavigationAttached::tab() const
void QQuickKeyNavigationAttached::setTab(QQuickItem *i)
{
Q_D(QQuickKeyNavigationAttached);
- if (d->tab == i)
+ if (d->tabSet && d->tab == i)
return;
d->tab = i;
d->tabSet = true;
@@ -562,7 +562,7 @@ QQuickItem *QQuickKeyNavigationAttached::backtab() const
void QQuickKeyNavigationAttached::setBacktab(QQuickItem *i)
{
Q_D(QQuickKeyNavigationAttached);
- if (d->backtab == i)
+ if (d->backtabSet && d->backtab == i)
return;
d->backtab = i;
d->backtabSet = true;
@@ -1607,17 +1607,9 @@ void QQuickItemPrivate::setLayoutMirror(bool mirror)
}
}
-void QQuickItemPrivate::setAccessibleFlagAndListener()
+void QQuickItemPrivate::setAccessible()
{
- Q_Q(QQuickItem);
- QQuickItem *item = q;
- while (item) {
- if (item->d_func()->isAccessible)
- break; // already set - grandparents should have the flag set as well.
-
- item->d_func()->isAccessible = true;
- item = item->d_func()->parentItem;
- }
+ isAccessible = true;
}
/*!
@@ -1757,6 +1749,19 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
surface. Using scene graph API directly is always significantly
faster.
+ \section1 Behavior Animations
+
+ If your Item uses the \l Behavior type to define animations for property
+ changes, you should always use either QObject::setProperty(),
+ QQmlProperty(), or QMetaProperty::write() when you need to modify those
+ properties from C++. This ensures that the QML engine knows about the
+ property change. Otherwise, the engine won't be able to carry out your
+ requested animation. For example, if you call \l setPosition() directly,
+ any behavior that reacts to changes in the x or y properties will not take
+ effect, as you are bypassing Qt's meta-object system. Note that these
+ functions incur a slight performance penalty. For more details, see
+ \l {Accessing Members of a QML Object Type from C++}.
+
\sa QQuickWindow, QQuickPaintedItem
*/
@@ -2584,9 +2589,6 @@ void QQuickItem::setParentItem(QQuickItem *parentItem)
d->itemChange(ItemParentHasChanged, d->parentItem);
d->parentNotifier.notify();
- if (d->isAccessible && d->parentItem) {
- d->parentItem->d_func()->setAccessibleFlagAndListener();
- }
emit parentChanged(d->parentItem);
if (isVisible() && d->parentItem)
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index 2ae67c4c23..e416facc6b 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -509,7 +509,7 @@ public:
inline qreal rotation() const { return extra.isAllocated()?extra->rotation:0; }
inline qreal opacity() const { return extra.isAllocated()?extra->opacity:1; }
- void setAccessibleFlagAndListener();
+ void setAccessible();
virtual qreal getImplicitWidth() const;
virtual qreal getImplicitHeight() const;
@@ -631,7 +631,7 @@ public:
bool backtabSet : 1;
};
-class QQuickKeyNavigationAttached : public QObject, public QQuickItemKeyFilter
+class Q_QUICK_PRIVATE_EXPORT QQuickKeyNavigationAttached : public QObject, public QQuickItemKeyFilter
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQuickKeyNavigationAttached)
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index 00a5400eb2..825845eca9 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -1987,12 +1987,14 @@ void QQuickPathView::refill()
}
}
+ bool currentChanged = false;
if (!currentVisible) {
d->currentItemOffset = 1.0;
if (d->currentItem) {
d->updateItem(d->currentItem, 1.0);
} else if (!waiting && d->currentIndex >= 0 && d->currentIndex < d->modelCount) {
if ((d->currentItem = d->getItem(d->currentIndex, d->currentIndex))) {
+ currentChanged = true;
d->updateItem(d->currentItem, 1.0);
if (QQuickPathViewAttached *att = d->attached(d->currentItem))
att->setIsCurrentItem(true);
@@ -2000,6 +2002,7 @@ void QQuickPathView::refill()
}
} else if (!waiting && !d->currentItem) {
if ((d->currentItem = d->getItem(d->currentIndex, d->currentIndex))) {
+ currentChanged = true;
d->currentItem->setFocus(true);
if (QQuickPathViewAttached *att = d->attached(d->currentItem))
att->setIsCurrentItem(true);
@@ -2019,6 +2022,8 @@ void QQuickPathView::refill()
d->releaseItem(d->itemCache.takeLast());
d->inRefill = false;
+ if (currentChanged)
+ emit currentItemChanged();
}
void QQuickPathView::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp
index 79db80595b..7ccd3a0fb4 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -318,7 +318,7 @@ QImage QQuickRenderControl::grab()
return QImage();
render();
- QImage grabContent = qt_gl_read_framebuffer(d->window->size() * d->window->devicePixelRatio(), false, false);
+ QImage grabContent = qt_gl_read_framebuffer(d->window->size() * d->window->effectiveDevicePixelRatio(), false, false);
return grabContent;
}
diff --git a/src/quick/items/qquickscreen.cpp b/src/quick/items/qquickscreen.cpp
index 926ac7b4ee..8ac5a1e292 100644
--- a/src/quick/items/qquickscreen.cpp
+++ b/src/quick/items/qquickscreen.cpp
@@ -142,6 +142,15 @@ QT_BEGIN_NAMESPACE
The number of physical pixels per millimeter.
*/
/*!
+ \qmlattachedproperty real Screen::devicePixelRatio
+ \readonly
+ \since 5.4
+
+ The ratio between physical pixels and device-independent pixels for the screen.
+
+ Common values are 1.0 on normal displays and 2.0 on Apple "retina" displays.
+*/
+/*!
\qmlattachedproperty Qt::ScreenOrientation Screen::primaryOrientation
\readonly
@@ -260,6 +269,13 @@ qreal QQuickScreenAttached::pixelDensity() const
return m_screen->physicalDotsPerInch() / 25.4;
}
+qreal QQuickScreenAttached::devicePixelRatio() const
+{
+ if (!m_screen)
+ return 1.0;
+ return m_screen->devicePixelRatio();
+}
+
Qt::ScreenOrientation QQuickScreenAttached::primaryOrientation() const
{
if (!m_screen)
@@ -340,6 +356,8 @@ void QQuickScreenAttached::screenChanged(QScreen *screen)
emit logicalPixelDensityChanged();
if (!oldScreen || screen->physicalDotsPerInch() != oldScreen->physicalDotsPerInch())
emit pixelDensityChanged();
+ if (!oldScreen || screen->devicePixelRatio() != oldScreen->devicePixelRatio())
+ emit devicePixelRatioChanged();
connect(screen, SIGNAL(geometryChanged(QRect)),
this, SIGNAL(widthChanged()));
diff --git a/src/quick/items/qquickscreen_p.h b/src/quick/items/qquickscreen_p.h
index d661cc6f56..257b18cfe0 100644
--- a/src/quick/items/qquickscreen_p.h
+++ b/src/quick/items/qquickscreen_p.h
@@ -57,6 +57,7 @@ class Q_AUTOTEST_EXPORT QQuickScreenAttached : public QObject
Q_PROPERTY(int desktopAvailableHeight READ desktopAvailableHeight NOTIFY desktopGeometryChanged)
Q_PROPERTY(qreal logicalPixelDensity READ logicalPixelDensity NOTIFY logicalPixelDensityChanged)
Q_PROPERTY(qreal pixelDensity READ pixelDensity NOTIFY pixelDensityChanged)
+ Q_PROPERTY(qreal devicePixelRatio READ devicePixelRatio NOTIFY devicePixelRatioChanged)
// TODO Qt 6 Rename primaryOrientation to orientation
Q_PROPERTY(Qt::ScreenOrientation primaryOrientation READ primaryOrientation NOTIFY primaryOrientationChanged)
// TODO Qt 6 Remove this orientation -> incomplete device orientation -> better use OrientationSensor
@@ -74,6 +75,7 @@ public:
int desktopAvailableHeight() const;
qreal logicalPixelDensity() const;
qreal pixelDensity() const;
+ qreal devicePixelRatio() const;
Qt::ScreenOrientation primaryOrientation() const;
Qt::ScreenOrientation orientation() const;
Qt::ScreenOrientations orientationUpdateMask() const;
@@ -91,6 +93,7 @@ Q_SIGNALS:
void desktopGeometryChanged();
void logicalPixelDensityChanged();
void pixelDensityChanged();
+ void devicePixelRatioChanged();
void primaryOrientationChanged();
void orientationChanged();
void orientationUpdateMaskChanged();
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index 52e5ba2464..ccff98828c 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -628,7 +628,7 @@ QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaint
// Crate large textures on high-dpi displays.
if (sourceItem())
- textureSize *= d->window->devicePixelRatio();
+ textureSize *= d->window->effectiveDevicePixelRatio();
const QSize minTextureSize = d->sceneGraphContext()->minimumFBOSize();
// Keep power-of-two by doubling the size.
@@ -637,7 +637,7 @@ QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaint
while (textureSize.height() < minTextureSize.height())
textureSize.rheight() *= 2;
- m_texture->setDevicePixelRatio(d->window->devicePixelRatio());
+ m_texture->setDevicePixelRatio(d->window->effectiveDevicePixelRatio());
m_texture->setSize(textureSize);
m_texture->setRecursive(m_recursive);
m_texture->setFormat(GLenum(m_format));
diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp
index 7a48beeda4..12020e879b 100644
--- a/src/quick/items/qquickspriteengine.cpp
+++ b/src/quick/items/qquickspriteengine.cpp
@@ -385,6 +385,10 @@ QImage QQuickSpriteEngine::assembledImage()
m_imageStateCount = 0;
int maxSize = 0;
+ //If there is no current OpenGL Context
+ if (!QOpenGLContext::currentContext())
+ return QImage();
+
QOpenGLContext::currentContext()->functions()->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize);
#ifdef SPRITE_IMAGE_DEBUG
qDebug() << "MAX TEXTURE SIZE" << maxSize;
diff --git a/src/quick/items/qquickspritesequence.cpp b/src/quick/items/qquickspritesequence.cpp
index 0d19a8aa83..0bef823b3c 100644
--- a/src/quick/items/qquickspritesequence.cpp
+++ b/src/quick/items/qquickspritesequence.cpp
@@ -243,7 +243,8 @@ void QQuickSpriteSequence::setGoalSprite(const QString &sprite)
if (m_goalState != sprite){
m_goalState = sprite;
emit goalSpriteChanged(sprite);
- m_spriteEngine->setGoal(m_spriteEngine->stateIndex(sprite));
+ if (m_spriteEngine)
+ m_spriteEngine->setGoal(m_spriteEngine->stateIndex(sprite));
}
}
@@ -257,10 +258,13 @@ void QQuickSpriteSequence::createEngine()
//TODO: delay until component complete
if (m_spriteEngine)
delete m_spriteEngine;
- if (m_sprites.count())
+ if (m_sprites.count()) {
m_spriteEngine = new QQuickSpriteEngine(m_sprites, this);
- else
+ if (!m_goalState.isEmpty())
+ m_spriteEngine->setGoal(m_spriteEngine->stateIndex(m_goalState));
+ } else {
m_spriteEngine = 0;
+ }
reset();
}
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index b943b8a4e6..bfa2fccd67 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -490,7 +490,6 @@ void QQuickTextPrivate::updateSize()
else
extra->doc->setTextWidth(extra->doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
- widthExceeded = extra->doc->textWidth() < extra->doc->idealWidth();
QSizeF dsize = extra->doc->size();
layedOutTextRect = QRectF(QPointF(0,0), dsize);
size = QSizeF(extra->doc->idealWidth(),dsize.height());
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index 27752d53b4..1f03fb21e2 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -1292,6 +1292,7 @@ void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
\li Qt.ImhDate - The text editor functions as a date field.
\li Qt.ImhTime - The text editor functions as a time field.
+ \li Qt.ImhMultiLine - The text editor doesn't close software input keyboard when Return or Enter key is pressed (since QtQuick 2.4).
\endlist
Flags that restrict input (exclusive flags) are:
@@ -4192,6 +4193,12 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
if (hasAcceptableInput(m_text) == AcceptableInput || fixup()) {
+
+ QInputMethod *inputMethod = QGuiApplication::inputMethod();
+ inputMethod->commit();
+ if (!(q->inputMethodHints() & Qt::ImhMultiLine))
+ inputMethod->hide();
+
emit q->accepted();
emit q->editingFinished();
}
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 34b1c474ed..6e82be383b 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -366,7 +366,7 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size)
runAndClearJobs(&beforeRenderingJobs);
if (!customRenderStage || !customRenderStage->render()) {
int fboId = 0;
- const qreal devicePixelRatio = q->devicePixelRatio();
+ const qreal devicePixelRatio = q->effectiveDevicePixelRatio();
renderer->setDeviceRect(QRect(QPoint(0, 0), size * devicePixelRatio));
if (renderTargetId) {
fboId = renderTargetId;
@@ -375,11 +375,10 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size)
renderer->setViewportRect(QRect(QPoint(0, 0), size * devicePixelRatio));
}
renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), size));
- renderer->setDevicePixelRatio(q->devicePixelRatio());
+ renderer->setDevicePixelRatio(devicePixelRatio);
context->renderNextFrame(renderer, fboId);
}
-
emit q->afterRendering();
runAndClearJobs(&afterRenderingJobs);
}
@@ -463,8 +462,7 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
q->setSurfaceType(windowManager ? windowManager->windowSurfaceType() : QSurface::OpenGLSurface);
q->setFormat(sg->defaultSurfaceFormat());
- animationController = new QQuickAnimatorController();
- animationController->m_window = q;
+ animationController = new QQuickAnimatorController(q);
delayedTouch = 0;
@@ -3178,7 +3176,7 @@ QImage QQuickWindow::grabWindow()
d->syncSceneGraph();
d->renderSceneGraph(size());
- QImage image = qt_gl_read_framebuffer(size() * devicePixelRatio(), false, false);
+ QImage image = qt_gl_read_framebuffer(size() * effectiveDevicePixelRatio(), false, false);
d->cleanupNodesOnShutdown();
d->context->invalidate();
context.doneCurrent();
@@ -3941,6 +3939,23 @@ void QQuickWindow::runJobsAfterSwap()
d->runAndClearJobs(&d->afterSwapJobs);
}
+/*!
+ * Returns the device pixel ratio for this window.
+ *
+ * This is different from QWindow::devicePixelRatio() in that it supports
+ * redirected rendering via QQuickRenderControl. When using a
+ * QQuickRenderControl, the QQuickWindow is often not created, meaning it is
+ * never shown and there is no underlying native window created in the
+ * windowing system. As a result, querying properties like the device pixel
+ * ratio cannot give correct results. Use this function instead.
+ *
+ * \sa QWindow::devicePixelRatio()
+ */
+int QQuickWindow::effectiveDevicePixelRatio() const
+{
+ QWindow *w = QQuickRenderControl::renderWindowFor(const_cast<QQuickWindow *>(this));
+ return w ? w->devicePixelRatio() : devicePixelRatio();
+}
#include "moc_qquickwindow.cpp"
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index 8d75a4767c..d02423d8af 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -143,6 +143,8 @@ public:
void scheduleRenderJob(QRunnable *job, RenderStage schedule);
+ int effectiveDevicePixelRatio() const;
+
Q_SIGNALS:
void frameSwapped();
Q_REVISION(2) void openglContextCreated(QOpenGLContext *context);
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index ac45cf70db..ef125e07a9 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -228,6 +228,7 @@ void qsg_dumpShadowRoots(BatchRootInfo *i, int indent)
void qsg_dumpShadowRoots(Node *n)
{
+#ifndef QT_NO_DEBUG_OUTPUT
static int indent = 0;
++indent;
@@ -247,6 +248,9 @@ void qsg_dumpShadowRoots(Node *n)
qsg_dumpShadowRoots(*child);
--indent;
+#else
+ Q_UNUSED(n)
+#endif
}
Updater::Updater(Renderer *r)
@@ -1073,6 +1077,7 @@ void Renderer::turnNodeIntoBatchRoot(Node *node)
void Renderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state)
{
+#ifndef QT_NO_DEBUG_OUTPUT
if (Q_UNLIKELY(debug_change())) {
QDebug debug = qDebug();
debug << "dirty:";
@@ -1100,7 +1105,7 @@ void Renderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state)
else
debug << node;
}
-
+#endif
// As this function calls nodeChanged recursively, we do it at the top
// to avoid that any of the others are processed twice.
if (state & QSGNode::DirtySubtreeBlocked) {
@@ -1847,7 +1852,7 @@ void Renderer::uploadBatch(Batch *b)
e = e->nextInBatch;
}
}
-
+#ifndef QT_NO_DEBUG_OUTPUT
if (Q_UNLIKELY(debug_upload())) {
const char *vd = b->vbo.data;
qDebug() << " -- Vertex Data, count:" << b->vertexCount << " - " << g->sizeOfVertex() << "bytes/vertex";
@@ -1880,11 +1885,11 @@ void Renderer::uploadBatch(Batch *b)
}
const quint16 *id =
-#ifdef QSG_SEPARATE_INDEX_BUFFER
+# ifdef QSG_SEPARATE_INDEX_BUFFER
(const quint16 *) (b->ibo.data);
-#else
+# else
(const quint16 *) (b->vbo.data + b->drawSets.at(0).indices);
-#endif
+# endif
{
QDebug iDump = qDebug();
iDump << " -- Index Data, count:" << b->indexCount;
@@ -1900,6 +1905,7 @@ void Renderer::uploadBatch(Batch *b)
qDebug() << " -- DrawSet: indexCount:" << s.indexCount << " vertices:" << s.vertices << " z:" << s.zorders << " indices:" << s.indices;
}
}
+#endif // QT_NO_DEBUG_OUTPUT
unmap(&b->vbo);
#ifdef QSG_SEPARATE_INDEX_BUFFER
@@ -2121,6 +2127,7 @@ void Renderer::renderMergedBatch(const Batch *batch)
Element *e = batch->first;
Q_ASSERT(e);
+#ifndef QT_NO_DEBUG_OUTPUT
if (Q_UNLIKELY(debug_render())) {
QDebug debug = qDebug();
debug << " -"
@@ -2139,6 +2146,7 @@ void Renderer::renderMergedBatch(const Batch *batch)
debug << "opacity:" << e->node->inheritedOpacity();
batch->uploadedThisFrame = false;
}
+#endif
QSGGeometryNode *gn = e->node;
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index b87ab3686f..2a0fae9f72 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -162,7 +162,6 @@ public:
, m_vsync(0)
, m_mode(VSyncMode)
, m_bad(0)
- , m_reallyBad(0)
, m_good(0)
{
QScreen *screen = QGuiApplication::primaryScreen();
@@ -185,6 +184,7 @@ public:
{
m_time = 0;
m_timer.start();
+ m_wallTime.restart();
QAnimationDriver::start();
}
@@ -192,7 +192,7 @@ public:
{
return m_mode == VSyncMode
? qint64(m_time)
- : QAnimationDriver::elapsed();
+ : qint64(m_time) + m_wallTime.elapsed();
}
void advance() Q_DECL_OVERRIDE
@@ -217,25 +217,22 @@ public:
m_time += m_vsync;
- if (delta > m_vsync * 5) {
- ++m_reallyBad;
- ++m_bad;
- } else if (delta > m_vsync * 1.25) {
- ++m_bad;
+ if (delta > m_vsync * 1.25) {
+ m_lag += (delta / m_vsync);
+ m_bad++;
+ // We tolerate one bad frame without resorting to timer based. This is
+ // done to cope with a slow loader frame followed by smooth animation.
+ // However, on the second frame with massive lag, we switch.
+ if (m_lag > 10 && m_bad > 2) {
+ m_mode = TimerMode;
+ qCDebug(QSG_LOG_INFO, "animation driver switched to timer mode");
+ m_wallTime.restart();
+ }
} else {
- // reset counters on a good frame.
- m_reallyBad = 0;
+ m_lag = 0;
m_bad = 0;
}
- // rational for the 3 and 50. If we have several really bad frames
- // in a row, that would indicate a huge performance problem and we should
- // switch right away. For the case of m_bad, we're a bit more tolerant.
- if (m_reallyBad > 3 || m_bad > 50) {
- m_mode = TimerMode;
- qCDebug(QSG_LOG_INFO, "animation driver switched to timer mode");
- }
-
} else {
if (delta < 1.25 * m_vsync) {
++m_good;
@@ -249,6 +246,8 @@ public:
if (m_good > 10 && !qsg_useConsistentTiming()) {
m_time = elapsed();
m_mode = VSyncMode;
+ m_bad = 0;
+ m_lag = 0;
qCDebug(QSG_LOG_INFO, "animation driver switched to vsync mode");
}
}
@@ -260,8 +259,9 @@ public:
float m_vsync;
Mode m_mode;
QElapsedTimer m_timer;
+ QElapsedTimer m_wallTime;
+ float m_lag;
int m_bad;
- int m_reallyBad;
int m_good;
};
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
index 802c92be9f..5cca474ea1 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -41,6 +41,7 @@
#include <private/qfontengine_p.h>
#include <private/qopenglextensions_p.h>
+#include <QtQuick/qquickwindow.h>
#include <QtQuick/private/qsgtexture_p.h>
#include <private/qrawfont_p.h>
@@ -58,6 +59,21 @@ static inline QVector4D qsg_premultiply(const QVector4D &c, float globalOpacity)
return QVector4D(c.x() * o, c.y() * o, c.z() * o, o);
}
+static inline int qsg_device_pixel_ratio(QOpenGLContext *ctx)
+{
+ int devicePixelRatio = 1;
+ if (ctx->surface()->surfaceClass() == QSurface::Window) {
+ QWindow *w = static_cast<QWindow *>(ctx->surface());
+ if (QQuickWindow *qw = qobject_cast<QQuickWindow *>(w))
+ devicePixelRatio = qw->effectiveDevicePixelRatio();
+ else
+ devicePixelRatio = w->devicePixelRatio();
+ } else {
+ devicePixelRatio = ctx->screen()->devicePixelRatio();
+ }
+ return devicePixelRatio;
+}
+
class QSGTextMaskShader : public QSGMaterialShader
{
public:
@@ -101,6 +117,7 @@ void QSGTextMaskShader::initialize()
m_matrix_id = program()->uniformLocation("matrix");
m_color_id = program()->uniformLocation("color");
m_textureScale_id = program()->uniformLocation("textureScale");
+ program()->setUniformValue("dpr", (float) qsg_device_pixel_ratio(QOpenGLContext::currentContext()));
}
void QSGTextMaskShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
@@ -350,8 +367,8 @@ void QSGTextMaskMaterial::init(QFontEngine::GlyphFormat glyphFormat)
: QFontEngine::Format_A32;
}
- qreal devicePixelRatio = ctx->surface()->surfaceClass() == QSurface::Window ?
- static_cast<QWindow *>(ctx->surface())->devicePixelRatio() : ctx->screen()->devicePixelRatio();
+ qreal devicePixelRatio = qsg_device_pixel_ratio(ctx);
+
QTransform glyphCacheTransform = QTransform::fromScale(devicePixelRatio, devicePixelRatio);
if (!fontEngine->supportsTransformation(glyphCacheTransform))
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index 962b0f866d..ecfbe0323c 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -41,6 +41,7 @@
#include <QtCore/private/qabstractanimation_p.h>
#include <QtGui/QOpenGLContext>
+#include <QtGui/QOffscreenSurface>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
@@ -274,15 +275,30 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window)
m_windows.remove(window);
hide(window);
QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
- if (gl)
- gl->makeCurrent(window);
+
+ bool current = false;
+ QScopedPointer<QOffscreenSurface> offscreenSurface;
+ if (gl) {
+ QSurface *surface = window;
+ // There may be no platform window if the window got closed.
+ if (!window->handle()) {
+ offscreenSurface.reset(new QOffscreenSurface);
+ offscreenSurface->setFormat(gl->format());
+ offscreenSurface->create();
+ surface = offscreenSurface.data();
+ }
+ current = gl->makeCurrent(surface);
+ }
+ if (Q_UNLIKELY(!current))
+ qCDebug(QSG_LOG_RENDERLOOP) << "cleanup without an OpenGL context";
+
d->cleanupNodesOnShutdown();
if (m_windows.size() == 0) {
rc->invalidate();
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
delete gl;
gl = 0;
- } else if (gl && window == gl->surface()) {
+ } else if (gl && window == gl->surface() && current) {
gl->doneCurrent();
}
}
@@ -358,7 +374,7 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame);
if (data.grabOnly) {
- grabContent = qt_gl_read_framebuffer(window->size() * window->devicePixelRatio(), false, false);
+ grabContent = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), false, false);
data.grabOnly = false;
}
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 5ed42d5e1d..5218552427 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -407,7 +407,7 @@ bool QSGRenderThread::event(QEvent *e)
QQuickWindowPrivate::get(window)->renderSceneGraph(windowSize);
qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- grabbing result";
- *ce->image = qt_gl_read_framebuffer(windowSize * window->devicePixelRatio(), false, false);
+ *ce->image = qt_gl_read_framebuffer(windowSize * window->effectiveDevicePixelRatio(), false, false);
}
qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- waking gui to handle result";
waitCondition.wakeOne();
@@ -545,6 +545,11 @@ void QSGRenderThread::syncAndRender()
qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- updatePending, doing sync";
sync(exposeRequested);
}
+#ifndef QSG_NO_RENDER_TIMING
+ if (profileFrames)
+ syncTime = threadTimer.nsecsElapsed();
+#endif
+ Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame);
if (!syncResultedInChanges && !repaintRequested) {
qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- no changes, render aborted";
@@ -554,10 +559,6 @@ void QSGRenderThread::syncAndRender()
return;
}
- if (profileFrames)
- syncTime = threadTimer.nsecsElapsed();
- Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame);
-
qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- rendering started";
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
index 56626e8e42..469cd1d21b 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp
+++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
@@ -290,7 +290,7 @@ QImage QSGWindowsRenderLoop::grab(QQuickWindow *window)
d->syncSceneGraph();
d->renderSceneGraph(window->size());
- QImage image = qt_gl_read_framebuffer(window->size() * window->devicePixelRatio(), false, false);
+ QImage image = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), false, false);
return image;
}
diff --git a/src/quick/scenegraph/shaders/styledtext.vert b/src/quick/scenegraph/shaders/styledtext.vert
index 14fefc2564..7001bbc262 100644
--- a/src/quick/scenegraph/shaders/styledtext.vert
+++ b/src/quick/scenegraph/shaders/styledtext.vert
@@ -1,6 +1,7 @@
uniform highp mat4 matrix;
uniform highp vec2 textureScale;
uniform highp vec2 shift;
+uniform highp float dpr;
attribute highp vec4 vCoord;
attribute highp vec2 tCoord;
@@ -12,5 +13,5 @@ void main()
{
sampleCoord = tCoord * textureScale;
shiftedSampleCoord = (tCoord - shift) * textureScale;
- gl_Position = matrix * floor(vCoord + 0.5);
+ gl_Position = matrix * floor(vCoord * dpr + 0.5) / dpr;
}
diff --git a/src/quick/scenegraph/shaders/styledtext_core.vert b/src/quick/scenegraph/shaders/styledtext_core.vert
index 65bdb66814..c522877bb3 100644
--- a/src/quick/scenegraph/shaders/styledtext_core.vert
+++ b/src/quick/scenegraph/shaders/styledtext_core.vert
@@ -9,10 +9,11 @@ out vec2 shiftedSampleCoord;
uniform mat4 matrix;
uniform vec2 textureScale;
uniform vec2 shift;
+uniform float dpr;
void main()
{
sampleCoord = tCoord * textureScale;
shiftedSampleCoord = (tCoord - shift) * textureScale;
- gl_Position = matrix * round(vCoord);
+ gl_Position = matrix * round(vCoord * dpr) / dpr;
}
diff --git a/src/quick/scenegraph/shaders/textmask.vert b/src/quick/scenegraph/shaders/textmask.vert
index dd8918839e..4c678270d0 100644
--- a/src/quick/scenegraph/shaders/textmask.vert
+++ b/src/quick/scenegraph/shaders/textmask.vert
@@ -1,5 +1,6 @@
uniform highp mat4 matrix;
uniform highp vec2 textureScale;
+uniform highp float dpr;
attribute highp vec4 vCoord;
attribute highp vec2 tCoord;
@@ -9,5 +10,5 @@ varying highp vec2 sampleCoord;
void main()
{
sampleCoord = tCoord * textureScale;
- gl_Position = matrix * floor(vCoord + 0.5);
+ gl_Position = matrix * floor(vCoord * dpr + 0.5) / dpr;
}
diff --git a/src/quick/scenegraph/shaders/textmask_core.vert b/src/quick/scenegraph/shaders/textmask_core.vert
index d145d33195..f996040f70 100644
--- a/src/quick/scenegraph/shaders/textmask_core.vert
+++ b/src/quick/scenegraph/shaders/textmask_core.vert
@@ -7,9 +7,10 @@ out vec2 sampleCoord;
uniform mat4 matrix;
uniform vec2 textureScale;
+uniform float dpr;
void main()
{
sampleCoord = tCoord * textureScale;
- gl_Position = matrix * round(vCoord);
+ gl_Position = matrix * round(vCoord * dpr) / dpr;
}
diff --git a/src/quick/util/qquickanimatorcontroller.cpp b/src/quick/util/qquickanimatorcontroller.cpp
index e009de205c..cfaa439072 100644
--- a/src/quick/util/qquickanimatorcontroller.cpp
+++ b/src/quick/util/qquickanimatorcontroller.cpp
@@ -44,10 +44,19 @@
QT_BEGIN_NAMESPACE
-QQuickAnimatorController::QQuickAnimatorController()
- : m_window(0)
+QQuickAnimatorController::QQuickAnimatorController(QQuickWindow *window)
+ : m_window(window)
, m_nodesAreInvalid(false)
{
+ m_guiEntity = new QQuickAnimatorControllerGuiThreadEntity();
+ m_guiEntity->controller = this;
+ connect(window, SIGNAL(frameSwapped()), m_guiEntity, SLOT(frameSwapped()));
+}
+
+void QQuickAnimatorControllerGuiThreadEntity::frameSwapped()
+{
+ if (!controller.isNull())
+ controller->stopProxyJobs();
}
QQuickAnimatorController::~QQuickAnimatorController()
@@ -71,6 +80,8 @@ QQuickAnimatorController::~QQuickAnimatorController()
if (!m_animatorRoots.contains(job))
delete job;
}
+
+ delete m_guiEntity;
}
static void qquickanimator_invalidate_node(QAbstractAnimationJob *job)
@@ -211,6 +222,27 @@ void QQuickAnimatorController::afterNodeSync()
}
}
+void QQuickAnimatorController::proxyWasDestroyed(QQuickAnimatorProxyJob *proxy)
+{
+ lock();
+ m_proxiesToStop.remove(proxy);
+ unlock();
+}
+
+void QQuickAnimatorController::stopProxyJobs()
+{
+ // Need to make a copy under lock and then stop while unlocked.
+ // Stopping triggers writeBack which in turn may lock, so it needs
+ // to be outside the lock. It is also safe because deletion of
+ // proxies happens on the GUI thread, where this code is also executing.
+ lock();
+ QSet<QQuickAnimatorProxyJob *> jobs = m_proxiesToStop;
+ m_proxiesToStop.clear();
+ unlock();
+ foreach (QQuickAnimatorProxyJob *p, jobs)
+ p->stop();
+}
+
void QQuickAnimatorController::animationFinished(QAbstractAnimationJob *job)
{
/* We are currently on the render thread and m_deleting is primarily
@@ -221,8 +253,10 @@ void QQuickAnimatorController::animationFinished(QAbstractAnimationJob *job)
*/
if (!m_deleting.contains(job)) {
QQuickAnimatorProxyJob *proxy = m_animatorRoots[job];
- if (proxy)
- QCoreApplication::postEvent(proxy, new QEvent(QEvent::User));
+ if (proxy) {
+ m_window->update();
+ m_proxiesToStop << proxy;
+ }
// else already gone...
}
}
@@ -254,12 +288,14 @@ void QQuickAnimatorController::startJob(QQuickAnimatorProxyJob *proxy, QAbstract
{
proxy->markJobManagedByController();
m_starting[job] = proxy;
+ m_stopping.remove(job);
requestSync();
}
void QQuickAnimatorController::stopJob(QQuickAnimatorProxyJob *proxy, QAbstractAnimationJob *job)
{
m_stopping[job] = proxy;
+ m_starting.remove(job);
requestSync();
}
diff --git a/src/quick/util/qquickanimatorcontroller_p.h b/src/quick/util/qquickanimatorcontroller_p.h
index bd44adf928..b13c174606 100644
--- a/src/quick/util/qquickanimatorcontroller_p.h
+++ b/src/quick/util/qquickanimatorcontroller_p.h
@@ -43,12 +43,14 @@
QT_BEGIN_NAMESPACE
+class QQuickAnimatorControllerGuiThreadEntity;
+
class QQuickAnimatorController : public QObject, public QAnimationJobChangeListener
{
Q_OBJECT
public:
- QQuickAnimatorController();
+ QQuickAnimatorController(QQuickWindow *window);
~QQuickAnimatorController();
void advance();
@@ -68,6 +70,9 @@ public:
void lock() { m_mutex.lock(); }
void unlock() { m_mutex.unlock(); }
+
+ void proxyWasDestroyed(QQuickAnimatorProxyJob *proxy);
+ void stopProxyJobs();
void windowNodesDestroyed();
public Q_SLOTS:
@@ -85,11 +90,25 @@ public:
QHash<QQuickItem *, QQuickTransformAnimatorJob::Helper *> m_transforms;
QSet<QQuickItem *> m_deletedSinceLastFrame;
QQuickWindow *m_window;
+ QQuickAnimatorControllerGuiThreadEntity *m_guiEntity;
+ QSet<QQuickAnimatorProxyJob *> m_proxiesToStop;
QMutex m_mutex;
bool m_nodesAreInvalid;
};
+class QQuickAnimatorControllerGuiThreadEntity : public QObject
+{
+ Q_OBJECT
+public:
+ QPointer<QQuickAnimatorController> controller;
+
+public Q_SLOTS:
+ void frameSwapped();
+};
+
+
+
QT_END_NAMESPACE
#endif // QQUICKANIMATORCONTROLLER_P_H
diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
index 8c72c09738..536413bba9 100644
--- a/src/quick/util/qquickanimatorjob.cpp
+++ b/src/quick/util/qquickanimatorjob.cpp
@@ -85,6 +85,8 @@ QQuickAnimatorProxyJob::QQuickAnimatorProxyJob(QAbstractAnimationJob *job, QObje
QQuickAnimatorProxyJob::~QQuickAnimatorProxyJob()
{
deleteJob();
+ if (m_controller)
+ m_controller->proxyWasDestroyed(this);
}
void QQuickAnimatorProxyJob::deleteJob()
@@ -179,15 +181,6 @@ void QQuickAnimatorProxyJob::startedByController()
m_internalState = State_Running;
}
-bool QQuickAnimatorProxyJob::event(QEvent *e)
-{
- if (e->type() == QEvent::User) {
- stop();
- return true;
- }
- return QObject::event(e);
-}
-
static void qquick_syncback_helper(QAbstractAnimationJob *job)
{
if (job->isRenderThreadJob()) {
diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h
index 4bdcd6917d..d87c9072a2 100644
--- a/src/quick/util/qquickanimatorjob_p.h
+++ b/src/quick/util/qquickanimatorjob_p.h
@@ -72,8 +72,6 @@ public:
void markJobManagedByController() { m_jobManagedByController = true; }
protected:
- bool event(QEvent *);
-
void updateCurrentTime(int);
void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
diff --git a/src/quick/util/qquickfontmetrics.cpp b/src/quick/util/qquickfontmetrics.cpp
index a447d3cda0..b65ad3f1ea 100644
--- a/src/quick/util/qquickfontmetrics.cpp
+++ b/src/quick/util/qquickfontmetrics.cpp
@@ -41,6 +41,7 @@ QT_BEGIN_NAMESPACE
\qmltype FontMetrics
\instantiates QQuickFontMetrics
\inqmlmodule QtQuick
+ \since 5.4
\ingroup qtquick-text-utility
\brief Provides metrics for a given font
diff --git a/src/quick/util/qquicktextmetrics.cpp b/src/quick/util/qquicktextmetrics.cpp
index 6d31ef582d..fc5b6f11c4 100644
--- a/src/quick/util/qquicktextmetrics.cpp
+++ b/src/quick/util/qquicktextmetrics.cpp
@@ -41,6 +41,7 @@ QT_BEGIN_NAMESPACE
\qmltype TextMetrics
\instantiates QQuickTextMetrics
\inqmlmodule QtQuick
+ \since 5.4
\ingroup qtquick-text-utility
\brief Provides metrics for a given font and text