Ensure all platforms send geometry events if request was not fulfilled
The logic of deciding whether or not to send resize and move events has been centralized in QGuiApplication. This ensures that if a window with geometry 100,100+200x200 is moved and resized to e.g. 0,0+100x100, but the window manager denies the request (because the window would e.g. overlap with system UI), and issues a geometry update with the original geometry, 100,100+200x200, we will still treat that as warrant of a move/resize event to the application, so the application knows that its position and size is as before. [ChangeLog][Qt Gui][QPA] QWindowSystemInterfacePrivate::handleGeometryChange no longer takes the old geometry as an argument. Task-number: QTBUG-57608 Change-Id: I1d471cc7a257fef958bdb1e56184fa95489403a3 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
This commit is contained in:
parent
9381ca77b2
commit
3a31c70879
@ -2213,7 +2213,7 @@ void QGuiApplicationPrivate::processWindowScreenChangedEvent(QWindowSystemInterf
|
||||
}
|
||||
// we may have changed scaling, so trigger resize event if needed
|
||||
if (window->handle()) {
|
||||
QWindowSystemInterfacePrivate::GeometryChangeEvent gce(window, QHighDpi::fromNativePixels(window->handle()->geometry(), window), QRect());
|
||||
QWindowSystemInterfacePrivate::GeometryChangeEvent gce(window, QHighDpi::fromNativePixels(window->handle()->geometry(), window));
|
||||
processGeometryChangeEvent(&gce);
|
||||
}
|
||||
}
|
||||
@ -2238,35 +2238,46 @@ void QGuiApplicationPrivate::processGeometryChangeEvent(QWindowSystemInterfacePr
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
QRect newRect = e->newGeometry;
|
||||
QRect oldRect = e->oldGeometry.isNull() ? window->d_func()->geometry : e->oldGeometry;
|
||||
const QRect lastReportedGeometry = window->d_func()->geometry;
|
||||
const QRect requestedGeometry = e->requestedGeometry;
|
||||
const QRect actualGeometry = e->newGeometry;
|
||||
|
||||
bool isResize = oldRect.size() != newRect.size();
|
||||
bool isMove = oldRect.topLeft() != newRect.topLeft();
|
||||
// We send size and move events only if the geometry has changed from
|
||||
// what was last reported, or if the user tried to set a new geometry,
|
||||
// but the window manager responded by keeping the old geometry. In the
|
||||
// latter case we send move/resize events with the same geometry as the
|
||||
// last reported geometry, to indicate that the window wasn't moved or
|
||||
// resized. Note that this logic does not apply to the property changes
|
||||
// of the window, as we don't treat them as part of this request/response
|
||||
// protocol of QWindow/QPA.
|
||||
const bool isResize = actualGeometry.size() != lastReportedGeometry.size()
|
||||
|| requestedGeometry.size() != actualGeometry.size();
|
||||
const bool isMove = actualGeometry.topLeft() != lastReportedGeometry.topLeft()
|
||||
|| requestedGeometry.topLeft() != actualGeometry.topLeft();
|
||||
|
||||
window->d_func()->geometry = newRect;
|
||||
window->d_func()->geometry = actualGeometry;
|
||||
|
||||
if (isResize || window->d_func()->resizeEventPending) {
|
||||
QResizeEvent e(newRect.size(), oldRect.size());
|
||||
QResizeEvent e(actualGeometry.size(), lastReportedGeometry.size());
|
||||
QGuiApplication::sendSpontaneousEvent(window, &e);
|
||||
|
||||
window->d_func()->resizeEventPending = false;
|
||||
|
||||
if (oldRect.width() != newRect.width())
|
||||
window->widthChanged(newRect.width());
|
||||
if (oldRect.height() != newRect.height())
|
||||
window->heightChanged(newRect.height());
|
||||
if (actualGeometry.width() != lastReportedGeometry.width())
|
||||
window->widthChanged(actualGeometry.width());
|
||||
if (actualGeometry.height() != lastReportedGeometry.height())
|
||||
window->heightChanged(actualGeometry.height());
|
||||
}
|
||||
|
||||
if (isMove) {
|
||||
//### frame geometry
|
||||
QMoveEvent e(newRect.topLeft(), oldRect.topLeft());
|
||||
QMoveEvent e(actualGeometry.topLeft(), lastReportedGeometry.topLeft());
|
||||
QGuiApplication::sendSpontaneousEvent(window, &e);
|
||||
|
||||
if (oldRect.x() != newRect.x())
|
||||
window->xChanged(newRect.x());
|
||||
if (oldRect.y() != newRect.y())
|
||||
window->yChanged(newRect.y());
|
||||
if (actualGeometry.x() != lastReportedGeometry.x())
|
||||
window->xChanged(actualGeometry.x());
|
||||
if (actualGeometry.y() != lastReportedGeometry.y())
|
||||
window->yChanged(actualGeometry.y());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,13 +273,18 @@ void QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationState
|
||||
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
|
||||
}
|
||||
|
||||
/*!
|
||||
If \a oldRect is null, Qt will use the previously reported geometry instead.
|
||||
*/
|
||||
QT_DEFINE_QPA_EVENT_HANDLER(void, handleGeometryChange, QWindow *window, const QRect &newRect, const QRect &oldRect)
|
||||
QWindowSystemInterfacePrivate::GeometryChangeEvent::GeometryChangeEvent(QWindow *window, const QRect &newGeometry)
|
||||
: WindowSystemEvent(GeometryChange)
|
||||
, window(window)
|
||||
, requestedGeometry(window->handle() ? window->handle()->QPlatformWindow::geometry() : QRect())
|
||||
, newGeometry(newGeometry)
|
||||
{
|
||||
}
|
||||
|
||||
QT_DEFINE_QPA_EVENT_HANDLER(void, handleGeometryChange, QWindow *window, const QRect &newRect)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
QWindowSystemInterfacePrivate::GeometryChangeEvent *e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(window, QHighDpi::fromNativePixels(newRect, window), QHighDpi::fromNativePixels(oldRect, window));
|
||||
QWindowSystemInterfacePrivate::GeometryChangeEvent *e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(window, QHighDpi::fromNativePixels(newRect, window));
|
||||
if (window->handle()) {
|
||||
// Persist the new geometry so that QWindow::geometry() can be queried in the resize event
|
||||
window->handle()->QPlatformWindow::setGeometry(newRect);
|
||||
|
@ -160,7 +160,7 @@ public:
|
||||
|
||||
// rect is relative to parent
|
||||
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
|
||||
static void handleGeometryChange(QWindow *window, const QRect &newRect, const QRect &oldRect = QRect());
|
||||
static void handleGeometryChange(QWindow *window, const QRect &newRect);
|
||||
|
||||
// region is in local coordinates, do not confuse with geometry which is parent-relative
|
||||
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
|
||||
|
@ -131,12 +131,10 @@ public:
|
||||
|
||||
class GeometryChangeEvent : public WindowSystemEvent {
|
||||
public:
|
||||
GeometryChangeEvent(QWindow *window, const QRect &newGeometry, const QRect &oldGeometry)
|
||||
: WindowSystemEvent(GeometryChange), window(window), newGeometry(newGeometry), oldGeometry(oldGeometry)
|
||||
{ }
|
||||
GeometryChangeEvent(QWindow *window, const QRect &newGeometry);
|
||||
QPointer<QWindow> window;
|
||||
QRect requestedGeometry;
|
||||
QRect newGeometry;
|
||||
QRect oldGeometry;
|
||||
};
|
||||
|
||||
class EnterEvent : public WindowSystemEvent {
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
#include <qpa/qplatformintegration.h>
|
||||
#include <private/qguiapplication_p.h>
|
||||
#include <private/qwindow_p.h>
|
||||
#ifndef QT_NO_OPENGL
|
||||
# include <QtGui/private/qopenglcontext_p.h>
|
||||
# include <QtGui/QOpenGLContext>
|
||||
@ -234,21 +235,19 @@ void QEglFSWindow::setVisible(bool visible)
|
||||
|
||||
void QEglFSWindow::setGeometry(const QRect &r)
|
||||
{
|
||||
QRect rect;
|
||||
bool forceFullscreen = m_flags.testFlag(HasNativeWindow);
|
||||
if (forceFullscreen)
|
||||
// Persist the requested rect, like a normal setGeometry call
|
||||
QPlatformWindow::setGeometry(r);
|
||||
|
||||
// Take care of WM behavior, constrain/modify geometry
|
||||
QRect rect = r;
|
||||
if (m_flags.testFlag(HasNativeWindow))
|
||||
rect = screen()->availableGeometry();
|
||||
else
|
||||
rect = r;
|
||||
|
||||
const bool changed = rect != QPlatformWindow::geometry();
|
||||
QPlatformWindow::setGeometry(rect);
|
||||
// React to the setGeometry, as if from a WM callback
|
||||
QRect lastReportedGeometry = qt_window_private(window())->geometry;
|
||||
QWindowSystemInterface::handleGeometryChange(window(), rect);
|
||||
|
||||
// if we corrected the size, trigger a resize event
|
||||
if (rect != r)
|
||||
QWindowSystemInterface::handleGeometryChange(window(), rect, r);
|
||||
|
||||
if (changed)
|
||||
if (rect != lastReportedGeometry)
|
||||
QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), rect.size()));
|
||||
}
|
||||
|
||||
|
@ -151,19 +151,12 @@
|
||||
qWarning() << m_qioswindow->window()
|
||||
<< "is backed by a UIView that has a transform set. This is not supported.";
|
||||
|
||||
// The original geometry requested by setGeometry() might be different
|
||||
// from what we end up with after applying window constraints.
|
||||
QRect requestedGeometry = m_qioswindow->geometry();
|
||||
|
||||
QRect actualGeometry = QRectF::fromCGRect(self.frame).toRect();
|
||||
|
||||
QRect previousGeometry = requestedGeometry != actualGeometry ?
|
||||
requestedGeometry : qt_window_private(m_qioswindow->window())->geometry;
|
||||
|
||||
QWindow *window = m_qioswindow->window();
|
||||
QWindowSystemInterface::handleGeometryChange<QWindowSystemInterface::SynchronousDelivery>(window, actualGeometry, previousGeometry);
|
||||
QRect lastReportedGeometry = qt_window_private(window)->geometry;
|
||||
QRect currentGeometry = QRectF::fromCGRect(self.frame).toRect();
|
||||
QWindowSystemInterface::handleGeometryChange<QWindowSystemInterface::SynchronousDelivery>(window, currentGeometry);
|
||||
|
||||
if (actualGeometry.size() != previousGeometry.size()) {
|
||||
if (currentGeometry.size() != lastReportedGeometry.size()) {
|
||||
// Trigger expose event on resize
|
||||
[self setNeedsDisplay];
|
||||
|
||||
|
@ -2077,10 +2077,6 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
|
||||
if (!newScreen)
|
||||
return;
|
||||
|
||||
// FIXME: In the case of the requestedGeometry not matching the actualGeometry due
|
||||
// to e.g. the window manager applying restrictions to the geometry, the application
|
||||
// will never see a move/resize event if the actualGeometry is the same as the current
|
||||
// geometry, and may think the requested geometry was fulfilled.
|
||||
QWindowSystemInterface::handleGeometryChange(window(), actualGeometry);
|
||||
|
||||
// QPlatformScreen::screen() is updated asynchronously, so we can't compare it
|
||||
|
Loading…
x
Reference in New Issue
Block a user