6#include <QtCore/qtimer.h>
7#include <QtCore/qsettings.h>
8#include <QtCore/qlibraryinfo.h>
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>
16#include <private/qhighdpiscaling_p.h>
17#include <private/qqmlmetatype_p.h>
18#include <private/qquickpixmap_p.h>
19#include <private/qquickview_p.h>
20#include <private/qv4compileddata_p.h>
24struct QuitLockDisabler
26 const bool quitLockEnabled;
28 Q_NODISCARD_CTOR QuitLockDisabler()
29 : quitLockEnabled(QCoreApplication::isQuitLockEnabled())
31 QCoreApplication::setQuitLockEnabled(
false);
36 QCoreApplication::setQuitLockEnabled(quitLockEnabled);
42 m_dummyItem.reset(
new QQuickItem);
48 const QString platformName = QGuiApplication::platformName();
49 m_supportsMultipleWindows = (platformName == QStringLiteral(
"windows")
50 || platformName == QStringLiteral(
"cocoa")
51 || platformName == QStringLiteral(
"xcb")
52 || platformName == QStringLiteral(
"wayland"));
54 QCoreApplication::instance()->installEventFilter(
this);
56 m_fpsTimer.setInterval(1000);
57 connect(&m_fpsTimer, &QTimer::timeout,
this, &QQmlPreviewHandler::fpsTimerHit);
67 const QWindowList windows = QGuiApplication::allWindows();
68 for (QWindow *window : windows)
74 if (m_currentWindow && (event->type() == QEvent::Move) &&
75 qobject_cast<QQuickWindow*>(obj) == m_currentWindow) {
76 m_lastPosition.takePosition(m_currentWindow);
79 return QObject::eventFilter(obj, event);
84 return m_currentRootItem;
89 m_engines.append(qmlEngine);
94 const bool found = m_engines.removeOne(qmlEngine);
96 for (QObject *obj : m_createdObjects)
97 if (obj && ::qmlEngine(obj) == qmlEngine)
99 m_createdObjects.removeAll(
nullptr);
104 QSharedPointer<QuitLockDisabler> disabler(
new QuitLockDisabler);
107 m_component.reset(
nullptr);
108 QQuickPixmap::purgeCache();
110 const int numEngines = m_engines.size();
111 if (numEngines > 1) {
112 emit error(QString::fromLatin1(
"%1 QML engines available. We cannot decide which one "
113 "should load the component.").arg(numEngines));
115 }
else if (numEngines == 0) {
116 emit error(QLatin1String(
"No QML engines found."));
119 m_lastPosition.loadWindowPositionSettings(url);
121 QQmlEngine *engine = m_engines.front();
122 engine->clearSingletons();
123 engine->clearComponentCache();
124 m_component.reset(
new QQmlComponent(engine, url,
this));
126 auto onStatusChanged = [disabler,
this](QQmlComponent::Status status) {
128 case QQmlComponent::Null:
129 case QQmlComponent::Loading:
131 case QQmlComponent::Ready:
134 case QQmlComponent::Error:
135 emit error(m_component->errorString());
142 disconnect(m_component.data(), &QQmlComponent::statusChanged,
this,
nullptr);
146 if (onStatusChanged(m_component->status()))
147 connect(m_component.data(), &QQmlComponent::statusChanged,
this, onStatusChanged);
153 if (
const auto cu = QQmlMetaType::obtainCompilationUnit(url))
154 QQmlMetaType::unregisterInternalCompositeType(cu);
159 if (m_component.isNull() || !m_component->isReady())
160 emit error(QLatin1String(
"Component is not ready."));
162 QuitLockDisabler disabler;
170 m_zoomFactor = newFactor;
171 QTimer::singleShot(0,
this, &QQmlPreviewHandler::doZoom);
176 if (!m_currentWindow)
178 if (qFuzzyIsNull(m_zoomFactor)) {
179 emit error(QString::fromLatin1(
"Zooming with factor: %1 will result in nothing "
180 "so it will be ignored.").arg(m_zoomFactor));
184 bool resetZoom =
false;
185 if (m_zoomFactor < 0) {
190 m_currentWindow->setGeometry(m_currentWindow->geometry());
192 m_lastPosition.takePosition(m_currentWindow, QQmlPreviewPosition::InitializePosition);
193 m_currentWindow->destroy();
195 for (QScreen *screen : QGuiApplication::screens())
196 QHighDpiScaling::setScreenFactor(screen, m_zoomFactor);
198 QHighDpiScaling::updateHighDpiScaling();
200 m_currentWindow->show();
201 m_lastPosition.initLastSavedWindowPosition(m_currentWindow);
206 qDeleteAll(m_createdObjects);
207 m_createdObjects.clear();
208 setCurrentWindow(
nullptr);
217 return flags | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint
218 | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint;
221 return flags | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
229 if (QWindow *window = qobject_cast<QWindow *>(object)) {
230 setCurrentWindow(qobject_cast<QQuickWindow *>(window));
231 for (QWindow *otherWindow : QGuiApplication::allWindows()) {
232 if (QQuickWindow *quickWindow = qobject_cast<QQuickWindow *>(otherWindow)) {
233 if (quickWindow == m_currentWindow)
235 quickWindow->setVisible(
false);
236 quickWindow->setFlags(quickWindow->flags() & ~Qt::WindowStaysOnTopHint);
239 }
else if (QQuickItem *item = qobject_cast<QQuickItem *>(object)) {
240 setCurrentWindow(
nullptr);
241 for (QWindow *window : QGuiApplication::allWindows()) {
242 if (QQuickWindow *quickWindow = qobject_cast<QQuickWindow *>(window)) {
243 if (m_currentWindow !=
nullptr) {
244 emit error(QLatin1String(
"Multiple QQuickWindows available. We cannot "
245 "decide which one to use."));
248 setCurrentWindow(quickWindow);
250 window->setVisible(
false);
251 window->setFlag(Qt::WindowStaysOnTopHint,
false);
255 if (m_currentWindow ==
nullptr) {
256 setCurrentWindow(
new QQuickWindow);
257 m_createdObjects.append(m_currentWindow.data());
260 for (QQuickItem *oldItem : m_currentWindow->contentItem()->childItems())
261 oldItem->setParentItem(m_dummyItem.data());
265 if (QQuickView *view = qobject_cast<QQuickView *>(m_currentWindow))
266 QQuickViewPrivate::get(view)->setRootObject(item);
268 item->setParentItem(m_currentWindow->contentItem());
270 m_currentWindow->resize(item->size().toSize());
272 m_currentRootItem = item;
274 emit error(QLatin1String(
"Created object is neither a QWindow nor a QQuickItem."));
277 if (m_currentWindow) {
278 m_lastPosition.initLastSavedWindowPosition(m_currentWindow);
279 m_currentWindow->setFlags(fixFlags(m_currentWindow->flags()) | Qt::WindowStaysOnTopHint);
280 m_currentWindow->setVisible(
true);
286 if (window == m_currentWindow.data())
289 if (m_currentWindow) {
290 disconnect(m_currentWindow.data(), &QQuickWindow::beforeSynchronizing,
291 this, &QQmlPreviewHandler::beforeSynchronizing);
292 disconnect(m_currentWindow.data(), &QQuickWindow::afterSynchronizing,
293 this, &QQmlPreviewHandler::afterSynchronizing);
294 disconnect(m_currentWindow.data(), &QQuickWindow::beforeRendering,
295 this, &QQmlPreviewHandler::beforeRendering);
296 disconnect(m_currentWindow.data(), &QQuickWindow::frameSwapped,
297 this, &QQmlPreviewHandler::frameSwapped);
299 m_rendering = FrameTime();
300 m_synchronizing = FrameTime();
303 m_currentWindow = window;
305 if (m_currentWindow) {
306 connect(m_currentWindow.data(), &QQuickWindow::beforeSynchronizing,
307 this, &QQmlPreviewHandler::beforeSynchronizing, Qt::DirectConnection);
308 connect(m_currentWindow.data(), &QQuickWindow::afterSynchronizing,
309 this, &QQmlPreviewHandler::afterSynchronizing, Qt::DirectConnection);
310 connect(m_currentWindow.data(), &QQuickWindow::beforeRendering,
311 this, &QQmlPreviewHandler::beforeRendering, Qt::DirectConnection);
312 connect(m_currentWindow.data(), &QQuickWindow::frameSwapped,
313 this, &QQmlPreviewHandler::frameSwapped, Qt::DirectConnection);
320 m_synchronizing.beginFrame();
326 if (m_rendering.elapsed >= 0)
327 m_rendering.endFrame();
328 m_synchronizing.recordFrame();
329 m_synchronizing.endFrame();
334 m_rendering.beginFrame();
339 m_rendering.recordFrame();
349 elapsed = timer.elapsed();
355 min =
static_cast<quint16>(qMax(0ll, elapsed));
357 max =
static_cast<quint16>(qMin(qint64(std::numeric_limits<quint16>::max()), elapsed));
358 total =
static_cast<quint16>(qBound(0ll, qint64(std::numeric_limits<quint16>::max()),
366 min = std::numeric_limits<quint16>::max();
375 m_synchronizing.number,
378 m_synchronizing.total,
389 m_synchronizing.reset();
394 if (!m_supportsMultipleWindows)
396 QObject *object = m_component->create();
397 m_createdObjects.append(object);
403#include "moc_qqmlpreviewhandler.cpp"
void dropCU(const QUrl &url)
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 removeEngine(QQmlEngine *engine)
void addEngine(QQmlEngine *engine)
void loadUrl(const QUrl &url)
static void closeAllWindows()
Qt::WindowFlags fixFlags(Qt::WindowFlags flags)