diff --git a/debian/control b/debian/control index 5f3205e8dd..9074d89cd6 100644 --- a/debian/control +++ b/debian/control @@ -5,7 +5,7 @@ Build-Depends: cmake (>= 3.4~), debhelper-compat (= 13), ninja-build, extra-cmake-modules (>= 1.4.0~), - libddm-dev, + libddm-dev (> 0.2.2), libdtk6core-bin, libdtk6core-dev, libdtk6declarative-dev, @@ -53,7 +53,7 @@ Depends: qml6-module-qtquick-layouts, ${shlibs:Depends}, Conflicts: libwaylib, qwlroots Replaces: libwaylib, qwlroots -Recommends: ddm, +Recommends: ddm (> 0.2.2), Description: a Wayland compositor based on wlroots and QML, designed with an attractive and elegant appearance. Package: treeland-dev diff --git a/misc/dbus/org.deepin.compositor1.xml b/misc/dbus/org.deepin.compositor1.xml index 2a61387d78..bf620e651b 100644 --- a/misc/dbus/org.deepin.compositor1.xml +++ b/misc/dbus/org.deepin.compositor1.xml @@ -8,5 +8,7 @@ + + diff --git a/src/core/shellhandler.cpp b/src/core/shellhandler.cpp index 105bb4f69b..db227e46c9 100644 --- a/src/core/shellhandler.cpp +++ b/src/core/shellhandler.cpp @@ -124,7 +124,10 @@ WXWayland *ShellHandler::createXWayland(WServer *server, void ShellHandler::removeXWayland(WXWayland *xwayland) { m_xwaylands.removeOne(xwayland); - xwayland->safeDeleteLater(); + // Ensure xwayland is removed from interfaceList + if (auto server = WServer::from(xwayland)) + server->detach(xwayland); + delete xwayland; } void ShellHandler::initInputMethodHelper(WServer *server, WSeat *seat) diff --git a/src/core/treeland.cpp b/src/core/treeland.cpp index 09ca0fe58c..597b924454 100644 --- a/src/core/treeland.cpp +++ b/src/core/treeland.cpp @@ -79,7 +79,7 @@ class TreelandPrivate : public QObject connect(qmlEngine, &QQmlEngine::quit, q, &Treeland::quit, Qt::QueuedConnection); helper = qmlEngine->singletonInstance("Treeland", "Helper"); connect(helper, &Helper::requestQuit, q, &Treeland::quit, Qt::QueuedConnection); - helper->init(); + helper->init(q); #ifndef DISABLE_DDM auto userModel = qmlEngine->singletonInstance("Treeland", "UserModel"); diff --git a/src/core/treeland.h b/src/core/treeland.h index 36cf55662a..ff174971a9 100644 --- a/src/core/treeland.h +++ b/src/core/treeland.h @@ -43,6 +43,7 @@ class Treeland Q_SIGNALS: void socketDisconnected(); + void SessionChanged(); public Q_SLOTS: bool ActivateWayland(QDBusUnixFileDescriptor fd); diff --git a/src/greeter/greeterproxy.cpp b/src/greeter/greeterproxy.cpp index 5fcf3caea7..f172ce0503 100644 --- a/src/greeter/greeterproxy.cpp +++ b/src/greeter/greeterproxy.cpp @@ -293,82 +293,14 @@ void GreeterProxy::unlock(const QString &user, const QString &password) } } -static QString getSessionPathByUser(UserPtr userInfo); - void GreeterProxy::logout() { qCDebug(treelandGreeter) << "Logout."; d->isLoggedIn = false; Q_EMIT isLoggedInChanged(); - auto user = userModel()->currentUser(); - QThreadPool::globalInstance()->start([user]() { - const auto path = getSessionPathByUser(user); - if (path.isEmpty()) { - qCWarning(treelandGreeter, "No session logged in."); - return; - } - qCDebug(treelandGreeter) << "Terminate the session" << path; - auto reply = DDBusSender::system() - .service("org.freedesktop.login1") - .path(path) - .interface("org.freedesktop.login1.Session") - .method("Terminate") - .call(); - if (reply.isError()) { - qCWarning(treelandGreeter) << "Failed to logout, error:" << reply.error().message(); - } - }); -} - -QString getSessionPathByUser(UserPtr userInfo) -{ - if (!userInfo) { - qCWarning(treelandGreeter) << "No user logged in."; - return {}; - } - - QDBusPendingReply> sessionsRelpy = - DDBusSender::system() - .service("org.freedesktop.login1") - .path("/org/freedesktop/login1") - .interface("org.freedesktop.login1.Manager") - .method("ListSessions") - .call(); - if (sessionsRelpy.isError()) { - qCWarning(treelandGreeter) << "Failed to logout, error:" << sessionsRelpy.error().message(); - return {}; - } - - QStringList userSessions; - const auto sessions = sessionsRelpy.value(); - for (auto item : sessions) { - if (item.uid != userInfo->UID()) - continue; - // TODO multiple seats. - if (item.seat.isEmpty()) - continue; - userSessions << item.path.path(); - } - std::sort(userSessions.begin(), userSessions.end(), [](const QString &s1, const QString &s2) { - return s1.localeAwareCompare(s2) > 0; - }); - for (auto item : userSessions) { - QDBusPendingReply relpy = DDBusSender::system() - .service("org.freedesktop.login1") - .path(item) - .interface("org.freedesktop.login1.Session") - .property("Active") - .get(); - if (relpy.value().toBool()) - return item; - } - return {}; -} - -void GreeterProxy::activateUser(const QString &user) -{ - auto userInfo = userModel()->get(user); - SocketWriter(d->socket) << quint32(GreeterMessages::ActivateUser) << user; + auto session = Helper::instance()->activeSession().lock(); + SocketWriter(d->socket) << quint32(GreeterMessages::Logout) << session->id; + Helper::instance()->removeSession(session); } void GreeterProxy::connected() @@ -483,7 +415,8 @@ void GreeterProxy::readyRead() } break; case DaemonMessages::UserActivateMessage: { QString user; - input >> user; + int sessionId; + input >> user >> sessionId; // NOTE: maybe DDM will active dde user. if (!d->userModel->getUser(user)) { @@ -494,8 +427,10 @@ void GreeterProxy::readyRead() } d->userModel->setCurrentUserName(user); + // userLoggedIn signal is connected with Helper::updateActiveUserSession + Q_EMIT d->userModel->userLoggedIn(user, sessionId); - qCInfo(treelandGreeter) << "activate successfully: " << user; + qCInfo(treelandGreeter) << "activate successfully: " << user << ", XDG_SESSION_ID: " << sessionId; } break; case DaemonMessages::UserLoggedIn: { QString user; diff --git a/src/greeter/greeterproxy.h b/src/greeter/greeterproxy.h index fcdeca60c8..f1da0ecb0f 100644 --- a/src/greeter/greeterproxy.h +++ b/src/greeter/greeterproxy.h @@ -80,7 +80,6 @@ public Q_SLOTS: void init(); void login(const QString &user, const QString &password, int sessionIndex); - void activateUser(const QString &user); void unlock(const QString &user, const QString &password); void logout(); diff --git a/src/greeter/usermodel.h b/src/greeter/usermodel.h index 9da8cafbed..23fdeed515 100644 --- a/src/greeter/usermodel.h +++ b/src/greeter/usermodel.h @@ -86,6 +86,7 @@ class UserModel : public QAbstractListModel void currentUserNameChanged(); void updateTranslations(const QLocale &locale); void countChanged(); + void userLoggedIn(const QString &username, int sessionId); private Q_SLOTS: void onUserAdded(quint64 uid); diff --git a/src/plugins/lockscreen/qml/UserList.qml b/src/plugins/lockscreen/qml/UserList.qml index b615c5f7bf..238f5f8b35 100644 --- a/src/plugins/lockscreen/qml/UserList.qml +++ b/src/plugins/lockscreen/qml/UserList.qml @@ -29,7 +29,6 @@ D.Popup { function selectCurrentUser(userName, index) { UserModel.currentUserName = userName users.lastCheckedIndex = index - GreeterModel.proxy.activateUser(userName) userList.close() } diff --git a/src/seat/helper.cpp b/src/seat/helper.cpp index 2d1b1669e4..4522dec292 100644 --- a/src/seat/helper.cpp +++ b/src/seat/helper.cpp @@ -38,6 +38,8 @@ #include "common/treelandlogging.h" #include "modules/ddm/ddminterfacev1.h" #include "treelandconfig.hpp" +#include "core/treeland.h" +#include "greeter/greeterproxy.h" #include #include @@ -169,6 +171,16 @@ static QByteArray readWindowProperty(xcb_connection_t *connection, return data; } +Session::~Session() +{ + qCDebug(treelandCore) << "Deleting session for uid:" << uid << socket; + Q_EMIT aboutToBeDestroyed(); + if (xwayland) + Helper::instance()->shellHandler()->removeXWayland(xwayland); + if (socket) + delete socket; +} + Helper *Helper::m_instance = nullptr; Helper::Helper(QObject *parent) @@ -892,6 +904,11 @@ void Helper::onSurfaceWrapperAdded(SurfaceWrapper *wrapper) bool isXwayland = wrapper->type() == SurfaceWrapper::Type::XWayland; bool isLayer = wrapper->type() == SurfaceWrapper::Type::Layer; + connect(m_activeSession.lock().get(), &Session::aboutToBeDestroyed, wrapper, [this, wrapper]() { + onSurfaceWrapperAboutToRemove(wrapper); + m_rootSurfaceContainer->destroyForSurface(wrapper); + }); + if (isXdgToplevel || isXdgPopup || isLayer) { auto *attached = new Personalization(wrapper->shellSurface(), m_personalization, wrapper); @@ -1044,8 +1061,9 @@ void Helper::deleteTaskSwitch() } } -void Helper::init() +void Helper::init(Treeland::Treeland *treeland) { + m_treeland = treeland; auto engine = qmlEngine(); m_userModel = engine->singletonInstance("Treeland", "UserModel"); @@ -1263,13 +1281,9 @@ void Helper::init() xwaylandOutputManager->setScaleOverride(1.0); xdgOutputManager->setFilter([this](WClient *client) { return !isXWaylandClient(client); }); xwaylandOutputManager->setFilter([this](WClient *client) { return isXWaylandClient(client); }); - auto updateSession = [this] { - auto user = m_userModel->currentUser(); - const uid_t uid = user ? user->UID() : getuid(); - updateActiveUserSession(uid); - }; - updateSession(); - connect(m_userModel, &UserModel::currentUserNameChanged, this, updateSession); + // User dde does not has a real Logind session, so just pass 0 as id + updateActiveUserSession(QStringLiteral("dde"), 0); + connect(m_userModel, &UserModel::userLoggedIn, this, &Helper::updateActiveUserSession); m_xdgDecorationManager = m_server->attach(); connect(m_xdgDecorationManager, &WXdgDecorationManager::surfaceModeChanged, @@ -2175,13 +2189,50 @@ std::shared_ptr Helper::sessionForSocket(WSocket *socket) const return nullptr; } +/** + * Get the currently active session + * + * @returns weak_ptr to the active session + */ +std::weak_ptr Helper::activeSession() const +{ + return m_activeSession; +} + +/** + * Remove a session from the session list + * + * @param session The session to remove + */ +void Helper::removeSession(std::shared_ptr session) +{ + if (!session) + return; + + if (m_activeSession.lock() == session) { + m_activeSession.reset(); + m_activatedSurface = nullptr; + Q_EMIT activatedSurfaceChanged(); + } + + for (auto s : std::as_const(m_sessions)) { + if (s.get() == session.get()) { + m_sessions.removeOne(s); + break; + } + } + + session.reset(); +} + /** * Ensure a session exists for the given uid, creating it if necessary * + * @param id An existing logind session ID * @param uid User ID to ensure session for * @returns Session for the given uid, or nullptr on failure */ -std::shared_ptr Helper::ensureSession(uid_t uid) +std::shared_ptr Helper::ensureSession(int id, uid_t uid) { // Helper lambda to create WSocket and WXWayland auto createWSocket = [this]() { @@ -2223,10 +2274,6 @@ std::shared_ptr Helper::ensureSession(uid_t uid) } } }); - connect(xwayland, &QObject::destroyed, this, [this, xwayland]() { - removeXWayland(xwayland); - }); - return xwayland; }; // Check if session already exists for uid @@ -2253,67 +2300,49 @@ std::shared_ptr Helper::ensureSession(uid_t uid) return session; } - // Session does not exist, create new session + // Session does not exist, create new session with deleter auto session = std::make_shared(); + session->id = id; session->uid = uid; session->socket = createWSocket(); if (!session->socket) { + session.reset(); return nullptr; } session->xwayland = createXWayland(session->socket); if (!session->xwayland) { - delete session->socket; + session.reset(); return nullptr; } + // Add session to list m_sessions.append(session); return session; } /** - * Remove the given WXWayland and clean up its session. - * This is called when an XWayland instance is destroyed. - * - * @param xwayland WXWayland to remove - */ -void Helper::removeXWayland(WXWayland *xwayland) -{ - if (!xwayland) - return; - - if (auto session = sessionForXWayland(xwayland)) { - session->xwayland = nullptr; - session->noTitlebarAtom = XCB_ATOM_NONE; - } - - m_shellHandler->removeXWayland(xwayland); -} - -/** - * Get the WXWayland for the given uid, optionally creating it if missing + * Get the WXWayland for the given uid * * @param uid User ID to get WXWayland for - * @param createIfMissing Whether to create the session if it does not exist * @returns WXWayland for the given uid, or nullptr if not found/created */ -WXWayland *Helper::xwaylandForUid(uid_t uid, bool createIfMissing) +WXWayland *Helper::xwaylandForUid(uid_t uid) { - auto session = createIfMissing ? ensureSession(uid) : sessionForUid(uid); + auto session = sessionForUid(uid); return session ? session->xwayland : nullptr; } /** - * Get the WSocket for the given uid, optionally creating it if missing + * Get the WSocket for the given uid * * @param uid User ID to get WSocket for - * @param createIfMissing Whether to create the session if it does not exist * @returns WSocket for the given uid, or nullptr if not found/created */ -WSocket *Helper::waylandSocketForUid(uid_t uid, bool createIfMissing) +WSocket *Helper::waylandSocketForUid(uid_t uid) { - auto session = createIfMissing ? ensureSession(uid) : sessionForUid(uid); + auto session = sessionForUid(uid); return session ? session->socket : nullptr; } @@ -2348,16 +2377,16 @@ WXWayland *Helper::defaultXWaylandSocket() const * This will update XWayland visibility and emit socketFileChanged if the * active session changed. * - * @param uid User ID to set as active session + * @param username Username to set as active session */ -void Helper::updateActiveUserSession(uid_t uid) +void Helper::updateActiveUserSession(const QString &username, int id) { // Get previous active session auto previous = m_activeSession.lock(); // Get new session for uid, creating if necessary - auto session = ensureSession(uid); + auto session = ensureSession(id, getpwnam(username.toLocal8Bit().data())->pw_uid); if (!session) { - qCWarning(treelandInput) << "Failed to ensure session for uid" << uid; + qCWarning(treelandInput) << "Failed to ensure session for user" << username; return; } do { @@ -2370,14 +2399,16 @@ void Helper::updateActiveUserSession(uid_t uid) previous->socket->setEnabled(false); session->socket->setEnabled(true); Q_EMIT socketFileChanged(); + // Notify session changed through DBus, treeland-sd will listen it to update envs + Q_EMIT m_treeland->SessionChanged(); // Store last active surface of previous session if (previous) previous->lastActivatedSurface = m_activatedSurface; // Restore last activated surface for new session if (session->lastActivatedSurface) - m_activatedSurface = session->lastActivatedSurface; + setActivatedSurface(session->lastActivatedSurface); else - m_activatedSurface = nullptr; + setActivatedSurface(nullptr); Q_EMIT activatedSurfaceChanged(); } while (false); diff --git a/src/seat/helper.h b/src/seat/helper.h index 6345ecfca5..b10ab23e35 100644 --- a/src/seat/helper.h +++ b/src/seat/helper.h @@ -104,16 +104,28 @@ struct wlr_idle_inhibitor_v1; struct wlr_output_power_v1_set_mode_event; struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request; +namespace Treeland { +class Treeland; +} + QW_BEGIN_NAMESPACE class qw_ext_foreign_toplevel_image_capture_source_manager_v1; QW_END_NAMESPACE -struct Session { +struct Session : QObject { + Q_OBJECT +public: + int id = 0; uid_t uid = 0; WSocket *socket = nullptr; WXWayland *xwayland = nullptr; quint32 noTitlebarAtom = XCB_ATOM_NONE; SurfaceWrapper *lastActivatedSurface = nullptr; + + ~Session(); + +Q_SIGNALS: + void aboutToBeDestroyed(); }; class Helper : public WSeatEventFilter @@ -162,7 +174,7 @@ class Helper : public WSeatEventFilter ShellHandler *shellHandler() const; Workspace *workspace() const; - void init(); + void init(Treeland::Treeland *treeland); TogglableGesture *multiTaskViewGesture() const { @@ -189,8 +201,13 @@ class Helper : public WSeatEventFilter void addSocket(WSocket *socket); void removeXWayland(WXWayland *xwayland); - WXWayland *xwaylandForUid(uid_t uid, bool createIfMissing = true); - WSocket *waylandSocketForUid(uid_t uid, bool createIfMissing = true); + void removeSession(std::shared_ptr session); + WXWayland *xwaylandForUid(uid_t uid); + WSocket *waylandSocketForUid(uid_t uid); + std::shared_ptr sessionForUid(uid_t uid) const; + std::shared_ptr sessionForXWayland(WXWayland *xwayland) const; + std::shared_ptr sessionForSocket(WSocket *socket) const; + std::weak_ptr activeSession() const; WSocket *defaultWaylandSocket() const; WXWayland *defaultXWaylandSocket() const; @@ -325,15 +342,13 @@ private Q_SLOTS: void updateIdleInhibitor(); void setNoAnimation(bool noAnimation); - std::shared_ptr sessionForUid(uid_t uid) const; - std::shared_ptr sessionForXWayland(WXWayland *xwayland) const; - std::shared_ptr sessionForSocket(WSocket *socket) const; - std::shared_ptr ensureSession(uid_t uid); - void updateActiveUserSession(uid_t uid); + std::shared_ptr ensureSession(int id, uid_t uid); + void updateActiveUserSession(const QString &username, int id); bool isXWaylandClient(WClient *client); static Helper *m_instance; TreelandConfig *m_config = nullptr; + Treeland::Treeland *m_treeland = nullptr; FpsDisplayManager *m_fpsManager = nullptr; CurrentMode m_currentMode{ CurrentMode::Normal }; diff --git a/src/systemd-socket.cpp b/src/systemd-socket.cpp index e24f30ba81..b61e939e48 100644 --- a/src/systemd-socket.cpp +++ b/src/systemd-socket.cpp @@ -23,6 +23,21 @@ typedef QMap StringMap; Q_DECLARE_METATYPE(StringMap) +class SignalReceiver : public QObject +{ + Q_OBJECT +public: + SignalReceiver(std::function activateFdFunc, QObject *parent = nullptr) + : QObject(parent), activateFd(activateFdFunc) { + } +public Q_SLOTS: + void onSessionChanged() { + activateFd(); + } +private: + std::function activateFd; +}; + int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); @@ -51,8 +66,8 @@ int main(int argc, char *argv[]) QDBusUnixFileDescriptor unixFileDescriptor(SD_LISTEN_FDS_START); - auto active = [unixFileDescriptor, type](const QDBusConnection &connection) { - auto activateFd = [unixFileDescriptor, type, connection] { + auto active = [unixFileDescriptor, type](QDBusConnection connection) { + auto activateFd = [unixFileDescriptor, type, &connection] { QDBusInterface updateFd("org.deepin.Compositor1", "/org/deepin/Compositor1", "org.deepin.Compositor1", @@ -113,6 +128,14 @@ int main(int argc, char *argv[]) compositorWatcher, activateFd); + // Listen to SessionChanged signal and activate fd when session changed + connection.connect("org.deepin.Compositor1", + "/org/deepin/Compositor1", + "org.deepin.Compositor1", + "SessionChanged", + new SignalReceiver(activateFd), + SLOT(onSessionChanged())); + activateFd(); }; @@ -121,3 +144,5 @@ int main(int argc, char *argv[]) return app.exec(); } + +#include "systemd-socket.moc" \ No newline at end of file diff --git a/waylib/src/server/kernel/wsocket.cpp b/waylib/src/server/kernel/wsocket.cpp index c6aa634875..377b5f3093 100644 --- a/waylib/src/server/kernel/wsocket.cpp +++ b/waylib/src/server/kernel/wsocket.cpp @@ -251,10 +251,11 @@ void WSocketPrivate::addClient(WClient *client) class Q_DECL_HIDDEN WClientPrivate : public WObjectPrivate { public: - WClientPrivate(wl_client *handle, WSocket *socket, WClient *qq) + WClientPrivate(wl_client *handle, WSocket *socket, WClient *qq, bool isWlClientOwned) : WObjectPrivate(qq) , handle(handle) , socket(socket) + , isWlClientOwned(isWlClientOwned) { auto listener = new WlClientDestroyListener(qq); wl_client_add_destroy_listener(handle, &listener->destroy); @@ -277,12 +278,13 @@ class Q_DECL_HIDDEN WClientPrivate : public WObjectPrivate WSocket *socket = nullptr; mutable QSharedPointer credentials; mutable int pidFD = -1; + bool isWlClientOwned = true; }; void WlClientDestroyListener::handle_destroy(wl_listener *listener, void *data) { WlClientDestroyListener *self = wl_container_of(listener, self, destroy); - if (self->client) { + if (self->client && self->client->handle()) { Q_ASSERT(reinterpret_cast(data) == self->client->handle()); self->client->d_func()->handle = nullptr; auto socket = self->client->socket(); @@ -294,9 +296,9 @@ void WlClientDestroyListener::handle_destroy(wl_listener *listener, void *data) delete self; } -WClient::WClient(wl_client *client, WSocket *socket) +WClient::WClient(wl_client *client, WSocket *socket, bool isWlClientOwned) : QObject(nullptr) - , WObject(*new WClientPrivate(client, socket, this)) + , WObject(*new WClientPrivate(client, socket, this, isWlClientOwned)) { } @@ -467,7 +469,7 @@ void WSocket::close() if (!d->clients.isEmpty()) { for (auto client : std::as_const(d->clients)) - delete client; + removeClient(client); d->clients.clear(); Q_EMIT clientsChanged(); @@ -720,7 +722,7 @@ WClient *WSocket::addClient(int fd) return wclient; } -WClient *WSocket::addClient(wl_client *client) +WClient *WSocket::addClient(wl_client *client, bool isWlClientOwned) { W_D(WSocket); @@ -731,7 +733,7 @@ WClient *WSocket::addClient(wl_client *client) if (d->clients.contains(wclient)) return wclient; } else { - wclient = new WClient(client, this); + wclient = new WClient(client, this, isWlClientOwned); } d->addClient(wclient); @@ -756,6 +758,14 @@ bool WSocket::removeClient(WClient *client) return false; Q_EMIT aboutToBeDestroyedClient(client); + + auto handle = client->handle(); + if (handle && client->d_func()->isWlClientOwned) { + // Set handle to nullptr to prevent handle_destroy from calling removeClient again + client->d_func()->handle = nullptr; + wl_client_destroy(handle); + } + delete client; Q_EMIT clientsChanged(); diff --git a/waylib/src/server/kernel/wsocket.h b/waylib/src/server/kernel/wsocket.h index 8faf098ee1..7f022374a6 100644 --- a/waylib/src/server/kernel/wsocket.h +++ b/waylib/src/server/kernel/wsocket.h @@ -52,7 +52,7 @@ public Q_SLOTS: private: friend class WSocket; friend class WlClientDestroyListener; - explicit WClient(wl_client *client, WSocket *socket); + explicit WClient(wl_client *client, WSocket *socket, bool isWlClientOwned = true); ~WClient() = default; using QObject::deleteLater; }; @@ -94,7 +94,7 @@ class WAYLIB_SERVER_EXPORT WSocket : public QObject, public WObject bool listen(struct wl_display *display); WClient *addClient(int fd); - WClient *addClient(wl_client *client); + WClient *addClient(wl_client *client, bool isWlClientOwned = true); bool removeClient(wl_client *client); bool removeClient(WClient *client); const QList &clients() const; diff --git a/waylib/src/server/protocols/wxwayland.cpp b/waylib/src/server/protocols/wxwayland.cpp index 7da8ca25b2..f78286a1a2 100644 --- a/waylib/src/server/protocols/wxwayland.cpp +++ b/waylib/src/server/protocols/wxwayland.cpp @@ -339,7 +339,7 @@ void WXWayland::create(WServer *server) auto s = qw_xwayland_server::from(handle->handle()->server); QObject::connect(s, &qw_xwayland_server::notify_start, this, [d] { - d->socket->addClient(d->waylandClient()); + d->socket->addClient(d->waylandClient(), false); }); }