summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel/qwindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/kernel/qwindow.cpp')
-rw-r--r--src/gui/kernel/qwindow.cpp183
1 files changed, 146 insertions, 37 deletions
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index 2f775ec664..b40fd7e8e8 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -128,7 +128,7 @@ QWindow::QWindow(QScreen *targetScreen)
, QSurface(QSurface::Window)
{
Q_D(QWindow);
- d->init(targetScreen);
+ d->init(nullptr, targetScreen);
}
static QWindow *nonDesktopParent(QWindow *parent)
@@ -169,11 +169,11 @@ QWindow::QWindow(QWindow *parent)
\sa setParent()
*/
QWindow::QWindow(QWindowPrivate &dd, QWindow *parent)
- : QObject(dd, nonDesktopParent(parent))
+ : QObject(dd, nullptr)
, QSurface(QSurface::Window)
{
Q_D(QWindow);
- d->init();
+ d->init(nonDesktopParent(parent));
}
/*!
@@ -183,6 +183,8 @@ QWindow::~QWindow()
{
Q_D(QWindow);
d->destroy();
+ // Decouple from parent before window goes under
+ setParent(nullptr);
QGuiApplicationPrivate::window_list.removeAll(this);
if (!QGuiApplicationPrivate::is_app_closing)
QGuiApplicationPrivate::instance()->modalWindowList.removeOne(this);
@@ -206,15 +208,19 @@ QWindowPrivate::QWindowPrivate()
QWindowPrivate::~QWindowPrivate()
= default;
-void QWindowPrivate::init(QScreen *targetScreen)
+void QWindowPrivate::init(QWindow *parent, QScreen *targetScreen)
{
Q_Q(QWindow);
+ q->QObject::setParent(parent);
+
isWindow = true;
parentWindow = static_cast<QWindow *>(q->QObject::parent());
+ QScreen *connectScreen = targetScreen ? targetScreen : QGuiApplication::primaryScreen();
+
if (!parentWindow)
- connectToScreen(targetScreen ? targetScreen : QGuiApplication::primaryScreen());
+ connectToScreen(connectScreen);
// If your application aborts here, you are probably creating a QWindow
// before the screen list is populated.
@@ -224,6 +230,27 @@ void QWindowPrivate::init(QScreen *targetScreen)
QGuiApplicationPrivate::window_list.prepend(q);
requestedFormat = QSurfaceFormat::defaultFormat();
+ devicePixelRatio = connectScreen->devicePixelRatio();
+
+ QObject::connect(q, &QWindow::screenChanged, q, [q, this](QScreen *){
+ // We may have changed scaling; trigger resize event if needed,
+ // except on Windows, where we send resize events during WM_DPICHANGED
+ // event handling. FIXME: unify DPI change handling across all platforms.
+#ifndef Q_OS_WIN
+ if (q->handle()) {
+ QWindowSystemInterfacePrivate::GeometryChangeEvent gce(q, QHighDpi::fromNativePixels(q->handle()->geometry(), q));
+ QGuiApplicationPrivate::processGeometryChangeEvent(&gce);
+ }
+#else
+ Q_UNUSED(q);
+#endif
+ updateDevicePixelRatio();
+ });
+
+ if (parentWindow) {
+ QChildWindowEvent childAddedEvent(QEvent::ChildWindowAdded, q);
+ QCoreApplication::sendEvent(parentWindow, &childAddedEvent);
+ }
}
/*!
@@ -428,14 +455,14 @@ void QWindowPrivate::updateSiblingPosition(SiblingPosition position)
QObjectList &siblings = q->parent()->d_ptr->children;
- const int siblingCount = siblings.size() - 1;
+ const qsizetype siblingCount = siblings.size() - 1;
if (siblingCount == 0)
return;
- const int currentPosition = siblings.indexOf(q);
+ const qsizetype currentPosition = siblings.indexOf(q);
Q_ASSERT(currentPosition >= 0);
- const int targetPosition = position == PositionTop ? siblingCount : 0;
+ const qsizetype targetPosition = position == PositionTop ? siblingCount : 0;
if (currentPosition == targetPosition)
return;
@@ -494,7 +521,9 @@ void QWindowPrivate::setTopLevelScreen(QScreen *newScreen, bool recreate)
}
}
-void QWindowPrivate::create(bool recursive, WId nativeHandle)
+static constexpr auto kForeignWindowId = "_q_foreignWinId";
+
+void QWindowPrivate::create(bool recursive)
{
Q_Q(QWindow);
if (platformWindow)
@@ -505,11 +534,16 @@ void QWindowPrivate::create(bool recursive, WId nativeHandle)
// the platformWindow, if there was one, is now gone, so make this flag reflect reality now
updateRequestPending = false;
- const qreal currentDevicePixelRatio = q->devicePixelRatio();
-
if (q->parent())
q->parent()->create();
+ if (platformWindow) {
+ // Creating the parent window will end up creating any child window
+ // that was already visible, via setVisible. If this applies to us,
+ // we will already have a platform window at this point.
+ return;
+ }
+
// QPlatformWindow will poll geometry() during construction below. Set the
// screen here so that high-dpi scaling will use the correct scale factor.
if (q->isTopLevel()) {
@@ -517,6 +551,8 @@ void QWindowPrivate::create(bool recursive, WId nativeHandle)
setTopLevelScreen(screen, false);
}
+ const WId nativeHandle = q->property(kForeignWindowId).value<WId>();
+
QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
platformWindow = nativeHandle ? platformIntegration->createForeignWindow(q, nativeHandle)
: platformIntegration->createPlatformWindow(q);
@@ -552,10 +588,7 @@ void QWindowPrivate::create(bool recursive, WId nativeHandle)
QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceCreated);
QGuiApplication::sendEvent(q, &e);
- if (!qFuzzyCompare(currentDevicePixelRatio, q->devicePixelRatio())) {
- QEvent dprChangeEvent(QEvent::DevicePixelRatioChange);
- QGuiApplication::sendEvent(q, &dprChangeEvent);
- }
+ updateDevicePixelRatio();
if (needsUpdate)
q->requestUpdate();
@@ -599,7 +632,9 @@ void QWindowPrivate::setMinOrMaxSize(QSize *oldSizeMember, const QSize &size,
// resize window if current size is outside of min and max limits
if (minimumSize.width() <= maximumSize.width()
|| minimumSize.height() <= maximumSize.height()) {
- q->resize(q->geometry().size().expandedTo(minimumSize).boundedTo(maximumSize));
+ const QSize currentSize = q->size();
+ const QSize boundedSize = currentSize.expandedTo(minimumSize).boundedTo(maximumSize);
+ q->resize(boundedSize);
}
}
@@ -689,6 +724,7 @@ void QWindow::create()
Returns the window's platform id.
\note This function will cause the platform window to be created if it is not already.
+ Returns 0, if the platform window creation failed.
For platforms where this id might be useful, the value returned
will uniquely represent the window inside the corresponding screen.
@@ -702,6 +738,9 @@ WId QWindow::winId() const
if (!d->platformWindow)
const_cast<QWindow *>(this)->create();
+ if (!d->platformWindow)
+ return 0;
+
return d->platformWindow->winId();
}
@@ -745,6 +784,10 @@ void QWindow::setParent(QWindow *parent)
return;
}
+ QEvent parentAboutToChangeEvent(QEvent::ParentWindowAboutToChange);
+ QCoreApplication::sendEvent(this, &parentAboutToChangeEvent);
+
+ const auto previousParent = d->parentWindow;
QObject::setParent(parent);
d->parentWindow = parent;
@@ -767,6 +810,19 @@ void QWindow::setParent(QWindow *parent)
}
QGuiApplicationPrivate::updateBlockedStatus(this);
+
+ if (previousParent) {
+ QChildWindowEvent childRemovedEvent(QEvent::ChildWindowRemoved, this);
+ QCoreApplication::sendEvent(previousParent, &childRemovedEvent);
+ }
+
+ if (parent) {
+ QChildWindowEvent childAddedEvent(QEvent::ChildWindowAdded, this);
+ QCoreApplication::sendEvent(parent, &childAddedEvent);
+ }
+
+ QEvent parentChangedEvent(QEvent::ParentWindowChange);
+ QCoreApplication::sendEvent(this, &parentChangedEvent);
}
/*!
@@ -1333,14 +1389,31 @@ Qt::ScreenOrientation QWindow::contentOrientation() const
qreal QWindow::devicePixelRatio() const
{
Q_D(const QWindow);
+ return d->devicePixelRatio;
+}
+
+/*
+ Updates the cached devicePixelRatio value by polling for a new value.
+ Sends QEvent::DevicePixelRatioChange to the window if the DPR has changed.
+ Returns true if the DPR was changed.
+*/
+bool QWindowPrivate::updateDevicePixelRatio()
+{
+ Q_Q(QWindow);
// If there is no platform window use the associated screen's devicePixelRatio,
// which typically is the primary screen and will be correct for single-display
// systems (a very common case).
- if (!d->platformWindow)
- return screen()->devicePixelRatio();
+ const qreal newDevicePixelRatio = platformWindow ?
+ platformWindow->devicePixelRatio() * QHighDpiScaling::factor(q) : q->screen()->devicePixelRatio();
- return d->platformWindow->devicePixelRatio() * QHighDpiScaling::factor(this);
+ if (newDevicePixelRatio == devicePixelRatio)
+ return false;
+
+ devicePixelRatio = newDevicePixelRatio;
+ QEvent dprChangeEvent(QEvent::DevicePixelRatioChange);
+ QGuiApplication::sendEvent(q, &dprChangeEvent);
+ return true;
}
Qt::WindowState QWindowPrivate::effectiveState(Qt::WindowStates state)
@@ -1611,20 +1684,18 @@ void QWindow::setY(int arg)
\property QWindow::width
\brief the width of the window's geometry
*/
-void QWindow::setWidth(int arg)
+void QWindow::setWidth(int w)
{
- if (width() != arg)
- resize(arg, height());
+ resize(w, height());
}
/*!
\property QWindow::height
\brief the height of the window's geometry
*/
-void QWindow::setHeight(int arg)
+void QWindow::setHeight(int h)
{
- if (height() != arg)
- resize(width(), arg);
+ resize(width(), h);
}
/*!
@@ -1946,12 +2017,16 @@ void QWindow::resize(int w, int h)
void QWindow::resize(const QSize &newSize)
{
Q_D(QWindow);
+
+ const QSize oldSize = size();
+ if (newSize == oldSize)
+ return;
+
d->positionPolicy = QWindowPrivate::WindowFrameExclusive;
if (d->platformWindow) {
d->platformWindow->setGeometry(
QHighDpi::toNativeWindowGeometry(QRect(position(), newSize), this));
} else {
- const QSize oldSize = d->geometry.size();
d->geometry.setSize(newSize);
if (newSize.width() != oldSize.width())
emit widthChanged(newSize.width());
@@ -1988,6 +2063,16 @@ void QWindowPrivate::destroy()
QObject *object = childrenWindows.at(i);
if (object->isWindowType()) {
QWindow *w = static_cast<QWindow*>(object);
+ auto *childPlatformWindow = w->handle();
+ if (!childPlatformWindow)
+ continue;
+
+ // Decouple the foreign window from this window,
+ // so that destroying our native handle doesn't
+ // bring down the foreign window as well.
+ if (childPlatformWindow->isForeignWindow())
+ childPlatformWindow->setParent(nullptr);
+
qt_window_private(w)->destroy();
}
}
@@ -2160,20 +2245,26 @@ QObject *QWindow::focusObject() const
/*!
Shows the window.
- This is equivalent to calling showFullScreen(), showMaximized(), or showNormal(),
+ For child windows, this is equivalent to calling showNormal().
+ Otherwise, it is equivalent to calling showFullScreen(), showMaximized(), or showNormal(),
depending on the platform's default behavior for the window type and flags.
\sa showFullScreen(), showMaximized(), showNormal(), hide(), QStyleHints::showIsFullScreen(), flags()
*/
void QWindow::show()
{
- Qt::WindowState defaultState = QGuiApplicationPrivate::platformIntegration()->defaultWindowState(d_func()->windowFlags);
- if (defaultState == Qt::WindowFullScreen)
- showFullScreen();
- else if (defaultState == Qt::WindowMaximized)
- showMaximized();
- else
+ if (parent()) {
showNormal();
+ } else {
+ const auto *platformIntegration = QGuiApplicationPrivate::platformIntegration();
+ Qt::WindowState defaultState = platformIntegration->defaultWindowState(d_func()->windowFlags);
+ if (defaultState == Qt::WindowFullScreen)
+ showFullScreen();
+ else if (defaultState == Qt::WindowMaximized)
+ showMaximized();
+ else
+ showNormal();
+ }
}
/*!
@@ -2779,7 +2870,12 @@ QPointF QWindow::mapToGlobal(const QPointF &pos) const
// Map the position (and the window's global position) to native coordinates, perform
// the addition, and then map back to device independent coordinates.
QPointF nativeLocalPos = QHighDpi::toNativeLocalPosition(pos, this);
- QPointF nativeWindowGlobalPos = QHighDpi::toNativeGlobalPosition(QPointF(d->globalPosition()), this);
+ // Get the native window position directly from the platform window
+ // if available (it can be null if the window hasn't been shown yet),
+ // or fall back to scaling the QWindow position.
+ QPointF nativeWindowGlobalPos = d->platformWindow
+ ? d->platformWindow->mapToGlobal(QPoint(0,0)).toPointF()
+ : QHighDpi::toNativeGlobalPosition(QPointF(d->globalPosition()), this);
QPointF nativeGlobalPos = nativeLocalPos + nativeWindowGlobalPos;
QPointF deviceIndependentGlobalPos = QHighDpi::fromNativeGlobalPosition(nativeGlobalPos, this);
return deviceIndependentGlobalPos;
@@ -2817,7 +2913,12 @@ QPointF QWindow::mapFromGlobal(const QPointF &pos) const
// Calculate local position in the native coordinate system. (See comment for the
// corresponding mapToGlobal() code above).
QPointF nativeGlobalPos = QHighDpi::toNativeGlobalPosition(pos, this);
- QPointF nativeWindowGlobalPos = QHighDpi::toNativeGlobalPosition(QPointF(d->globalPosition()), this);
+ // Get the native window position directly from the platform window
+ // if available (it can be null if the window hasn't been shown yet),
+ // or fall back to scaling the QWindow position.
+ QPointF nativeWindowGlobalPos = d->platformWindow
+ ? d->platformWindow->mapToGlobal(QPoint(0,0)).toPointF()
+ : QHighDpi::toNativeGlobalPosition(QPointF(d->globalPosition()), this);
QPointF nativeLocalPos = nativeGlobalPos - nativeWindowGlobalPos;
QPointF deviceIndependentLocalPos = QHighDpi::fromNativeLocalPosition(nativeLocalPos, this);
return deviceIndependentLocalPos;
@@ -2899,7 +3000,11 @@ QWindow *QWindow::fromWinId(WId id)
}
QWindow *window = new QWindow;
- qt_window_private(window)->create(false, id);
+
+ // Persist the winId in a private property so that we
+ // can recreate the window after being destroyed.
+ window->setProperty(kForeignWindowId, id);
+ window->create();
if (!window->handle()) {
delete window;
@@ -3048,10 +3153,14 @@ void *QWindow::resolveInterface(const char *name, int revision) const
QT_NATIVE_INTERFACE_RETURN_IF(QCocoaWindow, platformWindow);
#endif
-#if defined(Q_OS_UNIX)
+#if QT_CONFIG(wayland)
QT_NATIVE_INTERFACE_RETURN_IF(QWaylandWindow, platformWindow);
#endif
+#if defined(Q_OS_WASM)
+ QT_NATIVE_INTERFACE_RETURN_IF(QWasmWindow, platformWindow);
+#endif
+
return nullptr;
}