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.
This commit is contained in:
Vlad Zahorodnii 2020-06-01 13:43:49 +03:00 committed by Vlad Zahorodnii
parent 68ec39f433
commit cc3eb54b32
15 changed files with 73 additions and 41 deletions

View file

@ -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)

View file

@ -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;

View file

@ -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)";

View file

@ -51,7 +51,6 @@ public:
QStringList activities() const override;
QVector<VirtualDesktop *> desktops() const override;
QPoint clientPos() const override;
QSize clientSize() const override;
QPoint clientContentPos() const override {
return m_contentPos;
}

View file

@ -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();

View file

@ -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());
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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());

View file

@ -43,7 +43,6 @@ public:
QStringList activities() const override;
QVector<VirtualDesktop *> desktops() const override;
QPoint clientPos() const override;
QSize clientSize() const override;
QRect transparentRect() const override;
Layer layer() const override {
return UnmanagedLayer;

View file

@ -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());
}

View file

@ -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);

View file

@ -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();

View file

@ -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;