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 }