[plasma/kwin] src: main_wayland: only restart Xwayland if the GPU it's using was removed
Xaver Hugl <[email protected]> Tue, 4 Aug 2026 15:18:41 +0000 (UTC)
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit 63081f49911a5f3e9744acb0390f20ddfa6badcb by Xaver Hugl.
Committed on 04/08/2026 at 14:17.
Pushed by zamundaaa into branch 'master'.
main_wayland: only restart Xwayland if the GPU it's using was removed
That way it becomes possible to change the primary GPU without killing
Xwayland.
M +15 -4 src/main_wayland.cpp
M +7 -7 src/wayland/linuxdmabufv1clientbuffer.cpp
M +1 -1 src/wayland/linuxdmabufv1clientbuffer.h
https://invent.kde.org/plasma/kwin/-/commit/63081f49911a5f3e9744acb0390f20ddfa6badcb
diff --git a/src/main_wayland.cpp b/src/main_wayland.cpp
index 848f43f5c5e..b0cb35d78f7 100644
--- a/src/main_wayland.cpp
+++ b/src/main_wayland.cpp
@@ -14,13 +14,17 @@
#include "backends/virtual/virtual_backend.h"
#include "backends/wayland/wayland_backend.h"
#include "compositor.h"
+#include "core/gpumanager.h"
#include "core/outputbackend.h"
+#include "core/renderdevice.h"
#include "core/session.h"
#include "effect/effecthandler.h"
#include "inputmethod.h"
#include "tabletmodemanager.h"
#include "utils/realtime.h"
+#include "wayland/clientconnection.h"
#include "wayland/display.h"
+#include "wayland/linuxdmabufv1clientbuffer.h"
#include "wayland/seat.h"
#include "wayland_server.h"
#include "workspace.h"
@@ -171,10 +175,17 @@ void ApplicationWayland::performStartup()
m_xwayland->xwaylandLauncher()->addEnvironmentVariables(m_xwaylandExtraEnvironment);
m_xwayland->xwaylandLauncher()->passFileDescriptors(std::move(m_xwaylandFds));
m_xwayland->init();
- connect(Compositor::self(), &Compositor::primaryGpuChanged, m_xwayland.get(), [this]() {
- // Xwayland will automatically be started again
- // once a client tries to connect to it
- m_xwayland->xwaylandLauncher()->stop();
+ connect(GpuManager::self(), &GpuManager::renderDeviceRemoved, m_xwayland.get(), [this](RenderDevice *removed) {
+ if (!waylandServer()->xWaylandConnection() || !waylandServer()->linuxDmabuf()) {
+ return;
+ }
+ const auto mainDevice = waylandServer()->linuxDmabuf()->mainDevice(waylandServer()->xWaylandConnection()->client());
+ if (mainDevice == removed->deviceId()) {
+ // Xwayland breaks if the GPU it's using was hotunplugged,
+ // so we manually stop it here. It will automatically be
+ // started again once a client tries to connect to it
+ m_xwayland->xwaylandLauncher()->stop();
+ }
});
}
#endif
diff --git a/src/wayland/linuxdmabufv1clientbuffer.cpp b/src/wayland/linuxdmabufv1clientbuffer.cpp
index 989bb5fccd9..ebd6b06e9ee 100644
--- a/src/wayland/linuxdmabufv1clientbuffer.cpp
+++ b/src/wayland/linuxdmabufv1clientbuffer.cpp
@@ -178,7 +178,7 @@ void LinuxDmaBufParamsV1::zwp_linux_buffer_params_v1_create(Resource *resource,
m_attrs.format = format;
auto clientBuffer = new LinuxDmaBufV1ClientBuffer(std::move(m_attrs));
- const dev_t target = m_targetDevice.value_or(m_integration->mainDevice(resource->client()));
+ const dev_t target = m_targetDevice.value_or(m_integration->mainDevice(resource->client()).value());
const auto &devices = GpuManager::s_self->renderDevices();
bool success = renderBackend->testImportBuffer(clientBuffer, target);
if (success) {
@@ -246,7 +246,7 @@ void LinuxDmaBufParamsV1::zwp_linux_buffer_params_v1_create_immed(Resource *reso
m_attrs.format = format;
auto clientBuffer = new LinuxDmaBufV1ClientBuffer(std::move(m_attrs));
- const dev_t target = m_targetDevice.value_or(m_integration->mainDevice(resource->client()));
+ const dev_t target = m_targetDevice.value_or(m_integration->mainDevice(resource->client()).value());
const auto &devices = GpuManager::s_self->renderDevices();
bool success = renderBackend->testImportBuffer(clientBuffer, target);
if (success) {
@@ -406,10 +406,10 @@ void LinuxDmaBufV1ClientBufferIntegration::setSupportedFormatsWithModifiers(cons
}
}
-dev_t LinuxDmaBufV1ClientBufferIntegration::mainDevice(wl_client *client) const
+std::optional<dev_t> LinuxDmaBufV1ClientBufferIntegration::mainDevice(wl_client *client) const
{
- Q_ASSERT(d->mainDevices.contains(client));
- return d->mainDevices[client];
+ const auto it = d->mainDevices.find(client);
+ return it == d->mainDevices.end() ? std::nullopt : std::optional(*it);
}
void LinuxDmaBufV1ClientBuffer::buffer_destroy_resource(wl_resource *resource)
@@ -483,7 +483,7 @@ LinuxDmaBufV1Feedback::~LinuxDmaBufV1Feedback() = default;
void LinuxDmaBufV1Feedback::setScanoutTranches(DrmDevice *scanoutDevice, const FormatModifierMap &formats)
{
Q_ASSERT(d->m_client);
- const dev_t mainDevice = d->m_bufferintegration->q->mainDevice(d->m_client);
+ const dev_t mainDevice = d->m_bufferintegration->q->mainDevice(d->m_client).value();
setScanoutTranches(createScanoutTranches(d->m_bufferintegration->defaultTranches, mainDevice, scanoutDevice, formats));
}
@@ -545,7 +545,7 @@ LinuxDmaBufV1FeedbackPrivate::LinuxDmaBufV1FeedbackPrivate(LinuxDmaBufV1ClientBu
void LinuxDmaBufV1FeedbackPrivate::send(Resource *resource)
{
- const dev_t mainDevice = m_bufferintegration->q->mainDevice(resource->client());
+ const dev_t mainDevice = m_bufferintegration->q->mainDevice(resource->client()).value();
send_format_table(resource->handle, m_bufferintegration->table->file.fd(), m_bufferintegration->table->file.size());
if (resource->version() < ZWP_LINUX_BUFFER_PARAMS_V1_SET_SAMPLING_DEVICE_SINCE_VERSION) {
QByteArray bytes;
diff --git a/src/wayland/linuxdmabufv1clientbuffer.h b/src/wayland/linuxdmabufv1clientbuffer.h
index 3a37449f9c1..a2b630b7984 100644
--- a/src/wayland/linuxdmabufv1clientbuffer.h
+++ b/src/wayland/linuxdmabufv1clientbuffer.h
@@ -78,7 +78,7 @@ public:
void setSupportedFormatsWithModifiers(const QList<LinuxDmaBufV1Feedback::Tranche> &tranches);
- dev_t mainDevice(wl_client *client) const;
+ std::optional<dev_t> mainDevice(wl_client *client) const;
private:
friend class LinuxDmaBufV1ClientBufferIntegrationPrivate;