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) };