File indexing completed on 2024-05-19 16:33:11

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 "../src/server/compositor_interface.h"
0007 #include "../src/server/display.h"
0008 #include "../src/server/output_interface.h"
0009 #include "../src/server/seat_interface.h"
0010 #include "../src/server/shell_interface.h"
0011 
0012 #include <QFile>
0013 #include <QGuiApplication>
0014 #include <private/qabstracteventdispatcher_p.h>
0015 #if QT_CONFIG(glib)
0016 #include <private/qeventdispatcher_glib_p.h>
0017 #else
0018 #include <private/qeventdispatcher_unix_p.h>
0019 #endif
0020 
0021 #include <iostream>
0022 #include <unistd.h>
0023 
0024 static int startXServer()
0025 {
0026     const QByteArray process = QByteArrayLiteral("Xwayland");
0027     int pipeFds[2];
0028     if (pipe(pipeFds) != 0) {
0029         std::cerr << "FATAL ERROR failed to create pipe to start X Server " << process.constData() << std::endl;
0030         exit(1);
0031     }
0032 
0033     pid_t pid = fork();
0034     if (pid == 0) {
0035         // child process - should be turned into Xwayland
0036         // writes to pipe, closes read side
0037         close(pipeFds[0]);
0038         char fdbuf[16];
0039         sprintf(fdbuf, "%d", pipeFds[1]);
0040         execlp(process.constData(), process.constData(), "-displayfd", fdbuf, (char *)nullptr);
0041         close(pipeFds[1]);
0042         exit(20);
0043     }
0044     // parent process - this is the wayland server
0045     // reads from pipe, closes write side
0046     close(pipeFds[1]);
0047     return pipeFds[0];
0048 }
0049 
0050 static void readDisplayFromPipe(int pipe)
0051 {
0052     QFile readPipe;
0053     if (!readPipe.open(pipe, QIODevice::ReadOnly)) {
0054         std::cerr << "FATAL ERROR failed to open pipe to start X Server XWayland" << std::endl;
0055         exit(1);
0056     }
0057     QByteArray displayNumber = readPipe.readLine();
0058 
0059     displayNumber.prepend(QByteArray(":"));
0060     displayNumber.remove(displayNumber.size() - 1, 1);
0061     std::cout << "X-Server started on display " << displayNumber.constData() << std::endl;
0062 
0063     setenv("DISPLAY", displayNumber.constData(), true);
0064 
0065     // close our pipe
0066     close(pipe);
0067 }
0068 
0069 int main(int argc, char **argv)
0070 {
0071     using namespace KWayland::Server;
0072 
0073     // set our own event dispatcher to be able to dispatch events before the event loop is started
0074 #if QT_CONFIG(glib)
0075     QAbstractEventDispatcher *eventDispatcher = new QEventDispatcherGlib();
0076 #else
0077     QAbstractEventDispatcher *eventDispatcher = new QEventDispatcherUNIX();
0078 #endif
0079     QCoreApplication::setEventDispatcher(eventDispatcher);
0080 
0081     // first create the Server and setup with minimum to get an XWayland connected
0082     Display display;
0083     display.start();
0084     display.createShm();
0085     CompositorInterface *compositor = display.createCompositor(&display);
0086     compositor->create();
0087     ShellInterface *shell = display.createShell();
0088     shell->create();
0089     OutputInterface *output = display.createOutput(&display);
0090     output->setPhysicalSize(QSize(10, 10));
0091     output->addMode(QSize(1024, 768));
0092     output->create();
0093 
0094     // starts XWayland by forking and opening a pipe
0095     const int pipe = startXServer();
0096     if (pipe == -1) {
0097         exit(1);
0098     }
0099 
0100     fd_set rfds;
0101     struct timeval tv;
0102     tv.tv_sec = 0;
0103     tv.tv_usec = 0;
0104     do {
0105         eventDispatcher->processEvents(QEventLoop::WaitForMoreEvents);
0106         FD_ZERO(&rfds);
0107         FD_SET(pipe, &rfds);
0108     } while (select(pipe + 1, &rfds, nullptr, nullptr, &tv) == 0);
0109 
0110     // now Xwayland is ready and we can read the pipe to get the display
0111     readDisplayFromPipe(pipe);
0112 
0113     QGuiApplication app(argc, argv);
0114 
0115     SeatInterface *seat = display.createSeat();
0116     seat->setName(QStringLiteral("testSeat0"));
0117     seat->create();
0118 
0119     return app.exec();
0120 }