From 4296a38a30bf5bb9a36b1684cf57957e7dae6dc6 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Tue, 18 Aug 2020 15:51:20 +0300 Subject: [PATCH] Move geometry handling code from XdgSurfaceClient to WaylandClient --- waylandclient.cpp | 167 +++++++++++++++++++++++++++++++++++++++++ waylandclient.h | 16 ++++ xdgshellclient.cpp | 183 ++------------------------------------------- xdgshellclient.h | 18 +---- 4 files changed, 192 insertions(+), 192 deletions(-) diff --git a/waylandclient.cpp b/waylandclient.cpp index cf895d9ed..f1c4ea7e9 100644 --- a/waylandclient.cpp +++ b/waylandclient.cpp @@ -28,6 +28,13 @@ using namespace KWaylandServer; namespace KWin { +enum WaylandGeometryType { + WaylandGeometryClient = 0x1, + WaylandGeometryFrame = 0x2, + WaylandGeometryBuffer = 0x4, +}; +Q_DECLARE_FLAGS(WaylandGeometryTypes, WaylandGeometryType) + WaylandClient::WaylandClient(SurfaceInterface *surface) { // Note that we cannot setup compositing here because we may need to call visibleRect(), @@ -332,4 +339,164 @@ void WaylandClient::internalHide() emit windowHidden(this); } +QRect WaylandClient::frameRectToBufferRect(const QRect &rect) const +{ + return QRect(rect.topLeft(), surface()->size()); +} + +QRect WaylandClient::requestedFrameGeometry() const +{ + return m_requestedFrameGeometry; +} + +QPoint WaylandClient::requestedPos() const +{ + return m_requestedFrameGeometry.topLeft(); +} + +QSize WaylandClient::requestedSize() const +{ + return m_requestedFrameGeometry.size(); +} + +QRect WaylandClient::requestedClientGeometry() const +{ + return m_requestedClientGeometry; +} + +QRect WaylandClient::bufferGeometry() const +{ + return m_bufferGeometry; +} + +QSize WaylandClient::requestedClientSize() const +{ + return requestedClientGeometry().size(); +} + +void WaylandClient::setFrameGeometry(const QRect &rect, ForceGeometry_t force) +{ + m_requestedFrameGeometry = rect; + + if (isShade()) { + if (m_requestedFrameGeometry.height() == borderTop() + borderBottom()) { + qCDebug(KWIN_CORE) << "Passed shaded frame geometry to setFrameGeometry()"; + } else { + m_requestedClientGeometry = frameRectToClientRect(m_requestedFrameGeometry); + m_requestedFrameGeometry.setHeight(borderTop() + borderBottom()); + } + } else { + m_requestedClientGeometry = frameRectToClientRect(m_requestedFrameGeometry); + } + + if (areGeometryUpdatesBlocked()) { + m_frameGeometry = m_requestedFrameGeometry; + if (pendingGeometryUpdate() == PendingGeometryForced) { + return; + } + if (force == ForceGeometrySet) { + setPendingGeometryUpdate(PendingGeometryForced); + } else { + setPendingGeometryUpdate(PendingGeometryNormal); + } + return; + } + + m_frameGeometry = frameGeometryBeforeUpdateBlocking(); + + if (requestedClientSize() != clientSize()) { + requestGeometry(requestedFrameGeometry()); + } else { + updateGeometry(requestedFrameGeometry()); + } +} + +void WaylandClient::move(int x, int y, ForceGeometry_t force) +{ + Q_ASSERT(pendingGeometryUpdate() == PendingGeometryNone || areGeometryUpdatesBlocked()); + QPoint p(x, y); + if (!areGeometryUpdatesBlocked() && p != rules()->checkPosition(p)) { + qCDebug(KWIN_CORE) << "forced position fail:" << p << ":" << rules()->checkPosition(p); + } + m_requestedFrameGeometry.moveTopLeft(p); + m_requestedClientGeometry.moveTopLeft(framePosToClientPos(p)); + if (force == NormalGeometrySet && m_frameGeometry.topLeft() == p) { + return; + } + m_frameGeometry.moveTopLeft(m_requestedFrameGeometry.topLeft()); + if (areGeometryUpdatesBlocked()) { + if (pendingGeometryUpdate() == PendingGeometryForced) { + return; + } + if (force == ForceGeometrySet) { + setPendingGeometryUpdate(PendingGeometryForced); + } else { + setPendingGeometryUpdate(PendingGeometryNormal); + } + return; + } + const QRect oldBufferGeometry = bufferGeometryBeforeUpdateBlocking(); + const QRect oldClientGeometry = clientGeometryBeforeUpdateBlocking(); + const QRect oldFrameGeometry = frameGeometryBeforeUpdateBlocking(); + m_clientGeometry.moveTopLeft(m_requestedClientGeometry.topLeft()); + m_bufferGeometry = frameRectToBufferRect(m_frameGeometry); + updateGeometryBeforeUpdateBlocking(); + updateWindowRules(Rules::Position); + screens()->setCurrent(this); + workspace()->updateStackingOrder(); + emit bufferGeometryChanged(this, oldBufferGeometry); + emit clientGeometryChanged(this, oldClientGeometry); + emit frameGeometryChanged(this, oldFrameGeometry); + addRepaintDuringGeometryUpdates(); +} + +void WaylandClient::requestGeometry(const QRect &rect) +{ + m_requestedFrameGeometry = rect; + m_requestedClientGeometry = frameRectToClientRect(rect); +} + +void WaylandClient::updateGeometry(const QRect &rect) +{ + const QRect oldClientGeometry = m_clientGeometry; + const QRect oldFrameGeometry = m_frameGeometry; + const QRect oldBufferGeometry = m_bufferGeometry; + + m_clientGeometry = frameRectToClientRect(rect); + m_frameGeometry = rect; + m_bufferGeometry = frameRectToBufferRect(rect); + + WaylandGeometryTypes changedGeometries; + + if (m_clientGeometry != oldClientGeometry) { + changedGeometries |= WaylandGeometryClient; + } + if (m_frameGeometry != oldFrameGeometry) { + changedGeometries |= WaylandGeometryFrame; + } + if (m_bufferGeometry != oldBufferGeometry) { + changedGeometries |= WaylandGeometryBuffer; + } + + if (!changedGeometries) { + return; + } + + updateWindowRules(Rules::Position | Rules::Size); + updateGeometryBeforeUpdateBlocking(); + + if (changedGeometries & WaylandGeometryBuffer) { + emit bufferGeometryChanged(this, oldBufferGeometry); + } + if (changedGeometries & WaylandGeometryClient) { + emit clientGeometryChanged(this, oldClientGeometry); + } + if (changedGeometries & WaylandGeometryFrame) { + emit frameGeometryChanged(this, oldFrameGeometry); + } + emit geometryShapeChanged(this, oldFrameGeometry); + + addRepaintDuringGeometryUpdates(); +} + } // namespace KWin diff --git a/waylandclient.h b/waylandclient.h index 1f4f57e13..664883a6c 100644 --- a/waylandclient.h +++ b/waylandclient.h @@ -18,6 +18,7 @@ class WaylandClient : public AbstractClient public: WaylandClient(KWaylandServer::SurfaceInterface *surface); + QRect bufferGeometry() const override; QString captionNormal() const override; QString captionSuffix() const override; QStringList activities() const override; @@ -34,12 +35,21 @@ public: void setOpacity(double opacity) override; AbstractClient *findModal(bool allow_itself = false) override; void resizeWithChecks(const QSize &size, ForceGeometry_t force = NormalGeometrySet) override; + void setFrameGeometry(const QRect &rect, ForceGeometry_t force = NormalGeometrySet) override; + using AbstractClient::move; + void move(int x, int y, ForceGeometry_t force = NormalGeometrySet) override; void killWindow() override; QByteArray windowRole() const override; bool isShown(bool shaded_is_shown) const override; bool isHiddenInternal() const override; void hideClient(bool hide) override; + virtual QRect frameRectToBufferRect(const QRect &rect) const; + QRect requestedFrameGeometry() const; + QPoint requestedPos() const; + QSize requestedSize() const; + QRect requestedClientGeometry() const; + QSize requestedClientSize() const; bool isHidden() const; void updateDepth(); @@ -51,6 +61,9 @@ protected: void doSetActive() override; void updateCaption() override; + virtual void requestGeometry(const QRect &rect); + virtual void updateGeometry(const QRect &rect); + private: void updateClientArea(); void updateClientOutputs(); @@ -62,6 +75,9 @@ private: QString m_captionNormal; QString m_captionSuffix; double m_opacity = 1.0; + QRect m_requestedFrameGeometry; + QRect m_bufferGeometry; + QRect m_requestedClientGeometry; quint32 m_windowId; bool m_isHidden = false; }; diff --git a/xdgshellclient.cpp b/xdgshellclient.cpp index f8bcdb0d9..7f76a5f22 100644 --- a/xdgshellclient.cpp +++ b/xdgshellclient.cpp @@ -38,12 +38,6 @@ using namespace KWaylandServer; namespace KWin { -enum XdgSurfaceGeometryType { - XdgSurfaceGeometryClient = 0x1, - XdgSurfaceGeometryFrame = 0x2, - XdgSurfaceGeometryBuffer = 0x4, -}; - XdgSurfaceClient::XdgSurfaceClient(XdgSurfaceInterface *shellSurface) : WaylandClient(shellSurface->surface()) , m_shellSurface(shellSurface) @@ -109,45 +103,15 @@ XdgSurfaceClient::~XdgSurfaceClient() qDeleteAll(m_configureEvents); } -QRect XdgSurfaceClient::requestedFrameGeometry() const -{ - return m_requestedFrameGeometry; -} - -QPoint XdgSurfaceClient::requestedPos() const -{ - return m_requestedFrameGeometry.topLeft(); -} - -QSize XdgSurfaceClient::requestedSize() const -{ - return m_requestedFrameGeometry.size(); -} - -QRect XdgSurfaceClient::requestedClientGeometry() const -{ - return m_requestedClientGeometry; -} - QRect XdgSurfaceClient::inputGeometry() const { return isDecorated() ? AbstractClient::inputGeometry() : bufferGeometry(); } -QRect XdgSurfaceClient::bufferGeometry() const -{ - return m_bufferGeometry; -} - -QSize XdgSurfaceClient::requestedClientSize() const -{ - return requestedClientGeometry().size(); -} - QMatrix4x4 XdgSurfaceClient::inputTransformation() const { QMatrix4x4 transformation; - transformation.translate(-m_bufferGeometry.x(), -m_bufferGeometry.y()); + transformation.translate(-bufferGeometry().x(), -bufferGeometry().y()); return transformation; } @@ -158,13 +122,13 @@ XdgSurfaceConfigure *XdgSurfaceClient::lastAcknowledgedConfigure() const bool XdgSurfaceClient::stateCompare() const { - if (m_requestedFrameGeometry != m_frameGeometry) { + if (requestedFrameGeometry() != frameGeometry()) { return true; } - if (m_requestedClientGeometry != m_clientGeometry) { + if (requestedClientGeometry() != clientGeometry()) { return true; } - if (m_requestedClientGeometry.isEmpty()) { + if (requestedClientGeometry().isEmpty()) { return true; } return false; @@ -326,146 +290,13 @@ bool XdgSurfaceClient::isInitialPositionSet() const return m_plasmaShellSurface ? m_plasmaShellSurface->isPositionSet() : false; } -/** - * Sets the frame geometry of the XdgSurfaceClient to \a rect. - * - * Because geometry updates are asynchronous on Wayland, there are no any guarantees that - * the frame geometry will be changed immediately. We may need to send a configure event to - * the client if the current window geometry size and the requested window geometry size - * don't match. frameGeometryChanged() will be emitted when the requested frame geometry - * has been applied. - * - * Notice that the client may attach a buffer smaller than the one in the configure event. - */ -void XdgSurfaceClient::setFrameGeometry(const QRect &rect, ForceGeometry_t force) -{ - m_requestedFrameGeometry = rect; - - // XdgToplevelClient currently doesn't support shaded clients, but let's stick with - // what X11Client does. Hopefully, one day we will be able to unify setFrameGeometry() - // for all AbstractClient subclasses. It's going to be great! - - if (isShade()) { - if (m_requestedFrameGeometry.height() == borderTop() + borderBottom()) { - qCDebug(KWIN_CORE) << "Passed shaded frame geometry to setFrameGeometry()"; - } else { - m_requestedClientGeometry = frameRectToClientRect(m_requestedFrameGeometry); - m_requestedFrameGeometry.setHeight(borderTop() + borderBottom()); - } - } else { - m_requestedClientGeometry = frameRectToClientRect(m_requestedFrameGeometry); - } - - if (areGeometryUpdatesBlocked()) { - m_frameGeometry = m_requestedFrameGeometry; - if (pendingGeometryUpdate() == PendingGeometryForced) { - return; - } - if (force == ForceGeometrySet) { - setPendingGeometryUpdate(PendingGeometryForced); - } else { - setPendingGeometryUpdate(PendingGeometryNormal); - } - return; - } - - m_frameGeometry = frameGeometryBeforeUpdateBlocking(); - - // Notice that the window geometry size of (0, 0) has special meaning to xdg shell clients. - // It basically says "pick whatever size you think is the best, dawg." - - if (requestedClientSize() != clientSize()) { - requestGeometry(requestedFrameGeometry()); - } else { - updateGeometry(requestedFrameGeometry()); - } -} - -void XdgSurfaceClient::move(int x, int y, ForceGeometry_t force) -{ - Q_ASSERT(pendingGeometryUpdate() == PendingGeometryNone || areGeometryUpdatesBlocked()); - QPoint p(x, y); - if (!areGeometryUpdatesBlocked() && p != rules()->checkPosition(p)) { - qCDebug(KWIN_CORE) << "forced position fail:" << p << ":" << rules()->checkPosition(p); - } - m_requestedFrameGeometry.moveTopLeft(p); - m_requestedClientGeometry.moveTopLeft(framePosToClientPos(p)); - if (force == NormalGeometrySet && m_frameGeometry.topLeft() == p) { - return; - } - m_frameGeometry.moveTopLeft(m_requestedFrameGeometry.topLeft()); - if (areGeometryUpdatesBlocked()) { - if (pendingGeometryUpdate() == PendingGeometryForced) { - return; - } - if (force == ForceGeometrySet) { - setPendingGeometryUpdate(PendingGeometryForced); - } else { - setPendingGeometryUpdate(PendingGeometryNormal); - } - return; - } - m_clientGeometry.moveTopLeft(m_requestedClientGeometry.topLeft()); - m_bufferGeometry = frameRectToBufferRect(m_frameGeometry); - updateWindowRules(Rules::Position); - screens()->setCurrent(this); - workspace()->updateStackingOrder(); - emit frameGeometryChanged(this, frameGeometryBeforeUpdateBlocking()); - addRepaintDuringGeometryUpdates(); - updateGeometryBeforeUpdateBlocking(); -} - void XdgSurfaceClient::requestGeometry(const QRect &rect) { - m_requestedFrameGeometry = rect; - m_requestedClientGeometry = frameRectToClientRect(rect); + WaylandClient::requestGeometry(rect); scheduleConfigure(); // Send the configure event later. } -void XdgSurfaceClient::updateGeometry(const QRect &rect) -{ - const QRect oldClientGeometry = m_clientGeometry; - const QRect oldFrameGeometry = m_frameGeometry; - const QRect oldBufferGeometry = m_bufferGeometry; - - m_clientGeometry = frameRectToClientRect(rect); - m_frameGeometry = rect; - m_bufferGeometry = frameRectToBufferRect(rect); - - uint changedGeometries = 0; - - if (m_clientGeometry != oldClientGeometry) { - changedGeometries |= XdgSurfaceGeometryClient; - } - if (m_frameGeometry != oldFrameGeometry) { - changedGeometries |= XdgSurfaceGeometryFrame; - } - if (m_bufferGeometry != oldBufferGeometry) { - changedGeometries |= XdgSurfaceGeometryBuffer; - } - - if (!changedGeometries) { - return; - } - - updateWindowRules(Rules::Position | Rules::Size); - updateGeometryBeforeUpdateBlocking(); - - if (changedGeometries & XdgSurfaceGeometryBuffer) { - emit bufferGeometryChanged(this, oldBufferGeometry); - } - if (changedGeometries & XdgSurfaceGeometryClient) { - emit clientGeometryChanged(this, oldClientGeometry); - } - if (changedGeometries & XdgSurfaceGeometryFrame) { - emit frameGeometryChanged(this, oldFrameGeometry); - } - emit geometryShapeChanged(this, oldFrameGeometry); - - addRepaintDuringGeometryUpdates(); -} - /** * \internal * \todo We have to check the current frame geometry in checkWorskpacePosition(). @@ -492,8 +323,8 @@ QRect XdgSurfaceClient::frameRectToBufferRect(const QRect &rect) const void XdgSurfaceClient::addDamage(const QRegion &damage) { - const int offsetX = m_bufferGeometry.x() - m_frameGeometry.x(); - const int offsetY = m_bufferGeometry.y() - m_frameGeometry.y(); + const int offsetX = bufferGeometry().x() - frameGeometry().x(); + const int offsetY = bufferGeometry().y() - frameGeometry().y(); repaints_region += damage.translated(offsetX, offsetY); Toplevel::addDamage(damage); } diff --git a/xdgshellclient.h b/xdgshellclient.h index 8f5b4c299..a1c9f1ec2 100644 --- a/xdgshellclient.h +++ b/xdgshellclient.h @@ -53,26 +53,17 @@ public: explicit XdgSurfaceClient(KWaylandServer::XdgSurfaceInterface *shellSurface); ~XdgSurfaceClient() override; + QRect frameRectToBufferRect(const QRect &rect) const override; QRect inputGeometry() const override; - QRect bufferGeometry() const override; QMatrix4x4 inputTransformation() const override; - void setFrameGeometry(const QRect &rect, ForceGeometry_t force = NormalGeometrySet) override; - using AbstractClient::move; - void move(int x, int y, ForceGeometry_t force = NormalGeometrySet) override; bool isInitialPositionSet() const override; void destroyClient() override; void setVirtualKeyboardGeometry(const QRect &geo) override; - QRect frameRectToBufferRect(const QRect &rect) const; - QRect requestedFrameGeometry() const; - QPoint requestedPos() const; - QSize requestedSize() const; - QRect requestedClientGeometry() const; - QSize requestedClientSize() const; - virtual void installPlasmaShellSurface(KWaylandServer::PlasmaShellSurfaceInterface *shellSurface) = 0; protected: + void requestGeometry(const QRect &rect) override; void addDamage(const QRegion &damage) override; virtual XdgSurfaceConfigure *sendRoleConfigure() const = 0; @@ -82,8 +73,6 @@ protected: XdgSurfaceConfigure *lastAcknowledgedConfigure() const; void scheduleConfigure(); void sendConfigure(); - void requestGeometry(const QRect &rect); - void updateGeometry(const QRect &rect); QPointer m_plasmaShellSurface; @@ -104,9 +93,6 @@ private: QQueue m_configureEvents; QScopedPointer m_lastAcknowledgedConfigure; QRect m_windowGeometry; - QRect m_requestedFrameGeometry; - QRect m_bufferGeometry; - QRect m_requestedClientGeometry; bool m_haveNextWindowGeometry = false; };