1 #include "qfontconfigdatabase.h"
3 #include <QImageReader>
4 #include <QWindowSystemInterface>
5 #include <QPlatformCursor>
6 #include <QPaintEngine>
8 #include <QtGui/QPlatformWindowFormat>
10 #include <QtGui/private/qpixmap_raster_p.h>
11 #include <QtGui/QPlatformWindow>
13 #include "qwaylandintegration.h"
14 #include "qwaylandwindowsurface.h"
23 class QWaylandCursor : QPlatformCursor {
25 QWaylandCursor(QWaylandDisplay *display,
26 QPlatformScreen *screen)
27 : QPlatformCursor(screen)
28 , mBuffer(0), mDisplay(display) { }
30 void changeCursor(QCursor *cursor, QWidget *widget);
31 QWaylandShmBuffer *mBuffer;
32 QWaylandDisplay *mDisplay;
35 #define DATADIR "/usr/share"
37 static const struct pointer_image {
39 int hotspot_x, hotspot_y;
40 } pointer_images[] = {
41 /* FIXME: Half of these are wrong... */
43 { DATADIR "/wayland/left_ptr.png", 10, 5 },
44 /* Qt::UpArrowCursor */
45 { DATADIR "/wayland/top_side.png", 18, 8 },
47 { DATADIR "/wayland/top_side.png", 18, 8 },
49 { DATADIR "/wayland/top_side.png", 18, 8 },
51 { DATADIR "/wayland/xterm.png", 15, 15 },
52 /* Qt::SizeVerCursor */
53 { DATADIR "/wayland/top_side.png", 18, 8 },
54 /* Qt::SizeHorCursor */
55 { DATADIR "/wayland/bottom_left_corner.png", 6, 30 },
56 /* Qt::SizeBDiagCursor */
57 { DATADIR "/wayland/bottom_right_corner.png", 28, 28 },
58 /* Qt::SizeFDiagCursor */
59 { DATADIR "/wayland/bottom_side.png", 16, 20 },
60 /* Qt::SizeAllCursor */
61 { DATADIR "/wayland/left_side.png", 10, 20 },
63 { DATADIR "/wayland/right_side.png", 30, 19 },
64 /* Qt::SplitVCursor */
65 { DATADIR "/wayland/sb_v_double_arrow.png", 15, 15 },
66 /* Qt::SplitHCursor */
67 { DATADIR "/wayland/sb_h_double_arrow.png", 15, 15 },
68 /* Qt::PointingHandCursor */
69 { DATADIR "/wayland/hand2.png", 14, 8 },
70 /* Qt::ForbiddenCursor */
71 { DATADIR "/wayland/top_right_corner.png", 26, 8 },
72 /* Qt::WhatsThisCursor */
73 { DATADIR "/wayland/top_right_corner.png", 26, 8 },
75 { DATADIR "/wayland/top_right_corner.png", 26, 8 },
76 /* Qt::OpenHandCursor */
77 { DATADIR "/wayland/hand1.png", 18, 11 },
78 /* Qt::ClosedHandCursor */
79 { DATADIR "/wayland/grabbing.png", 20, 17 },
80 /* Qt::DragCopyCursor */
81 { DATADIR "/wayland/dnd-copy.png", 13, 13 },
82 /* Qt::DragMoveCursor */
83 { DATADIR "/wayland/dnd-move.png", 13, 13 },
84 /* Qt::DragLinkCursor */
85 { DATADIR "/wayland/dnd-link.png", 13, 13 },
88 void QWaylandCursor::changeCursor(QCursor *cursor, QWidget *widget)
90 const struct pointer_image *p;
97 switch (cursor->shape()) {
99 p = &pointer_images[cursor->shape()];
101 case Qt::UpArrowCursor:
102 case Qt::CrossCursor:
105 case Qt::IBeamCursor:
106 p = &pointer_images[cursor->shape()];
108 case Qt::SizeVerCursor: /* 5 */
109 case Qt::SizeHorCursor:
110 case Qt::SizeBDiagCursor:
111 case Qt::SizeFDiagCursor:
112 case Qt::SizeAllCursor:
113 case Qt::BlankCursor: /* 10 */
115 case Qt::SplitVCursor:
116 case Qt::SplitHCursor:
117 case Qt::PointingHandCursor:
118 p = &pointer_images[cursor->shape()];
120 case Qt::ForbiddenCursor:
121 case Qt::WhatsThisCursor: /* 15 */
124 case Qt::OpenHandCursor:
125 case Qt::ClosedHandCursor:
126 case Qt::DragCopyCursor:
127 case Qt::DragMoveCursor: /* 20 */
128 case Qt::DragLinkCursor:
129 p = &pointer_images[cursor->shape()];
133 case Qt::BitmapCursor:
138 p = &pointer_images[0];
139 qWarning("unhandled cursor %d", cursor->shape());
142 QImageReader reader(p->filename);
144 if (mBuffer == NULL || mBuffer->mImage.size() != reader.size()) {
148 mBuffer = new QWaylandShmBuffer(mDisplay, reader.size(),
149 QImage::Format_ARGB32);
152 reader.read(&mBuffer->mImage);
154 mDisplay->setCursor(mBuffer, p->hotspot_x, p->hotspot_y);
157 void QWaylandDisplay::setCursor(QWaylandBuffer *buffer, int32_t x, int32_t y)
159 /* Qt doesn't tell us which input device we should set the cursor
160 * for, so set it for all devices. */
161 for (int i = 0; i < mInputDevices.count(); i++) {
162 QWaylandInputDevice *inputDevice = mInputDevices.at(i);
163 inputDevice->attach(buffer, x, y);
167 struct wl_surface *QWaylandDisplay::createSurface()
169 return wl_compositor_create_surface(mCompositor);
172 struct wl_buffer *QWaylandDisplay::createShmBuffer(int fd,
173 int width, int height,
175 struct wl_visual *visual)
177 return wl_shm_create_buffer(mShm, fd, width, height, stride, visual);
180 struct wl_buffer *QWaylandDisplay::createDrmBuffer(int name,
181 int width, int height,
183 struct wl_visual *visual)
185 return wl_drm_create_buffer(mDrm, name, width, height, stride, visual);
188 struct wl_visual *QWaylandDisplay::rgbVisual()
190 return wl_display_get_rgb_visual(mDisplay);
193 struct wl_visual *QWaylandDisplay::argbVisual()
195 return wl_display_get_argb_visual(mDisplay);
198 struct wl_visual *QWaylandDisplay::argbPremultipliedVisual()
200 return wl_display_get_premultiplied_argb_visual(mDisplay);
203 void QWaylandDisplay::drmHandleDevice(void *data,
204 struct wl_drm *drm, const char *device)
207 QWaylandDisplay *qwd = (QWaylandDisplay *) data;
210 qwd->mDeviceName = strdup(device);
212 qwd->mFd = open(qwd->mDeviceName, O_RDWR);
214 qWarning("drm open failed: %m");
218 if (drmGetMagic(qwd->mFd, &magic)) {
219 qWarning("DRI2: failed to get drm magic");
223 wl_drm_authenticate(qwd->mDrm, magic);
226 void QWaylandDisplay::drmHandleAuthenticated(void *data, struct wl_drm *drm)
229 QWaylandDisplay *qwd = (QWaylandDisplay *) data;
231 const char *extensions;
233 qwd->mEglDisplay = eglGetDRMDisplayMESA(qwd->mFd);
234 if (qwd->mEglDisplay == NULL) {
235 qWarning("failed to create display");
239 if (!eglInitialize(qwd->mEglDisplay, &major, &minor)) {
240 qWarning("failed to initialize display");
241 qwd->mEglDisplay = NULL;
245 extensions = eglQueryString(qwd->mEglDisplay, EGL_EXTENSIONS);
246 if (!strstr(extensions, "EGL_KHR_surfaceless_gles2")) {
247 qWarning("EGL_KHR_surfaceless_opengles2 not available");
248 eglTerminate(qwd->mEglDisplay);
249 qwd->mEglDisplay = NULL;
254 const struct wl_drm_listener QWaylandDisplay::drmListener = {
255 QWaylandDisplay::drmHandleDevice,
256 QWaylandDisplay::drmHandleAuthenticated
259 void QWaylandDisplay::shellHandleConfigure(void *data, struct wl_shell *shell,
260 uint32_t time, uint32_t edges,
261 struct wl_surface *surface,
262 int32_t x, int32_t y,
263 int32_t width, int32_t height)
269 QWaylandWindow *ww = (QWaylandWindow *) wl_surface_get_user_data(surface);
271 ww->configure(time, edges, x, y, width, height);
274 const struct wl_shell_listener QWaylandDisplay::shellListener = {
275 QWaylandDisplay::shellHandleConfigure,
278 void QWaylandDisplay::outputHandleGeometry(void *data,
279 struct wl_output *output,
280 int32_t width, int32_t height)
283 QWaylandDisplay *qwd = (QWaylandDisplay *) data;
284 QWaylandScreen *screen;
286 screen = new QWaylandScreen();
287 screen->mGeometry = QRect(0, 0, width, height);
289 screen->mFormat = QImage::Format_ARGB32_Premultiplied;
290 screen->mOutput = output;
292 new QWaylandCursor(qwd, screen);
294 qwd->mScreens.append(screen);
297 const struct wl_output_listener QWaylandDisplay::outputListener = {
298 QWaylandDisplay::outputHandleGeometry
301 void QWaylandDisplay::displayHandleGlobal(struct wl_display *display,
303 const char *interface,
304 uint32_t version, void *data)
307 QWaylandDisplay *qwd = (QWaylandDisplay *) data;
309 if (strcmp(interface, "compositor") == 0) {
310 qwd->mCompositor = wl_compositor_create(display, id);
311 } else if (strcmp(interface, "drm") == 0) {
312 qwd->mDrm = wl_drm_create(display, id);
313 wl_drm_add_listener(qwd->mDrm, &drmListener, qwd);
314 } else if (strcmp(interface, "shm") == 0) {
315 qwd->mShm = wl_shm_create(display, id);
316 } else if (strcmp(interface, "shell") == 0) {
317 qwd->mShell = wl_shell_create(display, id);
318 wl_shell_add_listener(qwd->mShell, &shellListener, qwd);
319 } else if (strcmp(interface, "output") == 0) {
320 struct wl_output *output = wl_output_create(display, id);
321 wl_output_add_listener(output, &outputListener, qwd);
322 } else if (strcmp(interface, "input_device") == 0) {
323 QWaylandInputDevice *inputDevice =
324 new QWaylandInputDevice(display, id);
325 qwd->mInputDevices.append(inputDevice);
329 static void roundtripCallback(void *data)
331 bool *done = (bool *) data;
336 static void forceRoundtrip(struct wl_display *display)
340 wl_display_sync_callback(display, roundtripCallback, &done);
341 wl_display_iterate(display, WL_DISPLAY_WRITABLE);
344 wl_display_iterate(display, WL_DISPLAY_READABLE);
347 static const char socket_name[] = "\0wayland";
349 void QWaylandDisplay::eventDispatcher(void)
351 wl_display_iterate(mDisplay, WL_DISPLAY_READABLE);
355 QWaylandDisplay::sourceUpdate(uint32_t mask, void *data)
357 QWaylandDisplay *qwd = (QWaylandDisplay *) data;
359 /* FIXME: We get a callback here when we ask wl_display for the
360 * fd, but at that point we don't have the socket notifier as we
361 * need the fd to create that. We'll probably need to split that
362 * API into get_fd and set_update_func functions. */
363 if (qwd->mWriteNotifier == NULL)
366 qwd->mWriteNotifier->setEnabled(mask & WL_DISPLAY_WRITABLE);
371 void QWaylandDisplay::flushRequests(void)
373 wl_display_iterate(mDisplay, WL_DISPLAY_WRITABLE);
376 QWaylandDisplay::QWaylandDisplay(void)
379 mDisplay = wl_display_create(socket_name, sizeof socket_name);
380 if (mDisplay == NULL) {
381 fprintf(stderr, "failed to create display: %m\n");
385 wl_display_add_global_listener(mDisplay,
386 QWaylandDisplay::displayHandleGlobal, this);
388 /* Process connection events. */
389 wl_display_iterate(mDisplay, WL_DISPLAY_READABLE);
390 if (!mShm || !mDeviceName)
391 forceRoundtrip(mDisplay);
393 /* Force a roundtrip to finish the drm authentication so we
394 * initialize EGL before proceeding */
395 forceRoundtrip(mDisplay);
396 if (mEglDisplay == NULL)
397 qDebug("EGL not available");
399 qDebug("EGL initialized");
401 int fd = wl_display_get_fd(mDisplay, sourceUpdate, this);
402 mReadNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
403 connect(mReadNotifier,
404 SIGNAL(activated(int)), this, SLOT(eventDispatcher()));
406 mWriteNotifier = new QSocketNotifier(fd, QSocketNotifier::Write, this);
407 connect(mWriteNotifier,
408 SIGNAL(activated(int)), this, SLOT(flushRequests()));
409 mWriteNotifier->setEnabled(false);
412 QWaylandDisplay::~QWaylandDisplay(void)
415 wl_display_destroy(mDisplay);
418 QWaylandIntegration::QWaylandIntegration(bool useOpenGL)
419 : mFontDb(new QFontconfigDatabase())
420 , mDisplay(new QWaylandDisplay())
421 , mUseOpenGL(useOpenGL)
425 QList<QPlatformScreen *>
426 QWaylandIntegration::screens() const
428 return mDisplay->screens();
431 QPixmapData *QWaylandIntegration::createPixmapData(QPixmapData::PixelType type) const
434 return new QGLPixmapData(type);
435 return new QRasterPixmapData(type);
438 QWaylandWindow::QWaylandWindow(QWidget *window, QWaylandDisplay *display)
439 : QPlatformWindow(window)
450 QWaylandWindow::~QWaylandWindow()
456 WId QWaylandWindow::winId() const
461 void QWaylandWindow::setParent(const QPlatformWindow *parent)
463 QWaylandWindow *wParent = (QWaylandWindow *)parent;
465 mParentWindow = wParent;
468 void QWaylandWindow::setVisible(bool visible)
471 mSurface = mDisplay->createSurface();
472 wl_surface_set_user_data(mSurface, this);
475 wl_surface_destroy(mSurface);
480 void QWaylandWindow::attach(QWaylandBuffer *buffer)
482 QRect geometry = widget()->geometry();
486 wl_surface_attach(mSurface, mBuffer->mBuffer);
487 wl_surface_map(mSurface, geometry.x(), geometry.y(),
488 geometry.width(), geometry.height());
492 void QWaylandWindow::configure(uint32_t time, uint32_t edges,
493 int32_t x, int32_t y,
494 int32_t width, int32_t height)
498 QRect geometry = QRect(x, y, width, height);
500 QWindowSystemInterface::handleGeometryChange(widget(), geometry);
503 QPlatformWindow *QWaylandIntegration::createPlatformWindow(QWidget *widget, WId winId) const
506 return new QWaylandWindow(widget, mDisplay);
509 QWindowSurface *QWaylandIntegration::createWindowSurface(QWidget *widget, WId winId) const
515 return new QWaylandDrmWindowSurface(widget, mDisplay);
516 return new QWaylandShmWindowSurface(widget, mDisplay);
519 QPlatformFontDatabase *QWaylandIntegration::fontDatabase() const