diff options
Diffstat (limited to 'src/plugins/platforms/wayland/qwaylanddisplay.cpp')
-rw-r--r-- | src/plugins/platforms/wayland/qwaylanddisplay.cpp | 241 |
1 files changed, 132 insertions, 109 deletions
diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp index 27f4334..1c56561 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp +++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp @@ -46,13 +46,23 @@ #include "qwaylandcursor.h" #include "qwaylandinputdevice.h" +#ifdef QT_WAYLAND_GL_SUPPORT +#include "gl_integration/qwaylandglintegration.h" +#endif + +#include <QtCore/QAbstractEventDispatcher> +#include <QtGui/QApplication> + #include <unistd.h> #include <fcntl.h> #include <stdio.h> +#include <errno.h> -struct wl_surface *QWaylandDisplay::createSurface() +struct wl_surface *QWaylandDisplay::createSurface(void *handle) { - return wl_compositor_create_surface(mCompositor); + struct wl_surface * surface = wl_compositor_create_surface(mCompositor); + wl_surface_set_user_data(surface, handle); + return surface; } struct wl_buffer *QWaylandDisplay::createShmBuffer(int fd, @@ -78,10 +88,12 @@ struct wl_visual *QWaylandDisplay::argbPremultipliedVisual() return wl_display_get_premultiplied_argb_visual(mDisplay); } -struct wl_egl_display *QWaylandDisplay::nativeDisplay() +#ifdef QT_WAYLAND_GL_SUPPORT +QWaylandGLIntegration * QWaylandDisplay::eglIntegration() { - return mNativeEglDisplay; + return mEglIntegration; } +#endif void QWaylandDisplay::shellHandleConfigure(void *data, struct wl_shell *shell, uint32_t time, uint32_t edges, @@ -101,147 +113,158 @@ 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::QWaylandDisplay(void) { - QWaylandDisplay *waylandDisplay = (QWaylandDisplay *) data; + mDisplay = wl_display_connect(NULL); + if (mDisplay == NULL) { + qErrnoWarning(errno, "Failed to create display"); + qFatal("No wayland connection available."); + } - QRect outputRect = QRect(x, y, width, height); - waylandDisplay->createNewScreen(output, outputRect); -} + wl_display_add_global_listener(mDisplay, QWaylandDisplay::displayHandleGlobal, this); -const struct wl_output_listener QWaylandDisplay::outputListener = { - QWaylandDisplay::outputHandleGeometry -}; +#ifdef QT_WAYLAND_GL_SUPPORT + mEglIntegration = QWaylandGLIntegration::createGLIntegration(this); +#endif -void QWaylandDisplay::displayHandleGlobal(struct wl_display *display, - uint32_t id, - const char *interface, - uint32_t version, void *data) -{ - 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) { - QWaylandInputDevice *inputDevice = - new QWaylandInputDevice(display, id); - qwd->mInputDevices.append(inputDevice); - } + qRegisterMetaType<uint32_t>("uint32_t"); + +#ifdef QT_WAYLAND_GL_SUPPORT + mEglIntegration->initialize(); +#endif + + connect(QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()), this, SLOT(flushRequests())); + + mFd = wl_display_get_fd(mDisplay, sourceUpdate, this); + + mReadNotifier = new QSocketNotifier(mFd, QSocketNotifier::Read, this); + connect(mReadNotifier, SIGNAL(activated(int)), this, SLOT(readEvents())); + + waitForScreens(); } -void QWaylandDisplay::iterate() +QWaylandDisplay::~QWaylandDisplay(void) { - wl_display_iterate(mDisplay, WL_DISPLAY_READABLE | WL_DISPLAY_WRITABLE); + close(mFd); +#ifdef QT_WAYLAND_GL_SUPPORT + delete mEglIntegration; +#endif + wl_display_destroy(mDisplay); } -void QWaylandDisplay::readEvents(void) +void QWaylandDisplay::createNewScreen(struct wl_output *output, QRect geometry) { - wl_display_iterate(mDisplay, WL_DISPLAY_READABLE); + QWaylandScreen *waylandScreen = new QWaylandScreen(this,output,geometry); + mScreens.append(waylandScreen); } -int -QWaylandDisplay::sourceUpdate(uint32_t mask, void *data) +void QWaylandDisplay::syncCallback(wl_display_sync_func_t func, 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); + wl_display_sync_callback(mDisplay, func, data); +} - return 0; +void QWaylandDisplay::frameCallback(wl_display_frame_func_t func, struct wl_surface *surface, void *data) +{ + wl_display_frame_callback(mDisplay, surface, func, data); } -void QWaylandDisplay::flushRequests(void) +void QWaylandDisplay::flushRequests() { - wl_display_iterate(mDisplay, WL_DISPLAY_WRITABLE); + if (mSocketMask & WL_DISPLAY_WRITABLE) + wl_display_iterate(mDisplay, WL_DISPLAY_WRITABLE); } -QWaylandDisplay::QWaylandDisplay(void) - : mWriteNotifier(0) +void QWaylandDisplay::readEvents() { -#ifdef QT_WAYLAND_GL_SUPPORT - EGLint major, minor; -#endif - mDisplay = wl_display_connect(NULL); - if (mDisplay == NULL) { - fprintf(stderr, "failed to create display: %m\n"); +// verify that there is still data on the socket + fd_set fds; + FD_ZERO(&fds); + FD_SET(mFd, &fds); + fd_set nds; + FD_ZERO(&nds); + fd_set rs = fds; + fd_set ws = nds; + fd_set es = nds; + timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 0; + int ret = ::select(mFd+1, &rs, &ws, &es, &timeout ); + + if (ret <= 0) { + //qDebug("QWaylandDisplay::readEvents() No data... blocking avoided"); return; } - wl_display_add_global_listener(mDisplay, - QWaylandDisplay::displayHandleGlobal, this); - -#ifdef QT_WAYLAND_GL_SUPPORT - mNativeEglDisplay = wl_egl_display_create(mDisplay); -#else - mNativeEglDisplay = 0; -#endif - - readEvents(); + wl_display_iterate(mDisplay, WL_DISPLAY_READABLE); +} -#ifdef QT_WAYLAND_GL_SUPPORT - mEglDisplay = eglGetDisplay((EGLNativeDisplayType)mNativeEglDisplay); - if (mEglDisplay == NULL) { - qWarning("EGL not available"); - } else { - if (!eglInitialize(mEglDisplay, &major, &minor)) { - qWarning("failed to initialize EGL display"); - return; - } - } -#else - mEglDisplay = 0; -#endif +void QWaylandDisplay::blockingReadEvents() +{ + wl_display_iterate(mDisplay, WL_DISPLAY_READABLE); +} - int fd = wl_display_get_fd(mDisplay, sourceUpdate, this); - mReadNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this); - connect(mReadNotifier, - SIGNAL(activated(int)), this, SLOT(readEvents())); +int QWaylandDisplay::sourceUpdate(uint32_t mask, void *data) +{ + QWaylandDisplay *waylandDisplay = static_cast<QWaylandDisplay *>(data); + waylandDisplay->mSocketMask = mask; - mWriteNotifier = new QSocketNotifier(fd, QSocketNotifier::Write, this); - connect(mWriteNotifier, - SIGNAL(activated(int)), this, SLOT(flushRequests())); - mWriteNotifier->setEnabled(false); + return 0; } -QWaylandDisplay::~QWaylandDisplay(void) +void QWaylandDisplay::outputHandleGeometry(void *data, + struct wl_output *output, + int32_t x, int32_t y, + int32_t width, int32_t height) { - close(mFd); -#ifdef QT_WAYLAND_GL_SUPPORT - eglTerminate(mEglDisplay); -#endif - wl_display_destroy(mDisplay); + //call back function called from another thread; + //but its safe to call createScreen from another thread since + //QWaylandScreen does a moveToThread + QWaylandDisplay *waylandDisplay = static_cast<QWaylandDisplay *>(data); + QRect outputRect = QRect(x, y, width, height); + waylandDisplay->createNewScreen(output,outputRect); } -void QWaylandDisplay::createNewScreen(struct wl_output *output, QRect geometry) +const struct wl_output_listener QWaylandDisplay::outputListener = { + QWaylandDisplay::outputHandleGeometry +}; + +void QWaylandDisplay::waitForScreens() { - QWaylandScreen *waylandScreen = new QWaylandScreen(this,output,geometry); - mScreens.append(waylandScreen); + flushRequests(); + while (mScreens.isEmpty()) + blockingReadEvents(); } -void QWaylandDisplay::syncCallback(wl_display_sync_func_t func, void *data) +void QWaylandDisplay::displayHandleGlobal(struct wl_display *display, + uint32_t id, + const char *interface, + uint32_t version, + void *data) { - wl_display_sync_callback(mDisplay, func, data); + Q_UNUSED(display); + QWaylandDisplay *that = static_cast<QWaylandDisplay *>(data); + that->displayHandleGlobal(id, QByteArray(interface), version); } -void QWaylandDisplay::frameCallback(wl_display_frame_func_t func, void *data) +void QWaylandDisplay::displayHandleGlobal(uint32_t id, + const QByteArray &interface, + uint32_t version) { - wl_display_frame_callback(mDisplay, func, data); + Q_UNUSED(version); + + if (interface == "output") { + struct wl_output *output = wl_output_create(mDisplay, id); + wl_output_add_listener(output, &outputListener, this); + } else 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(mDisplay, id); + mInputDevices.append(inputDevice); + } } |