[wayland] Make XdgShellClient::init() more comprehensible

Summary:
Currently the init method is just a big pile of connects to lambdas,
which makes the code very difficult to read and moreover to change.
This change moves most of those lambda to handleFoo methods so one has
more clear view of what the init method is actually doing.

Reviewers: #kwin

Subscribers: kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D24197
This commit is contained in:
Vlad Zahorodnii 2019-09-15 13:54:53 +03:00
parent 7bc83a8653
commit 3047a68905
2 changed files with 213 additions and 185 deletions

View file

@ -102,76 +102,21 @@ void XdgShellClient::init()
m_windowType = NET::OnScreenDisplay;
}
connect(s, &SurfaceInterface::sizeChanged, this,
[this] {
m_clientSize = surface()->size();
doSetGeometry(QRect(pos(), m_clientSize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom())));
}
);
connect(surface(), &SurfaceInterface::sizeChanged, this, &XdgShellClient::handleSurfaceSizeChanged);
connect(s, &SurfaceInterface::unmapped, this, &XdgShellClient::unmap);
connect(s, &SurfaceInterface::unbound, this, &XdgShellClient::destroyClient);
connect(s, &SurfaceInterface::destroyed, this, &XdgShellClient::destroyClient);
if (m_xdgShellSurface) {
m_caption = m_xdgShellSurface->title().simplified();
// delay till end of init
QTimer::singleShot(0, this, &XdgShellClient::updateCaption);
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::destroyed, this, &XdgShellClient::destroyClient);
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::titleChanged, this,
[this] (const QString &caption) {
const auto oldSuffix = m_captionSuffix;
m_caption = caption.simplified();
updateCaption();
if (m_captionSuffix == oldSuffix) {
// don't emit caption change twice
// it already got emitted by the changing suffix
emit captionChanged();
}
}
);
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::configureAcknowledged, this, &XdgShellClient::handleConfigureAcknowledged);
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::moveRequested, this,
[this] {
// TODO: check the seat and serial
performMouseCommand(Options::MouseMove, Cursor::pos());
}
);
m_caption = m_xdgShellSurface->title().simplified();
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::titleChanged, this, &XdgShellClient::handleWindowTitleChanged);
QTimer::singleShot(0, this, &XdgShellClient::updateCaption);
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::resizeRequested, this,
[this] (SeatInterface *seat, quint32 serial, Qt::Edges edges) {
// TODO: check the seat and serial
Q_UNUSED(seat)
Q_UNUSED(serial)
if (!isResizable() || isShade()) {
return;
}
if (isMoveResize()) {
finishMoveResize(false);
}
setMoveResizePointerButtonDown(true);
setMoveOffset(Cursor::pos() - pos()); // map from global
setInvertedMoveOffset(rect().bottomRight() - moveOffset());
setUnrestrictedMoveResize(false);
auto toPosition = [edges] {
Position pos = PositionCenter;
if (edges.testFlag(Qt::TopEdge)) {
pos = PositionTop;
} else if (edges.testFlag(Qt::BottomEdge)) {
pos = PositionBottom;
}
if (edges.testFlag(Qt::LeftEdge)) {
pos = Position(pos | PositionLeft);
} else if (edges.testFlag(Qt::RightEdge)) {
pos = Position(pos | PositionRight);
}
return pos;
};
setMoveResizePointerMode(toPosition());
if (!startMoveResize()) {
setMoveResizePointerButtonDown(false);
}
updateCursor();
}
);
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::moveRequested, this, &XdgShellClient::handleMoveRequested);
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::resizeRequested, this, &XdgShellClient::handleResizeRequested);
// Determine the resource name, this is inspired from ICCCM 4.1.2.5
// the binary name of the invoked client.
@ -182,89 +127,19 @@ void XdgShellClient::init()
}
setResourceClass(resourceName, m_xdgShellSurface->windowClass());
setDesktopFileName(m_xdgShellSurface->windowClass());
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::windowClassChanged, this,
[this, resourceName] (const QByteArray &windowClass) {
setResourceClass(resourceName, windowClass);
if (m_isInitialized && supportsWindowRules()) {
setupWindowRules(true);
applyWindowRules();
}
setDesktopFileName(windowClass);
}
);
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::windowClassChanged, this, &XdgShellClient::handleWindowClassChanged);
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::maximizedChanged, this,
[this] (bool maximized) {
// If the maximized state of the client hasn't been changed due to a window
// rule or because the requested state is the same as the current, then the
// compositor still has to send a configure event.
RequestGeometryBlocker blocker(this);
maximize(maximized ? MaximizeFull : MaximizeRestore);
}
);
// TODO: consider output!
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::fullscreenChanged, this, &XdgShellClient::clientFullScreenChanged);
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::transientForChanged, this, &XdgShellClient::setTransient);
connect(this, &XdgShellClient::geometryChanged, this, &XdgShellClient::updateClientOutputs);
connect(screens(), &Screens::changed, this, &XdgShellClient::updateClientOutputs);
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::minimizeRequested, this, &XdgShellClient::handleMinimizeRequested);
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::maximizedChanged, this, &XdgShellClient::handleMaximizeRequested);
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::fullscreenChanged, this, &XdgShellClient::handleFullScreenRequested);
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::windowMenuRequested, this, &XdgShellClient::handleWindowMenuRequested);
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::transientForChanged, this, &XdgShellClient::handleTransientForChanged);
auto global = static_cast<XdgShellInterface *>(m_xdgShellSurface->global());
connect(global, &XdgShellInterface::pingDelayed,
this, [this](qint32 serial) {
auto it = m_pingSerials.find(serial);
if (it != m_pingSerials.end()) {
qCDebug(KWIN_CORE) << "First ping timeout:" << caption();
setUnresponsive(true);
}
});
connect(global, &XdgShellInterface::pingDelayed, this, &XdgShellClient::handlePingDelayed);
connect(global, &XdgShellInterface::pingTimeout, this, &XdgShellClient::handlePingTimeout);
connect(global, &XdgShellInterface::pongReceived, this, &XdgShellClient::handlePongReceived);
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::configureAcknowledged, this, [this](int serial) {
m_lastAckedConfigureRequest = serial;
});
connect(global, &XdgShellInterface::pingTimeout,
this, [this](qint32 serial) {
auto it = m_pingSerials.find(serial);
if (it != m_pingSerials.end()) {
if (it.value() == PingReason::CloseWindow) {
qCDebug(KWIN_CORE) << "Final ping timeout on a close attempt, asking to kill:" << caption();
//for internal windows, killing the window will delete this
QPointer<QObject> guard(this);
killWindow();
if (!guard) {
return;
}
}
m_pingSerials.erase(it);
}
});
connect(global, &XdgShellInterface::pongReceived,
this, [this](qint32 serial){
auto it = m_pingSerials.find(serial);
if (it != m_pingSerials.end()) {
setUnresponsive(false);
m_pingSerials.erase(it);
}
});
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::windowMenuRequested, this,
[this] (SeatInterface *seat, quint32 serial, const QPoint &surfacePos) {
// TODO: check serial on seat
Q_UNUSED(seat)
Q_UNUSED(serial)
performMouseCommand(Options::MouseOperationsMenu, pos() + surfacePos);
}
);
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::minimizeRequested, this,
[this] {
performMouseCommand(Options::MouseMinimize, Cursor::pos());
}
);
auto configure = [this] {
if (m_closing) {
return;
@ -277,18 +152,12 @@ void XdgShellClient::init()
connect(this, &AbstractClient::activeChanged, this, configure);
connect(this, &AbstractClient::clientStartUserMovedResized, this, configure);
connect(this, &AbstractClient::clientFinishUserMovedResized, this, configure);
connect(this, &XdgShellClient::geometryChanged, this, &XdgShellClient::updateClientOutputs);
connect(screens(), &Screens::changed, this, &XdgShellClient::updateClientOutputs);
} else if (m_xdgShellPopup) {
connect(m_xdgShellPopup, &XdgShellPopupInterface::grabRequested, this, [this](SeatInterface *seat, quint32 serial) {
Q_UNUSED(seat)
Q_UNUSED(serial)
//TODO - should check the parent had focus
m_hasPopupGrab = true;
});
connect(m_xdgShellPopup, &XdgShellPopupInterface::configureAcknowledged, this, [this](int serial) {
m_lastAckedConfigureRequest = serial;
});
connect(m_xdgShellPopup, &XdgShellPopupInterface::configureAcknowledged, this, &XdgShellClient::handleConfigureAcknowledged);
connect(m_xdgShellPopup, &XdgShellPopupInterface::grabRequested, this, &XdgShellClient::handleGrabRequested);
connect(m_xdgShellPopup, &XdgShellPopupInterface::destroyed, this, &XdgShellClient::destroyClient);
}
@ -301,10 +170,10 @@ void XdgShellClient::init()
connect(waylandServer(), &WaylandServer::foreignTransientChanged, this, [this](KWayland::Server::SurfaceInterface *child) {
if (child == surface()) {
setTransient();
handleTransientForChanged();
}
});
setTransient();
handleTransientForChanged();
AbstractClient::updateColorScheme(QString());
}
@ -1210,11 +1079,184 @@ void XdgShellClient::updatePendingGeometry()
updateMaximizeMode(maximizeMode);
}
void XdgShellClient::clientFullScreenChanged(bool fullScreen)
void XdgShellClient::handleConfigureAcknowledged(quint32 serial)
{
m_lastAckedConfigureRequest = serial;
}
void XdgShellClient::handleSurfaceSizeChanged()
{
m_clientSize = surface()->size();
doSetGeometry(QRect(pos(), m_clientSize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom())));
}
void XdgShellClient::handleTransientForChanged()
{
SurfaceInterface *transientSurface = nullptr;
if (m_xdgShellSurface) {
if (auto transient = m_xdgShellSurface->transientFor().data()) {
transientSurface = transient->surface();
}
}
if (m_xdgShellPopup) {
transientSurface = m_xdgShellPopup->transientFor().data();
}
if (!transientSurface) {
transientSurface = waylandServer()->findForeignTransientForSurface(surface());
}
XdgShellClient *transientClient = waylandServer()->findClient(transientSurface);
if (transientClient != transientFor()) {
// Remove from main client.
if (transientFor()) {
transientFor()->removeTransient(this);
}
setTransientFor(transientClient);
if (transientClient) {
transientClient->addTransient(this);
}
}
m_transient = (transientSurface != nullptr);
}
void XdgShellClient::handleWindowClassChanged(const QByteArray &windowClass)
{
setResourceClass(resourceName(), windowClass);
if (m_isInitialized && supportsWindowRules()) {
setupWindowRules(true);
applyWindowRules();
}
setDesktopFileName(windowClass);
}
void XdgShellClient::handleWindowTitleChanged(const QString &title)
{
const QString oldSuffix = m_captionSuffix;
m_caption = title.simplified();
updateCaption();
if (m_captionSuffix == oldSuffix) {
// Don't emit caption change twice it already got emitted by the changing suffix.
emit captionChanged();
}
}
void XdgShellClient::handleMoveRequested(SeatInterface *seat, quint32 serial)
{
// FIXME: Check the seat and serial.
Q_UNUSED(seat)
Q_UNUSED(serial)
performMouseCommand(Options::MouseMove, Cursor::pos());
}
void XdgShellClient::handleResizeRequested(SeatInterface *seat, quint32 serial, Qt::Edges edges)
{
// FIXME: Check the seat and serial.
Q_UNUSED(seat)
Q_UNUSED(serial)
if (!isResizable() || isShade()) {
return;
}
if (isMoveResize()) {
finishMoveResize(false);
}
setMoveResizePointerButtonDown(true);
setMoveOffset(Cursor::pos() - pos()); // map from global
setInvertedMoveOffset(rect().bottomRight() - moveOffset());
setUnrestrictedMoveResize(false);
auto toPosition = [edges] {
Position position = PositionCenter;
if (edges.testFlag(Qt::TopEdge)) {
position = PositionTop;
} else if (edges.testFlag(Qt::BottomEdge)) {
position = PositionBottom;
}
if (edges.testFlag(Qt::LeftEdge)) {
position = Position(position | PositionLeft);
} else if (edges.testFlag(Qt::RightEdge)) {
position = Position(position | PositionRight);
}
return position;
};
setMoveResizePointerMode(toPosition());
if (!startMoveResize()) {
setMoveResizePointerButtonDown(false);
}
updateCursor();
}
void XdgShellClient::handleMinimizeRequested()
{
performMouseCommand(Options::MouseMinimize, Cursor::pos());
}
void XdgShellClient::handleMaximizeRequested(bool maximized)
{
// If the maximized state of the client hasn't been changed due to a window
// rule or because the requested state is the same as the current, then the
// compositor still has to send a configure event.
RequestGeometryBlocker blocker(this);
maximize(maximized ? MaximizeFull : MaximizeRestore);
}
void XdgShellClient::handleFullScreenRequested(bool fullScreen, OutputInterface *output)
{
// FIXME: Consider output as well.
Q_UNUSED(output);
setFullScreen(fullScreen, false);
}
void XdgShellClient::handleWindowMenuRequested(SeatInterface *seat, quint32 serial, const QPoint &surfacePos)
{
// FIXME: Check the seat and serial.
Q_UNUSED(seat)
Q_UNUSED(serial)
performMouseCommand(Options::MouseOperationsMenu, pos() + surfacePos);
}
void XdgShellClient::handleGrabRequested(SeatInterface *seat, quint32 serial)
{
// FIXME: Check the seat and serial as well whether the parent had focus.
Q_UNUSED(seat)
Q_UNUSED(serial)
m_hasPopupGrab = true;
}
void XdgShellClient::handlePingDelayed(quint32 serial)
{
auto it = m_pingSerials.find(serial);
if (it != m_pingSerials.end()) {
qCDebug(KWIN_CORE) << "First ping timeout:" << caption();
setUnresponsive(true);
}
}
void XdgShellClient::handlePingTimeout(quint32 serial)
{
auto it = m_pingSerials.find(serial);
if (it != m_pingSerials.end()) {
if (it.value() == PingReason::CloseWindow) {
qCDebug(KWIN_CORE) << "Final ping timeout on a close attempt, asking to kill:" << caption();
//for internal windows, killing the window will delete this
QPointer<QObject> guard(this);
killWindow();
if (!guard) {
return;
}
}
m_pingSerials.erase(it);
}
}
void XdgShellClient::handlePongReceived(quint32 serial)
{
auto it = m_pingSerials.find(serial);
if (it != m_pingSerials.end()) {
setUnresponsive(false);
m_pingSerials.erase(it);
}
}
void XdgShellClient::resizeWithChecks(int w, int h, ForceGeometry_t force)
{
Q_UNUSED(force)
@ -1494,33 +1536,6 @@ bool XdgShellClient::isTransient() const
return m_transient;
}
void XdgShellClient::setTransient()
{
SurfaceInterface *s = nullptr;
if (m_xdgShellSurface) {
if (auto transient = m_xdgShellSurface->transientFor().data()) {
s = transient->surface();
}
}
if (m_xdgShellPopup) {
s = m_xdgShellPopup->transientFor().data();
}
if (!s) {
s = waylandServer()->findForeignTransientForSurface(surface());
}
auto t = waylandServer()->findClient(s);
if (t != transientFor()) {
// remove from main client
if (transientFor())
transientFor()->removeTransient(this);
setTransientFor(t);
if (t) {
t->addTransient(this);
}
}
m_transient = (s != nullptr);
}
bool XdgShellClient::hasTransientPlacementHint() const
{
return isTransient() && transientFor() && m_xdgShellPopup;

View file

@ -141,7 +141,21 @@ protected:
void updateCaption() override;
private Q_SLOTS:
void clientFullScreenChanged(bool fullScreen);
void handleConfigureAcknowledged(quint32 serial);
void handleSurfaceSizeChanged();
void handleTransientForChanged();
void handleWindowClassChanged(const QByteArray &windowClass);
void handleWindowTitleChanged(const QString &title);
void handleMoveRequested(KWayland::Server::SeatInterface *seat, quint32 serial);
void handleResizeRequested(KWayland::Server::SeatInterface *seat, quint32 serial, Qt::Edges edges);
void handleMinimizeRequested();
void handleMaximizeRequested(bool maximized);
void handleFullScreenRequested(bool fullScreen, KWayland::Server::OutputInterface *output);
void handleWindowMenuRequested(KWayland::Server::SeatInterface *seat, quint32 serial, const QPoint &surfacePos);
void handleGrabRequested(KWayland::Server::SeatInterface *seat, quint32 serial);
void handlePingDelayed(quint32 serial);
void handlePingTimeout(quint32 serial);
void handlePongReceived(quint32 serial);
private:
/**
@ -157,7 +171,6 @@ private:
void destroyClient();
void createWindowId();
void updateIcon();
void setTransient();
bool shouldExposeToWindowManagement();
void updateClientOutputs();
void updateWindowMargins();