Commit 1176f31e authored by Aleix Pol Gonzalez's avatar Aleix Pol Gonzalez 🐧 Committed by Nate Graham
Browse files

Support KWindowSystem interface with activation support

Allow internal uses of KWindowSystem to support activating other
clients.

BUG: 453748
BUG: 453785
parent d3a37aa9
Pipeline #178012 passed with stage
in 24 minutes and 43 seconds
......@@ -9,6 +9,12 @@
#include <QGuiApplication>
#include <QWindow>
#include <wayland/display.h>
#include <wayland/seat_interface.h>
#include <wayland_server.h>
#include <window.h>
#include <workspace.h>
#include <xdgactivationv1.h>
Q_DECLARE_METATYPE(NET::WindowType)
......@@ -17,7 +23,7 @@ namespace KWin
WindowSystem::WindowSystem()
: QObject()
, KWindowSystemPrivate()
, KWindowSystemPrivateV2()
{
}
......@@ -313,4 +319,30 @@ QRect WindowSystem::workArea(int desktop)
return {};
}
void WindowSystem::requestToken(QWindow *win, uint32_t serial, const QString &appId)
{
Q_UNUSED(win); // it's coming from within kwin, it doesn't matter the window
auto seat = KWin::waylandServer()->seat();
auto token = KWin::waylandServer()->xdgActivationIntegration()->requestToken(true, nullptr, seat->display()->serial(), seat, appId);
// Ensure that xdgActivationTokenArrived is always emitted asynchronously
QTimer::singleShot(0, [serial, token] {
Q_EMIT KWindowSystem::self()->xdgActivationTokenArrived(serial, token);
});
}
void WindowSystem::setCurrentToken(const QString &token)
{
Q_UNUSED(token)
// KWin cannot activate own windows
}
quint32 WindowSystem::lastInputSerial(QWindow *window)
{
auto w = workspace()->findInternal(window);
if (!w) {
return 0;
}
return w->lastUsageSerial();
}
}
......@@ -12,7 +12,7 @@
namespace KWin
{
class WindowSystem : public QObject, public KWindowSystemPrivate
class WindowSystem : public QObject, public KWindowSystemPrivateV2
{
Q_OBJECT
public:
......@@ -66,6 +66,10 @@ public:
QPoint constrainViewportRelativePosition(const QPoint &pos) override;
void connectNotify(const QMetaMethod &signal) override;
void requestToken(QWindow *win, uint32_t serial, const QString &app_id) override;
void setCurrentToken(const QString &token) override;
quint32 lastInputSerial(QWindow *window) override;
};
}
......@@ -492,7 +492,7 @@ bool WaylandServer::init(InitializationFlags flags)
auto activation = new KWaylandServer::XdgActivationV1Interface(m_display, this);
auto init = [this, activation] {
new XdgActivationV1Integration(activation, this);
m_xdgActivationIntegration = new XdgActivationV1Integration(activation, this);
};
if (Workspace::self()) {
init();
......
......@@ -55,6 +55,7 @@ namespace KWin
class Window;
class Output;
class XdgActivationV1Integration;
class XdgPopupWindow;
class XdgSurfaceWindow;
class XdgToplevelWindow;
......@@ -232,6 +233,11 @@ public:
*/
QString socketName() const;
XdgActivationV1Integration *xdgActivationIntegration() const
{
return m_xdgActivationIntegration;
}
Q_SIGNALS:
void windowAdded(KWin::Window *);
void windowRemoved(KWin::Window *);
......@@ -287,6 +293,7 @@ private:
KWaylandServer::XdgForeignV2Interface *m_XdgForeign = nullptr;
KWaylandServer::KeyStateInterface *m_keyState = nullptr;
KWaylandServer::PrimaryOutputV1Interface *m_primary = nullptr;
XdgActivationV1Integration *m_xdgActivationIntegration = nullptr;
QList<Window *> m_windows;
InitializationFlags m_initFlags;
QHash<Output *, WaylandOutput *> m_waylandOutputs;
......
......@@ -25,6 +25,7 @@ namespace KWin
static bool isPrivilegedInWindowManagement(const ClientConnection *client)
{
Q_ASSERT(client);
auto requestedInterfaces = client->property("requestedInterfaces").toStringList();
return requestedInterfaces.contains(QLatin1String("org_kde_plasma_window_management"));
}
......@@ -50,30 +51,36 @@ XdgActivationV1Integration::XdgActivationV1Integration(XdgActivationV1Interface
});
activation->setActivationTokenCreator([this](ClientConnection *client, SurfaceInterface *surface, uint serial, SeatInterface *seat, const QString &appId) -> QString {
Workspace *ws = Workspace::self();
if (ws->activeWindow() && ws->activeWindow()->surface() != surface && !isPrivilegedInWindowManagement(client)) {
Q_ASSERT(client); // Should always be available as it's coming straight from the wayland implementation
const bool isPrivileged = isPrivilegedInWindowManagement(client);
if (!isPrivileged && ws->activeWindow() && ws->activeWindow()->surface() != surface) {
qCWarning(KWIN_CORE) << "Cannot grant a token to" << client;
return QStringLiteral("not-granted-666");
}
static int i = 0;
const auto newToken = QStringLiteral("kwin-%1").arg(++i);
if (m_currentActivationToken) {
clear();
}
QSharedPointer<PlasmaWindowActivationInterface> pwActivation(waylandServer()->plasmaActivationFeedback()->createActivation(appId));
m_currentActivationToken.reset(new ActivationToken{newToken, client, surface, serial, seat, appId, pwActivation});
if (!appId.isEmpty()) {
const auto icon = QIcon::fromTheme(Window::iconFromDesktopFile(appId), QIcon::fromTheme(QStringLiteral("system-run")));
Q_EMIT effects->startupAdded(m_currentActivationToken->token, icon);
}
return newToken;
return requestToken(isPrivileged, surface, serial, seat, appId);
});
connect(activation, &XdgActivationV1Interface::activateRequested, this, &XdgActivationV1Integration::activateSurface);
}
QString XdgActivationV1Integration::requestToken(bool isPrivileged, SurfaceInterface *surface, uint serial, SeatInterface *seat, const QString &appId)
{
static int i = 0;
const auto newToken = QStringLiteral("kwin-%1").arg(++i);
if (m_currentActivationToken) {
clear();
}
QSharedPointer<PlasmaWindowActivationInterface> pwActivation(waylandServer()->plasmaActivationFeedback()->createActivation(appId));
m_currentActivationToken.reset(new ActivationToken{newToken, isPrivileged, surface, serial, seat, appId, pwActivation});
if (!appId.isEmpty()) {
const auto icon = QIcon::fromTheme(Window::iconFromDesktopFile(appId), QIcon::fromTheme(QStringLiteral("system-run")));
Q_EMIT effects->startupAdded(m_currentActivationToken->token, icon);
}
return newToken;
}
void XdgActivationV1Integration::activateSurface(SurfaceInterface *surface, const QString &token)
{
Workspace *ws = Workspace::self();
......@@ -91,7 +98,7 @@ void XdgActivationV1Integration::activateSurface(SurfaceInterface *surface, cons
auto ownerWindow = waylandServer()->findWindow(m_currentActivationToken->surface);
qCDebug(KWIN_CORE) << "activating" << window << surface << "on behalf of" << m_currentActivationToken->surface << "into" << ownerWindow;
if (ws->activeWindow() == ownerWindow || ws->activeWindow()->lastUsageSerial() < m_currentActivationToken->serial || isPrivilegedInWindowManagement(m_currentActivationToken->client)) {
if (ws->activeWindow() == ownerWindow || ws->activeWindow()->lastUsageSerial() < m_currentActivationToken->serial || m_currentActivationToken->isPrivileged) {
ws->activateWindow(window);
} else {
qCWarning(KWIN_CORE) << "Activation requested while owner isn't active" << (ownerWindow ? ownerWindow->desktopFileName() : "null")
......
......@@ -36,13 +36,15 @@ public:
~ActivationToken();
const QString token;
const KWaylandServer::ClientConnection *client;
const bool isPrivileged;
QPointer<const KWaylandServer::SurfaceInterface> surface;
const uint serial;
const KWaylandServer::SeatInterface *seat;
QString applicationId;
QSharedPointer<KWaylandServer::PlasmaWindowActivationInterface> activation;
};
QString requestToken(bool isPrivileged, KWaylandServer::SurfaceInterface *surface, uint serial, KWaylandServer::SeatInterface *seat, const QString &appId);
void activateSurface(KWaylandServer::SurfaceInterface *surface, const QString &token);
private:
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment