Move geometry handling code from XdgSurfaceClient to WaylandClient

master
Vlad Zahorodnii 2020-08-18 15:51:20 +03:00
parent a9fd5ac19f
commit 4296a38a30
4 changed files with 192 additions and 192 deletions

View File

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

View File

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

View File

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

View File

@ -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<KWaylandServer::PlasmaShellSurfaceInterface> m_plasmaShellSurface;
@ -104,9 +93,6 @@ private:
QQueue<XdgSurfaceConfigure *> m_configureEvents;
QScopedPointer<XdgSurfaceConfigure> m_lastAcknowledgedConfigure;
QRect m_windowGeometry;
QRect m_requestedFrameGeometry;
QRect m_bufferGeometry;
QRect m_requestedClientGeometry;
bool m_haveNextWindowGeometry = false;
};