Watch whether the Wayland socket goes away

The Wayland Backend watches the socket it uses for communicating with the
Wayland compositor. If the socket is removed we have to perform a kind of
emergency stop. The backend tears down all data structures created from
the Wayland display and emits a signal that the system compositor died.

In addition the Wayland Backend starts to monitor the XDG_RUNTIME_DIR for
the socket to be added again. If the socket is created again the backend
reinitializes the Wayland connection.

This also requires the Compositor to restart. Therefore it connects to
the new signals emitted by the Wayland Backend to stop and start
compositing.
This commit is contained in:
Martin Gräßlin 2013-07-03 11:56:05 +02:00
parent 8699fe5e5a
commit ca9642b80f
3 changed files with 114 additions and 9 deletions

View file

@ -36,6 +36,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "useractions.h"
#include "compositingprefs.h"
#include "xcbutils.h"
#if HAVE_WAYLAND
#include "wayland_backend.h"
#endif
#include <stdio.h>
@ -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

View file

@ -26,6 +26,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// Qt
#include <QDebug>
#include <QImage>
#include <QFileSystemWatcher>
#include <QSocketNotifier>
#include <QTemporaryFile>
// 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_seat*>(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)

View file

@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// KWin
#include <kwinglobals.h>
// Qt
#include <QDir>
#include <QHash>
#include <QImage>
#include <QObject>
@ -32,6 +33,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
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<WaylandSeat> m_seat;
QScopedPointer<ShmPool> m_shm;
bool m_systemCompositorDied;
QString m_socketName;
QDir m_runtimeDir;
QFileSystemWatcher *m_socketWatcher;
KWIN_SINGLETON(WaylandBackend)
};