wayland_server.cpp 27.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/********************************************************************
 KWin - the KDE window manager
 This file is part of the KDE project.

Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "wayland_server.h"
Vlad Zahorodnii's avatar
Vlad Zahorodnii committed
21
#include "x11client.h"
22
#include "platform.h"
23
#include "composite.h"
24
#include "idle_inhibition.h"
25
#include "screens.h"
26
#include "xdgshellclient.h"
27
#include "workspace.h"
28

29 30
// Client
#include <KWayland/Client/connection_thread.h>
31
#include <KWayland/Client/event_queue.h>
32
#include <KWayland/Client/registry.h>
33
#include <KWayland/Client/compositor.h>
34 35
#include <KWayland/Client/seat.h>
#include <KWayland/Client/datadevicemanager.h>
36
#include <KWayland/Client/shm_pool.h>
37
#include <KWayland/Client/surface.h>
38
// Server
David Edmundson's avatar
David Edmundson committed
39
#include <KWayland/Server/appmenu_interface.h>
40
#include <KWayland/Server/compositor_interface.h>
41
#include <KWayland/Server/datadevicemanager_interface.h>
Martin Flöser's avatar
Martin Flöser committed
42
#include <KWayland/Server/datasource_interface.h>
43
#include <KWayland/Server/display.h>
44
#include <KWayland/Server/dpms_interface.h>
45
#include <KWayland/Server/idle_interface.h>
46
#include <KWayland/Server/idleinhibit_interface.h>
Roman Gilg's avatar
Roman Gilg committed
47
#include <KWayland/Server/linuxdmabuf_v1_interface.h>
48
#include <KWayland/Server/output_interface.h>
49
#include <KWayland/Server/plasmashell_interface.h>
50
#include <KWayland/Server/plasmavirtualdesktop_interface.h>
51
#include <KWayland/Server/plasmawindowmanagement_interface.h>
52
#include <KWayland/Server/pointerconstraints_interface.h>
53
#include <KWayland/Server/pointergestures_interface.h>
54
#include <KWayland/Server/qtsurfaceextension_interface.h>
55
#include <KWayland/Server/seat_interface.h>
56
#include <KWayland/Server/server_decoration_interface.h>
57
#include <KWayland/Server/server_decoration_palette_interface.h>
58
#include <KWayland/Server/shadow_interface.h>
59
#include <KWayland/Server/subcompositor_interface.h>
60
#include <KWayland/Server/blur_interface.h>
61 62
#include <KWayland/Server/outputmanagement_interface.h>
#include <KWayland/Server/outputconfiguration_interface.h>
63
#include <KWayland/Server/xdgdecoration_interface.h>
64
#include <KWayland/Server/xdgshell_interface.h>
Marco Martin's avatar
Marco Martin committed
65
#include <KWayland/Server/xdgforeign_interface.h>
David Edmundson's avatar
David Edmundson committed
66
#include <KWayland/Server/xdgoutput_interface.h>
67
#include <KWayland/Server/keystate_interface.h>
68 69 70 71
#include <KWayland/Server/filtered_display.h>

// KF
#include <KServiceTypeTrader>
72

73
// Qt
74
#include <QCryptographicHash>
75 76
#include <QDir>
#include <QFileInfo>
77
#include <QThread>
78 79
#include <QWindow>

80 81 82
// system
#include <sys/types.h>
#include <sys/socket.h>
83
#include <unistd.h>
84

85 86 87
//screenlocker
#include <KScreenLocker/KsldApp>

88 89 90 91 92 93 94 95 96 97
using namespace KWayland::Server;

namespace KWin
{

KWIN_SINGLETON_FACTORY(WaylandServer)

WaylandServer::WaylandServer(QObject *parent)
    : QObject(parent)
{
98
    qRegisterMetaType<KWayland::Server::OutputInterface::DpmsMode>();
99 100
}

101 102 103 104
WaylandServer::~WaylandServer()
{
    destroyInputMethodConnection();
}
105 106

void WaylandServer::destroyInternalConnection()
107
{
108
    emit terminatingInternalClientConnection();
109
    if (m_internalConnection.client) {
110 111 112 113 114 115 116 117 118
        // delete all connections hold by plugins like e.g. widget style
        const auto connections = KWayland::Client::ConnectionThread::connections();
        for (auto c : connections) {
            if (c == m_internalConnection.client) {
                continue;
            }
            emit c->connectionDied();
        }

119
        delete m_internalConnection.registry;
120
        delete m_internalConnection.compositor;
121 122
        delete m_internalConnection.seat;
        delete m_internalConnection.ddm;
123
        delete m_internalConnection.shm;
124
        dispatch();
125 126 127
        m_internalConnection.client->deleteLater();
        m_internalConnection.clientThread->quit();
        m_internalConnection.clientThread->wait();
128
        delete m_internalConnection.clientThread;
129
        m_internalConnection.client = nullptr;
130
        m_internalConnection.server->destroy();
131
        m_internalConnection.server = nullptr;
132 133
    }
}
134

135 136 137 138
void WaylandServer::terminateClientConnections()
{
    destroyInternalConnection();
    destroyInputMethodConnection();
139 140 141 142 143
    if (m_display) {
        const auto connections = m_display->connections();
        for (auto it = connections.begin(); it != connections.end(); ++it) {
            (*it)->destroy();
        }
144 145 146
    }
}

147 148 149 150 151 152 153 154 155 156 157 158 159 160
template <class T>
void WaylandServer::createSurface(T *surface)
{
    if (!Workspace::self()) {
        // it's possible that a Surface gets created before Workspace is created
        return;
    }
    if (surface->client() == m_xwayland.client) {
        // skip Xwayland clients, those are created using standard X11 way
        return;
    }
    if (surface->client() == m_screenLockerClientConnection) {
        ScreenLocker::KSldApp::self()->lockScreenShown();
    }
161
    XdgShellClient *client = new XdgShellClient(surface);
162 163 164
    if (ServerSideDecorationInterface *deco = ServerSideDecorationInterface::get(surface->surface())) {
        client->installServerSideDecoration(deco);
    }
165 166 167 168 169 170 171 172 173
    auto it = std::find_if(m_plasmaShellSurfaces.begin(), m_plasmaShellSurfaces.end(),
        [client] (PlasmaShellSurfaceInterface *surface) {
            return client->surface() == surface->surface();
        }
    );
    if (it != m_plasmaShellSurfaces.end()) {
        client->installPlasmaShellSurface(*it);
        m_plasmaShellSurfaces.erase(it);
    }
David Edmundson's avatar
David Edmundson committed
174 175 176
    if (auto menu = m_appMenuManager->appMenuForSurface(surface->surface())) {
        client->installAppMenu(menu);
    }
177 178 179
    if (auto palette = m_paletteManager->paletteForSurface(surface->surface())) {
        client->installPalette(palette);
    }
Vlad Zahorodnii's avatar
Vlad Zahorodnii committed
180
    m_clients << client;
181 182 183
    if (client->readyForPainting()) {
        emit shellClientAdded(client);
    } else {
184
        connect(client, &XdgShellClient::windowShown, this, &WaylandServer::shellClientShown);
185
    }
Marco Martin's avatar
Marco Martin committed
186 187

    //not directly connected as the connection is tied to client instead of this
188
    connect(m_XdgForeign, &KWayland::Server::XdgForeignInterface::transientChanged, client, [this](KWayland::Server::SurfaceInterface *child) {
Marco Martin's avatar
Marco Martin committed
189 190
        emit foreignTransientChanged(child);
    });
191 192
}

193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
class KWinDisplay : public KWayland::Server::FilteredDisplay
{
public:
    KWinDisplay(QObject *parent)
        : KWayland::Server::FilteredDisplay(parent)
    {}

    static QByteArray sha256(const QString &fileName)
    {
        QFile f(fileName);
        if (f.open(QFile::ReadOnly)) {
            QCryptographicHash hash(QCryptographicHash::Sha256);
            if (hash.addData(&f)) {
                return hash.result();
            }
        }
        return QByteArray();
    }

    bool isTrustedOrigin(KWayland::Server::ClientConnection *client) const {
213
        const auto fullPathSha = sha256(client->executablePath());
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
        const auto localSha = sha256(QLatin1String("/proc/") + QString::number(client->processId()) + QLatin1String("/exe"));
        const bool trusted = !localSha.isEmpty() && fullPathSha == localSha;

        if (!trusted) {
            qCWarning(KWIN_CORE) << "Could not trust" << client->executablePath() << "sha" << localSha << fullPathSha;
        }

        return trusted;
    }

    QStringList fetchRequestedInterfaces(KWayland::Server::ClientConnection *client) const {
        const auto serviceQuery = QStringLiteral("exist Exec and exist [X-KDE-Wayland-Interfaces] and '%1' =~ Exec").arg(client->executablePath());
        const auto servicesFound = KServiceTypeTrader::self()->query(QStringLiteral("Application"), serviceQuery);

        if (servicesFound.isEmpty()) {
229
            qCDebug(KWIN_CORE) << "Could not find the desktop file for" << client->executablePath();
230 231 232
            return {};
        }

233 234 235
        const auto interfaces = servicesFound.first()->property("X-KDE-Wayland-Interfaces").toStringList();
        qCDebug(KWIN_CORE) << "Interfaces for" << client->executablePath() << interfaces;
        return interfaces;
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
    }

    QSet<QByteArray> interfacesBlackList = {"org_kde_kwin_remote_access_manager", "org_kde_plasma_window_management", "org_kde_kwin_fake_input", "org_kde_kwin_keystate"};

    bool allowInterface(KWayland::Server::ClientConnection *client, const QByteArray &interfaceName) override {
        if (client->processId() == getpid()) {
            return true;
        }

        if (!interfacesBlackList.contains(interfaceName)) {
            return true;
        }

        if (client->executablePath().isEmpty()) {
            qCWarning(KWIN_CORE) << "Could not identify process with pid" << client->processId();
            return false;
        }

        {
            auto requestedInterfaces = client->property("requestedInterfaces");
            if (requestedInterfaces.isNull()) {
                requestedInterfaces = fetchRequestedInterfaces(client);
                client->setProperty("requestedInterfaces", requestedInterfaces);
            }
            if (!requestedInterfaces.toStringList().contains(QString::fromUtf8(interfaceName))) {
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
261
                qCWarning(KWIN_CORE) << "Did not grant the interface" << interfaceName << "to" << client->executablePath() << ". Please request it under X-KDE-Wayland-Interfaces";
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
                return false;
            }
        }

        {
            auto trustedOrigin = client->property("isPrivileged");
            if (trustedOrigin.isNull()) {
                trustedOrigin = isTrustedOrigin(client);
                client->setProperty("isPrivileged", trustedOrigin);
            }

            if (!trustedOrigin.toBool()) {
                return false;
            }
        }
        qCDebug(KWIN_CORE) << "authorized" << client->executablePath() << interfaceName;
        return true;
    }
};

282
bool WaylandServer::init(const QByteArray &socketName, InitializationFlags flags)
283
{
284
    m_initFlags = flags;
285
    m_display = new KWinDisplay(this);
286 287
    if (!socketName.isNull() && !socketName.isEmpty()) {
        m_display->setSocketName(QString::fromUtf8(socketName));
288 289
    } else {
        m_display->setAutomaticSocketNaming(true);
290 291
    }
    m_display->start();
292 293 294
    if (!m_display->isRunning()) {
        return false;
    }
295 296
    m_compositor = m_display->createCompositor(m_display);
    m_compositor->create();
297 298 299 300 301 302 303 304
    connect(m_compositor, &CompositorInterface::surfaceCreated, this,
        [this] (SurfaceInterface *surface) {
            // check whether we have a Toplevel with the Surface's id
            Workspace *ws = Workspace::self();
            if (!ws) {
                // it's possible that a Surface gets created before Workspace is created
                return;
            }
305 306 307 308
            if (surface->client() != xWaylandConnection()) {
                // setting surface is only relevat for Xwayland clients
                return;
            }
309 310 311 312 313 314 315 316
            auto check = [surface] (const Toplevel *t) {
                return t->surfaceId() == surface->id();
            };
            if (Toplevel *t = ws->findToplevel(check)) {
                t->setSurface(surface);
            }
        }
    );
David Edmundson's avatar
David Edmundson committed
317

David Edmundson's avatar
David Edmundson committed
318 319 320 321 322
    m_xdgShell6 = m_display->createXdgShell(XdgShellInterfaceVersion::UnstableV6, m_display);
    m_xdgShell6->create();
    connect(m_xdgShell6, &XdgShellInterface::surfaceCreated, this, &WaylandServer::createSurface<XdgShellSurfaceInterface>);
    connect(m_xdgShell6, &XdgShellInterface::xdgPopupCreated, this, &WaylandServer::createSurface<XdgShellPopupInterface>);

David Edmundson's avatar
David Edmundson committed
323 324 325 326
    m_xdgShell = m_display->createXdgShell(XdgShellInterfaceVersion::Stable, m_display);
    m_xdgShell->create();
    connect(m_xdgShell, &XdgShellInterface::surfaceCreated, this, &WaylandServer::createSurface<XdgShellSurfaceInterface>);
    connect(m_xdgShell, &XdgShellInterface::xdgPopupCreated, this, &WaylandServer::createSurface<XdgShellPopupInterface>);
David Edmundson's avatar
David Edmundson committed
327

328 329 330
    m_xdgDecorationManager = m_display->createXdgDecorationManager(m_xdgShell, m_display);
    m_xdgDecorationManager->create();
    connect(m_xdgDecorationManager, &XdgDecorationManagerInterface::xdgDecorationInterfaceCreated, this,  [this] (XdgDecorationInterface *deco) {
331
        if (XdgShellClient *client = findXdgShellClient(deco->surface()->surface())) {
332 333 334 335
            client->installXdgDecoration(deco);
        }
    });

336
    m_display->createShm();
337 338
    m_seat = m_display->createSeat(m_display);
    m_seat->create();
339
    m_display->createPointerGestures(PointerGesturesInterfaceVersion::UnstableV1, m_display)->create();
340
    m_display->createPointerConstraints(PointerConstraintsInterfaceVersion::UnstableV1, m_display)->create();
341 342
    m_dataDeviceManager = m_display->createDataDeviceManager(m_display);
    m_dataDeviceManager->create();
343 344 345
    m_idle = m_display->createIdle(m_display);
    m_idle->create();
    auto idleInhibition = new IdleInhibition(m_idle);
346
    connect(this, &WaylandServer::shellClientAdded, idleInhibition, &IdleInhibition::registerClient);
347
    m_display->createIdleInhibitManager(IdleInhibitManagerInterfaceVersion::UnstableV1, m_display)->create();
348 349 350 351
    m_plasmaShell = m_display->createPlasmaShell(m_display);
    m_plasmaShell->create();
    connect(m_plasmaShell, &PlasmaShellInterface::surfaceCreated,
        [this] (PlasmaShellSurfaceInterface *surface) {
352
            if (XdgShellClient *client = findXdgShellClient(surface->surface())) {
353
                client->installPlasmaShellSurface(surface);
354 355 356 357 358 359 360
            } else {
                m_plasmaShellSurfaces << surface;
                connect(surface, &QObject::destroyed, this,
                    [this, surface] {
                        m_plasmaShellSurfaces.removeOne(surface);
                    }
                );
361 362 363
            }
        }
    );
David Edmundson's avatar
David Edmundson committed
364 365 366 367
    m_appMenuManager = m_display->createAppMenuManagerInterface(m_display);
    m_appMenuManager->create();
    connect(m_appMenuManager, &AppMenuManagerInterface::appMenuCreated,
        [this] (AppMenuInterface *appMenu) {
368
            if (XdgShellClient *client = findXdgShellClient(appMenu->surface())) {
David Edmundson's avatar
David Edmundson committed
369 370 371 372
                client->installAppMenu(appMenu);
            }
        }
    );
373 374 375 376
    m_paletteManager = m_display->createServerSideDecorationPaletteManager(m_display);
    m_paletteManager->create();
    connect(m_paletteManager, &ServerSideDecorationPaletteManagerInterface::paletteCreated,
        [this] (ServerSideDecorationPaletteInterface *palette) {
377
            if (XdgShellClient *client = findXdgShellClient(palette->surface())) {
378 379 380 381
                client->installPalette(palette);
            }
        }
    );
David Edmundson's avatar
David Edmundson committed
382

383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
    m_windowManagement = m_display->createPlasmaWindowManagement(m_display);
    m_windowManagement->create();
    m_windowManagement->setShowingDesktopState(PlasmaWindowManagementInterface::ShowingDesktopState::Disabled);
    connect(m_windowManagement, &PlasmaWindowManagementInterface::requestChangeShowingDesktop, this,
        [] (PlasmaWindowManagementInterface::ShowingDesktopState state) {
            if (!workspace()) {
                return;
            }
            bool set = false;
            switch (state) {
            case PlasmaWindowManagementInterface::ShowingDesktopState::Disabled:
                set = false;
                break;
            case PlasmaWindowManagementInterface::ShowingDesktopState::Enabled:
                set = true;
                break;
            default:
                Q_UNREACHABLE();
                break;
            }
            if (set == workspace()->showingDesktop()) {
                return;
            }
            workspace()->setShowingDesktop(set);
        }
    );
409 410 411 412 413 414


    m_virtualDesktopManagement = m_display->createPlasmaVirtualDesktopManagement(m_display);
    m_virtualDesktopManagement->create();
    m_windowManagement->setPlasmaVirtualDesktopManagementInterface(m_virtualDesktopManagement);

415 416
    auto shadowManager = m_display->createShadowManager(m_display);
    shadowManager->create();
417 418

    m_display->createDpmsManager(m_display)->create();
419 420 421 422

    m_decorationManager = m_display->createServerSideDecorationManager(m_display);
    connect(m_decorationManager, &ServerSideDecorationManagerInterface::decorationCreated, this,
        [this] (ServerSideDecorationInterface *deco) {
423
            if (XdgShellClient *c = findXdgShellClient(deco->surface())) {
424 425
                c->installServerSideDecoration(deco);
            }
426
            connect(deco, &ServerSideDecorationInterface::modeRequested, this,
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
427
                [deco] (ServerSideDecorationManagerInterface::Mode mode) {
428 429 430 431
                    // always acknowledge the requested mode
                    deco->setMode(mode);
                }
            );
432 433 434
        }
    );
    m_decorationManager->create();
435 436 437

    m_outputManagement = m_display->createOutputManagement(m_display);
    connect(m_outputManagement, &OutputManagementInterface::configurationChangeRequested,
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
438
            this, [](KWayland::Server::OutputConfigurationInterface *config) {
439
                kwinApp()->platform()->requestOutputsChange(config);
440
    });
441
    m_outputManagement->create();
442

David Edmundson's avatar
David Edmundson committed
443 444 445
    m_xdgOutputManager = m_display->createXdgOutputManager(m_display);
    m_xdgOutputManager->create();

446
    m_display->createSubCompositor(m_display)->create();
447

Marco Martin's avatar
Marco Martin committed
448 449 450
    m_XdgForeign = m_display->createXdgForeignInterface(m_display);
    m_XdgForeign->create();

451 452 453
    m_keyState = m_display->createKeyStateInterface(m_display);
    m_keyState->create();

454
    return true;
455 456
}

Roman Gilg's avatar
Roman Gilg committed
457 458 459 460 461 462 463 464 465
KWayland::Server::LinuxDmabufUnstableV1Interface *WaylandServer::linuxDmabuf()
{
    if (!m_linuxDmabuf) {
        m_linuxDmabuf = m_display->createLinuxDmabufInterface(m_display);
        m_linuxDmabuf->create();
    }
    return m_linuxDmabuf;
}

Marco Martin's avatar
Marco Martin committed
466 467 468 469 470
SurfaceInterface *WaylandServer::findForeignTransientForSurface(SurfaceInterface *surface)
{
    return m_XdgForeign->transientFor(surface);
}

471 472
void WaylandServer::shellClientShown(Toplevel *t)
{
473
    XdgShellClient *c = dynamic_cast<XdgShellClient *>(t);
474
    if (!c) {
475
        qCWarning(KWIN_CORE) << "Failed to cast a Toplevel which is supposed to be a XdgShellClient to XdgShellClient";
476 477
        return;
    }
478
    disconnect(c, &XdgShellClient::windowShown, this, &WaylandServer::shellClientShown);
479 480 481
    emit shellClientAdded(c);
}

482 483
void WaylandServer::initWorkspace()
{
484 485
    VirtualDesktopManager::self()->setVirtualDesktopManagement(m_virtualDesktopManagement);

486 487 488 489 490 491 492 493 494 495 496
    if (m_windowManagement) {
        connect(workspace(), &Workspace::showingDesktopChanged, this,
            [this] (bool set) {
                using namespace KWayland::Server;
                m_windowManagement->setShowingDesktopState(set ?
                    PlasmaWindowManagementInterface::ShowingDesktopState::Enabled :
                    PlasmaWindowManagementInterface::ShowingDesktopState::Disabled
                );
            }
        );
    }
497

498
    if (hasScreenLockerIntegration()) {
499 500 501 502 503 504 505 506 507
        if (m_internalConnection.interfacesAnnounced) {
            initScreenLocker();
        } else {
            connect(m_internalConnection.registry, &KWayland::Client::Registry::interfacesAnnounced, this, &WaylandServer::initScreenLocker);
        }
    } else {
        emit initialized();
    }
}
508

509 510 511 512 513 514 515 516 517 518 519 520
void WaylandServer::initScreenLocker()
{
    ScreenLocker::KSldApp::self();
    ScreenLocker::KSldApp::self()->setWaylandDisplay(m_display);
    ScreenLocker::KSldApp::self()->setGreeterEnvironment(kwinApp()->processStartupEnvironment());
    ScreenLocker::KSldApp::self()->initialize();

    connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::greeterClientConnectionChanged, this,
        [this] () {
            m_screenLockerClientConnection = ScreenLocker::KSldApp::self()->greeterClientConnection();
        }
    );
521

522 523 524
    connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::unlocked, this,
        [this] () {
            m_screenLockerClientConnection = nullptr;
525
        }
526 527
    );

528
    if (m_initFlags.testFlag(InitializationFlag::LockScreen)) {
529
        ScreenLocker::KSldApp::self()->lock(ScreenLocker::EstablishLock::Immediate);
530
    }
531
    emit initialized();
532
}
533

534
WaylandServer::SocketPairConnection WaylandServer::createConnection()
535
{
536
    SocketPairConnection ret;
537 538 539
    int sx[2];
    if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sx) < 0) {
        qCWarning(KWIN_CORE) << "Could not create socket";
540 541 542 543 544 545 546 547 548 549 550
        return ret;
    }
    ret.connection = m_display->createClient(sx[0]);
    ret.fd = sx[1];
    return ret;
}

int WaylandServer::createXWaylandConnection()
{
    const auto socket = createConnection();
    if (!socket.connection) {
551 552
        return -1;
    }
553
    m_xwayland.client = socket.connection;
554
    m_xwayland.destroyConnection = connect(m_xwayland.client, &KWayland::Server::ClientConnection::disconnected, this,
555 556 557 558
        [] {
            qFatal("Xwayland Connection died");
        }
    );
559
    return socket.fd;
560 561
}

562 563 564 565 566 567 568 569 570 571
void WaylandServer::destroyXWaylandConnection()
{
    if (!m_xwayland.client) {
        return;
    }
    disconnect(m_xwayland.destroyConnection);
    m_xwayland.client->destroy();
    m_xwayland.client = nullptr;
}

572 573
int WaylandServer::createInputMethodConnection()
{
574 575
    const auto socket = createConnection();
    if (!socket.connection) {
576 577
        return -1;
    }
578 579
    m_inputMethodServerConnection = socket.connection;
    return socket.fd;
580 581
}

582 583 584 585 586 587 588 589 590
void WaylandServer::destroyInputMethodConnection()
{
    if (!m_inputMethodServerConnection) {
        return;
    }
    m_inputMethodServerConnection->destroy();
    m_inputMethodServerConnection = nullptr;
}

591 592
void WaylandServer::createInternalConnection()
{
593 594
    const auto socket = createConnection();
    if (!socket.connection) {
595 596
        return;
    }
597
    m_internalConnection.server = socket.connection;
598
    using namespace KWayland::Client;
599
    m_internalConnection.client = new ConnectionThread();
600
    m_internalConnection.client->setSocketFd(socket.fd);
601 602 603 604
    m_internalConnection.clientThread = new QThread;
    m_internalConnection.client->moveToThread(m_internalConnection.clientThread);
    m_internalConnection.clientThread->start();

605 606
    connect(m_internalConnection.client, &ConnectionThread::connected, this,
        [this] {
607 608 609 610
            Registry *registry = new Registry(this);
            EventQueue *eventQueue = new EventQueue(this);
            eventQueue->setup(m_internalConnection.client);
            registry->setEventQueue(eventQueue);
611
            registry->create(m_internalConnection.client);
612
            m_internalConnection.registry = registry;
613
            connect(registry, &Registry::shmAnnounced, this,
614
                [this] (quint32 name, quint32 version) {
615
                    m_internalConnection.shm = m_internalConnection.registry->createShmPool(name, version, this);
616 617
                }
            );
618
            connect(registry, &Registry::interfacesAnnounced, this,
619
                [this, registry] {
620
                    m_internalConnection.interfacesAnnounced = true;
621

622 623 624 625
                    const auto compInterface = registry->interface(Registry::Interface::Compositor);
                    if (compInterface.name != 0) {
                        m_internalConnection.compositor = registry->createCompositor(compInterface.name, compInterface.version, this);
                    }
626 627 628 629 630 631 632 633
                    const auto seatInterface = registry->interface(Registry::Interface::Seat);
                    if (seatInterface.name != 0) {
                        m_internalConnection.seat = registry->createSeat(seatInterface.name, seatInterface.version, this);
                    }
                    const auto ddmInterface = registry->interface(Registry::Interface::DataDeviceManager);
                    if (ddmInterface.name != 0) {
                        m_internalConnection.ddm = registry->createDataDeviceManager(ddmInterface.name, ddmInterface.version, this);
                    }
634 635
                }
            );
636 637 638 639 640 641
            registry->setup();
        }
    );
    m_internalConnection.client->initConnection();
}

642
void WaylandServer::removeClient(AbstractClient *c)
643 644 645 646 647
{
    m_clients.removeAll(c);
    emit shellClientRemoved(c);
}

648 649 650 651 652
void WaylandServer::dispatch()
{
    if (!m_display) {
        return;
    }
653 654
    if (m_internalConnection.server) {
        m_internalConnection.server->flush();
655 656 657 658
    }
    m_display->dispatchEvents(0);
}

659
static AbstractClient *findClientInList(const QList<AbstractClient *> &clients, quint32 id)
660
{
661
    auto it = std::find_if(clients.begin(), clients.end(),
662
        [id] (AbstractClient *c) {
663 664 665
            return c->windowId() == id;
        }
    );
666
    if (it == clients.end()) {
667 668 669 670 671
        return nullptr;
    }
    return *it;
}

672
static AbstractClient *findClientInList(const QList<AbstractClient *> &clients, KWayland::Server::SurfaceInterface *surface)
673 674
{
    auto it = std::find_if(clients.begin(), clients.end(),
675
        [surface] (AbstractClient *c) {
676 677 678 679 680 681 682 683 684
            return c->surface() == surface;
        }
    );
    if (it == clients.end()) {
        return nullptr;
    }
    return *it;
}

685
AbstractClient *WaylandServer::findClient(quint32 id) const
686 687 688 689
{
    if (id == 0) {
        return nullptr;
    }
690
    if (AbstractClient *c = findClientInList(m_clients, id)) {
691 692 693 694 695
        return c;
    }
    return nullptr;
}

696
AbstractClient *WaylandServer::findClient(SurfaceInterface *surface) const
697 698 699 700
{
    if (!surface) {
        return nullptr;
    }
701
    if (AbstractClient *c = findClientInList(m_clients, surface)) {
702 703 704 705 706
        return c;
    }
    return nullptr;
}

707
XdgShellClient *WaylandServer::findXdgShellClient(SurfaceInterface *surface) const
708
{
709
    return qobject_cast<XdgShellClient *>(findClient(surface));
710 711
}

712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
quint32 WaylandServer::createWindowId(SurfaceInterface *surface)
{
    auto it = m_clientIds.constFind(surface->client());
    quint16 clientId = 0;
    if (it != m_clientIds.constEnd()) {
        clientId = it.value();
    } else {
        clientId = createClientId(surface->client());
    }
    Q_ASSERT(clientId != 0);
    quint32 id = clientId;
    // TODO: this does not prevent that two surfaces of same client get same id
    id = (id << 16) | (surface->id() & 0xFFFF);
    if (findClient(id)) {
        qCWarning(KWIN_CORE) << "Invalid client windowId generated:" << id;
        return 0;
    }
    return id;
}

quint16 WaylandServer::createClientId(ClientConnection *c)
{
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
734
    const QSet<unsigned short> ids(m_clientIds.constBegin(), m_clientIds.constEnd());
735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753
    quint16 id = 1;
    if (!ids.isEmpty()) {
        for (quint16 i = ids.count() + 1; i >= 1 ; i--) {
            if (!ids.contains(i)) {
                id = i;
                break;
            }
        }
    }
    Q_ASSERT(!ids.contains(id));
    m_clientIds.insert(c, id);
    connect(c, &ClientConnection::disconnected, this,
        [this] (ClientConnection *c) {
            m_clientIds.remove(c);
        }
    );
    return id;
}

754 755
bool WaylandServer::isScreenLocked() const
{
756 757 758
    if (!hasScreenLockerIntegration()) {
        return false;
    }
759 760
    return ScreenLocker::KSldApp::self()->lockState() == ScreenLocker::KSldApp::Locked ||
           ScreenLocker::KSldApp::self()->lockState() == ScreenLocker::KSldApp::AcquiringLock;
761 762
}

763 764
bool WaylandServer::hasScreenLockerIntegration() const
{
765
    return !m_initFlags.testFlag(InitializationFlag::NoLockScreenIntegration);
766 767
}

768 769
bool WaylandServer::hasGlobalShortcutSupport() const
{
770
    return !m_initFlags.testFlag(InitializationFlag::NoGlobalShortcuts);
771 772
}

773 774 775 776 777 778 779
void WaylandServer::simulateUserActivity()
{
    if (m_idle) {
        m_idle->simulateUserActivity();
    }
}

780 781 782 783 784 785 786 787 788 789
void WaylandServer::updateKeyState(KWin::Xkb::LEDs leds)
{
    if (!m_keyState)
        return;

    m_keyState->setState(KeyStateInterface::Key::CapsLock, leds & KWin::Xkb::LED::CapsLock ? KeyStateInterface::State::Locked : KeyStateInterface::State::Unlocked);
    m_keyState->setState(KeyStateInterface::Key::NumLock, leds & KWin::Xkb::LED::NumLock ? KeyStateInterface::State::Locked : KeyStateInterface::State::Unlocked);
    m_keyState->setState(KeyStateInterface::Key::ScrollLock, leds & KWin::Xkb::LED::ScrollLock ? KeyStateInterface::State::Locked : KeyStateInterface::State::Unlocked);
}

790
}