diff --git a/src/core/shellhandler.cpp b/src/core/shellhandler.cpp index 72521e125..48ea3afe0 100644 --- a/src/core/shellhandler.cpp +++ b/src/core/shellhandler.cpp @@ -772,13 +772,25 @@ void ShellHandler::registerSurfaceToForeignToplevel(SurfaceWrapper *wrapper) if (!wrapper->skipDockPreView()) { m_treelandForeignToplevel->addSurface(wrapper); } - connect(wrapper, &SurfaceWrapper::skipDockPreViewChanged, this, [this, wrapper] { + + QMetaObject::Connection skipConn; + skipConn = connect(wrapper, &SurfaceWrapper::skipDockPreViewChanged, this, [this, wrapper] { if (wrapper->skipDockPreView()) { m_treelandForeignToplevel->removeSurface(wrapper); } else { m_treelandForeignToplevel->addSurface(wrapper); } }); + + connect(wrapper, &SurfaceWrapper::aboutToBeInvalidated, this, [this, wrapper, skipConn] { + // Only remove if the surface was actually added (skipDockPreView is false). + if (!wrapper->skipDockPreView()) { + m_treelandForeignToplevel->removeSurface(wrapper); + } + // Disconnect skipDockPreViewChanged to prevent double-remove when + // invalidate() calls setSkipDockPreView(true) after this signal. + QObject::disconnect(skipConn); + }); } void ShellHandler::setupDockPreview() diff --git a/src/modules/input-manager/inputmanagerinterfacev1.cpp b/src/modules/input-manager/inputmanagerinterfacev1.cpp index 3a227dfae..ecc690b4b 100644 --- a/src/modules/input-manager/inputmanagerinterfacev1.cpp +++ b/src/modules/input-manager/inputmanagerinterfacev1.cpp @@ -52,8 +52,14 @@ void TreelandInputManagerInterfaceV1Private::destroy(Resource *resource) void TreelandInputManagerInterfaceV1Private::bind_resource(Resource *resource) { + // Report capabilities available on the seat. wl_seat is created before this + // global, so the client has normally bound it; the null case only occurs in + // the disconnect race. A client without a wl_seat binding cannot receive + // seat-referencing events, so it is skipped by protocol semantics. TreelandInputManagerInterfaceV1::DeviceTypes types = q->inputDeviceListTypes(); struct wlr_seat_client *seatClient = Helper::instance()->seat()->handle()->client_for_wl_client(resource->client()); + if (!seatClient) + return; struct wl_resource *clientResource; wl_resource_for_each(clientResource, &seatClient->resources) { send_capability_available(resource->handle, types.toInt(), clientResource); @@ -173,6 +179,8 @@ void TreelandInputManagerInterfaceV1::sendCapabilityAvailable(TreelandInputManag for (const auto &resource : d->resourceMap()) { struct wlr_seat_client *seatClient = Helper::instance()->seat()->handle()->client_for_wl_client(resource->client()); + if (!seatClient) + continue; // No wl_seat binding: cannot deliver seat-referencing capability events. struct wl_resource *clientResource; wl_resource_for_each(clientResource, &seatClient->resources) { d->send_capability_available(resource->handle, types.toInt(), clientResource); @@ -185,6 +193,8 @@ void TreelandInputManagerInterfaceV1::sendCapabilityUnavailable(TreelandInputMan for (const auto &resource : d->resourceMap()) { struct wlr_seat_client *seatClient = Helper::instance()->seat()->handle()->client_for_wl_client(resource->client()); + if (!seatClient) + continue; // No wl_seat binding: cannot deliver seat-referencing capability events. struct wl_resource *clientResource; wl_resource_for_each(clientResource, &seatClient->resources) { d->send_capability_unavailable(resource->handle, types.toInt(), clientResource); @@ -267,6 +277,8 @@ void TreelandInputManagerInterfaceV1::onInputAdded(WInputDevice *input) for (const auto &resource : d->resourceMap()) { struct wlr_seat_client *seatClient = Helper::instance()->seat()->handle()->client_for_wl_client(resource->client()); + if (!seatClient) + continue; // No wl_seat binding: cannot deliver seat-referencing capability events. struct wl_resource *clientResource; wl_resource_for_each(clientResource, &seatClient->resources) { d->send_capability_available(resource->handle, type.toInt(), clientResource); @@ -292,6 +304,8 @@ void TreelandInputManagerInterfaceV1::onInputRemoved(WInputDevice *input) for (const auto &resource : d->resourceMap()) { struct wlr_seat_client *seatClient = Helper::instance()->seat()->handle()->client_for_wl_client(resource->client()); + if (!seatClient) + continue; // No wl_seat binding: cannot deliver seat-referencing capability events. struct wl_resource *clientResource; wl_resource_for_each(clientResource, &seatClient->resources) { d->send_capability_unavailable(resource->handle, type.toInt(), clientResource);