From cc3eb54b323eb7ecfd5e657d6fe24093015000f5 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Mon, 1 Jun 2020 13:43:49 +0300 Subject: [PATCH] Introduce the client geometry in Toplevel In most cases, we don't need to react to client geometry changes, but in code that deals with server-side window decorations, we need to react to client geometry changes. The problem is that frame and client geometry updates are not correlated even though there is a connection between the frame geometry and the client geometry. This change introduces the client geometry in the Toplevel class in order to allow monitoring client geometry updates from DecoratedClientImpl. --- abstract_client.cpp | 6 ++++++ abstract_client.h | 2 ++ deleted.cpp | 5 ----- deleted.h | 1 - events.cpp | 1 + internal_client.cpp | 14 +++++--------- internal_client.h | 2 -- toplevel.cpp | 1 + toplevel.h | 21 ++++++++++++++++++++- unmanaged.cpp | 5 ----- unmanaged.h | 1 - x11client.cpp | 10 ++++++++++ x11client.h | 7 ------- xdgshellclient.cpp | 36 ++++++++++++++++++++++++++++-------- xdgshellclient.h | 2 -- 15 files changed, 73 insertions(+), 41 deletions(-) diff --git a/abstract_client.cpp b/abstract_client.cpp index 2a0a60ea62..1d2acb217b 100644 --- a/abstract_client.cpp +++ b/abstract_client.cpp @@ -1984,10 +1984,16 @@ QRect AbstractClient::frameGeometryBeforeUpdateBlocking() const return m_frameGeometryBeforeUpdateBlocking; } +QRect AbstractClient::clientGeometryBeforeUpdateBlocking() const +{ + return m_clientGeometryBeforeUpdateBlocking; +} + void AbstractClient::updateGeometryBeforeUpdateBlocking() { m_bufferGeometryBeforeUpdateBlocking = bufferGeometry(); m_frameGeometryBeforeUpdateBlocking = frameGeometry(); + m_clientGeometryBeforeUpdateBlocking = clientGeometry(); } void AbstractClient::doMove(int, int) diff --git a/abstract_client.h b/abstract_client.h index e574d245ec..cf6c3fccd2 100644 --- a/abstract_client.h +++ b/abstract_client.h @@ -1040,6 +1040,7 @@ protected: void setPendingGeometryUpdate(PendingGeometry_t update); QRect bufferGeometryBeforeUpdateBlocking() const; QRect frameGeometryBeforeUpdateBlocking() const; + QRect clientGeometryBeforeUpdateBlocking() const; void updateGeometryBeforeUpdateBlocking(); /** * Schedules a repaint for the visibleRect before and after a @@ -1270,6 +1271,7 @@ private: QRect m_visibleRectBeforeGeometryUpdate; QRect m_bufferGeometryBeforeUpdateBlocking; QRect m_frameGeometryBeforeUpdateBlocking; + QRect m_clientGeometryBeforeUpdateBlocking; QRect m_virtualKeyboardGeometry; QRect m_keyboardGeometryRestore; QRect m_maximizeGeometryRestore; diff --git a/deleted.cpp b/deleted.cpp index ca0cef866c..d730463025 100644 --- a/deleted.cpp +++ b/deleted.cpp @@ -206,11 +206,6 @@ QPoint Deleted::clientPos() const return contentsRect.topLeft(); } -QSize Deleted::clientSize() const -{ - return contentsRect.size(); -} - void Deleted::debug(QDebug& stream) const { stream << "\'ID:" << window() << "\' (deleted)"; diff --git a/deleted.h b/deleted.h index 22757677ca..4dbd3f4867 100644 --- a/deleted.h +++ b/deleted.h @@ -51,7 +51,6 @@ public: QStringList activities() const override; QVector desktops() const override; QPoint clientPos() const override; - QSize clientSize() const override; QPoint clientContentPos() const override { return m_contentPos; } diff --git a/events.cpp b/events.cpp index ffc96d9b22..694b479d7c 100644 --- a/events.cpp +++ b/events.cpp @@ -1294,6 +1294,7 @@ void Unmanaged::configureNotifyEvent(xcb_configure_notify_event_t *e) if (newgeom != m_frameGeometry) { addWorkspaceRepaint(visibleRect()); // damage old area QRect old = m_frameGeometry; + m_clientGeometry = newgeom; m_frameGeometry = newgeom; emit frameGeometryChanged(this, old); // update shadow region addRepaintFull(); diff --git a/internal_client.cpp b/internal_client.cpp index f22840b29d..4d94037e69 100644 --- a/internal_client.cpp +++ b/internal_client.cpp @@ -38,7 +38,6 @@ namespace KWin InternalClient::InternalClient(QWindow *window) : m_internalWindow(window) - , m_clientSize(window->size()) , m_windowId(window->winId()) , m_internalWindowFlags(window->flags()) { @@ -139,11 +138,6 @@ QPoint InternalClient::clientContentPos() const return -1 * clientPos(); } -QSize InternalClient::clientSize() const -{ - return m_clientSize; -} - QSize InternalClient::minSize() const { return m_internalWindow->minimumSize(); @@ -334,7 +328,7 @@ void InternalClient::setFrameGeometry(const QRect &rect, ForceGeometry_t force) const QRect newClientGeometry = frameRectToClientRect(rect); - if (m_clientSize == newClientGeometry.size()) { + if (clientSize() == newClientGeometry.size()) { commitGeometry(rect); } else { requestGeometry(rect); @@ -530,13 +524,15 @@ void InternalClient::commitGeometry(const QRect &rect) return; } + m_clientGeometry = frameRectToClientRect(rect); m_frameGeometry = rect; - m_clientSize = frameRectToClientRect(frameGeometry()).size(); - addWorkspaceRepaint(visibleRect()); syncGeometryToInternalWindow(); + if (clientGeometryBeforeUpdateBlocking() != clientGeometry()) { + emit clientGeometryChanged(this, clientGeometryBeforeUpdateBlocking()); + } if (frameGeometryBeforeUpdateBlocking() != frameGeometry()) { emit frameGeometryChanged(this, frameGeometryBeforeUpdateBlocking()); } diff --git a/internal_client.h b/internal_client.h index ec038f0695..b1b3b968fc 100644 --- a/internal_client.h +++ b/internal_client.h @@ -42,7 +42,6 @@ public: QString captionNormal() const override; QString captionSuffix() const override; QPoint clientContentPos() const override; - QSize clientSize() const override; QSize minSize() const override; QSize maxSize() const override; void debug(QDebug &stream) const override; @@ -101,7 +100,6 @@ private: void updateInternalWindowGeometry(); QWindow *m_internalWindow = nullptr; - QSize m_clientSize = QSize(0, 0); QString m_captionNormal; QString m_captionSuffix; double m_opacity = 1.0; diff --git a/toplevel.cpp b/toplevel.cpp index 15f4350ce3..e5e9e82b48 100644 --- a/toplevel.cpp +++ b/toplevel.cpp @@ -92,6 +92,7 @@ void Toplevel::copyToDeleted(Toplevel* c) { m_internalId = c->internalId(); m_frameGeometry = c->m_frameGeometry; + m_clientGeometry = c->m_clientGeometry; m_visual = c->m_visual; bit_depth = c->bit_depth; info = c->info; diff --git a/toplevel.h b/toplevel.h index 131b0ce43d..a21e84a89e 100644 --- a/toplevel.h +++ b/toplevel.h @@ -327,6 +327,10 @@ public: * server-side and client-side drop shadows, etc. */ QRect frameGeometry() const; + /** + * Returns the geometry of the client window, in global screen coordinates. + */ + QRect clientGeometry() const; /** * Returns the extents of the server-side decoration. * @@ -372,7 +376,7 @@ public: * The default implementation is a 1:1 mapping meaning the frame is part of the content. */ virtual QPoint clientContentPos() const; - virtual QSize clientSize() const = 0; + QSize clientSize() const; /** * Returns a rectangle that the window occupies on the screen, including drop-shadows. */ @@ -657,6 +661,10 @@ Q_SIGNALS: * This signal is emitted when the Toplevel's frame geometry changes. */ void frameGeometryChanged(KWin::Toplevel *toplevel, const QRect &oldGeometry); + /** + * This signal is emitted when the Toplevel's client geometry has changed. + */ + void clientGeometryChanged(KWin::Toplevel *toplevel, const QRect &oldGeometry); protected Q_SLOTS: /** @@ -705,6 +713,7 @@ protected: void deleteEffectWindow(); void setDepth(int depth); QRect m_frameGeometry; + QRect m_clientGeometry; xcb_visualid_t m_visual; int bit_depth; NETWinInfo* info; @@ -754,6 +763,16 @@ inline void Toplevel::setWindowHandles(xcb_window_t w) m_client.reset(w, false); } +inline QRect Toplevel::clientGeometry() const +{ + return m_clientGeometry; +} + +inline QSize Toplevel::clientSize() const +{ + return m_clientGeometry.size(); +} + inline QRect Toplevel::frameGeometry() const { return m_frameGeometry; diff --git a/unmanaged.cpp b/unmanaged.cpp index 529eb5f1b3..334e69fbd6 100644 --- a/unmanaged.cpp +++ b/unmanaged.cpp @@ -152,11 +152,6 @@ QPoint Unmanaged::clientPos() const return QPoint(0, 0); // unmanaged windows don't have decorations } -QSize Unmanaged::clientSize() const -{ - return size(); -} - QRect Unmanaged::transparentRect() const { return QRect(clientPos(), clientSize()); diff --git a/unmanaged.h b/unmanaged.h index 2915218192..1890c753fb 100644 --- a/unmanaged.h +++ b/unmanaged.h @@ -43,7 +43,6 @@ public: QStringList activities() const override; QVector desktops() const override; QPoint clientPos() const override; - QSize clientSize() const override; QRect transparentRect() const override; Layer layer() const override { return UnmanagedLayer; diff --git a/x11client.cpp b/x11client.cpp index 00cd48ac35..7eb06b52c2 100644 --- a/x11client.cpp +++ b/x11client.cpp @@ -160,6 +160,7 @@ X11Client::X11Client() //client constructed be connected to the workspace wrapper m_frameGeometry = QRect(0, 0, 100, 100); // So that decorations don't start with size being (0,0) + m_clientGeometry = QRect(0, 0, 100, 100); connect(clientMachine(), &ClientMachine::localhostChanged, this, &X11Client::updateCaption); connect(options, &Options::condensedTitleChanged, this, &X11Client::updateCaption); @@ -2898,6 +2899,9 @@ void X11Client::move(int x, int y, ForceGeometry_t force) screens()->setCurrent(this); workspace()->updateStackingOrder(); // client itself is not damaged + if (clientGeometryBeforeUpdateBlocking() != clientGeometry()) { + emit clientGeometryChanged(this, clientGeometryBeforeUpdateBlocking()); + } if (frameGeometryBeforeUpdateBlocking() != frameGeometry()) { emit frameGeometryChanged(this, frameGeometryBeforeUpdateBlocking()); } @@ -4190,6 +4194,9 @@ void X11Client::setFrameGeometry(const QRect &rect, ForceGeometry_t force) if (bufferGeometryBeforeUpdateBlocking().size() != m_bufferGeometry.size()) { discardWindowPixmap(); } + if (clientGeometryBeforeUpdateBlocking() != m_clientGeometry) { + emit clientGeometryChanged(this, clientGeometryBeforeUpdateBlocking()); + } if (frameGeometryBeforeUpdateBlocking() != m_frameGeometry) { emit frameGeometryChanged(this, frameGeometryBeforeUpdateBlocking()); } @@ -4247,6 +4254,9 @@ void X11Client::plainResize(int w, int h, ForceGeometry_t force) if (bufferGeometryBeforeUpdateBlocking().size() != m_bufferGeometry.size()) { discardWindowPixmap(); } + if (clientGeometryBeforeUpdateBlocking() != clientGeometry()) { + emit clientGeometryChanged(this, clientGeometryBeforeUpdateBlocking()); + } if (frameGeometryBeforeUpdateBlocking() != frameGeometry()) { emit frameGeometryChanged(this, frameGeometryBeforeUpdateBlocking()); } diff --git a/x11client.h b/x11client.h index 8d5f193c45..7da1b7659d 100644 --- a/x11client.h +++ b/x11client.h @@ -123,7 +123,6 @@ public: QSize minSize() const override; QSize maxSize() const override; QSize basicUnit() const; - QSize clientSize() const override; QPoint inputPos() const { return input_offset; } // Inside of geometry() bool windowEvent(xcb_generic_event_t *e); @@ -508,7 +507,6 @@ private: MaximizeMode max_mode; QRect m_bufferGeometry = QRect(0, 0, 100, 100); - QRect m_clientGeometry = QRect(0, 0, 100, 100); QRect geom_fs_restore; xcb_colormap_t m_colormap; QString cap_normal, cap_iconic, cap_suffix; @@ -624,11 +622,6 @@ inline bool X11Client::isManaged() const return m_managed; } -inline QSize X11Client::clientSize() const -{ - return m_clientGeometry.size(); -} - inline void X11Client::plainResize(const QSize& s, ForceGeometry_t force) { plainResize(s.width(), s.height(), force); diff --git a/xdgshellclient.cpp b/xdgshellclient.cpp index 0ea08021cf..df9bd92bf4 100644 --- a/xdgshellclient.cpp +++ b/xdgshellclient.cpp @@ -49,6 +49,12 @@ using namespace KWaylandServer; namespace KWin { +enum XdgSurfaceGeometryType { + XdgSurfaceGeometryClient = 0x1, + XdgSurfaceGeometryFrame = 0x2, + XdgSurfaceGeometryBuffer = 0x4, +}; + XdgSurfaceClient::XdgSurfaceClient(XdgSurfaceInterface *shellSurface) : WaylandClient(shellSurface->surface()) , m_shellSurface(shellSurface) @@ -156,11 +162,6 @@ QRect XdgSurfaceClient::clientGeometry() const return m_clientGeometry; } -QSize XdgSurfaceClient::clientSize() const -{ - return m_clientGeometry.size(); -} - QMatrix4x4 XdgSurfaceClient::inputTransformation() const { QMatrix4x4 transformation; @@ -437,20 +438,39 @@ void XdgSurfaceClient::requestGeometry(const QRect &rect) 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); - m_clientGeometry = frameRectToClientRect(rect); - if (oldFrameGeometry == m_frameGeometry) { + 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(); - emit frameGeometryChanged(this, oldFrameGeometry); + if (changedGeometries & XdgSurfaceGeometryClient) { + emit clientGeometryChanged(this, oldClientGeometry); + } + if (changedGeometries & XdgSurfaceGeometryFrame) { + emit frameGeometryChanged(this, oldFrameGeometry); + } emit geometryShapeChanged(this, oldFrameGeometry); addRepaintDuringGeometryUpdates(); diff --git a/xdgshellclient.h b/xdgshellclient.h index ca51045e62..c859120bd9 100644 --- a/xdgshellclient.h +++ b/xdgshellclient.h @@ -66,7 +66,6 @@ public: QRect inputGeometry() const override; QRect bufferGeometry() const override; - QSize clientSize() const override; QMatrix4x4 inputTransformation() const override; void setFrameGeometry(const QRect &rect, ForceGeometry_t force = NormalGeometrySet) override; using AbstractClient::move; @@ -122,7 +121,6 @@ private: QRect m_requestedFrameGeometry; QRect m_bufferGeometry; QRect m_requestedClientGeometry; - QRect m_clientGeometry; bool m_isClosing = false; bool m_isHidden = false; bool m_haveNextWindowGeometry = false;