From 58b426fb62774b328be77f0c1b7bd31e0321daf0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B8rgen=20Lind?= <jorgen.lind@nokia.com>
Date: Thu, 31 Mar 2011 15:58:46 +0200
Subject: Lighthouse: Make wayland event handling happen in a separate thread

---
 src/plugins/platforms/wayland/qwaylanddisplay.cpp  | 101 ++++-----------------
 src/plugins/platforms/wayland/qwaylanddisplay.h    |  30 ++----
 src/plugins/platforms/wayland/qwaylandscreen.cpp   |   1 +
 .../platforms/wayland/qwaylandshmsurface.cpp       |   4 +-
 .../platforms/wayland/qwaylandshmwindow.cpp        |  37 +-------
 src/plugins/platforms/wayland/qwaylandshmwindow.h  |   9 --
 src/plugins/platforms/wayland/qwaylandwindow.cpp   |  56 +++++++++++-
 src/plugins/platforms/wayland/qwaylandwindow.h     |  14 ++-
 src/plugins/platforms/wayland/wayland.pro          |   6 +-
 9 files changed, 104 insertions(+), 154 deletions(-)

diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp
index 1c1702f..4f456c9 100644
--- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp
+++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp
@@ -45,11 +45,14 @@
 #include "qwaylandscreen.h"
 #include "qwaylandcursor.h"
 #include "qwaylandinputdevice.h"
+#include "qwaylandeventthread.h"
 
 #ifdef QT_WAYLAND_GL_SUPPORT
 #include "gl_integration/qwaylandglintegration.h"
 #endif
 
+#include <QtGui/QApplication>
+
 #include <unistd.h>
 #include <fcntl.h>
 #include <stdio.h>
@@ -110,117 +113,53 @@ const struct wl_shell_listener QWaylandDisplay::shellListener = {
     QWaylandDisplay::shellHandleConfigure,
 };
 
-void QWaylandDisplay::outputHandleGeometry(void *data,
-                                           struct wl_output *output,
-                                           int32_t x, int32_t y,
-                                           int32_t width, int32_t height)
-{
-    QWaylandDisplay *waylandDisplay = (QWaylandDisplay *) data;
-
-    QRect outputRect = QRect(x, y, width, height);
-    waylandDisplay->createNewScreen(output, outputRect);
-}
-
-const struct wl_output_listener QWaylandDisplay::outputListener = {
-    QWaylandDisplay::outputHandleGeometry
-};
-
-void QWaylandDisplay::displayHandleGlobal(struct wl_display *display,
-                                          uint32_t id,
-                                          const char *interface,
-                                          uint32_t version, void *data)
+void QWaylandDisplay::displayHandleGlobal(uint32_t id, QByteArray interface, uint32_t version)
 {
     Q_UNUSED(version);
-    QWaylandDisplay *qwd = (QWaylandDisplay *) data;
-
-    if (strcmp(interface, "compositor") == 0) {
-        qwd->mCompositor = wl_compositor_create(display, id);
-    } else if (strcmp(interface, "shm") == 0) {
-        qwd->mShm = wl_shm_create(display, id);
-    } else if (strcmp(interface, "shell") == 0) {
-        qwd->mShell = wl_shell_create(display, id);
-        wl_shell_add_listener(qwd->mShell, &shellListener, qwd);
-    } else if (strcmp(interface, "output") == 0) {
-        struct wl_output *output = wl_output_create(display, id);
-        wl_output_add_listener(output, &outputListener, qwd);
-    } else if (strcmp(interface, "input_device") == 0) {
+
+    if (interface == "compositor") {
+        mCompositor = wl_compositor_create(mDisplay, id);
+    } else if (interface == "shm") {
+        mShm = wl_shm_create(mDisplay, id);
+    } else if (interface == "shell"){
+        mShell = wl_shell_create(mDisplay, id);
+        wl_shell_add_listener(mShell, &shellListener, this);
+    } else if (interface == "input_device") {
         QWaylandInputDevice *inputDevice =
-            new QWaylandInputDevice(display, id);
-        qwd->mInputDevices.append(inputDevice);
+            new QWaylandInputDevice(mDisplay, id);
+        mInputDevices.append(inputDevice);
     }
 }
 
-void QWaylandDisplay::iterate()
-{
-    wl_display_iterate(mDisplay, WL_DISPLAY_READABLE | WL_DISPLAY_WRITABLE);
-}
-
-void QWaylandDisplay::readEvents(void)
-{
-    wl_display_iterate(mDisplay, WL_DISPLAY_READABLE);
-}
-
-int
-QWaylandDisplay::sourceUpdate(uint32_t mask, void *data)
-{
-    QWaylandDisplay *qwd = (QWaylandDisplay *) data;
-
-    /* FIXME: We get a callback here when we ask wl_display for the
-     * fd, but at that point we don't have the socket notifier as we
-     * need the fd to create that.  We'll probably need to split that
-     * API into get_fd and set_update_func functions. */
-    if (qwd->mWriteNotifier == NULL)
-        return 0;
-
-    qwd->mWriteNotifier->setEnabled(mask & WL_DISPLAY_WRITABLE);
-
-    return 0;
-}
-
-void QWaylandDisplay::flushRequests(void)
-{
-    wl_display_iterate(mDisplay, WL_DISPLAY_WRITABLE);
-}
-
 QWaylandDisplay::QWaylandDisplay(void)
-    : mWriteNotifier(0)
 {
     mDisplay = wl_display_connect(NULL);
     if (mDisplay == NULL) {
         qErrnoWarning(errno, "Failed to create display");
         qFatal("No wayland connection available.");
     }
-
-    wl_display_add_global_listener(mDisplay,
-                                   QWaylandDisplay::displayHandleGlobal, this);
-
 #ifdef QT_WAYLAND_GL_SUPPORT
     mEglIntegration = QWaylandGLIntegration::createGLIntegration(this);
 #endif
 
-    readEvents();
+    mEventThread = new QWaylandEventThread(this);
+
+
+    mEventThread->waitForScreens();
 
 #ifdef QT_WAYLAND_GL_SUPPORT
     mEglIntegration->initialize();
 #endif
 
-    int fd = wl_display_get_fd(mDisplay, sourceUpdate, this);
-    mReadNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
-    connect(mReadNotifier,
-            SIGNAL(activated(int)), this, SLOT(readEvents()));
 
-    mWriteNotifier = new QSocketNotifier(fd, QSocketNotifier::Write, this);
-    connect(mWriteNotifier,
-            SIGNAL(activated(int)), this, SLOT(flushRequests()));
-    mWriteNotifier->setEnabled(false);
 }
 
 QWaylandDisplay::~QWaylandDisplay(void)
 {
-    close(mFd);
 #ifdef QT_WAYLAND_GL_SUPPORT
     delete mEglIntegration;
 #endif
+    delete mEventThread;
     wl_display_destroy(mDisplay);
 }
 
diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.h b/src/plugins/platforms/wayland/qwaylanddisplay.h
index 481f829..4cfb7b5 100644
--- a/src/plugins/platforms/wayland/qwaylanddisplay.h
+++ b/src/plugins/platforms/wayland/qwaylanddisplay.h
@@ -45,6 +45,8 @@
 #include <QtCore/QObject>
 #include <QtCore/QRect>
 
+#include <QtCore/QWaitCondition>
+
 #include <wayland-client.h>
 
 class QWaylandInputDevice;
@@ -53,6 +55,7 @@ class QWaylandBuffer;
 class QPlatformScreen;
 class QWaylandScreen;
 class QWaylandGLIntegration;
+class QWaylandEventThread;
 
 class QWaylandDisplay : public QObject {
     Q_OBJECT
@@ -61,7 +64,6 @@ public:
     QWaylandDisplay(void);
     ~QWaylandDisplay(void);
 
-    void createNewScreen(struct wl_output *output, QRect geometry);
     QList<QPlatformScreen *> screens() const { return mScreens; }
     struct wl_surface *createSurface(void *handle);
     struct wl_buffer *createShmBuffer(int fd, int width, int height,
@@ -76,49 +78,33 @@ public:
 #endif
     void setCursor(QWaylandBuffer *buffer, int32_t x, int32_t y);
 
+
     void syncCallback(wl_display_sync_func_t func, void *data);
     void frameCallback(wl_display_frame_func_t func, void *data);
 
-    void iterate();
-
     struct wl_display *wl_display() const { return mDisplay; }
 public slots:
-    void readEvents(void);
-    void flushRequests(void);
+    void createNewScreen(struct wl_output *output, QRect geometry);
+    void displayHandleGlobal(uint32_t id, QByteArray interface, uint32_t version);
 
 private:
     struct wl_display *mDisplay;
+    QWaylandEventThread *mEventThread;
     struct wl_compositor *mCompositor;
     struct wl_shm *mShm;
     struct wl_shell *mShell;
-    char *mDeviceName;
-    int mFd;
     QList<QPlatformScreen *> mScreens;
     QList<QWaylandInputDevice *> mInputDevices;
-    QSocketNotifier *mReadNotifier;
-    QSocketNotifier *mWriteNotifier;
+
 #ifdef QT_WAYLAND_GL_SUPPORT
     QWaylandGLIntegration *mEglIntegration;
 #endif
 
-    static void displayHandleGlobal(struct wl_display *display,
-                                    uint32_t id,
-                                    const char *interface,
-                                    uint32_t version, void *data);
-
-    static void outputHandleGeometry(void *data,
-                                     struct wl_output *output,
-                                     int32_t x, int32_t y,
-                                     int32_t width, int32_t height);
-
     static void shellHandleConfigure(void *data, struct wl_shell *shell,
                                      uint32_t time, uint32_t edges,
                                      struct wl_surface *surface,
                                      int32_t width, int32_t height);
 
-    static int sourceUpdate(uint32_t mask, void *data);
-
-    static const struct wl_output_listener outputListener;
     static const struct wl_shell_listener shellListener;
 };
 
diff --git a/src/plugins/platforms/wayland/qwaylandscreen.cpp b/src/plugins/platforms/wayland/qwaylandscreen.cpp
index 35e2532..4f50cb6 100644
--- a/src/plugins/platforms/wayland/qwaylandscreen.cpp
+++ b/src/plugins/platforms/wayland/qwaylandscreen.cpp
@@ -53,6 +53,7 @@ QWaylandScreen::QWaylandScreen(QWaylandDisplay *waylandDisplay, struct wl_output
     , mFormat(QImage::Format_ARGB32_Premultiplied)
     , mWaylandCursor(new QWaylandCursor(this))
 {
+    moveToThread(waylandDisplay->thread());
 }
 
 QWaylandScreen::~QWaylandScreen()
diff --git a/src/plugins/platforms/wayland/qwaylandshmsurface.cpp b/src/plugins/platforms/wayland/qwaylandshmsurface.cpp
index cc6b2a1..34f4436 100644
--- a/src/plugins/platforms/wayland/qwaylandshmsurface.cpp
+++ b/src/plugins/platforms/wayland/qwaylandshmsurface.cpp
@@ -111,9 +111,7 @@ void QWaylandShmWindowSurface::beginPaint(const QRegion &)
 {
     QWaylandShmWindow *waylandWindow = static_cast<QWaylandShmWindow *>(window()->platformWindow());
     Q_ASSERT(waylandWindow->windowType() == QWaylandWindow::Shm);
-    while (waylandWindow->waitingForFrameSync()) {
-        mDisplay->iterate();
-    }
+    waylandWindow->waitForFrameSync();
 }
 
 void QWaylandShmWindowSurface::flush(QWidget *widget, const QRegion &region, const QPoint &offset)
diff --git a/src/plugins/platforms/wayland/qwaylandshmwindow.cpp b/src/plugins/platforms/wayland/qwaylandshmwindow.cpp
index 2808ed6..c083e58 100644
--- a/src/plugins/platforms/wayland/qwaylandshmwindow.cpp
+++ b/src/plugins/platforms/wayland/qwaylandshmwindow.cpp
@@ -45,10 +45,10 @@
 
 #include <QtCore/QVector>
 
+#include <QtCore/QDebug>
+
 QWaylandShmWindow::QWaylandShmWindow(QWidget *widget)
     : QWaylandWindow(widget)
-    , mBuffer(0)
-    , mWaitingForFrameSync(false)
 {
     newSurfaceCreated();
 }
@@ -69,36 +69,3 @@ QPlatformGLContext * QWaylandShmWindow::glContext() const
     return 0;
 }
 
-void QWaylandShmWindow::attach(QWaylandBuffer *buffer)
-{
-    mBuffer = buffer;
-    if (mSurface) {
-        wl_surface_attach(mSurface, buffer->buffer(),0,0);
-    }
-}
-
-
-void QWaylandShmWindow::damage(const QRegion &region)
-{
-    QVector<QRect> rects = region.rects();
-    for (int i = 0; i < rects.size(); i++) {
-        const QRect rect = rects.at(i);
-        wl_surface_damage(mSurface,
-                          rect.x(), rect.y(), rect.width(), rect.height());
-    }
-    mWaitingForFrameSync = true;
-    mDisplay->frameCallback(QWaylandShmWindow::frameCallback, this);
-}
-
-void QWaylandShmWindow::newSurfaceCreated()
-{
-    if (mBuffer) {
-        wl_surface_attach(mSurface,mBuffer->buffer(),0,0);
-    }
-}
-
-void QWaylandShmWindow::frameCallback(void *data, uint32_t time)
-{
-    QWaylandShmWindow *self = static_cast<QWaylandShmWindow*>(data);
-    self->mWaitingForFrameSync = false;
-}
diff --git a/src/plugins/platforms/wayland/qwaylandshmwindow.h b/src/plugins/platforms/wayland/qwaylandshmwindow.h
index 3876c52..5dc6351 100644
--- a/src/plugins/platforms/wayland/qwaylandshmwindow.h
+++ b/src/plugins/platforms/wayland/qwaylandshmwindow.h
@@ -53,15 +53,6 @@ public:
 
     WindowType windowType() const;
     QPlatformGLContext *glContext() const;
-    void attach(QWaylandBuffer *buffer);
-    void damage(const QRegion &region);
-    bool waitingForFrameSync() const { return mWaitingForFrameSync; }
-protected:
-    void newSurfaceCreated();
-private:
-    static void frameCallback(void *data, uint32_t time);
-    QWaylandBuffer *mBuffer;
-    bool mWaitingForFrameSync;
 };
 
 #endif // QWAYLANDSHMWINDOW_H
diff --git a/src/plugins/platforms/wayland/qwaylandwindow.cpp b/src/plugins/platforms/wayland/qwaylandwindow.cpp
index e994616..aa72ad5 100644
--- a/src/plugins/platforms/wayland/qwaylandwindow.cpp
+++ b/src/plugins/platforms/wayland/qwaylandwindow.cpp
@@ -43,6 +43,7 @@
 
 #include "qwaylanddisplay.h"
 #include "qwaylandscreen.h"
+#include "qwaylandbuffer.h"
 
 #include <QtGui/QWidget>
 #include <QtGui/QWindowSystemInterface>
@@ -52,6 +53,8 @@
 QWaylandWindow::QWaylandWindow(QWidget *window)
     : QPlatformWindow(window)
     , mDisplay(QWaylandScreen::waylandScreenFromWidget(window)->display())
+    , mBuffer(0)
+    , mWaitingForFrameSync(false)
 {
     static WId id = 1;
     mWindowId = id++;
@@ -73,7 +76,7 @@ WId QWaylandWindow::winId() const
 void QWaylandWindow::setParent(const QPlatformWindow *parent)
 {
     Q_UNUSED(parent);
-    qWarning("Trying to add a raster window as a sub-window");
+    qWarning("Sub window is not supported");
 }
 
 void QWaylandWindow::setVisible(bool visible)
@@ -103,3 +106,54 @@ void QWaylandWindow::configure(uint32_t time, uint32_t edges,
 
     QWindowSystemInterface::handleGeometryChange(widget(), geometry);
 }
+
+void QWaylandWindow::attach(QWaylandBuffer *buffer)
+{
+    mBuffer = buffer;
+    if (mSurface) {
+        wl_surface_attach(mSurface, buffer->buffer(),0,0);
+    }
+}
+
+
+void QWaylandWindow::damage(const QRegion &region)
+{
+    //We have to do sync stuff before calling damage, or we might
+    //get a frame callback before we get the timestamp
+    mDisplay->frameCallback(QWaylandWindow::frameCallback, this);
+    mWaitingForFrameSync = true;
+
+    QVector<QRect> rects = region.rects();
+    for (int i = 0; i < rects.size(); i++) {
+        const QRect rect = rects.at(i);
+        wl_surface_damage(mSurface,
+                          rect.x(), rect.y(), rect.width(), rect.height());
+    }
+}
+
+void QWaylandWindow::newSurfaceCreated()
+{
+    if (mBuffer) {
+        wl_surface_attach(mSurface,mBuffer->buffer(),0,0);
+    }
+}
+
+void QWaylandWindow::frameCallback(void *data, uint32_t time)
+{
+    Q_UNUSED(time);
+    QWaylandWindow *self = static_cast<QWaylandWindow*>(data);
+    if (self->mWaitingForFrameSync) {
+        self->mWaitingForFrameSync = false;
+        self->mFrameSyncWait.wakeAll();
+    }
+}
+
+void QWaylandWindow::waitForFrameSync()
+{
+    if (!mWaitingForFrameSync) {
+        return;
+    }
+    QMutex lock;
+    lock.lock();
+    mFrameSyncWait.wait(&lock);
+}
diff --git a/src/plugins/platforms/wayland/qwaylandwindow.h b/src/plugins/platforms/wayland/qwaylandwindow.h
index afc214e..ad4bba4 100644
--- a/src/plugins/platforms/wayland/qwaylandwindow.h
+++ b/src/plugins/platforms/wayland/qwaylandwindow.h
@@ -43,6 +43,8 @@
 #define QWAYLANDWINDOW_H
 
 #include <QtGui/QPlatformWindow>
+#include <QtCore/QWaitCondition>
+#include <QtCore/QMutex>
 
 #include "qwaylanddisplay.h"
 
@@ -69,11 +71,21 @@ public:
     void configure(uint32_t time, uint32_t edges,
                    int32_t x, int32_t y, int32_t width, int32_t height);
 
+    void attach(QWaylandBuffer *buffer);
+    void damage(const QRegion &region);
+
+    void waitForFrameSync();
 protected:
     struct wl_surface *mSurface;
-    virtual void newSurfaceCreated() = 0;
+    virtual void newSurfaceCreated();
     QWaylandDisplay *mDisplay;
+    QWaylandBuffer *mBuffer;
     WId mWindowId;
+    bool mWaitingForFrameSync;
+    QWaitCondition mFrameSyncWait;
+
+private:
+    static void frameCallback(void *data, uint32_t time);
 
 
 };
diff --git a/src/plugins/platforms/wayland/wayland.pro b/src/plugins/platforms/wayland/wayland.pro
index e5c866b..849299a 100644
--- a/src/plugins/platforms/wayland/wayland.pro
+++ b/src/plugins/platforms/wayland/wayland.pro
@@ -14,7 +14,8 @@ SOURCES =   main.cpp \
             qwaylanddisplay.cpp \
             qwaylandwindow.cpp \
             qwaylandscreen.cpp \
-            qwaylandshmwindow.cpp
+            qwaylandshmwindow.cpp \
+            qwaylandeventthread.cpp
 
 HEADERS =   qwaylandintegration.h \
             qwaylandcursor.h \
@@ -23,7 +24,8 @@ HEADERS =   qwaylandintegration.h \
             qwaylandscreen.h \
             qwaylandshmsurface.h \
             qwaylandbuffer.h \
-            qwaylandshmwindow.h
+            qwaylandshmwindow.h \
+            qwaylandeventthread.h
 
 INCLUDEPATH += $$QMAKE_INCDIR_WAYLAND
 LIBS += $$QMAKE_LIBS_WAYLAND
-- 
cgit v0.12