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