summaryrefslogtreecommitdiffstats
path: root/src/plugins
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 /src/plugins
parent6c3eb39832876a65291546476b92fd94950b1208 (diff)
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>
Diffstat (limited to 'src/plugins')
-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
8 files changed, 100 insertions, 60 deletions
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.