File indexing completed on 2024-05-19 05:30:34
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 }