diff --git a/shell_client.h b/shell_client.h --- a/shell_client.h +++ b/shell_client.h @@ -41,6 +41,10 @@ { Q_OBJECT public: + enum PingReason { + CloseWindow = 0, + FocusWindow + }; ShellClient(KWayland::Server::ShellSurfaceInterface *surface); ShellClient(KWayland::Server::XdgShellSurfaceInterface *surface); ShellClient(KWayland::Server::XdgShellPopupInterface *surface); @@ -236,6 +240,7 @@ int m_requestGeometryBlockCounter = 0; QRect m_blockedRequestGeometry; QString m_caption; + QHash m_pingSerials; bool m_compositingSetup = false; }; diff --git a/shell_client.cpp b/shell_client.cpp --- a/shell_client.cpp +++ b/shell_client.cpp @@ -218,6 +218,38 @@ initSurface(m_shellSurface); } else if (m_xdgShellSurface) { initSurface(m_xdgShellSurface); + + auto global = static_cast(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::pingTimeout, + this, [this](qint32 serial) { + auto it = m_pingSerials.find(serial); + if (it != m_pingSerials.end()) { + if (it.value() == CloseWindow) { + qCDebug(KWIN_CORE) << "Final ping timeout on a close attempt, asking to kill:" << caption(); + killWindow(); + } + 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 @@ -237,10 +269,22 @@ } m_xdgShellSurface->configure(xdgSurfaceStates()); }; + configure(); connect(this, &AbstractClient::activeChanged, this, configure); connect(this, &AbstractClient::clientStartUserMovedResized, this, configure); connect(this, &AbstractClient::clientFinishUserMovedResized, this, configure); } else if (m_xdgShellPopup) { + qDebug() << "setting up popup"; + //TODO - should probably check the parent had focus and whatever + //can maybe just call setFocus() or something + connect(m_xdgShellPopup, &XdgShellPopupInterface::grabbed, this, [this](SeatInterface *seat, quint32 serial) { + Q_UNUSED(serial) + seat->setFocusedPointerSurface(surface()); + }); + + QRect position = QRect(m_xdgShellPopup->transientOffset(), m_xdgShellPopup->initialSize()); + m_xdgShellPopup->configure(position); + connect(m_xdgShellPopup, &XdgShellPopupInterface::destroyed, this, &ShellClient::destroyClient); } @@ -564,12 +608,11 @@ { if (m_xdgShellSurface && isCloseable()) { m_xdgShellSurface->close(); - return; - } - if (m_qtExtendedSurface && isCloseable()) { + const qint32 pingSerial = static_cast(m_xdgShellSurface->global())->ping(m_xdgShellSurface); + m_pingSerials.insert(pingSerial, CloseWindow); + } else if (m_qtExtendedSurface && isCloseable()) { m_qtExtendedSurface->close(); - } - if (m_internalWindow) { + } else if (m_internalWindow) { m_internalWindow->hide(); } } @@ -822,6 +865,10 @@ void ShellClient::takeFocus() { if (rules()->checkAcceptFocus(wantsInput())) { + if (m_xdgShellSurface) { + const qint32 pingSerial = static_cast(m_xdgShellSurface->global())->ping(m_xdgShellSurface); + m_pingSerials.insert(pingSerial, FocusWindow); + } setActive(true); } @@ -1008,6 +1055,15 @@ if (m_xdgShellSurface) { m_xdgShellSurface->configure(xdgSurfaceStates(), size); } + if (m_xdgShellPopup) { + auto parent = transientFor(); + if (parent) { + const QPoint globalClientContentPos = parent->geometry().topLeft() + parent->clientPos(); + const QPoint relativeOffset = rect.topLeft() -globalClientContentPos; + m_xdgShellPopup->configure(QRect(relativeOffset, rect.size())); + } + } + m_blockedRequestGeometry = QRect(); if (m_internal) { m_internalWindow->setGeometry(QRect(rect.topLeft() + QPoint(borderLeft(), borderTop()), rect.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom()))); @@ -1390,6 +1446,9 @@ if (isLockScreen()) { return false; } + if (m_xdgShellPopup) { + return false; + } if (m_shellSurface) { if (m_shellSurface->isTransient() && !m_shellSurface->acceptsKeyboardFocus()) { return false; @@ -1508,6 +1567,9 @@ if (m_shellSurface) { m_shellSurface->popupDone(); } + if (m_xdgShellPopup) { + m_xdgShellPopup->popupDone(); + } } } diff --git a/wayland_server.h b/wayland_server.h --- a/wayland_server.h +++ b/wayland_server.h @@ -205,6 +205,7 @@ KWayland::Server::SeatInterface *m_seat = nullptr; KWayland::Server::ShellInterface *m_shell = nullptr; KWayland::Server::XdgShellInterface *m_xdgShell = nullptr; + KWayland::Server::XdgShellInterface *m_xdgShell6 = nullptr; KWayland::Server::PlasmaShellInterface *m_plasmaShell = nullptr; KWayland::Server::PlasmaWindowManagementInterface *m_windowManagement = nullptr; KWayland::Server::QtSurfaceExtensionInterface *m_qtExtendedSurface = nullptr; diff --git a/wayland_server.cpp b/wayland_server.cpp --- a/wayland_server.cpp +++ b/wayland_server.cpp @@ -201,6 +201,13 @@ connect(m_xdgShell, &XdgShellInterface::surfaceCreated, this, &WaylandServer::createSurface); // TODO: verify seat and serial connect(m_xdgShell, &XdgShellInterface::popupCreated, this, &WaylandServer::createSurface); + + m_xdgShell6 = m_display->createXdgShell(XdgShellInterfaceVersion::UnstableV6, m_display); + m_xdgShell6->create(); + connect(m_xdgShell6, &XdgShellInterface::surfaceCreated, this, &WaylandServer::createSurface); + connect(m_xdgShell6, &XdgShellInterface::xdgPopupCreated, this, &WaylandServer::createSurface); + + m_display->createShm(); m_seat = m_display->createSeat(m_display); m_seat->create();