File: waylandservertest.cpp

package info (click to toggle)
kwin 4%3A6.5.4-3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 53,376 kB
  • sloc: cpp: 240,899; javascript: 2,225; xml: 2,096; ansic: 775; sh: 37; python: 15; makefile: 8
file content (112 lines) | stat: -rw-r--r-- 3,328 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/*
    SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>

    SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "wayland/compositor.h"
#include "wayland/display.h"
#include "wayland/output.h"
#include "wayland/seat.h"
#include "wayland/xdgshell.h"

#include "fakeoutput.h"

#include <QFile>
#include <QGuiApplication>
#include <private/qeventdispatcher_glib_p.h>

#include <iostream>
#include <sys/select.h>
#include <unistd.h>

static int startXServer()
{
    const QByteArray process = QByteArrayLiteral("Xwayland");
    int pipeFds[2];
    if (pipe(pipeFds) != 0) {
        std::cerr << "FATAL ERROR failed to create pipe to start X Server " << process.constData() << std::endl;
        exit(1);
    }

    pid_t pid = fork();
    if (pid == 0) {
        // child process - should be turned into Xwayland
        // writes to pipe, closes read side
        close(pipeFds[0]);
        char fdbuf[16];
        sprintf(fdbuf, "%d", pipeFds[1]);
        execlp(process.constData(), process.constData(), "-displayfd", fdbuf, (char *)nullptr);
        close(pipeFds[1]);
        exit(20);
    }
    // parent process - this is the wayland server
    // reads from pipe, closes write side
    close(pipeFds[1]);
    return pipeFds[0];
}

static void readDisplayFromPipe(int pipe)
{
    QFile readPipe;
    if (!readPipe.open(pipe, QIODevice::ReadOnly)) {
        std::cerr << "FATAL ERROR failed to open pipe to start X Server XWayland" << std::endl;
        exit(1);
    }
    QByteArray displayNumber = readPipe.readLine();

    displayNumber.prepend(QByteArray(":"));
    displayNumber.remove(displayNumber.size() - 1, 1);
    std::cout << "X-Server started on display " << displayNumber.constData() << std::endl;

    setenv("DISPLAY", displayNumber.constData(), true);

    // close our pipe
    close(pipe);
}

int main(int argc, char **argv)
{
    using namespace KWin;

    // set our own event dispatcher to be able to dispatch events before the event loop is started
    QAbstractEventDispatcher *eventDispatcher = new QEventDispatcherGlib();
    QCoreApplication::setEventDispatcher(eventDispatcher);

    // first create the Server and setup with minimum to get an XWayland connected
    KWin::Display display;
    display.start();
    display.createShm();
    new CompositorInterface(&display, &display);
    new XdgShellInterface(&display, &display);

    auto outputHandle = std::make_unique<FakeOutput>();
    outputHandle->setMode(QSize(1024, 768), 60000);
    outputHandle->setPhysicalSize(QSize(10, 10));

    auto outputInterface = std::make_unique<OutputInterface>(&display, outputHandle.get());

    // starts XWayland by forking and opening a pipe
    const int pipe = startXServer();
    if (pipe == -1) {
        exit(1);
    }

    fd_set rfds;
    struct timeval tv;
    tv.tv_sec = 0;
    tv.tv_usec = 0;
    do {
        eventDispatcher->processEvents(QEventLoop::WaitForMoreEvents);
        FD_ZERO(&rfds);
        FD_SET(pipe, &rfds);
    } while (select(pipe + 1, &rfds, nullptr, nullptr, &tv) == 0);

    // now Xwayland is ready and we can read the pipe to get the display
    readDisplayFromPipe(pipe);

    QGuiApplication app(argc, argv);

    new SeatInterface(&display, QStringLiteral("testSeat0"));

    return app.exec();
}