[wayland] Use QProcess to start XWayland server
The code didn't use QProcess as in the early days of main_wayland.cpp Xwayland had to be started before the QGuiApplication was constructed. As this requirement doesn't exist any more we can use QProcess and improve the interaction by e.g. provide useful error messages if Xwayland couldn't be started.
This commit is contained in:
parent
9954f1167f
commit
64e01ac2ca
2 changed files with 67 additions and 55 deletions
118
main_wayland.cpp
118
main_wayland.cpp
|
@ -60,7 +60,6 @@ static void sighandler(int)
|
||||||
QApplication::exit();
|
QApplication::exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int startXServer(int waylandSocket, int wmFd);
|
|
||||||
static void readDisplay(int pipe);
|
static void readDisplay(int pipe);
|
||||||
|
|
||||||
//************************************
|
//************************************
|
||||||
|
@ -79,6 +78,10 @@ ApplicationWayland::~ApplicationWayland()
|
||||||
Xcb::setInputFocus(XCB_INPUT_FOCUS_POINTER_ROOT);
|
Xcb::setInputFocus(XCB_INPUT_FOCUS_POINTER_ROOT);
|
||||||
xcb_disconnect(x11Connection());
|
xcb_disconnect(x11Connection());
|
||||||
}
|
}
|
||||||
|
if (m_xwaylandProcess) {
|
||||||
|
m_xwaylandProcess->terminate();
|
||||||
|
m_xwaylandProcess->waitForFinished();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplicationWayland::performStartup()
|
void ApplicationWayland::performStartup()
|
||||||
|
@ -118,26 +121,7 @@ void ApplicationWayland::continueStartupWithScreens()
|
||||||
}
|
}
|
||||||
createCompositor();
|
createCompositor();
|
||||||
|
|
||||||
int sx[2];
|
startXwaylandServer();
|
||||||
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sx) < 0) {
|
|
||||||
std::cerr << "FATAL ERROR: failed to open socket to open XCB connection" << std::endl;
|
|
||||||
exit(1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int fd = waylandServer()->createXWaylandConnection();
|
|
||||||
if (fd == -1) {
|
|
||||||
std::cerr << "FATAL ERROR: failed to open socket for Xwayland" << std::endl;
|
|
||||||
exit(1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_xcbConnectionFd = sx[0];
|
|
||||||
const int xDisplayPipe = startXServer(fd, sx[1]);
|
|
||||||
QFutureWatcher<void> *watcher = new QFutureWatcher<void>(this);
|
|
||||||
QObject::connect(watcher, &QFutureWatcher<void>::finished, this, &ApplicationWayland::continueStartupWithX, Qt::QueuedConnection);
|
|
||||||
QObject::connect(watcher, &QFutureWatcher<void>::finished, watcher, &QFutureWatcher<void>::deleteLater, Qt::QueuedConnection);
|
|
||||||
watcher->setFuture(QtConcurrent::run(readDisplay, xDisplayPipe));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplicationWayland::continueStartupWithX()
|
void ApplicationWayland::continueStartupWithX()
|
||||||
|
@ -264,49 +248,73 @@ bool ApplicationWayland::notify(QObject *o, QEvent *e)
|
||||||
return Application::notify(o, e);
|
return Application::notify(o, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void ApplicationWayland::startXwaylandServer()
|
||||||
* Starts the Xwayland-Server.
|
|
||||||
* The new process is started by forking into it.
|
|
||||||
**/
|
|
||||||
static int startXServer(int waylandSocket, int wmFd)
|
|
||||||
{
|
{
|
||||||
int pipeFds[2];
|
int pipeFds[2];
|
||||||
if (pipe(pipeFds) != 0) {
|
if (pipe(pipeFds) != 0) {
|
||||||
std::cerr << "FATAL ERROR failed to create pipe to start Xwayland " << std::endl;
|
std::cerr << "FATAL ERROR failed to create pipe to start Xwayland " << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
int sx[2];
|
||||||
pid_t pid = fork();
|
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sx) < 0) {
|
||||||
if (pid == 0) {
|
std::cerr << "FATAL ERROR: failed to open socket to open XCB connection" << std::endl;
|
||||||
// child process - should be turned into X-Server
|
exit(1);
|
||||||
// writes to pipe, closes read side
|
return;
|
||||||
close(pipeFds[0]);
|
}
|
||||||
char fdbuf[16];
|
int fd = dup(sx[1]);
|
||||||
sprintf(fdbuf, "%d", pipeFds[1]);
|
if (fd < 0) {
|
||||||
char wmfdbuf[16];
|
std::cerr << "FATAL ERROR: failed to open socket to open XCB connection" << std::endl;
|
||||||
int fd = dup(wmFd);
|
|
||||||
if (fd < 0) {
|
|
||||||
std::cerr << "FATAL ERROR: failed to open socket to open XCB connection" << std::endl;
|
|
||||||
exit(20);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
sprintf(wmfdbuf, "%d", fd);
|
|
||||||
|
|
||||||
int wlfd = dup(waylandSocket);
|
|
||||||
if (wlfd < 0) {
|
|
||||||
std::cerr << "FATAL ERROR: failed to open socket for Xwayland" << std::endl;
|
|
||||||
exit(20);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
qputenv("WAYLAND_SOCKET", QByteArray::number(wlfd));
|
|
||||||
execlp("Xwayland", "Xwayland", "-displayfd", fdbuf, "-rootless", "-wm", wmfdbuf, (char *)0);
|
|
||||||
close(pipeFds[1]);
|
|
||||||
exit(20);
|
exit(20);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
// parent process - this is KWin
|
|
||||||
// reads from pipe, closes write side
|
const int waylandSocket = waylandServer()->createXWaylandConnection();
|
||||||
|
if (waylandSocket == -1) {
|
||||||
|
std::cerr << "FATAL ERROR: failed to open socket for Xwayland" << std::endl;
|
||||||
|
exit(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const int wlfd = dup(waylandSocket);
|
||||||
|
if (wlfd < 0) {
|
||||||
|
std::cerr << "FATAL ERROR: failed to open socket for Xwayland" << std::endl;
|
||||||
|
exit(20);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_xcbConnectionFd = sx[0];
|
||||||
|
|
||||||
|
m_xwaylandProcess = new QProcess(kwinApp());
|
||||||
|
m_xwaylandProcess->setProgram(QStringLiteral("Xwayland"));
|
||||||
|
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||||
|
env.insert("WAYLAND_SOCKET", QByteArray::number(wlfd));
|
||||||
|
m_xwaylandProcess->setProcessEnvironment(env);
|
||||||
|
m_xwaylandProcess->setArguments({QStringLiteral("-displayfd"),
|
||||||
|
QString::number(pipeFds[1]),
|
||||||
|
QStringLiteral("-rootless"),
|
||||||
|
QStringLiteral("-wm"),
|
||||||
|
QString::number(fd)});
|
||||||
|
connect(m_xwaylandProcess, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error), this,
|
||||||
|
[] (QProcess::ProcessError error) {
|
||||||
|
if (error == QProcess::FailedToStart) {
|
||||||
|
std::cerr << "FATAL ERROR: failed to start Xwayland" << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cerr << "FATAL ERROR: Xwayland failed, going to exit now" << std::endl;
|
||||||
|
}
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const int xDisplayPipe = pipeFds[0];
|
||||||
|
connect(m_xwaylandProcess, &QProcess::started, this,
|
||||||
|
[this, xDisplayPipe] {
|
||||||
|
QFutureWatcher<void> *watcher = new QFutureWatcher<void>(this);
|
||||||
|
QObject::connect(watcher, &QFutureWatcher<void>::finished, this, &ApplicationWayland::continueStartupWithX, Qt::QueuedConnection);
|
||||||
|
QObject::connect(watcher, &QFutureWatcher<void>::finished, watcher, &QFutureWatcher<void>::deleteLater, Qt::QueuedConnection);
|
||||||
|
watcher->setFuture(QtConcurrent::run(readDisplay, xDisplayPipe));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
m_xwaylandProcess->start();
|
||||||
close(pipeFds[1]);
|
close(pipeFds[1]);
|
||||||
return pipeFds[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void readDisplay(int pipe)
|
static void readDisplay(int pipe)
|
||||||
|
|
|
@ -22,6 +22,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include <QtCore/private/qeventdispatcher_unix_p.h>
|
#include <QtCore/private/qeventdispatcher_unix_p.h>
|
||||||
|
|
||||||
|
class QProcess;
|
||||||
|
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -49,10 +51,12 @@ private:
|
||||||
void createX11Connection();
|
void createX11Connection();
|
||||||
void continueStartupWithScreens();
|
void continueStartupWithScreens();
|
||||||
void continueStartupWithX();
|
void continueStartupWithX();
|
||||||
|
void startXwaylandServer();
|
||||||
|
|
||||||
bool m_startXWayland = false;
|
bool m_startXWayland = false;
|
||||||
int m_xcbConnectionFd = -1;
|
int m_xcbConnectionFd = -1;
|
||||||
QStringList m_applicationsToStart;
|
QStringList m_applicationsToStart;
|
||||||
|
QProcess *m_xwaylandProcess = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EventDispatcher : public QEventDispatcherUNIX
|
class EventDispatcher : public QEventDispatcherUNIX
|
||||||
|
|
Loading…
Reference in a new issue