Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqmlpreviewhandler.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <QtCore/qtimer.h>
7#include <QtCore/qsettings.h>
8#include <QtCore/qlibraryinfo.h>
9
10#include <QtGui/qwindow.h>
11#include <QtGui/qguiapplication.h>
12#include <QtQuick/qquickwindow.h>
13#include <QtQuick/qquickitem.h>
14#include <QtQml/qqmlcomponent.h>
15
16#include <private/qquickpixmap_p.h>
17#include <private/qquickview_p.h>
18#include <private/qhighdpiscaling_p.h>
19
21
37
39{
40 m_dummyItem.reset(new QQuickItem);
41
42 // TODO: Is there a better way to determine this? We want to keep the window alive when possible
43 // as otherwise it will reappear in a different place when (re)loading a file. However,
44 // the file we load might create another window, in which case the eglfs plugin (and
45 // others?) will do a qFatal as it only supports a single window.
46 const QString platformName = QGuiApplication::platformName();
47 m_supportsMultipleWindows = (platformName == QStringLiteral("windows")
48 || platformName == QStringLiteral("cocoa")
49 || platformName == QStringLiteral("xcb")
50 || platformName == QStringLiteral("wayland"));
51
52 QCoreApplication::instance()->installEventFilter(this);
53
54 m_fpsTimer.setInterval(1000);
55 connect(&m_fpsTimer, &QTimer::timeout, this, &QQmlPreviewHandler::fpsTimerHit);
56}
57
62
63static void closeAllWindows()
64{
66 for (QWindow *window : windows)
67 window->close();
68}
69
71{
72 if (m_currentWindow && (event->type() == QEvent::Move) &&
73 qobject_cast<QQuickWindow*>(obj) == m_currentWindow) {
74 m_lastPosition.takePosition(m_currentWindow);
75 }
76
78}
79
81{
82 return m_currentRootItem;
83}
84
89
91{
92 const bool found = m_engines.removeOne(qmlEngine);
93 Q_ASSERT(found);
94 for (QObject *obj : m_createdObjects)
95 if (obj && ::qmlEngine(obj) == qmlEngine)
96 delete obj;
97 m_createdObjects.removeAll(nullptr);
98}
99
101{
102 QSharedPointer<QuitLockDisabler> disabler(new QuitLockDisabler);
103
104 clear();
105 m_component.reset(nullptr);
107
108 const int numEngines = m_engines.size();
109 if (numEngines > 1) {
110 emit error(QString::fromLatin1("%1 QML engines available. We cannot decide which one "
111 "should load the component.").arg(numEngines));
112 return;
113 } else if (numEngines == 0) {
114 emit error(QLatin1String("No QML engines found."));
115 return;
116 }
117 m_lastPosition.loadWindowPositionSettings(url);
118
119 QQmlEngine *engine = m_engines.front();
120 engine->clearComponentCache();
121 m_component.reset(new QQmlComponent(engine, url, this));
122
123 auto onStatusChanged = [disabler, this](QQmlComponent::Status status) {
124 switch (status) {
127 return true; // try again later
129 tryCreateObject();
130 break;
132 emit error(m_component->errorString());
133 break;
134 default:
135 Q_UNREACHABLE();
136 break;
137 }
138
139 disconnect(m_component.data(), &QQmlComponent::statusChanged, this, nullptr);
140 return false; // we're done
141 };
142
143 if (onStatusChanged(m_component->status()))
144 connect(m_component.data(), &QQmlComponent::statusChanged, this, onStatusChanged);
145}
146
148{
149 if (m_component.isNull() || !m_component->isReady())
150 emit error(QLatin1String("Component is not ready."));
151
152 QuitLockDisabler disabler;
153 Q_UNUSED(disabler);
154 clear();
155 tryCreateObject();
156}
157
159{
160 m_zoomFactor = newFactor;
161 QTimer::singleShot(0, this, &QQmlPreviewHandler::doZoom);
162}
163
164void QQmlPreviewHandler::doZoom()
165{
166 if (!m_currentWindow)
167 return;
168 if (qFuzzyIsNull(m_zoomFactor)) {
169 emit error(QString::fromLatin1("Zooming with factor: %1 will result in nothing " \
170 "so it will be ignored.").arg(m_zoomFactor));
171 return;
172 }
173
174 bool resetZoom = false;
175 if (m_zoomFactor < 0) {
176 resetZoom = true;
177 m_zoomFactor = 1.0;
178 }
179
180 m_currentWindow->setGeometry(m_currentWindow->geometry());
181
182 m_lastPosition.takePosition(m_currentWindow, QQmlPreviewPosition::InitializePosition);
183 m_currentWindow->destroy();
184
185 for (QScreen *screen : QGuiApplication::screens())
186 QHighDpiScaling::setScreenFactor(screen, m_zoomFactor);
187 if (resetZoom)
189
190 m_currentWindow->show();
191 m_lastPosition.initLastSavedWindowPosition(m_currentWindow);
192}
193
195{
196 qDeleteAll(m_createdObjects);
197 m_createdObjects.clear();
198 setCurrentWindow(nullptr);
199}
200
201Qt::WindowFlags fixFlags(Qt::WindowFlags flags)
202{
203 // If only the type flag is given, some other window flags are automatically assumed. When we
204 // add a flag, we need to make those explicit.
205 switch (flags) {
206 case Qt::Window:
209 case Qt::Dialog:
210 case Qt::Tool:
212 default:
213 return flags;
214 }
215}
216
217void QQmlPreviewHandler::showObject(QObject *object)
218{
219 if (QWindow *window = qobject_cast<QWindow *>(object)) {
220 setCurrentWindow(qobject_cast<QQuickWindow *>(window));
221 for (QWindow *otherWindow : QGuiApplication::allWindows()) {
222 if (QQuickWindow *quickWindow = qobject_cast<QQuickWindow *>(otherWindow)) {
223 if (quickWindow == m_currentWindow)
224 continue;
225 quickWindow->setVisible(false);
226 quickWindow->setFlags(quickWindow->flags() & ~Qt::WindowStaysOnTopHint);
227 }
228 }
229 } else if (QQuickItem *item = qobject_cast<QQuickItem *>(object)) {
230 setCurrentWindow(nullptr);
231 for (QWindow *window : QGuiApplication::allWindows()) {
232 if (QQuickWindow *quickWindow = qobject_cast<QQuickWindow *>(window)) {
233 if (m_currentWindow != nullptr) {
234 emit error(QLatin1String("Multiple QQuickWindows available. We cannot "
235 "decide which one to use."));
236 return;
237 }
238 setCurrentWindow(quickWindow);
239 } else {
240 window->setVisible(false);
241 window->setFlag(Qt::WindowStaysOnTopHint, false);
242 }
243 }
244
245 if (m_currentWindow == nullptr) {
246 setCurrentWindow(new QQuickWindow);
247 m_createdObjects.append(m_currentWindow.data());
248 }
249
250 for (QQuickItem *oldItem : m_currentWindow->contentItem()->childItems())
251 oldItem->setParentItem(m_dummyItem.data());
252
253 // Special case for QQuickView, as that keeps a "root" pointer around, and uses it to
254 // automatically resize the window or the item.
255 if (QQuickView *view = qobject_cast<QQuickView *>(m_currentWindow))
256 QQuickViewPrivate::get(view)->setRootObject(item);
257 else
258 item->setParentItem(m_currentWindow->contentItem());
259
260 m_currentWindow->resize(item->size().toSize());
261 // used by debug translation service to get the states
262 m_currentRootItem = item;
263 } else {
264 emit error(QLatin1String("Created object is neither a QWindow nor a QQuickItem."));
265 }
266
267 if (m_currentWindow) {
268 m_lastPosition.initLastSavedWindowPosition(m_currentWindow);
269 m_currentWindow->setFlags(fixFlags(m_currentWindow->flags()) | Qt::WindowStaysOnTopHint);
270 m_currentWindow->setVisible(true);
271 }
272}
273
274void QQmlPreviewHandler::setCurrentWindow(QQuickWindow *window)
275{
276 if (window == m_currentWindow.data())
277 return;
278
279 if (m_currentWindow) {
281 this, &QQmlPreviewHandler::beforeSynchronizing);
282 disconnect(m_currentWindow.data(), &QQuickWindow::afterSynchronizing,
283 this, &QQmlPreviewHandler::afterSynchronizing);
285 this, &QQmlPreviewHandler::beforeRendering);
286 disconnect(m_currentWindow.data(), &QQuickWindow::frameSwapped,
287 this, &QQmlPreviewHandler::frameSwapped);
288 m_fpsTimer.stop();
289 m_rendering = FrameTime();
290 m_synchronizing = FrameTime();
291 }
292
293 m_currentWindow = window;
294
295 if (m_currentWindow) {
297 this, &QQmlPreviewHandler::beforeSynchronizing, Qt::DirectConnection);
298 connect(m_currentWindow.data(), &QQuickWindow::afterSynchronizing,
299 this, &QQmlPreviewHandler::afterSynchronizing, Qt::DirectConnection);
300 connect(m_currentWindow.data(), &QQuickWindow::beforeRendering,
301 this, &QQmlPreviewHandler::beforeRendering, Qt::DirectConnection);
302 connect(m_currentWindow.data(), &QQuickWindow::frameSwapped,
303 this, &QQmlPreviewHandler::frameSwapped, Qt::DirectConnection);
304 m_fpsTimer.start();
305 }
306}
307
308void QQmlPreviewHandler::beforeSynchronizing()
309{
310 m_synchronizing.beginFrame();
311}
312
313void QQmlPreviewHandler::afterSynchronizing()
314{
315
316 if (m_rendering.elapsed >= 0)
317 m_rendering.endFrame();
318 m_synchronizing.recordFrame();
319 m_synchronizing.endFrame();
320}
321
322void QQmlPreviewHandler::beforeRendering()
323{
324 m_rendering.beginFrame();
325}
326
327void QQmlPreviewHandler::frameSwapped()
328{
329 m_rendering.recordFrame();
330}
331
332void QQmlPreviewHandler::FrameTime::beginFrame()
333{
334 timer.start();
335}
336
337void QQmlPreviewHandler::FrameTime::recordFrame()
338{
339 elapsed = timer.elapsed();
340}
341
342void QQmlPreviewHandler::FrameTime::endFrame()
343{
344 if (elapsed < min)
345 min = static_cast<quint16>(qMax(0ll, elapsed));
346 if (elapsed > max)
347 max = static_cast<quint16>(qMin(qint64(std::numeric_limits<quint16>::max()), elapsed));
348 total = static_cast<quint16>(qBound(0ll, qint64(std::numeric_limits<quint16>::max()),
349 elapsed + total));
350 ++number;
351 elapsed = -1;
352}
353
354void QQmlPreviewHandler::FrameTime::reset()
355{
356 min = std::numeric_limits<quint16>::max();
357 max = 0;
358 total = 0;
359 number = 0;
360}
361
362void QQmlPreviewHandler::fpsTimerHit()
363{
364 const FpsInfo info = {
365 m_synchronizing.number,
366 m_synchronizing.min,
367 m_synchronizing.max,
368 m_synchronizing.total,
369
370 m_rendering.number,
371 m_rendering.min,
372 m_rendering.max,
373 m_rendering.total
374 };
375
376 emit fps(info);
377
378 m_rendering.reset();
379 m_synchronizing.reset();
380}
381
382void QQmlPreviewHandler::tryCreateObject()
383{
384 if (!m_supportsMultipleWindows)
386 QObject *object = m_component->create();
387 m_createdObjects.append(object);
388 showObject(object);
389}
390
392
393#include "moc_qqmlpreviewhandler.cpp"
\inmodule QtCore
static QCoreApplication * instance() noexcept
Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance.
static void setQuitLockEnabled(bool enabled)
void start() noexcept
\typealias QElapsedTimer::Duration Synonym for std::chrono::nanoseconds.
\inmodule QtCore
Definition qcoreevent.h:45
void setParentItem(QGraphicsItem *parent)
Sets this item's parent item to newParent.
\macro qGuiApp
static QWindowList allWindows()
Returns a list of all the windows in the application.
QString platformName
The name of the underlying platform plugin.
Collection of utility functions for UI scaling.
static void updateHighDpiScaling()
qsizetype size() const noexcept
Definition qlist.h:397
bool removeOne(const AT &t)
Definition qlist.h:598
reference front()
Definition qlist.h:687
void append(parameter_type t)
Definition qlist.h:458
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
virtual bool eventFilter(QObject *watched, QEvent *event)
Filters events if this object has been installed as an event filter for the watched object.
Definition qobject.cpp:1555
T * data() const noexcept
Definition qpointer.h:73
The QQmlComponent class encapsulates a QML component definition.
Status
\qmltype Component \instantiates QQmlComponent\inqmlmodule QtQml
Status status
\qmlproperty enumeration Component::status
bool isReady() const
Returns true if status() == QQmlComponent::Ready.
Q_INVOKABLE QString errorString() const
\qmlmethod string Component::errorString()
virtual QObject * create(QQmlContext *context=nullptr)
Create an object instance from this component, within the specified context.
void statusChanged(QQmlComponent::Status)
Emitted whenever the component's status changes.
The QQmlEngine class provides an environment for instantiating QML components.
Definition qqmlengine.h:57
void zoom(qreal newFactor)
QQuickItem * currentRootItem()
bool eventFilter(QObject *obj, QEvent *event) override
Filters events if this object has been installed as an event filter for the watched object.
void fps(const FpsInfo &info)
void removeEngine(QQmlEngine *engine)
void addEngine(QQmlEngine *engine)
void loadUrl(const QUrl &url)
QQmlPreviewHandler(QObject *parent=nullptr)
void loadWindowPositionSettings(const QUrl &url)
void takePosition(QWindow *window, InitializeState state=PositionInitialized)
void initLastSavedWindowPosition(QWindow *window)
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
static void purgeCache()
static QQuickViewPrivate * get(QQuickView *view)
The QQuickView class provides a window for displaying a Qt Quick user interface.
Definition qquickview.h:20
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
void frameSwapped()
This signal is emitted when a frame has been queued for presenting.
void beforeSynchronizing()
This signal is emitted before the scene graph is synchronized with the QML state.
QQuickItem * contentItem
\qmlattachedproperty Item Window::contentItem
void beforeRendering()
\qmlsignal QtQuick::Window::afterSynchronizing()
T * data() const noexcept
Returns the value of the pointer referenced by this object.
bool isNull() const noexcept
Returns true if this object refers to \nullptr.
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
The QScreen class is used to query screen properties. \inmodule QtGui.
Definition qscreen.h:32
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
Definition qtimer.cpp:241
void setInterval(int msec)
Definition qtimer.cpp:579
bool singleShot
whether the timer is a single-shot timer
Definition qtimer.h:22
void stop()
Stops the timer.
Definition qtimer.cpp:267
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
\inmodule QtCore
Definition qurl.h:94
\inmodule QtGui
Definition qwindow.h:63
void show()
Shows the window.
Definition qwindow.cpp:2254
Qt::WindowFlags flags
the window flags of the window
Definition qwindow.h:79
void setGeometry(int posx, int posy, int w, int h)
Sets the geometry of the window, excluding its window frame, to a rectangle constructed from posx,...
Definition qwindow.cpp:1802
void setVisible(bool visible)
Definition qwindow.cpp:689
qDeleteAll(list.begin(), list.end())
Combined button and popup list for selecting options.
constexpr const T & min(const T &a, const T &b)
Definition qnumeric.h:366
@ DirectConnection
@ Window
Definition qnamespace.h:207
@ WindowStaysOnTopHint
Definition qnamespace.h:233
@ WindowMaximizeButtonHint
Definition qnamespace.h:229
@ WindowMinimizeButtonHint
Definition qnamespace.h:228
@ Dialog
Definition qnamespace.h:208
@ Tool
Definition qnamespace.h:212
@ WindowTitleHint
Definition qnamespace.h:226
@ WindowSystemMenuHint
Definition qnamespace.h:227
@ WindowCloseButtonHint
Definition qnamespace.h:241
#define Q_NODISCARD_CTOR
DBusConnection const char DBusError * error
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:349
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLbitfield flags
struct _cl_event * event
GLhandleARB obj
[2]
QQmlEngine * qmlEngine(const QObject *obj)
Definition qqml.cpp:80
static void closeAllWindows()
Qt::WindowFlags fixFlags(Qt::WindowFlags flags)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
QScreen * screen
[1]
Definition main.cpp:29
static double elapsed(qint64 after, qint64 before)
#define emit
#define Q_UNUSED(x)
unsigned short quint16
Definition qtypes.h:48
long long qint64
Definition qtypes.h:60
double qreal
Definition qtypes.h:187
QUrl url("example.com")
[constructor-url-reference]
myObject disconnect()
[26]
QTimer * timer
[3]
QGraphicsItem * item
aWidget window() -> setWindowTitle("New Window Title")
[2]
QHostInfo info
[0]
QQuickView * view
[0]
QJSEngine engine
[0]
Q_NODISCARD_CTOR QuitLockDisabler()