diff options
author | Robert Griebl <robert.griebl@qt.io> | 2022-03-01 17:41:36 +0100 |
---|---|---|
committer | Robert Griebl <robert.griebl@qt.io> | 2022-03-02 19:04:47 +0000 |
commit | 59d78be1056a3ba9db7f05bed71a7b7f48ee6405 (patch) | |
tree | fec70da4af647f13b7e644ada1e91102583f8dc0 | |
parent | 3fe0a999d7a89141c7c03ca797fc7d65e07e9c52 (diff) | |
download | qtapplicationmanager-59d78be1056a3ba9db7f05bed71a7b7f48ee6405.tar.gz |
Create extra sockets only just before the Wayland compositor is created
Otherwise there will be a window where the socket already exists in file
system, but is not adopted by the compositor yet, leading to "connection
refused" errors should a client try to connect.
Change-Id: Ic96c51c7e8175ab5e9ac40fc70b5f8dc97c11b71
Reviewed-by: Dominik Holland <dominik.holland@qt.io>
(cherry picked from commit 9429d8e84649a4c0a262c16a2eaf394dcc90c79b)
-rw-r--r-- | src/main-lib/main.cpp | 116 | ||||
-rw-r--r-- | src/window-lib/windowmanager.cpp | 3 | ||||
-rw-r--r-- | src/window-lib/windowmanager.h | 16 |
3 files changed, 83 insertions, 52 deletions
diff --git a/src/main-lib/main.cpp b/src/main-lib/main.cpp index d1d3d11e..03d56747 100644 --- a/src/main-lib/main.cpp +++ b/src/main-lib/main.cpp @@ -702,66 +702,82 @@ void Main::setupWindowManager(const QString &waylandSocketName, const QVariantLi m_windowManager->enableWatchdog(!uiWatchdog); #if defined(QT_WAYLANDCOMPOSITOR_LIB) - for (const auto &v : waylandExtraSockets) { - const QVariantMap &wes = v.toMap(); + connect(&m_windowManager->internalSignals, &WindowManagerInternalSignals::compositorAboutToBeCreated, + this, [this, waylandExtraSockets] { + // This needs to be delayed until directly before creating the Wayland compositor. + // Otherwise we have a "dangling" socket you cannot connect to. - const QString path = wes.value(qSL("path")).toString(); + for (const auto &v : waylandExtraSockets) { + const QVariantMap &wes = v.toMap(); - if (path.isEmpty()) - continue; - QFileInfo fi(path); - if (!fi.dir().mkpath(qSL("."))) - throw Exception("could not create path to extra Wayland socket: %1").arg(path); + const QString path = wes.value(qSL("path")).toString(); - auto sudo = SudoClient::instance(); + if (path.isEmpty()) + continue; - if (!sudo || sudo->isFallbackImplementation()) - QLocalServer::removeServer(path); // if it fails, we'll notice in listen() right away - else - sudo->removeRecursive(path); + try { + QFileInfo fi(path); + if (!fi.dir().mkpath(qSL("."))) + throw Exception("could not create path to extra Wayland socket: %1").arg(path); - QScopedPointer<QLocalServer> extraSocket(new QLocalServer); - extraSocket->setMaxPendingConnections(0); // disable Qt's new connection handling - if (!extraSocket->listen(path)) { - throw Exception("could not listen on extra Wayland socket %1: %2") - .arg(path, extraSocket->errorString()); - } - int mode = wes.value(qSL("permissions"), -1).toInt(); - int uid = wes.value(qSL("userId"), -1).toInt(); - int gid = wes.value(qSL("groupId"), -1).toInt(); - - QByteArray encodedPath = QFile::encodeName(path); - - if ((mode > 0) || (uid != -1) || (gid != -1)) { - if (!sudo || sudo->isFallbackImplementation()) { - if (mode > 0) { - if (::chmod(encodedPath, static_cast<mode_t>(mode)) != 0) - throw Exception(errno, "could not chmod(mode: %1) the extra Wayland socket %2") - .arg(QString::number(mode, 8), path); + auto sudo = SudoClient::instance(); + + if (!sudo || sudo->isFallbackImplementation()) { + if (!QLocalServer::removeServer(path)) { + throw Exception("could not clean up leftover extra Wayland socket %1").arg(path); + } + } else { + sudo->removeRecursive(path); } - if ((uid != -1) || (gid != -1)) { - if (::chown(encodedPath, static_cast<uid_t>(uid), static_cast<gid_t>(gid)) != 0) - throw Exception(errno, "could not chown(uid: %1, gid: %2) the extra Wayland socket %3") - .arg(uid).arg(gid).arg(path); + + QScopedPointer<QLocalServer> extraSocket(new QLocalServer); + extraSocket->setMaxPendingConnections(0); // disable Qt's new connection handling + if (!extraSocket->listen(path)) { + throw Exception("could not listen on extra Wayland socket %1: %2") + .arg(path, extraSocket->errorString()); } - } else { - if (!sudo->setOwnerAndPermissionsRecursive(path, static_cast<uid_t>(uid), - static_cast<gid_t>(gid), - static_cast<mode_t>(mode))) { - throw Exception(Error::IO, "could not change the owner to %1:%2 and the permission" - " bits to %3 for the extra Wayland socket %4: %5") - .arg(uid).arg(gid).arg(mode, 0, 8).arg(path).arg(sudo->lastError()); + int mode = wes.value(qSL("permissions"), -1).toInt(); + int uid = wes.value(qSL("userId"), -1).toInt(); + int gid = wes.value(qSL("groupId"), -1).toInt(); + + QByteArray encodedPath = QFile::encodeName(path); + + if ((mode > 0) || (uid != -1) || (gid != -1)) { + if (!sudo || sudo->isFallbackImplementation()) { + if (mode > 0) { + if (::chmod(encodedPath, static_cast<mode_t>(mode)) != 0) + throw Exception(errno, "could not chmod(mode: %1) the extra Wayland socket %2") + .arg(QString::number(mode, 8), path); + } + if ((uid != -1) || (gid != -1)) { + if (::chown(encodedPath, static_cast<uid_t>(uid), static_cast<gid_t>(gid)) != 0) + throw Exception(errno, "could not chown(uid: %1, gid: %2) the extra Wayland socket %3") + .arg(uid).arg(gid).arg(path); + } + } else { + if (!sudo->setOwnerAndPermissionsRecursive(path, static_cast<uid_t>(uid), + static_cast<gid_t>(gid), + static_cast<mode_t>(mode))) { + throw Exception(Error::IO, "could not change the owner to %1:%2 and the permission" + " bits to %3 for the extra Wayland socket %4: %5") + .arg(uid).arg(gid).arg(mode, 0, 8).arg(path).arg(sudo->lastError()); + } + // if we changed the owner, ~QLocalServer might not be able to clean up the + // socket inode, so we need to sudo this removal as well + QObject::connect(extraSocket.data(), &QObject::destroyed, [path, sudo]() { + sudo->removeRecursive(path); + }); + } } - // if we changed the owner, ~QLocalServer might not be able to clean up the - // socket inode, so we need to sudo this removal as well - QObject::connect(extraSocket.data(), &QObject::destroyed, [path, sudo]() { - sudo->removeRecursive(path); - }); + + m_windowManager->addWaylandSocket(extraSocket.take()); + } catch (const std::exception &e) { + qCCritical(LogSystem) << "ERROR:" << e.what(); } } - - m_windowManager->addWaylandSocket(extraSocket.take()); - } + }); +#else + Q_UNUSED(waylandExtraSockets) #endif QObject::connect(&m_applicationManager->internalSignals, &ApplicationManagerInternalSignals::newRuntimeCreated, diff --git a/src/window-lib/windowmanager.cpp b/src/window-lib/windowmanager.cpp index 69201f01..d237f295 100644 --- a/src/window-lib/windowmanager.cpp +++ b/src/window-lib/windowmanager.cpp @@ -687,6 +687,9 @@ void WindowManager::registerCompositorView(QQuickWindow *view) #if defined(AM_MULTI_PROCESS) if (!ApplicationManager::instance()->isSingleProcess()) { if (!d->waylandCompositor) { + // this will trigger the creation of extra sockets in main.cpp + emit internalSignals.compositorAboutToBeCreated(); + d->waylandCompositor = new WaylandCompositor(view, d->waylandSocketName); for (const auto &extraSocket : d->extraWaylandSockets) d->waylandCompositor->addSocketDescriptor(extraSocket); diff --git a/src/window-lib/windowmanager.h b/src/window-lib/windowmanager.h index 466275fd..8b7fc3dc 100644 --- a/src/window-lib/windowmanager.h +++ b/src/window-lib/windowmanager.h @@ -68,6 +68,17 @@ class Application; class AbstractRuntime; class WaylandCompositor; + +// A place to collect signals used internally by appman without polluting +// WindowManager's public QML API. +class WindowManagerInternalSignals : public QObject +{ + Q_OBJECT +signals: + // Emitted right before the WaylandCompositor instance is created + void compositorAboutToBeCreated(); +}; + class WindowManager : public QAbstractListModel { Q_OBJECT @@ -106,6 +117,9 @@ public: Q_INVOKABLE int indexOfWindow(Window *window) const; Q_INVOKABLE QObject *addExtension(QQmlComponent *component) const; + WindowManagerInternalSignals internalSignals; + +protected: bool eventFilter(QObject *watched, QEvent *event) override; signals: @@ -124,8 +138,6 @@ signals: void slowAnimationsChanged(bool); - void _inProcessSurfaceItemReleased(QSharedPointer<InProcessSurfaceItem>); - private slots: void inProcessSurfaceItemCreated(QSharedPointer<InProcessSurfaceItem> surfaceItem); void setupWindow(QT_PREPEND_NAMESPACE_AM(Window) *window); |