File indexing completed on 2024-12-01 05:02:04

0001 /*
0002     SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 #include "wayland/compositor.h"
0007 #include "wayland/display.h"
0008 #include "wayland/output.h"
0009 #include "wayland/seat.h"
0010 #include "wayland/xdgshell.h"
0011 
0012 #include "fakeoutput.h"
0013 
0014 #include <QFile>
0015 #include <QGuiApplication>
0016 #include <private/qeventdispatcher_glib_p.h>
0017 
0018 #include <iostream>
0019 #include <sys/select.h>
0020 #include <unistd.h>
0021 
0022 static int startXServer()
0023 {
0024     const QByteArray process = QByteArrayLiteral("Xwayland");
0025     int pipeFds[2];
0026     if (pipe(pipeFds) != 0) {
0027         std::cerr << "FATAL ERROR failed to create pipe to start X Server " << process.constData() << std::endl;
0028         exit(1);
0029     }
0030 
0031     pid_t pid = fork();
0032     if (pid == 0) {
0033         // child process - should be turned into Xwayland
0034         // writes to pipe, closes read side
0035         close(pipeFds[0]);
0036         char fdbuf[16];
0037         sprintf(fdbuf, "%d", pipeFds[1]);
0038         execlp(process.constData(), process.constData(), "-displayfd", fdbuf, (char *)nullptr);
0039         close(pipeFds[1]);
0040         exit(20);
0041     }
0042     // parent process - this is the wayland server
0043     // reads from pipe, closes write side
0044     close(pipeFds[1]);
0045     return pipeFds[0];
0046 }
0047 
0048 static void readDisplayFromPipe(int pipe)
0049 {
0050     QFile readPipe;
0051     if (!readPipe.open(pipe, QIODevice::ReadOnly)) {
0052         std::cerr << "FATAL ERROR failed to open pipe to start X Server XWayland" << std::endl;
0053         exit(1);
0054     }
0055     QByteArray displayNumber = readPipe.readLine();
0056 
0057     displayNumber.prepend(QByteArray(":"));
0058     displayNumber.remove(displayNumber.size() - 1, 1);
0059     std::cout << "X-Server started on display " << displayNumber.constData() << std::endl;
0060 
0061     setenv("DISPLAY", displayNumber.constData(), true);
0062 
0063     // close our pipe
0064     close(pipe);
0065 }
0066 
0067 int main(int argc, char **argv)
0068 {
0069     using namespace KWin;
0070 
0071     // set our own event dispatcher to be able to dispatch events before the event loop is started
0072     QAbstractEventDispatcher *eventDispatcher = new QEventDispatcherGlib();
0073     QCoreApplication::setEventDispatcher(eventDispatcher);
0074 
0075     // first create the Server and setup with minimum to get an XWayland connected
0076     KWin::Display display;
0077     display.start();
0078     display.createShm();
0079     new CompositorInterface(&display, &display);
0080     new XdgShellInterface(&display, &display);
0081 
0082     auto outputHandle = std::make_unique<FakeOutput>();
0083     outputHandle->setMode(QSize(1024, 768), 60000);
0084     outputHandle->setPhysicalSize(QSize(10, 10));
0085 
0086     auto outputInterface = std::make_unique<OutputInterface>(&display, outputHandle.get());
0087 
0088     // starts XWayland by forking and opening a pipe
0089     const int pipe = startXServer();
0090     if (pipe == -1) {
0091         exit(1);
0092     }
0093 
0094     fd_set rfds;
0095     struct timeval tv;
0096     tv.tv_sec = 0;
0097     tv.tv_usec = 0;
0098     do {
0099         eventDispatcher->processEvents(QEventLoop::WaitForMoreEvents);
0100         FD_ZERO(&rfds);
0101         FD_SET(pipe, &rfds);
0102     } while (select(pipe + 1, &rfds, nullptr, nullptr, &tv) == 0);
0103 
0104     // now Xwayland is ready and we can read the pipe to get the display
0105     readDisplayFromPipe(pipe);
0106 
0107     QGuiApplication app(argc, argv);
0108 
0109     SeatInterface *seat = new SeatInterface(&display);
0110     seat->setName(QStringLiteral("testSeat0"));
0111 
0112     return app.exec();
0113 }