summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohan Klokkhammer Helsing <johan.helsing@qt.io>2018-02-06 17:21:13 +0100
committerJohan Klokkhammer Helsing <johan.helsing@qt.io>2020-01-28 16:52:13 +0100
commita611c632bb906cf77dd3af29ddd7b166f79ad1b0 (patch)
tree931493fe4d13116efe738623f9e705c6025f1674
parent6c3eb39832876a65291546476b92fd94950b1208 (diff)
downloadqtbase-a611c632bb906cf77dd3af29ddd7b166f79ad1b0.tar.gz
Add QWindow::startSystemMove and startSystemResize
This can be used to create custom client side window decorations. Refactors the xcb implementation to use edges instead of corners and we now use the last mouse position for `root_x` and `root_y` in the `_NET_WM_MOVERESIZE` event. Touch has also been changed, so just pick a point that's currently being pressed. The workaround for QTBUG-69716 has now been moved to QSizeGrip, as the comment in the bug report says that it should ideally be fixed at the widget level. On Windows, we no longer abort when GetSystemMenu returns false. I assume this code was added to check whether the window didn't have any decorations and not resize in that case. However, since the point of this patch is to let windows without native decorations resize/move, it makes most sense to remove the check. Adds a manual test, which calls QWindow::startSystemMove and startSystemResize on touch and mouse events. [ChangeLog][QtGui] Added API for starting interactive window resize and move operations handled by the system. Fixes: QTBUG-73011 Change-Id: I7e47a0b2cff182af71d3d479d6e3746f08ea30aa Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
-rw-r--r--src/gui/kernel/qplatformwindow.cpp27
-rw-r--r--src/gui/kernel/qplatformwindow.h4
-rw-r--r--src/gui/kernel/qwindow.cpp72
-rw-r--r--src/gui/kernel/qwindow.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm16
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp50
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h4
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h4
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp13
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp62
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h9
-rw-r--r--src/widgets/widgets/qsizegrip.cpp16
-rw-r--r--tests/manual/startsystemmove/main.cpp111
-rw-r--r--tests/manual/startsystemmove/startsystemmove.pro4
15 files changed, 314 insertions, 82 deletions
diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp
index 65accc9f68..03f2e4d79e 100644
--- a/src/gui/kernel/qplatformwindow.cpp
+++ b/src/gui/kernel/qplatformwindow.cpp
@@ -482,19 +482,17 @@ bool QPlatformWindow::windowEvent(QEvent *event)
}
/*!
- Reimplement this method to start a system size grip drag
- operation if the system supports it and return true to indicate
- success.
- It is called from the mouse press event handler of the size grip.
+ Reimplement this method to start a system resize operation if
+ the system supports it and return true to indicate success.
+
+ The default implementation is empty and does nothing with \a edges.
- The default implementation is empty and does nothing with \a pos
- and \a corner.
+ \since 5.15
*/
-bool QPlatformWindow::startSystemResize(const QPoint &pos, Qt::Corner corner)
+bool QPlatformWindow::startSystemResize(Qt::Edges edges)
{
- Q_UNUSED(pos)
- Q_UNUSED(corner)
+ Q_UNUSED(edges)
return false;
}
@@ -502,18 +500,13 @@ bool QPlatformWindow::startSystemResize(const QPoint &pos, Qt::Corner corner)
Reimplement this method to start a system move operation if
the system supports it and return true to indicate success.
- The \a pos is a position of MouseButtonPress event or TouchBegin
- event from a sequence of mouse events that triggered the movement.
- It must be specified in window coordinates.
-
- The default implementation is empty and does nothing with \a pos.
+ The default implementation is empty and does nothing.
- \since 5.11
+ \since 5.15
*/
-bool QPlatformWindow::startSystemMove(const QPoint &pos)
+bool QPlatformWindow::startSystemMove()
{
- Q_UNUSED(pos)
return false;
}
diff --git a/src/gui/kernel/qplatformwindow.h b/src/gui/kernel/qplatformwindow.h
index b6aeb3a86a..7b85090cc0 100644
--- a/src/gui/kernel/qplatformwindow.h
+++ b/src/gui/kernel/qplatformwindow.h
@@ -132,8 +132,8 @@ public:
virtual bool windowEvent(QEvent *event);
- virtual bool startSystemResize(const QPoint &pos, Qt::Corner corner);
- virtual bool startSystemMove(const QPoint &pos);
+ virtual bool startSystemResize(Qt::Edges edges);
+ virtual bool startSystemMove();
virtual void setFrameStrutEventsEnabled(bool enabled);
virtual bool frameStrutEventsEnabled() const;
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index dad1b6ba2d..c099ec9692 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -1051,6 +1051,71 @@ void QWindow::lower()
}
/*!
+ \brief Start a system-specific resize operation
+ \since 5.15
+
+ Calling this will start an interactive resize operation on the window by platforms
+ that support it. The actual behavior may vary depending on the platform. Usually,
+ it will make the window resize so that its edge follows the mouse cursor.
+
+ On platforms that support it, this method of resizing windows is preferred over
+ \c setGeometry, because it allows a more native look-and-feel of resizing windows, e.g.
+ letting the window manager snap this window against other windows, or special resizing
+ behavior with animations when dragged to the edge of the screen.
+
+ \a edges should either be a single edge, or two adjacent edges (a corner). Other values
+ are not allowed.
+
+ Returns true if the operation was supported by the system.
+*/
+bool QWindow::startSystemResize(Qt::Edges edges)
+{
+ Q_D(QWindow);
+ if (Q_UNLIKELY(!isVisible() || !d->platformWindow || d->maximumSize == d->minimumSize))
+ return false;
+
+ const bool isSingleEdge = edges == Qt::TopEdge || edges == Qt::RightEdge || edges == Qt::BottomEdge || edges == Qt::LeftEdge;
+ const bool isCorner =
+ edges == (Qt::TopEdge | Qt::LeftEdge) ||
+ edges == (Qt::TopEdge | Qt::RightEdge) ||
+ edges == (Qt::BottomEdge | Qt::RightEdge) ||
+ edges == (Qt::BottomEdge | Qt::LeftEdge);
+
+ if (Q_UNLIKELY(!isSingleEdge && !isCorner)) {
+ qWarning() << "Invalid edges" << edges << "passed to QWindow::startSystemResize, ignoring.";
+ return false;
+ }
+
+ return d->platformWindow->startSystemResize(edges);
+}
+
+/*!
+ \brief Start a system-specific move operation
+ \since 5.15
+
+ Calling this will start an interactive move operation on the window by platforms
+ that support it. The actual behavior may vary depending on the platform. Usually,
+ it will make the window follow the mouse cursor until a mouse button is released.
+
+ On platforms that support it, this method of moving windows is preferred over
+ \c setPosition, because it allows a more native look-and-feel of moving windows, e.g.
+ letting the window manager snap this window against other windows, or special tiling
+ or resizing behavior with animations when dragged to the edge of the screen.
+ Furthermore, on some platforms such as Wayland, \c setPosition is not supported, so
+ this is the only way the application can influence its position.
+
+ Returns true if the operation was supported by the system.
+*/
+bool QWindow::startSystemMove()
+{
+ Q_D(QWindow);
+ if (Q_UNLIKELY(!isVisible() || !d->platformWindow))
+ return false;
+
+ return d->platformWindow->startSystemMove();
+}
+
+/*!
\property QWindow::opacity
\brief The opacity of the window in the windowing system.
\since 5.1
@@ -1793,7 +1858,10 @@ void QWindow::setFramePosition(const QPoint &point)
The position is in relation to the virtualGeometry() of its screen.
- \sa position()
+ For interactively moving windows, see startSystemMove(). For interactively
+ resizing windows, see startSystemResize().
+
+ \sa position(), startSystemMove()
*/
void QWindow::setPosition(const QPoint &pt)
{
@@ -1830,6 +1898,8 @@ void QWindow::setPosition(int posx, int posy)
set the size of the window, excluding any window frame, to a QSize
constructed from width \a w and height \a h
+ For interactively resizing windows, see startSystemResize().
+
\sa size(), geometry()
*/
void QWindow::resize(int w, int h)
diff --git a/src/gui/kernel/qwindow.h b/src/gui/kernel/qwindow.h
index 5ee1d00f5b..7aae7ffffa 100644
--- a/src/gui/kernel/qwindow.h
+++ b/src/gui/kernel/qwindow.h
@@ -292,6 +292,8 @@ public Q_SLOTS:
bool close();
void raise();
void lower();
+ bool startSystemResize(Qt::Edges edges);
+ bool startSystemMove();
void setTitle(const QString &);
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h
index fef72bc496..b15c0ac31c 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.h
+++ b/src/plugins/platforms/cocoa/qcocoawindow.h
@@ -218,6 +218,8 @@ protected:
void toggleFullScreen();
bool isTransitioningToFullScreen() const;
+ bool startSystemMove() override;
+
// private:
public: // for QNSView
friend class QCocoaBackingStore;
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 69d192b4f5..9cb4470e02 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -299,6 +299,22 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect)
// will call QPlatformWindow::setGeometry(rect) during resize confirmation (see qnsview.mm)
}
+bool QCocoaWindow::startSystemMove()
+{
+ switch (NSApp.currentEvent.type) {
+ case NSEventTypeLeftMouseDown:
+ case NSEventTypeRightMouseDown:
+ case NSEventTypeOtherMouseDown:
+ case NSEventTypeMouseMoved:
+ // The documentation only describes starting a system move
+ // based on mouse down events, but move events also work.
+ [m_view.window performWindowDragWithEvent:NSApp.currentEvent];
+ return true;
+ default:
+ return false;
+ }
+}
+
void QCocoaWindow::setVisible(bool visible)
{
qCDebug(lcQpaWindow) << "QCocoaWindow::setVisible" << window() << visible;
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index b7536066d0..e2f9c6cbb0 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -2604,37 +2604,41 @@ bool QWindowsWindow::setMouseGrabEnabled(bool grab)
return grab;
}
-static inline DWORD cornerToWinOrientation(Qt::Corner corner)
-{
- switch (corner) {
- case Qt::TopLeftCorner:
- return 0xf004; // SZ_SIZETOPLEFT;
- case Qt::TopRightCorner:
- return 0xf005; // SZ_SIZETOPRIGHT
- case Qt::BottomLeftCorner:
- return 0xf007; // SZ_SIZEBOTTOMLEFT
- case Qt::BottomRightCorner:
- return 0xf008; // SZ_SIZEBOTTOMRIGHT
- }
- return 0;
-}
-
-bool QWindowsWindow::startSystemResize(const QPoint &, Qt::Corner corner)
-{
- if (!GetSystemMenu(m_data.hwnd, FALSE))
+static inline DWORD edgesToWinOrientation(Qt::Edges edges)
+{
+ if (edges == Qt::LeftEdge)
+ return 0xf001; // SC_SIZELEFT;
+ else if (edges == (Qt::RightEdge))
+ return 0xf002; // SC_SIZERIGHT
+ else if (edges == (Qt::TopEdge))
+ return 0xf003; // SC_SIZETOP
+ else if (edges == (Qt::TopEdge | Qt::LeftEdge))
+ return 0xf004; // SC_SIZETOPLEFT
+ else if (edges == (Qt::TopEdge | Qt::RightEdge))
+ return 0xf005; // SC_SIZETOPRIGHT
+ else if (edges == (Qt::BottomEdge))
+ return 0xf006; // SC_SIZEBOTTOM
+ else if (edges == (Qt::BottomEdge | Qt::LeftEdge))
+ return 0xf007; // SC_SIZEBOTTOMLEFT
+ else if (edges == (Qt::BottomEdge | Qt::RightEdge))
+ return 0xf008; // SC_SIZEBOTTOMRIGHT
+
+ return 0xf000; // SC_SIZE
+}
+
+bool QWindowsWindow::startSystemResize(Qt::Edges edges)
+{
+ if (Q_UNLIKELY(!(window()->flags() & Qt::MSWindowsFixedSizeDialogHint)))
return false;
ReleaseCapture();
- PostMessage(m_data.hwnd, WM_SYSCOMMAND, cornerToWinOrientation(corner), 0);
+ PostMessage(m_data.hwnd, WM_SYSCOMMAND, edgesToWinOrientation(edges), 0);
setFlag(SizeGripOperation);
return true;
}
-bool QWindowsWindow::startSystemMove(const QPoint &)
+bool QWindowsWindow::startSystemMove()
{
- if (!GetSystemMenu(m_data.hwnd, FALSE))
- return false;
-
ReleaseCapture();
PostMessage(m_data.hwnd, WM_SYSCOMMAND, 0xF012 /*SC_DRAGMOVE*/, 0);
return true;
diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h
index 7c37c6b115..e1f7908687 100644
--- a/src/plugins/platforms/windows/qwindowswindow.h
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -277,8 +277,8 @@ public:
bool setMouseGrabEnabled(bool grab) override;
inline bool hasMouseCapture() const { return GetCapture() == m_data.hwnd; }
- bool startSystemResize(const QPoint &pos, Qt::Corner corner) override;
- bool startSystemMove(const QPoint &pos) override;
+ bool startSystemResize(Qt::Edges edges) override;
+ bool startSystemMove() override;
void setFrameStrutEventsEnabled(bool enabled) override;
bool frameStrutEventsEnabled() const override { return testFlag(FrameStrutEventsEnabled); }
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 2d89b971dc..8a4b577d2e 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -230,7 +230,7 @@ public:
bool xi2MouseEventsDisabled() const;
Qt::MouseButton xiToQtMouseButton(uint32_t b);
void xi2UpdateScrollingDevices();
- bool startSystemMoveResizeForTouchBegin(xcb_window_t window, const QPoint &point, int corner);
+ bool startSystemMoveResizeForTouch(xcb_window_t window, int edges);
void abortSystemMoveResizeForTouch();
bool isTouchScreen(int id);
@@ -334,7 +334,7 @@ private:
xcb_window_t window = XCB_NONE;
uint16_t deviceid;
uint32_t pointid;
- int corner;
+ int edges;
} m_startSystemMoveResizeInfo;
const bool m_canGrabServer;
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index 2d114c51b3..4620f0fd1d 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -753,7 +753,7 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
xcb_input_xi_allow_events(xcb_connection(), XCB_CURRENT_TIME, xiDeviceEvent->deviceid,
XCB_INPUT_EVENT_MODE_REJECT_TOUCH,
xiDeviceEvent->detail, xiDeviceEvent->event);
- window->doStartSystemMoveResize(QPoint(x, y), m_startSystemMoveResizeInfo.corner);
+ window->doStartSystemMoveResize(QPoint(x, y), m_startSystemMoveResizeInfo.edges);
m_startSystemMoveResizeInfo.window = XCB_NONE;
}
}
@@ -787,19 +787,20 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
touchPoint.state = Qt::TouchPointStationary;
}
-bool QXcbConnection::startSystemMoveResizeForTouchBegin(xcb_window_t window, const QPoint &point, int corner)
+bool QXcbConnection::startSystemMoveResizeForTouch(xcb_window_t window, int edges)
{
QHash<int, TouchDeviceData>::const_iterator devIt = m_touchDevices.constBegin();
for (; devIt != m_touchDevices.constEnd(); ++devIt) {
TouchDeviceData deviceData = devIt.value();
if (deviceData.qtTouchDevice->type() == QTouchDevice::TouchScreen) {
- QHash<int, QPointF>::const_iterator pointIt = deviceData.pointPressedPosition.constBegin();
- for (; pointIt != deviceData.pointPressedPosition.constEnd(); ++pointIt) {
- if (pointIt.value().toPoint() == point) {
+ auto pointIt = deviceData.touchPoints.constBegin();
+ for (; pointIt != deviceData.touchPoints.constEnd(); ++pointIt) {
+ Qt::TouchPointState state = pointIt.value().state;
+ if (state == Qt::TouchPointMoved || state == Qt::TouchPointPressed || state == Qt::TouchPointStationary) {
m_startSystemMoveResizeInfo.window = window;
m_startSystemMoveResizeInfo.deviceid = devIt.key();
m_startSystemMoveResizeInfo.pointid = pointIt.key();
- m_startSystemMoveResizeInfo.corner = corner;
+ m_startSystemMoveResizeInfo.edges = edges;
return true;
}
}
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index adca902c69..96cd3a70ed 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -2161,6 +2161,7 @@ QXcbWindow *QXcbWindow::toWindow() { return this; }
void QXcbWindow::handleMouseEvent(xcb_timestamp_t time, const QPoint &local, const QPoint &global,
Qt::KeyboardModifiers modifiers, QEvent::Type type, Qt::MouseEventSource source)
{
+ m_lastPointerPosition = local;
connection()->setTime(time);
Qt::MouseButton button = type == QEvent::MouseMove ? Qt::NoButton : connection()->button();
QWindowSystemInterface::handleMouseEvent(window(), time, local, global,
@@ -2345,45 +2346,66 @@ bool QXcbWindow::windowEvent(QEvent *event)
return QPlatformWindow::windowEvent(event);
}
-bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner)
+bool QXcbWindow::startSystemResize(Qt::Edges edges)
{
- return startSystemMoveResize(pos, corner);
+ return startSystemMoveResize(m_lastPointerPosition, edges);
}
-bool QXcbWindow::startSystemMove(const QPoint &pos)
+bool QXcbWindow::startSystemMove()
{
- return startSystemMoveResize(pos, 4);
+ return startSystemMoveResize(m_lastPointerPosition, 16);
}
-bool QXcbWindow::startSystemMoveResize(const QPoint &pos, int corner)
+bool QXcbWindow::startSystemMoveResize(const QPoint &pos, int edges)
{
- return false; // ### FIXME QTBUG-69716
const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE);
if (!connection()->wmSupport()->isSupportedByWM(moveResize))
return false;
- const QPoint globalPos = QHighDpi::toNativePixels(window()->mapToGlobal(pos), window()->screen());
-
// ### FIXME QTBUG-53389
- bool startedByTouch = connection()->startSystemMoveResizeForTouchBegin(m_window, globalPos, corner);
+ bool startedByTouch = connection()->startSystemMoveResizeForTouch(m_window, edges);
if (startedByTouch) {
- if (connection()->isUnity() || connection()->isGnome()) {
- // These desktops fail to move/resize via _NET_WM_MOVERESIZE (WM bug?).
+ if (connection()->isUnity()) {
+ // Unity fails to move/resize via _NET_WM_MOVERESIZE (WM bug?).
connection()->abortSystemMoveResizeForTouch();
return false;
}
- // KWin, Openbox, AwesomeWM have been tested to work with _NET_WM_MOVERESIZE.
+ // KWin, Openbox, AwesomeWM and Gnome have been tested to work with _NET_WM_MOVERESIZE.
} else { // Started by mouse press.
if (connection()->isUnity())
return false; // _NET_WM_MOVERESIZE on this WM is bouncy (WM bug?).
- doStartSystemMoveResize(globalPos, corner);
+ const QPoint globalPos = QHighDpi::toNativePixels(window()->mapToGlobal(pos), window()->screen());
+ doStartSystemMoveResize(globalPos, edges);
}
return true;
}
-void QXcbWindow::doStartSystemMoveResize(const QPoint &globalPos, int corner)
+static uint qtEdgesToXcbMoveResizeDirection(Qt::Edges edges)
+{
+ if (edges == (Qt::TopEdge | Qt::LeftEdge))
+ return 0;
+ if (edges == Qt::TopEdge)
+ return 1;
+ if (edges == (Qt::TopEdge | Qt::RightEdge))
+ return 2;
+ if (edges == Qt::RightEdge)
+ return 3;
+ if (edges == (Qt::RightEdge | Qt::BottomEdge))
+ return 4;
+ if (edges == Qt::BottomEdge)
+ return 5;
+ if (edges == (Qt::BottomEdge | Qt::LeftEdge))
+ return 6;
+ if (edges == Qt::LeftEdge)
+ return 7;
+
+ qWarning() << "Cannot convert " << edges << "to _NET_WM_MOVERESIZE direction.";
+ return 0;
+}
+
+void QXcbWindow::doStartSystemMoveResize(const QPoint &globalPos, int edges)
{
const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE);
xcb_client_message_event_t xev;
@@ -2394,16 +2416,10 @@ void QXcbWindow::doStartSystemMoveResize(const QPoint &globalPos, int corner)
xev.format = 32;
xev.data.data32[0] = globalPos.x();
xev.data.data32[1] = globalPos.y();
- if (corner == 4) {
+ if (edges == 16)
xev.data.data32[2] = 8; // move
- } else {
- const bool bottom = corner == Qt::BottomRightCorner || corner == Qt::BottomLeftCorner;
- const bool left = corner == Qt::BottomLeftCorner || corner == Qt::TopLeftCorner;
- if (bottom)
- xev.data.data32[2] = left ? 6 : 4; // bottomleft/bottomright
- else
- xev.data.data32[2] = left ? 0 : 2; // topleft/topright
- }
+ else
+ xev.data.data32[2] = qtEdgesToXcbMoveResizeDirection(Qt::Edges(edges));
xev.data.data32[3] = XCB_BUTTON_INDEX_1;
xev.data.data32[4] = 0;
xcb_ungrab_pointer(connection()->xcb_connection(), XCB_CURRENT_TIME);
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 976a442b11..d6f370eebe 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -107,8 +107,8 @@ public:
bool windowEvent(QEvent *event) override;
- bool startSystemResize(const QPoint &pos, Qt::Corner corner) override;
- bool startSystemMove(const QPoint &pos) override;
+ bool startSystemResize(Qt::Edges edges) override;
+ bool startSystemMove() override;
void setOpacity(qreal level) override;
void setMask(const QRegion &region) override;
@@ -168,8 +168,8 @@ public:
QXcbScreen *xcbScreen() const;
- bool startSystemMoveResize(const QPoint &pos, int corner);
- void doStartSystemMoveResize(const QPoint &globalPos, int corner);
+ bool startSystemMoveResize(const QPoint &pos, int edges);
+ void doStartSystemMoveResize(const QPoint &globalPos, int edges);
static bool isTrayIconWindow(QWindow *window)
{
@@ -264,6 +264,7 @@ protected:
QRegion m_exposeRegion;
QSize m_oldWindowSize;
+ QPoint m_lastPointerPosition;
xcb_visualid_t m_visualId = 0;
// Last sent state. Initialized to an invalid state, on purpose.
diff --git a/src/widgets/widgets/qsizegrip.cpp b/src/widgets/widgets/qsizegrip.cpp
index 2a4b4a0ad4..95a4beeb57 100644
--- a/src/widgets/widgets/qsizegrip.cpp
+++ b/src/widgets/widgets/qsizegrip.cpp
@@ -260,6 +260,17 @@ void QSizeGrip::paintEvent(QPaintEvent *event)
parameter.
*/
+static Qt::Edges edgesFromCorner(Qt::Corner corner)
+{
+ switch (corner) {
+ case Qt::TopLeftCorner: return Qt::TopEdge | Qt::LeftEdge;
+ case Qt::TopRightCorner: return Qt::TopEdge | Qt::RightEdge;
+ case Qt::BottomLeftCorner: return Qt::BottomEdge | Qt::LeftEdge;
+ case Qt::BottomRightCorner: return Qt::BottomEdge | Qt::RightEdge;
+ }
+ return Qt::Edges{};
+}
+
void QSizeGrip::mousePressEvent(QMouseEvent * e)
{
if (e->button() != Qt::LeftButton) {
@@ -281,8 +292,9 @@ void QSizeGrip::mousePressEvent(QMouseEvent * e)
&& !tlw->testAttribute(Qt::WA_DontShowOnScreen)
&& !tlw->hasHeightForWidth()) {
QPlatformWindow *platformWindow = tlw->windowHandle()->handle();
- const QPoint topLevelPos = mapTo(tlw, e->pos());
- d->m_platformSizeGrip = platformWindow && platformWindow->startSystemResize(topLevelPos, d->m_corner);
+ const Qt::Edges edges = edgesFromCorner(d->m_corner);
+ if (!QGuiApplication::platformName().contains(QStringLiteral("xcb"))) // ### FIXME QTBUG-69716
+ d->m_platformSizeGrip = platformWindow && platformWindow->startSystemResize(edges);
}
if (d->m_platformSizeGrip)
diff --git a/tests/manual/startsystemmove/main.cpp b/tests/manual/startsystemmove/main.cpp
new file mode 100644
index 0000000000..a121d1ed86
--- /dev/null
+++ b/tests/manual/startsystemmove/main.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui>
+
+constexpr qreal border = 20;
+
+class Window : public QRasterWindow
+{
+public:
+ explicit Window(QWindow *parent = nullptr) : QRasterWindow(parent)
+ {
+ resize(300, 200);
+ setMinimumSize(QSize(border*2, border*2));
+ }
+protected:
+ void resizeOrMove(const QPointF &p);
+ bool event(QEvent *event) override;
+ void paintEvent(QPaintEvent *event) override;
+};
+
+void Window::resizeOrMove(const QPointF &p)
+{
+ Qt::Edges edges;
+ if (p.x() > width() - border)
+ edges |= Qt::RightEdge;
+ if (p.x() < border)
+ edges |= Qt::LeftEdge;
+ if (p.y() < border)
+ edges |= Qt::TopEdge;
+ if (p.y() > height() - border)
+ edges |= Qt::BottomEdge;
+
+ if (edges != 0) {
+ qDebug() << "startSystemResize" << edges;
+ if (startSystemResize(edges))
+ qDebug() << " -> supported";
+ else
+ qDebug() << " -> not supported";
+ } else {
+ qDebug() << "startSystemMove";
+ if (startSystemMove())
+ qDebug() << " -> supported";
+ else
+ qDebug() << " -> not supported";
+ }
+}
+
+bool Window::event(QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ qDebug() << "Mouse press";
+ resizeOrMove(static_cast<QMouseEvent *>(event)->localPos());
+ return true;
+ case QEvent::TouchUpdate:
+ qDebug() << "Touch update";
+ resizeOrMove(static_cast<QTouchEvent *>(event)->touchPoints().first().pos());
+ return true;
+ case QEvent::TouchBegin:
+ qDebug() << "Touch begin";
+ resizeOrMove(static_cast<QTouchEvent *>(event)->touchPoints().first().pos());
+ return true;
+ default:
+ return QRasterWindow::event(event);
+ }
+}
+
+void Window::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event);
+ QPainter painter(this);
+ QRect fullRect(0, 0, width(), height());
+ QRect innerRect = fullRect.marginsRemoved(QMargins(border, border, border, border));
+ painter.fillRect(fullRect, QGradient::WarmFlame);
+ painter.fillRect(innerRect, QGradient::NightFade);
+ painter.drawText(QRectF(0, 0, width(), height()), Qt::AlignCenter, QStringLiteral("Click mouse or touch to move window\nDrag along the sides to resize."));
+}
+
+int main(int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+ Window window;
+ window.show();
+ return app.exec();
+}
diff --git a/tests/manual/startsystemmove/startsystemmove.pro b/tests/manual/startsystemmove/startsystemmove.pro
new file mode 100644
index 0000000000..568bda343b
--- /dev/null
+++ b/tests/manual/startsystemmove/startsystemmove.pro
@@ -0,0 +1,4 @@
+TEMPLATE = app
+QT = core gui
+SOURCES += main.cpp
+CONFIG += console