diff --git a/composite.cpp b/composite.cpp
index 56bee8c65a..187d05f58f 100644
--- a/composite.cpp
+++ b/composite.cpp
@@ -36,6 +36,9 @@ along with this program. If not, see .
#include "useractions.h"
#include "compositingprefs.h"
#include "xcbutils.h"
+#if HAVE_WAYLAND
+#include "wayland_backend.h"
+#endif
#include
@@ -113,6 +116,12 @@ Compositor::Compositor(QObject* workspace)
m_unusedSupportPropertyTimer.setInterval(compositorLostMessageDelay);
m_unusedSupportPropertyTimer.setSingleShot(true);
connect(&m_unusedSupportPropertyTimer, SIGNAL(timeout()), SLOT(deleteUnusedSupportProperties()));
+#if HAVE_WAYLAND
+ if (kwinApp()->operationMode() != Application::OperationModeX11) {
+ connect(Wayland::WaylandBackend::self(), &Wayland::WaylandBackend::systemCompositorDied, this, &Compositor::finish);
+ connect(Wayland::WaylandBackend::self(), &Wayland::WaylandBackend::backendReady, this, &Compositor::setup);
+ }
+#endif
// delay the call to setup by one event cycle
// The ctor of this class is invoked from the Workspace ctor, that means before
diff --git a/wayland_backend.cpp b/wayland_backend.cpp
index 2ee59e979b..4291c40049 100644
--- a/wayland_backend.cpp
+++ b/wayland_backend.cpp
@@ -26,6 +26,7 @@ along with this program. If not, see .
// Qt
#include
#include
+#include
#include
#include
// xcb
@@ -627,8 +628,8 @@ WaylandBackend *WaylandBackend::create(QObject *parent)
WaylandBackend::WaylandBackend(QObject *parent)
: QObject(parent)
- , m_display(wl_display_connect(NULL))
- , m_registry(wl_display_get_registry(m_display))
+ , m_display(nullptr)
+ , m_registry(nullptr)
, m_compositor(NULL)
, m_shell(NULL)
, m_surface(NULL)
@@ -636,15 +637,17 @@ WaylandBackend::WaylandBackend(QObject *parent)
, m_shellSurfaceSize(displayWidth(), displayHeight())
, m_seat()
, m_shm()
+ , m_systemCompositorDied(false)
+ , m_runtimeDir(qgetenv("XDG_RUNTIME_DIR"))
+ , m_socketWatcher(nullptr)
{
- qDebug() << "Created Wayland display";
+ m_socketName = qgetenv("WAYLAND_DISPLAY");
+ if (m_socketName.isEmpty()) {
+ m_socketName = QStringLiteral("wayland-0");
+ }
+
+ initConnection();
kwinApp()->setOperationMode(Application::OperationModeWaylandAndX11);
- // setup the registry
- wl_registry_add_listener(m_registry, &s_registryListener, this);
- wl_display_dispatch(m_display);
- int fd = wl_display_get_fd(m_display);
- QSocketNotifier *notifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
- connect(notifier, SIGNAL(activated(int)), SLOT(readEvents()));
}
WaylandBackend::~WaylandBackend()
@@ -672,13 +675,94 @@ WaylandBackend::~WaylandBackend()
s_self = NULL;
}
+void WaylandBackend::initConnection()
+{
+ m_display = wl_display_connect(nullptr);
+ if (!m_display) {
+ // TODO: maybe we should now really tear down
+ qWarning() << "Failed connecting to Wayland display";
+ return;
+ }
+ m_registry = wl_display_get_registry(m_display);
+ // setup the registry
+ wl_registry_add_listener(m_registry, &s_registryListener, this);
+ wl_display_dispatch(m_display);
+ int fd = wl_display_get_fd(m_display);
+ QSocketNotifier *notifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
+ connect(notifier, &QSocketNotifier::activated, this, &WaylandBackend::readEvents);
+
+ if (m_runtimeDir.exists()) {
+ m_socketWatcher = new QFileSystemWatcher(this);
+ m_socketWatcher->addPath(m_runtimeDir.absoluteFilePath(m_socketName));
+ connect(m_socketWatcher, &QFileSystemWatcher::fileChanged, this, &WaylandBackend::socketFileChanged);
+ }
+ qDebug() << "Created Wayland display";
+}
+
void WaylandBackend::readEvents()
{
// TODO: this still seems to block
+ if (m_systemCompositorDied) {
+ return;
+ }
wl_display_flush(m_display);
wl_display_dispatch(m_display);
}
+void WaylandBackend::socketFileChanged(const QString &socket)
+{
+ if (!QFile::exists(socket) && !m_systemCompositorDied) {
+ qDebug() << "We lost the system compositor at:" << socket;
+ m_systemCompositorDied = true;
+ emit systemCompositorDied();
+ m_seat.reset();
+ m_shm.reset();
+ if (m_shellSurface) {
+ free(m_shellSurface);
+ m_shellSurface = nullptr;
+ }
+ if (m_surface) {
+ free(m_surface);
+ m_surface = nullptr;
+ }
+ if (m_shell) {
+ free(m_shell);
+ m_shell = nullptr;
+ }
+ if (m_compositor) {
+ free(m_compositor);
+ m_compositor = nullptr;
+ }
+ if (m_registry) {
+ free(m_registry);
+ m_registry = nullptr;
+ }
+ if (m_display) {
+ free(m_display);
+ m_display = nullptr;
+ }
+ // need a new filesystem watcher
+ delete m_socketWatcher;
+ m_socketWatcher = new QFileSystemWatcher(this);
+ m_socketWatcher->addPath(m_runtimeDir.absolutePath());
+ connect(m_socketWatcher, &QFileSystemWatcher::directoryChanged, this, &WaylandBackend::socketDirectoryChanged);
+ }
+}
+
+void WaylandBackend::socketDirectoryChanged()
+{
+ if (!m_systemCompositorDied) {
+ return;
+ }
+ if (m_runtimeDir.exists(m_socketName)) {
+ qDebug() << "Socket reappeared";
+ delete m_socketWatcher;
+ m_socketWatcher = nullptr;
+ initConnection();
+ m_systemCompositorDied = false;
+ }
+}
+
void WaylandBackend::createSeat(uint32_t name)
{
wl_seat *seat = reinterpret_cast(wl_registry_bind(m_registry, name, &wl_seat_interface, 1));
@@ -704,6 +788,7 @@ void WaylandBackend::createSurface()
m_shellSurface = wl_shell_get_shell_surface(m_shell, m_surface);
wl_shell_surface_add_listener(m_shellSurface, &s_shellSurfaceListener, this);
wl_shell_surface_set_fullscreen(m_shellSurface, WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, NULL);
+ emit backendReady();
}
void WaylandBackend::createShm(uint32_t name)
diff --git a/wayland_backend.h b/wayland_backend.h
index 21f9b35bce..ad8ddad14d 100644
--- a/wayland_backend.h
+++ b/wayland_backend.h
@@ -22,6 +22,7 @@ along with this program. If not, see .
// KWin
#include
// Qt
+#include
#include
#include
#include
@@ -32,6 +33,7 @@ along with this program. If not, see .
class QTemporaryFile;
class QImage;
+class QFileSystemWatcher;
struct wl_cursor_theme;
struct wl_buffer;
struct wl_shm;
@@ -188,9 +190,14 @@ public:
void dispatchEvents();
Q_SIGNALS:
void shellSurfaceSizeChanged(const QSize &size);
+ void systemCompositorDied();
+ void backendReady();
private Q_SLOTS:
void readEvents();
+ void socketFileChanged(const QString &socket);
+ void socketDirectoryChanged();
private:
+ void initConnection();
void createSurface();
wl_display *m_display;
wl_registry *m_registry;
@@ -201,6 +208,10 @@ private:
QSize m_shellSurfaceSize;
QScopedPointer m_seat;
QScopedPointer m_shm;
+ bool m_systemCompositorDied;
+ QString m_socketName;
+ QDir m_runtimeDir;
+ QFileSystemWatcher *m_socketWatcher;
KWIN_SINGLETON(WaylandBackend)
};